使用广播实现QQ强制下线功能

实现强制下线功能的原理其实并不是很难,在界面上弹出一个对话框,让用户无法进行操作,其实我们只需要在界面中添加一个按钮,点击后让按钮发出一条强制下线的广播(如图)

首先新建一个BroadcastBestPractice项目

做一个登录界面activity_login与实现页面activity_main:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:background="@mipmap/qq"
    >
    <ImageView
        android:id="@+id/I1"
        android:layout_width="70dp"
        android:layout_height="70dp"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="40dp"
        android:background="@mipmap/ic_launcher"/>
    <LinearLayout
        android:id="@+id/ll_number"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@+id/I1"
        android:layout_centerVertical="true"
        android:layout_marginBottom="5dp"
        android:layout_marginLeft="10dp"
        android:layout_marginRight="10dp"
        android:layout_marginTop="15dp"
        android:background="#ffffff">
        <TextView
            android:id="@+id/tv_1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="账号:"
            android:padding="10dp"
            android:textColor="#100"
            android:textSize="18sp"/>
        <EditText
            android:id="@+id/E1"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginLeft="5dp"
            android:background="@null"
            android:hint="请输入admin"
            android:textSize="10dp"/>
    </LinearLayout>
    <LinearLayout
        android:id="@+id/ll_password"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@+id/ll_number"
        android:layout_centerVertical="true"
        android:layout_marginBottom="5dp"
        android:layout_marginLeft="10dp"
        android:layout_marginRight="10dp"
        android:background="#ffffff">
        <TextView
            android:id="@+id/tv_2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="密码:"
            android:padding="10dp"
            android:textColor="#100"
            android:textSize="18sp"/>
        <EditText
            android:id="@+id/E2"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginLeft="5dp"
            android:background="@null"
            android:inputType="numberPassword"
            android:hint="请输入123456"
            android:textSize="10dp"/>
    </LinearLayout>
    <Button
        android:id="@+id/b1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@id/ll_password"
        android:layout_marginLeft="10dp"
        android:layout_marginRight="10dp"
        android:layout_marginTop="50dp"
        android:background="#3C8DC4"
        android:text="登录"
        android:textColor="#ffffff"
        android:textSize="20sp"
        />
</RelativeLayout>
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.example.arturia.broadcastbestpractice.MainActivity">
<Button
    android:id="@+id/b2"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="强制下线?试试"/>

</android.support.constraint.ConstraintLayout>

实现页面只有一个button

这里的代码我们就不再解释了,效果如下

 所谓强制下线其实就是关闭当前所有活动,然后重返登录页面。

我们先创建一个专门的集合类作为管理活动类ActivityCollector:

public class ActivityCollector {
    public static List<Activity> activities=new ArrayList<>();
    public static void addActivity(Activity activity)
    {
        activities.add(activity);
    }
    public  static void removeActivity(Activity activity)
    {
        activities.remove(activity);
    }
    public static void  finishAll(){
        for(Activity e:activities)
        {
            if(!e.isFinishing()){
                e.finish();
            }
        }
    }

}

List集合用来暂存活动,addActivity()方法用来向list中添加活动,removeActivity()方法用于向List中移除活动,finishAll()方法用于将List中储存的活动全部销毁掉。

创建一个baseActivity类作为所有活动的父类

public class BaseActivity extends AppCompatActivity{
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        ActivityCollector.addActivity(this);
    }
    protected void onDistory()
    {
        super.onDestroy();
        ActivityCollector.removeActivity(this);
    }
}

后面我们的大部分代码在这个里面编写

修改LoginActivity中的代码,模拟登陆系统

public class LoginActivity extends AppCompatActivity {

    private EditText editText;
    private EditText editText2;
    private Button button1;
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_login);
        editText=(EditText)findViewById(R.id.E1);
        editText2=(EditText)findViewById(R.id.E2);
        button1=(Button)findViewById(R.id.b1);
        button1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                String account=editText.getText().toString();
                String password=editText2.getText().toString();
                if(account.equals("admain")&&password.equals("123456"))
                {
                    Intent intent=new Intent(LoginActivity.this,MainActivity.class);
                    startActivity(intent);
                    finish();
                }else {
                    Toast.makeText(LoginActivity.this,"密码或用户名输入错误",Toast.LENGTH_SHORT).show();
                }
            }
        });
    }
}

这里我们设置账号是“admin”,密码为“123456”,若输入正确则登录成功进入主页面activity_main,若输入错误,则弹出一个Toast,提示用户输入信息有误。

编写activity_main中代码,并编写Mainactivity

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.example.arturia.broadcastbestpractice.MainActivity">
<Button
    android:id="@+id/b2"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="点击实现强制下线"/>

</android.support.constraint.ConstraintLayout>

我们像其中添加了一个按钮,并在其点击事件中发送了一条广播,广播的值为:com.example.arturia.broadcastbestpractice.MainActivity,这条广播用于通知用户强制下线。因此可以说明广播下线的逻辑不是写在MainActivity里的,而是应该写在接收这条广播的广播接收器里面的。

所以我们接下来就创建一个广播接收器来接受这条强制下线广播。我们在BaseActivity中动态注册一个广播接收器

关于动态注册广播接收器,前面的帖子有讲到

下面是具体实现

public class BaseActivity extends AppCompatActivity{
    private  ForceOfflineReceiver receiver;
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        ActivityCollector.addActivity(this);
    }
    protected void onResume()
    {
        super.onResume();
        IntentFilter intentFilter=new IntentFilter();
        intentFilter.addAction("com.example.broadcastBestpractist.EORCE_OFFLINE");
        receiver=new ForceOfflineReceiver();
        registerReceiver(receiver,intentFilter);
    }
    protected void onPause()
    {
        super.onPause();
        if(receiver!=null)
        {
            unregisterReceiver(receiver);
            receiver=null;
        }
    }

    protected void onDistory()
    {
        super.onDestroy();
        ActivityCollector.removeActivity(this);
    }

    private class ForceOfflineReceiver extends BroadcastReceiver{
        @Override
        public void onReceive(final Context context, Intent intent) {
            AlertDialog.Builder dialog=new AlertDialog.Builder(context);
            dialog.setTitle("Error");
            dialog.setMessage("您的信息在另一个设备上登录,程序回到登录界面");
            dialog.setCancelable(false);
            dialog.setPositiveButton("OK", new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    ActivityCollector.finishAll();
                    Intent intent=new Intent(context,LoginActivity.class);
                    context.startActivity(intent);
                }
            });
            dialog.show();
        }
    }
}

和之前类似定义一个内部类ForeceOfflineReceiver,不同的是onReceive()中弹出的不再是Toast,而是一个对话框,因为要退出程序,当用户点击“OK”按钮,就会调用finishAll()将活动销毁,然后重新启动LoginActivity活动

我们注册广播接收器的时候重写了onResume()与onPause()两个生命函数,然后再里面注册与取消了ForeceOfflineReceiver。

我们之前用的都是onCreate()方法与OnDistory()方法,但这次为何要写在这里面呢?

这是因为我们只需要在栈顶的活动接收这条广播,非栈顶的活动并不需要去接收这条广播,因此这里用这两个方法这个问题就会得以解决。当一个活动不再是栈顶时就会自动取消广播接收器的注册了。。。

最后将主活动设置成LoginActivity的登录界面就ok啦!

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.arturia.broadcastbestpractice">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">

        </activity>
        <activity android:name=".LoginActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

修改代码将<intent-filter>移到.LoginACtivity中即可

我们的强制下线功能就做好了,预览如下

感谢支持@.@

猜你喜欢

转载自blog.csdn.net/M_Edison/article/details/82749404