Android开发入门教程

Android开发学习 -- Day12 广播实践 -- 强制下

2018-03-26  本文已影响10人  h080294

关于广播的简单实用,相信我们已经通过上面的学习掌握了。今天来进行实践操作,写一个具备强制下线的功能的demo。

关于强制下线功能,我们一定不会感到陌生,例如当我们在别处登陆同一账号时,当前的账号就会被强制挤下线。实现的思路也不难,就是在任意一个界面,弹出一个不可取消的对话框,必须要点击对话框中的确定按钮才行,点击确定后回到登陆页面。

强制下线功能要去我们关掉所有Activity,并回到登陆Activity。我们在最早学习Activity的时候,曾经在添加过类似的管理Activity功能,让我们回顾一下,创建一个ActivityCollector类,然后在BaseActivity中盗用添加和删除操作。

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 activity : activities){
            if (!activity.isFinishing()){
                activity.finish();
            }
        }
    }
}

public class BaseActivity extends AppCompatActivity{

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.d("BaseAvtivity", getClass().getSimpleName());
        ActivityCollector.addActivity(this);
    }

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

我们直接使用现成的代码就可以了,接下来创建一个登陆的界面LoginActivity,修改布局文件。关于布局的部分就不再讲解了,都是我们之前熟悉的和用过的控件:

<LinearLayout 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:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.johnhao.listviewdemo.activity.LoginActivity">

    <LinearLayout
        android:orientation="horizontal"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <TextView
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="用户名"
            android:textSize="20sp"/>

        <EditText
            android:id="@+id/edit_name"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="3"
            android:hint="用户名试试 tester"
            android:textSize="18sp"
            android:maxLength="20"/>

    </LinearLayout>


    <LinearLayout
        android:orientation="horizontal"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <TextView
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="密 码"
            android:textSize="20sp"/>

        <EditText
            android:id="@+id/edit_password"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="3"
            android:hint="登陆密码试试 123456"
            android:textSize="18sp"
            android:maxLength="20"/>

    </LinearLayout>

    <Button
        android:id="@+id/btn_login"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="right"
        android:layout_marginRight="10dp"
        android:background="#ffff00"
        android:text="Login"
        android:textAllCaps="false"
        android:textColor="#000000"/>

    <ImageView
        android:src="@drawable/qrcode"
        android:layout_gravity="center"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="30dp"/>

</LinearLayout>

修改LoginActivity代码:

public class LoginActivity extends BaseActivity {

    private Button btn;
    private EditText editUserName;
    private EditText editserPassword;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_login);
        setTitle("登陆");
        btn = findViewById(R.id.btn_login);
        editUserName = findViewById(R.id.edit_name);
        editserPassword = findViewById(R.id.edit_password);

        btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                String userName = editUserName.getText().toString();
                String userPassword = editserPassword.getText().toString();

                if (userName.equals("tester") && userPassword.equals("123456")) {
                    // 登陆成功
                    Intent intent = new Intent(LoginActivity.this, AfterLoginActivity.class);
                    startActivity(intent);
                    finish();
                } else if (userName.equals("") || userPassword.equals("")) {
                    // 用户名或密码为空
                    Toast.makeText(LoginActivity.this, "请输入用户名或者密码", Toast.LENGTH_SHORT).show();
                } else {
                    // 用户名或密码不符合
                    Toast.makeText(LoginActivity.this, "请输入正确的用户名和密码", Toast.LENGTH_SHORT).show();
                    editUserName.setText("");
                    editserPassword.setText("");
                }
            }
        });
    }
}

这里我们模拟了登陆的功能,让LoginActivity继承自BaseActivity,通过getText()方法获得用户输入的用户名和密码,并进行了一个简单的验证,当用户名为tester密码为123456时,成功登录到AfterLoginActivity,否则弹对应的Toast提示。

AfterLoginActivity我们暂时不用设置太多东西,一个TextView和一个用来强制下线的Button就够了。

<LinearLayout 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:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.johnhao.listviewdemo.activity.AfterLoginActivity">

    <TextView
        android:text="哈哈,居然登陆成功了"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="20dp"
        android:layout_gravity="center"/>

    <Button
        android:id="@+id/btn_offline"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="强制下线"
        android:layout_gravity="center"
        android:layout_marginTop="30dp"
        android:textColor="#ff3300"/>

</LinearLayout>

修改AfterLoginActivity代码:

public class AfterLoginActivity extends BaseActivity {

    private Button btn_offline;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_after_login);
        setTitle("登陆后的页面");
        btn_offline = findViewById(R.id.btn_offline);

        btn_offline.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Log.d("btn_offline", "onClick: ");
                Intent intent = new Intent("com.johnhao.listviewdemo.FORCE_OFFLINE");
                sendBroadcast(intent);
            }
        });
    }
}

我们给Button设置一个点击事件,点击Button后,就会发一个com.johnhao.listviewdemo.FORCE_OFFLINE的广播。接下来我们就要写强制下线的广播接收器了。那么我们应该在哪里创建这个接收器呢?首先,我们需要在接收这条广播是弹出一个阻塞式的对话框,这样就不能使用静态注册的方式来注册广播;另外,由于该弹窗要求在任何界面上都能弹出,所以我们又不能在每一个Activity内都注册一个动态的广播接收器。所以,最佳的方案是在BaseActivity中动态注册一个广播接收器,因为所有的Activity都继承自BaseActivity。

public class BaseActivity extends AppCompatActivity{

    private OfflineBroadcastReceiver offlineBroadcastReceiver;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.d("BaseAvtivity", getClass().getSimpleName());
        ActivityCollector.addActivity(this);
    }

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

    class OfflineBroadcastReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(final Context context, Intent intent) {
            Log.d("Offline", "onReceive: ");
            AlertDialog.Builder dialog = new AlertDialog.Builder(context);
            dialog.setTitle("警告");
            dialog.setMessage("账号在美国洛杉矶地区另一台设备上登陆,您已被强制下线。如果非本人操作,请尽快修改登陆密码");
            dialog.setCancelable(false);
            dialog.setPositiveButton("确定", new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    ActivityCollector.finishAll();
                    Intent intent = new Intent(context, LoginActivity.class);
                    startActivity(intent);
                }
            });
            dialog.show();
        }
    }

    @Override
    protected void onResume() {
        super.onResume();
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction("com.johnhao.listviewdemo.FORCE_OFFLINE");
        offlineBroadcastReceiver = new OfflineBroadcastReceiver();
        registerReceiver(offlineBroadcastReceiver, intentFilter);
    }

    @Override
    protected void onPause() {
        super.onPause();
        if (offlineBroadcastReceiver != null) {
            unregisterReceiver(offlineBroadcastReceiver);
            offlineBroadcastReceiver = null;
        }
    }
}

我们创建了一个内部类OfflineBroadcastReceiver,并继承自BroadcastReceiver,然后在onReceive()方法中,弹出了一个标准的对话框。关于对话框,我们在学习基本控件的时候已经了解过了,这里调用了setCancelable(false)方法来指定对话框不可取消,只能点击确定按钮。在确定按钮的点击事件中,我们调用了ActivityCollector管理类中的finishAll()方法来结束销毁的Activity,并重启LoginActivity。

对于OfflineBroadcastReceiver,我们是在onResume()方法中来注册的,并且在onPause()中取消注册。这是因为,我们只需要在栈顶的Activity能接收到这条强制下线的广播即可,非栈顶的Activity没有必要接收到它,所以动态注册和取消的逻辑写在了onResume()和onPause()中。

例子很简单,重新运行下程序:


关注获取更多
上一篇 下一篇

猜你喜欢

热点阅读