Android学习总结——强制下线功能

KateWyrick 8年前
   <p>强制下线的基本思想就是在界面上弹出一个对话框,让用户必须点击确定按钮跳转到登录界面,这里就有一个问题,通知强制下线时可能处于任何一个界面,我们总不能在每个界面都要实现弹出对话框的逻辑,所以这里可以利用广播来实现。</p>    <p>首先强制下线需要关闭所有活动,然后回到登录界面,所以我们这里创建一个ActivityCollector集合类来管理所有的活动,代码如下:</p>    <pre>  <code class="language-java">package com.example.xch.broadcastpractice;    import android.app.Activity;    import java.util.ArrayList;  import java.util.List;    /**   * Created by xch on 2016/12/15.   */    public class ActivityCollector {      public static List<Activity> activityList=new ArrayList<Activity>();      //将Activity加入集合      public static void addActivity(Activity activity){          activityList.add(activity);      }      //将Activity移除集合      public static void removeActivity(Activity activity){          activityList.remove(activity);      }      //关闭所有Activity      public static void finishAll(){          for(Activity activity:activityList){              if(!activity.isFinishing()){                  activity.finish();              }          }      }  }  </code></pre>    <p>然后创建BaseActivity类作为所有活动的父类:这个类继承自Activity,然后重写onCreate()方法调用ActivityCollector的addActivity()方法将当前正在创建的活动添加到活动管理器中,同理在onDestroy()中移除活动。</p>    <pre>  <code class="language-java">package com.example.xch.broadcastpractice;    import android.app.Activity;  import android.os.Bundle;    /**   * 作为所有活动的父类   * Created by xch on 2016/12/15.   */    public class BaseActivity extends Activity {      @Override      protected void onCreate(Bundle savedInstanceState) {          super.onCreate(savedInstanceState);          ActivityCollector.addActivity(this);//将Activity加入集合      }        @Override      protected void onDestroy() {          super.onDestroy();          ActivityCollector.removeActivity(this);//将Activity从集合移除      }  }  </code></pre>    <p>现在我们就可以随时随地将所有活动移除了。</p>    <p>下面我们模拟一个简单的登录功能,首先创建登录布局:activity_login.xml</p>    <pre>  <code class="language-java"><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"      xmlns:tools="http://schemas.android.com/tools"      android:layout_width="match_parent"      android:layout_height="match_parent"      android:gravity="center_horizontal"      android:orientation="vertical"      android:paddingBottom="@dimen/activity_vertical_margin"      android:paddingLeft="@dimen/activity_horizontal_margin"      android:paddingRight="@dimen/activity_horizontal_margin"      android:paddingTop="@dimen/activity_vertical_margin"      tools:context="com.example.xch.broadcastpractice.LoginActivity">        <!-- Login progress -->      <ProgressBar          android:id="@+id/login_progress"          style="?android:attr/progressBarStyleLarge"          android:layout_width="wrap_content"          android:layout_height="wrap_content"          android:layout_marginBottom="8dp"          android:visibility="gone" />        <ScrollView          android:id="@+id/login_form"          android:layout_width="match_parent"          android:layout_height="match_parent">            <LinearLayout              android:id="@+id/email_login_form"              android:layout_width="match_parent"              android:layout_height="wrap_content"              android:orientation="vertical">                <android.support.design.widget.TextInputLayout                  android:layout_width="match_parent"                  android:layout_height="wrap_content">                    <AutoCompleteTextView                      android:id="@+id/username"                      android:layout_width="match_parent"                      android:layout_height="wrap_content"                      android:hint="@string/prompt_email"                      android:inputType="textEmailAddress"                      android:maxLines="1"                      android:singleLine="true" />                </android.support.design.widget.TextInputLayout>                <android.support.design.widget.TextInputLayout                  android:layout_width="match_parent"                  android:layout_height="wrap_content">                    <EditText                      android:id="@+id/password"                      android:layout_width="match_parent"                      android:layout_height="wrap_content"                      android:hint="@string/prompt_password"                      android:imeActionId="@+id/login"                      android:imeActionLabel="@string/action_sign_in_short"                      android:imeOptions="actionUnspecified"                      android:inputType="textPassword"                      android:maxLines="1"                      android:singleLine="true" />                </android.support.design.widget.TextInputLayout>                <Button                  android:id="@+id/login"                  style="?android:textAppearanceSmall"                  android:layout_width="match_parent"                  android:layout_height="wrap_content"                  android:layout_marginTop="16dp"                  android:text="@string/action_sign_in"                  android:textStyle="bold" />            </LinearLayout>      </ScrollView>  </LinearLayout>  </code></pre>    <p>接下来编写登录界面的活动,新建LoginActivity继承自BaseActivity,代码如下:</p>    <pre>  <code class="language-java">package com.example.xch.broadcastpractice;    import android.content.Intent;  import android.os.Bundle;  import android.view.View;  import android.widget.Button;  import android.widget.EditText;  import android.widget.TextView;  import android.widget.Toast;    /**   * Created by xch on 2016/12/15.   */    public class LoginActivity extends BaseActivity {      private TextView usename;      private EditText password;      private Button login;      @Override      protected void onCreate(Bundle savedInstanceState) {          super.onCreate(savedInstanceState);          setContentView(R.layout.activity_login);          usename= (TextView) findViewById(R.id.username);          password= (EditText) findViewById(R.id.password);          login= (Button) findViewById(R.id.login);          login.setOnClickListener(new View.OnClickListener() {              @Override              public void onClick(View v) {                  String account=usename.getText().toString();                  String pwd=password.getText().toString();                  if(account.equals("xch_yang@126.com")&&pwd.equals("123456")){                      Intent intent=new Intent(LoginActivity.this,MainActivity.class);                      startActivity(intent);                      finish();                  }else{                      Toast.makeText(LoginActivity.this,"用户名或密码错误!",Toast.LENGTH_SHORT).show();                  }              }          });      }  }  </code></pre>    <p>这里直接使用一个默认值,如果登录成功就跳到MainActivity,否则就登录失败。所以我们在MainActivity中添加强制下线的功能。activity_main:</p>    <pre>  <code class="language-java"><?xml version="1.0" encoding="utf-8"?>  <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"      xmlns:tools="http://schemas.android.com/tools"      android:id="@+id/activity_main"      android:layout_width="match_parent"      android:layout_height="match_parent"      android:paddingBottom="@dimen/activity_vertical_margin"      android:paddingLeft="@dimen/activity_horizontal_margin"      android:paddingRight="@dimen/activity_horizontal_margin"      android:paddingTop="@dimen/activity_vertical_margin"      tools:context="com.example.xch.broadcastpractice.MainActivity">        <TextView          android:text="恭喜你,登录成功!"          android:layout_width="wrap_content"          android:layout_height="wrap_content"          android:layout_marginLeft="119dp"          android:layout_marginStart="119dp"          android:layout_marginTop="15dp"          android:id="@+id/textView"          android:layout_alignParentTop="true"          android:layout_alignParentLeft="true"          android:layout_alignParentStart="true" />        <Button          android:text="强制下线"          android:layout_width="wrap_content"          android:layout_height="wrap_content"          android:layout_marginTop="35dp"          android:id="@+id/force_offline"          android:layout_below="@+id/textView"          android:layout_alignParentLeft="true"          android:layout_alignParentStart="true"          android:layout_marginLeft="105dp"          android:layout_marginStart="105dp" />  </RelativeLayout>  </code></pre>    <p>MainActivity.class:</p>    <pre>  <code class="language-java">package com.example.xch.broadcastpractice;    import android.content.Intent;  import android.support.v7.app.AppCompatActivity;  import android.os.Bundle;  import android.view.View;  import android.widget.Button;    public class MainActivity extends BaseActivity {      private Button force_offline;        @Override      protected void onCreate(Bundle savedInstanceState) {          super.onCreate(savedInstanceState);          setContentView(R.layout.activity_main);          force_offline=(Button) findViewById(R.id.force_offline);          force_offline.setOnClickListener(new View.OnClickListener() {              @Override              public void onClick(View v) {                  Intent intent=new Intent("com.example.FORCE_OFFLINE");//发送广播,在广播接收器里实现强制下线的逻辑                  sendBroadcast(intent);              }          });      }  }  </code></pre>    <p>这里很简单,就是在按钮事件里发送了一条广播,然后在广播接收器里实现强制下线的逻辑。接下来创建广播接收器ForceOfflineReceiver继承自Broadcast。</p>    <pre>  <code class="language-java">package com.example.xch.broadcastpractice;    import android.app.AlertDialog;  import android.content.BroadcastReceiver;  import android.content.Context;  import android.content.DialogInterface;  import android.content.Intent;  import android.view.WindowManager;    /**   * Created by xch on 2016/12/15.   */    public class ForceOfflineReceiver extends BroadcastReceiver {      @Override      public void onReceive(final Context context, Intent intent) {          //实现强制下线的逻辑          AlertDialog.Builder dialogBuilder=new AlertDialog.Builder(context);//使用AlertDialog.Builder构建一个对话框          dialogBuilder.setTitle("warning");          dialogBuilder.setMessage("你已经被强制下线,请重新登录");          dialogBuilder.setCancelable(false);//将对话框设置为不可取消          dialogBuilder.setPositiveButton("确定", new DialogInterface.OnClickListener() {              @Override              public void onClick(DialogInterface dialog, int which) {                  ActivityCollector.finishAll(); //销毁所有活动                  Intent intent=new Intent(context,LoginActivity.class);                  intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);                  context.startActivity(intent); //重新启动登录界面              }          });          AlertDialog alertDialog=dialogBuilder.create();          //设置AlertDialog类型,保证在广播接收器中可以正常弹出          alertDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);          alertDialog.show();      }  }  </code></pre>    <p>这里要注意的是,由于我们是在广播中启动活动LoginActivity,因此一定要给Intent加上FLAG_ACTIVITY_NEW_TASK标志。最后还要把对话框的类型设置成TYPE_SYSTEM_ALERT,不然它将无法在广播接受器中弹出。</p>    <p>接下来对AndroidManifest.xml进行配置:</p>    <pre>  <code class="language-java"><?xml version="1.0" encoding="utf-8"?>  <manifest xmlns:android="http://schemas.android.com/apk/res/android"      package="com.example.xch.broadcastpractice">        <!-- To auto-complete the email text field in the login form with the user's emails -->      <uses-permission android:name="android.permission.GET_ACCOUNTS" />      <uses-permission android:name="android.permission.READ_PROFILE" />      <uses-permission android:name="android.permission.READ_CONTACTS" />        <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>        <application          android:allowBackup="true"          android:icon="@mipmap/ic_launcher"          android:label="@string/app_name"          android:supportsRtl="true"          android:theme="@style/AppTheme">          <activity android:name=".LoginActivity">              <intent-filter>                  <action android:name="android.intent.action.MAIN" />                    <category android:name="android.intent.category.LAUNCHER" />              </intent-filter>          </activity>          <activity android:name=".MainActivity"></activity>          <receiver android:name=".ForceOfflineReceiver">              <intent-filter>                  <action android:name="com.example.FORCE_OFFLINE"/>              </intent-filter>          </receiver>      </application>    </manifest>  </code></pre>    <p>由于我们在广播接收器里弹出了一个系统级别的对话框,因此要声明权限:android.permission.SYSTEM_ALERT_WINDOW,最后别忘了注册广播ForceOfflineReceiver和活动LoginActivity。</p>    <p>运行程序,进入登录界面:</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/05e4b7f9e3c0ef6f9d211a1b5daa246f.png"></p>    <p>成功登录之后进入程序主界面:</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/8a9dd104563df1335252794d769a51a1.png"></p>    <p>点击强制下线按钮,就会发出一条强制下线的广播,广播接受器接收广播之后就会弹出提示框,用户点击确定之后就会重新回到登录界面:</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/cacbdd6107c64e975275483ca596c44f.png"></p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/36eaff2c0d092e9ab0194b33d1d36143.png"></p>    <p> </p>    <p>来自:http://www.cnblogs.com/xch-yang/p/6182848.html</p>    <p> </p>