日本免费高清视频-国产福利视频导航-黄色在线播放国产-天天操天天操天天操天天操|www.shdianci.com

學無先后,達者為師

網站首頁 編程語言 正文

Android廣播機制原理與開發_Android

作者:Godams ? 更新時間: 2023-06-03 編程語言

廣播機制簡介

  • 標準廣播:完全異步執行,廣播發出后,所有廣播接收器幾乎都同一時刻收到這條廣播(無法被截斷)
  • 有序廣播:同步執行,廣播發出后同一時刻只會有一個廣播接收器能收到這條廣播消息,前面的接收器可以截斷正在傳遞的廣播

接收系統廣播

廣播接收器可在代碼中注冊和AndroidManifest.xml中注冊,前者為動態注冊,后者被稱為靜態注冊。

動態注冊監聽網絡變化

示例代碼:

public class MainActivity extends AppCompatActivity {
    private IntentFilter intentFilter;
    private NetworkChangeReceiver networkChangeReceiver;
    @Override
    protected void onCreate(Bundle savedInstanceState){
        super.onCreate(savedInstanceState);
        setContentView((R.layout.activity_main));
        intentFilter= new IntentFilter();
        intentFilter.addAction("android.net.conn.CONNECTIVITY_VHANGE");
        networkChangeReceiver = new NetworkChangeReceiver();
        registerReceiver(networkChangeReceiver, intentFilter);
    }
    @Override
    protected void onDestroy(){
        super.onDestroy();
        unregisterReceiver(networkChangeReceiver);
    }
    class NetworkChangeReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent){
            ConnectivityManager connectionManager = (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE);
            NetworkInfo networkInfo = connectionManager.getActiveNetworkInfo();
            if(networkInfo != null && networkInfo.isAvailable()){
                Toast.makeText(context, "network is available", Toast.LENGTH_SHORT).show();
            }else {
                Toast.makeText(context, "network is unavailable", Toast.LENGTH_SHORT).show();
            }
            Toast.makeText(context, "network changes", Toast.LENGTH_SHORT).show();
        }
    }
}

靜態注冊實現開機啟動

<receiver
            android:name=".BootCompleteReceiver"
            android:enabled="true"
            android:exported="true"></receiver>

Export屬性表示是否允許這個廣播接收器接收本程序以外的廣播,enable表示是否使用這個廣播接收器。

<receiver
            android:name=".BootCompleteReceiver"
            android:enabled="true"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED"/>
            </intent-filter>
        </receiver>

添加了filter就可以過濾了

可以通過左鍵新建-》其它來新建靜態注冊廣播

廣播接收器中不允許開線程,當onReceive方法運行較長時間而沒結束時,程序就會報錯,所以其中不能添加過多的邏輯或任何耗時操作。

發送自定義廣播

發送標準廣播

@Override
    protected void onCreate(Bundle savedInstanceState){
        super.onCreate(savedInstanceState);
        setContentView((R.layout.activity_main));
        Button button = (Button)findViewById(R.id.button);
        button.setOnClickListener(new View.OnClickListener(){
            @Override
            public void onClick(View v){
                Intent intent = new Intent("com.example.broadcasttest.MY_BROADCAST");
                sendBroadcast(intent);
            }
        });
    }

通過點擊按鈕發送廣播

public class myBroadcastReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        Toast.makeText(context, "receiverd in myBroadcastReceiver", Toast.LENGTH_SHORT).show();
    }
}

這里是自定義的接收器

<receiver
            android:name=".myBroadcastReceiver"
            android:enabled="true"
            android:exported="true">
            <intent-filter>
                <action android:name="com.example.broadcasttest.MY_BROADCAST"/>
            </intent-filter>
        </receiver>

在xml中定義過濾的廣播類型

發送有序廣播

廣播是一種跨進程的通信方式

protected void onCreate(Bundle savedInstanceState){
        super.onCreate(savedInstanceState);
        setContentView((R.layout.activity_main));
        Button button = (Button)findViewById(R.id.button);
        button.setOnClickListener(new View.OnClickListener(){
            @Override
            public void onClick(View v){
                Intent intent = new Intent("com.example.broadcasttest.MY_BROADCAST");
                sendOrderedBroadcast(intent, null);
            }
        });
    }

只需要修改一行代碼 sendOrederedBroadcast即可發送有序廣播,同時在接收器的xml文件中可以設置優先級

<receiver
            android:name=".myBroadcastReceiver"
            android:enabled="true"
            android:exported="true">
<!--            在這里設置優先級-->
            <intent-filter android:priority="100">
                <action android:name="com.example.broadcasttest.MY_BROADCAST"/>
            </intent-filter>
        </receiver>

如果想要在接收到廣播之后就讓廣播停止繼續傳遞呢,修改onReceive的代碼即可

public void onReceive(Context context, Intent intent) {
        Toast.makeText(context, "receiverd in myBroadcastReceiver", Toast.LENGTH_SHORT).show();
//        停止繼續傳遞
        abortBroadcast();
    }

使用本地廣播

前面我們發送和接收的廣播全部屬于系統全局廣播,即發出的廣播可以被其他任何應用程序接收到,并且我們也可以接收來自于其他任何應用程序的廣播。這樣就很容易引起安全性的問題,比如說我們發送的一些攜帶關鍵性數據的廣播有可能被其他的應用程序截獲,或者其他的程序不停地向我們的廣播接收器里發送各種垃圾廣播。

使用本地廣播則發出的廣播只能在應用程序內部傳遞,并且接收器也只能接收來自本應用程序發出的廣播。

public class MainActivity extends AppCompatActivity {
    private IntentFilter intentFilter;
    private LocalReceiver localReceiver;
    private LocalBroadcastManager localBroadcastManger;
    @Override
    protected void onCreate(Bundle savedInstanceState){
        super.onCreate(savedInstanceState);
        setContentView((R.layout.activity_main));
        localBroadcastManger = LocalBroadcastManager.getInstance(this); //獲取實例
        Button button = (Button) findViewById(R.id.button);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent intent = new Intent("com.example.broadcasttest.LOCAL_BROADCAST");
                localBroadcastManger.sendBroadcast(intent); //發送本地廣播
            }
        });
        intentFilter = new IntentFilter();
        intentFilter.addAction("com.example.broadcasttest.LOCAL_BROADCAST");
        localReceiver = new LocalReceiver();
        localBroadcastManger.registerReceiver(localReceiver, intentFilter); //注冊本地廣播監聽器
    }
    @Override
    protected void onDestroy(){
        super.onDestroy();
        localBroadcastManger.unregisterReceiver(localReceiver);
    }
    class LocalReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent){
            Toast.makeText(context, "received local broadcast", Toast.LENGTH_SHORT).show();
        }
    }
}

代碼的不同主要在于需要首先獲取實例,然后還要有注冊。

需要注意的是,本地廣播無法通過靜態注冊來接收。

使用廣播實現強制下線功能

強制下線功能首先需要實現下關閉所有的活動的功能,新建一個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 activity:activities){
            if(!activity.isFinishing()){
                activity.finish();
            }
        }
    }
}

然后創建baseActivity類作為活動的父類,代碼如下:

public class BaseActivity extends AppCompatActivity {
    private ForceOfflineReceiver receiver;
    @Override
    protected void onCreate(Bundle savedInstanceState){
        super.onCreate(savedInstanceState);
        ActivityCollector.addActivity(this);
    }
    @Override
    protected void onResume(){
        super.onResume();
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction("com.example.broadcastbestpractice.FORCE_OFFLINE");
        receiver = new ForceOfflineReceiver();
        registerReceiver(receiver, intentFilter);
    }
    @Override
    protected void onPause(){
        super.onPause();
        if(receiver != null){
            unregisterReceiver(receiver);
            receiver = null;
        }
    }
    @Override
    protected void onDestroy(){
        super.onDestroy();
        ActivityCollector.removeActivity(this);
    }
    class ForceOfflineReceiver extends BroadcastReceiver{
        @Override
        public void onReceive(final Context context, Intent intent){
            AlertDialog.Builder builder = new AlertDialog.Builder(context);
            builder.setTitle("warning");
            builder.setMessage("You are forced to be offline");
            builder.setCancelable(false);
            builder.setPositiveButton("OK", new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialogInterface, int which) {
                    ActivityCollector.finishAll(); //銷毀所有活動
                    Intent intent = new Intent(context, LoginActivity.class);
                    context.startActivity(intent); //重新啟動loginActivity
                }
            });
            builder.show();
        }
    }
}

我們可以注意到,之前編寫注冊和銷毀接收器的時候是在onCreate和onDestroy這兩個函數里的,但是上面代碼中卻寫在了onResume和onPause里面,這是因為我們每次都只需要在棧頂的活動接收廣播,非棧頂活動沒必要接收這條廣播。

除此之外,我們創建一個登陸的活動,在活動頁面上放置輸入框,并編寫登錄邏輯

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.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:id="@+id/container"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingBottom="@dimen/activity_vertical_margin"
    tools:context=".ui.login.LoginActivity">
    <LinearLayout
        android:orientation="horizontal"
        android:layout_width="match_parent"
        android:layout_height="60dp"
        tools:ignore="MissingConstraints">
        <TextView
            android:layout_width="90dp"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal"
            android:textSize="18sp"
            android:text="Account:"/>
        <EditText
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:id="@+id/account"
            android:layout_weight="1"
            android:layout_gravity="center_horizontal"/>
    </LinearLayout>
    <LinearLayout
        android:orientation="horizontal"
        android:layout_width="match_parent"
        android:layout_height="60dp"
        tools:ignore="MissingConstraints">
        <TextView
            android:layout_width="90dp"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal"
            android:textSize="18sp"
            android:text="password:"/>
        <EditText
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:id="@+id/password"
            android:layout_weight="1"
            android:layout_gravity="center_horizontal"/>
    </LinearLayout>
    <Button
        android:layout_width="match_parent"
        android:layout_height="60dp"
        android:id="@+id/login"
        android:text="Login"
        tools:ignore="MissingConstraints"></Button>
</androidx.constraintlayout.widget.ConstraintLayout>
public class LoginActivity extends AppCompatActivity {
    private EditText accountEdit;
    private EditText passwordEdit;
    private Button login;
    @Override
    protected void onCreate(Bundle savedInstanceState){
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_login);
        accountEdit = (EditText) findViewById(R.id.account);
        passwordEdit = (EditText) findViewById(R.id.password);
        login = (Button) findViewById(R.id.login);
        login.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                String account = accountEdit.getText().toString();
                String password = passwordEdit.getText().toString();
                //如果賬號是admin 且密碼是123456則登錄成功
                if(account.equals("admin") && password.equals("123456")){
                    Intent intent = new Intent(LoginActivity.this, MainActivity.class);
                    startActivity(intent);
                    finish();
                }else {
                    Toast.makeText(LoginActivity.this, "account is invalid", Toast.LENGTH_SHORT).show();
                }
            }
        });
    }
}

這樣就模擬了登錄的窗口,然后在mainActivity中加入觸發強制下線的代碼

public class MainActivity extends BaseActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Button forceOffline = (Button) findViewById(R.id.force_offline);
        forceOffline.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent("com.example.broadcastbestpractice.FROCE_OFFLINE");
                sendBroadcast(intent);
            }
        });
    }
}

這樣邏輯就差不多了,下面去AndroidManifest.xml中修改下程序入口即可:

原文鏈接:https://blog.csdn.net/qq_35481726/article/details/129113783

  • 上一篇:沒有了
  • 下一篇:沒有了
欄目分類
最近更新