Android

01: Android Studio目录结构介绍, 安卓开发入门
02: Android中的日志工具类Log详细介绍
03: 添加Button元素, 并且在活动中使用Toast和Menu
04: 安卓开发之Intent使用介绍(显式Intent和隐式Intent)
05: 安卓广播机制讲解(标准广播和有序广播)
06: 安卓广播实现强制下线功能(Kotlin语言实现)


1. 广播的最佳实践:实现强制下线功能

新建一个BroadcastBestPractice项目,然后开始动手吧。

(广播知识补充)

强制下线功能需要先关闭掉所有的活动,
然后回到登录界面。
先创建一个ActivityCollector类用于管理所有的活动,代码如下所示:
object ActivityCollector {
    private val activities = ArrayList<Activity>()
    fun addActivity(activity: Activity) {
        activities.add(activity)
    }

    fun removeActivity(activity: Activity) {
        activities.remove(activity)
    }

    fun finishAll() {
        for (activity in activities) {
            if (!activity.isFinishing) {
                activity.finish()
            }
        }
        activities.clear()
    }
}
然后创建BaseActivity类作为所有Activity的父类:
open class BaseActivity : AppCompatActivity() {
    //    创建一个新的活动时, 就把这个活动交给ActivityCollector进行管理
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        ActivityCollector.addActivity(this)
    }

    //     销毁一个活动时,  把这个活动从ActivityCollector中移除
    override fun onDestroy() {
        super.onDestroy()
        ActivityCollector.removeActivity(this)
    }
}
接下来我们创建一个LoginActivity作为登录界面,
并让AndroidStudio帮我们自动生成布局文件,
接下来我们编辑activity_login.xml,代码如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:orientation="vertical"
              android:layout_width="match_parent"
              android:layout_height="match_parent">

    <LinearLayout
            android:orientation="horizontal"
            android:layout_width="match_parent"
            android:layout_height="60dp">
        <TextView
                android:layout_width="90dp"
                android:layout_height="wrap_content"
                android:layout_gravity="center_vertical"
                android:textSize="18sp"
                android:text="Account:" />

        <EditText
                android:id="@+id/accountEdit"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:layout_gravity="center_vertical" />
    </LinearLayout>

    <LinearLayout
            android:orientation="horizontal"
            android:layout_width="match_parent"
            android:layout_height="60dp">
        <TextView
                android:layout_width="90dp"
                android:layout_height="wrap_content"
                android:layout_gravity="center_vertical"
                android:textSize="18sp"
                android:text="Password:" />

        <EditText
                android:id="@+id/passwordEdit"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:layout_gravity="center_vertical"
                android:inputType="textPassword" />
    </LinearLayout>

    <Button
            android:id="@+id/login"
            android:layout_width="200dp"
            android:layout_height="60dp"
            android:layout_gravity="center_horizontal"
            android:text="Login" />

</LinearLayout>

展示效果:
在这里插入图片描述

这里我们使用LinearLayout编写出了一个登录布局,
最外层是一个纵向的LinearLayout,里面包含了3行直接子元素。
第一行是一个横向LinearLayout,用于输人账号信息﹔
第二行也是一个横向的LinearLayout,用于输人密码信息
﹔第三行是一个登录按钮。

接下来我们修改LoginActivity里面的代码:

class LoginActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_login)
        login.setOnClickListener {
            val account = accountEdit.text.toString()
            val password = passwordEdit.text.toString()
//            如果账号是123456 密码是admin就登录成功
            if (account == "admin" && password == "123456") {
                val intent = Intent(this, MainActivity::class.java)
                startActivity(intent)
                finish()
            } else {
                Toast.makeText(
                    this, "account or password is invalid",
                    Toast.LENGTH_LONG
                ).show()
            }
        }
    }
}
这里我们模拟了一个非常简单的登录功能。
如果账号是admin,密码是123456,就认为登录成功并跳转到MainActivity,
否则就提示用户账号或密码错误。
因此,你就可以将MainActivity理解成是登录成功后进入的程序主界面了.

这里我们并不需要在主界面里提供什么花哨的功能,
只需要加人强制下线功能就可以了,
修改 activity_main.xml中的代码,如下所示:
<?xml version="1.0" encoding="utf-8"?>
<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:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <Button
        android:id="@+id/forceOffline"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Send force offline broadcast" />

</LinearLayout>
非常简单,只有一个按钮而已,用于触发强制下线功能。
然后修改MainActivity中的代码,如下所示:
class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        forceOffline.setOnClickListener {
            val intent=Intent("com.example.broadcastbestpractice.FORCE_OFFLINE")
            startActivity(intent)
        }
    }
}
同样非常简单,不过这里有个重点,我们在按钮的点击事件里面发送了一条广播,
广播的值为com.example.broadcastbestpractice.FORCE_OFFLINE,
这条广播就是用于通知程序强制用户下线的。
也就是说强制用户下线的逻辑并不是写在 MainActivity里的,
而是应该写在接收这条广播的广播接收器里面,
这样强制下线的功能就不会依附于任何的界面,不管是在程序的任何地方,
只需要发出这样一条广播,就可以完成强制下线的操作了。

那么毫无疑问,接下来我们就需要创建一个广播接收器来接收这条强制下线广播,

只需要在BaseActivity中动态注册一个广播接收器就可以了,
因为所有的活动都是继承自BaseActivity的。

修改BaseActivity 中的代码,如下所示:

package com.example.broadcastbestpractice

import android.app.AlertDialog
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity

open class BaseActivity : AppCompatActivity() {

    lateinit var receiver: ForceOfflineReceiver
 //    创建一个新的活动时, 就把这个活动交给ActivityCollector进行管理
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        ActivityCollector.addActivity(this)
    }

    override fun onResume() {
        super.onResume()
        val intentFilter = IntentFilter()
        intentFilter.addAction("com.example.broadcastbestpractice.FORCE_OFFLINE")
        receiver = ForceOfflineReceiver()
        registerReceiver(receiver, intentFilter)
    }

    override fun onPause() {
        super.onPause()
        unregisterReceiver(receiver)
    }
 //     销毁一个活动时,  把这个活动从ActivityCollector中移除
    override fun onDestroy() {
        super.onDestroy()
        ActivityCollector.removeActivity(this)
    }

    inner class ForceOfflineReceiver : BroadcastReceiver() {

        override fun onReceive(context: Context, intent: Intent) {
            AlertDialog.Builder(context).apply {
                setTitle("Warning")
                setMessage("You are forced to be offline. Please try to login again.")
                setCancelable(false)
                setPositiveButton("OK") { _, _ ->
                    ActivityCollector.finishAll() // 销毁所有Activity
                    val i = Intent(context, LoginActivity::class.java)
                    context.startActivity(i) // 重新启动LoginActivity
                }
                show()
            }
        }
    }
}
AlertDialog.Builder用来构建一个对话框,注意这里一定要调用setCancelable()
方法将对话框设为不可取消,
否则用户按一下Back键就可以关闭对话框继续使用程序了。
然后使用setPositiveButton()方法来给对话框注册确定按钮,
当用户点击了确定按钮时,
就调用ActivityCollector的 finishAll()方法来销毁掉所有活动,
并重新启动LoginActivity这个活动。

最后我们来修改AndroidManifest.xml:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.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/Theme.BroadcastBestPractice">
        <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>
    </application>

</manifest>
代码解释:
这里只需要对一处代码进行修改,
就是将主活动设置为LoginActivity而不再是MainActivity,
因为你肯定不希望用户在没登录的情况下就能直接进入到程序主界面吧?

在这里插入图片描述

接下来我们就可以运行程序了:
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述



Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐