1. 程式人生 > >Android的廣播Receiver動態註冊和靜態註冊

Android的廣播Receiver動態註冊和靜態註冊

廣播接收器註冊一共有兩種形式 : 靜態註冊和動態註冊.

兩者及其接收廣播的區別:

1.動態註冊的廣播 永遠要快於 靜態註冊的廣播,不管靜態註冊的優先順序設定的多高,不管動態註冊的優先順序有多低>\

2.動態註冊廣播不是 常駐型廣播 ,也就是說廣播跟隨activity的生命週期。注意: 在activity結束前,移除廣播接收器。

靜態註冊是常駐型 ,也就是說當應用程式關閉後,如果有資訊廣播來,程式也會被系統呼叫自動執行。

3.在同一個優先順序下,誰先啟動的快,誰將先接收到廣播.

下面這個Demo,介面如下,註冊兩個動態接收器(接收自定義廣播和系統廣播)和註冊靜態廣播(接收自定義靜態和廣播、手機USB的插拔事件、接收簡訊並讀取簡訊息)

工程目錄如下:注意看程式碼中的註釋

xml佈局檔案(activity_main.xml)

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:orientation="vertical" android:layout_width="fill_parent"
              android:layout_height="fill_parent">

    <Button
            android:id="@+id/send_static"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="傳送自定義靜態註冊廣播"/>

    <Button android:id="@+id/send_dynamic"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="傳送自定義動態註冊廣播"/>

    <Button
            android:id="@+id/send_system"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="傳送系統動態註冊廣播"/>

</LinearLayout>

Manifest.xml如下,這裡面定義的許可權資訊和註冊的廣播

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

    <!--監聽簡訊息-->
    <uses-permission android:name="android.permission.RECEIVE_SMS" />
    <uses-permission android:name="android.permission.READ_SMS" />

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme" >
        <activity android:name=".MainActivity" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

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

        <!-- 註冊自定義靜態廣播接收器 -->
        <receiver android:name=".StaticReceiver">
            <intent-filter>
                <action android:name="com.byread.static" />
            </intent-filter>
        </receiver>

        <!-- 註冊系統靜態廣播接收器 -->
        <receiver android:name=".SystemReceiver">
            <intent-filter>
                <action android:name="android.intent.action.BATTERY_LOW" />
                <action android:name="android.provider.Telephony.SMS_RECEIVED"/>
                <action android:name="android.hardware.usb.action.USB_STATE"/>
        </intent-filter>
        </receiver>


    </application>

</manifest>


MainActivity.java

package com.nii.receiver;

import android.Manifest;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
import com.nii.receiver.type.RequestPermissionType;
import com.nii.receiver.util.PermissionUtil;

public class MainActivity extends AppCompatActivity
{

    /**
     * 傳送靜態廣播按鈕
     */
    private Button sendStaticBtn;

    /**
     * 傳送動態廣播按鈕
     */
    private Button sendDynamicBtn;

    /**
     * 傳送系統廣播按鈕
     */
    private Button sendSystemBtn;

    /**
     * 靜態action
     */
    private static final String STATICACTION = "com.byread.static";

    /**
     * 動態action
     */
    private static final String DYNAMICACTION = "com.byread.dynamic";

    /**
     * USB裝置連線
     */
    private static final String SYSTEMACTION = Intent.ACTION_POWER_CONNECTED;

    private Context mContext;

    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        this.mContext = this;

        sendStaticBtn = (Button) findViewById(R.id.send_static);
        sendDynamicBtn = (Button) findViewById(R.id.send_dynamic);
        sendSystemBtn = (Button) findViewById(R.id.send_system);
        sendStaticBtn.setOnClickListener(new MyOnClickListener());
        sendDynamicBtn.setOnClickListener(new MyOnClickListener());
        sendSystemBtn.setOnClickListener(new MyOnClickListener());

        //申請讀取簡訊的許可權
        PermissionUtil.requestPermission(mContext, Manifest.permission.READ_SMS,
                RequestPermissionType.REQUEST_CODE_ASK_READ_SMS);

        PermissionUtil.requestPermission(mContext, Manifest.permission.RECEIVE_SMS,
                RequestPermissionType.REQUEST_CODE_ASK_RECEIVE_SMS);
    }
    class MyOnClickListener implements View.OnClickListener
    {
        @Override
        public void onClick(View v)
        {
            // 傳送自定義靜態註冊廣播訊息
            if (v.getId() == R.id.send_static)
            {
                Log.e("MainActivity", "傳送自定義靜態註冊廣播訊息");
                Intent intent = new Intent();
                intent.setAction(STATICACTION);
                intent.putExtra("msg", "接收靜態註冊廣播成功!");
                sendBroadcast(intent);
            }
            // 傳送自定義動態註冊廣播訊息
            else if (v.getId() == R.id.send_dynamic)
            {
                Log.e("MainActivity", "傳送自定義動態註冊廣播訊息");
                Intent intent = new Intent();
                intent.setAction(DYNAMICACTION);
                intent.putExtra("msg", "接收動態註冊廣播成功!");
                sendBroadcast(intent);
            }
            // 傳送系統動態註冊廣播訊息。當手機連線充電裝置時會由系統自己傳送廣播訊息。
            else if (v.getId() == R.id.send_system)
            {
                Log.e("MainActivity", "傳送系統動態註冊廣播訊息");
                Intent intent = new Intent();
                intent.setAction(SYSTEMACTION);
                intent.putExtra("msg", "正在充電。。。。");
            }
        }
    }

    @Override
    protected void onStart()
    {
        super.onStart();
        Log.e("MainActivity", "註冊廣播事件");

        // 註冊自定義動態廣播訊息
        IntentFilter filter_dynamic = new IntentFilter();
        filter_dynamic.addAction(DYNAMICACTION);
        registerReceiver(dynamicReceiver, filter_dynamic);

        // 註冊系統動態廣播訊息
        IntentFilter filter_system = new IntentFilter();
        filter_system.addAction(SYSTEMACTION);
        registerReceiver(systemReceiver, filter_system);
    }

    private BroadcastReceiver dynamicReceiver = new BroadcastReceiver()
    {

        @Override
        public void onReceive(Context context, Intent intent)
        {
            Log.e("MainActivity", "接收自定義動態註冊廣播訊息");
            if (intent.getAction().equals(DYNAMICACTION))
            {
                String msg = intent.getStringExtra("msg");
                Toast.makeText(context, msg, Toast.LENGTH_SHORT).show();
            }
        }
    };

    private BroadcastReceiver systemReceiver = new BroadcastReceiver()
    {
        @Override
        public void onReceive(Context context, Intent intent)
        {
            Log.e("MainActivity", "接收系統動態註冊廣播訊息");
            if (intent.getAction().equals(SYSTEMACTION))
            {
                String msg = intent.getStringExtra("msg");
                Toast.makeText(context, msg, Toast.LENGTH_SHORT).show();
            }
        }
    };
}
StaticReceiver.java
package com.nii.receiver;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Handler;
import android.widget.Toast;

/**
 * Created by wzj on 2017/2/19.
 */
public class StaticReceiver extends BroadcastReceiver
{

    /**
     * 接收廣播
     * @param context context
     * @param intent intent
     */
    @Override
    public void onReceive(Context context, Intent intent)
    {
        String msg = intent.getStringExtra("msg");
        Toast.makeText(context, msg, Toast.LENGTH_SHORT).show();
    }
}
SystemReceiver.java這裡面處理一些系統的事件
package com.nii.receiver;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.telephony.SmsMessage;
import android.text.format.DateFormat;
import android.util.Log;
import android.widget.Toast;
import com.nii.receiver.util.DialogUtil;

import java.util.Date;

/**
 * Created by wzj on 2017/2/19.
 */
public class SystemReceiver extends BroadcastReceiver
{

    /**
     * 接收系統靜態廣播
     *
     * @param context context
     * @param intent  intent
     */
    @Override
    public void onReceive(Context context, Intent intent)
    {
        if (intent.getAction().equals(Intent.ACTION_BATTERY_LOW))
        {
            Log.e("SystemReceiver", "電量低提示");
            Toast.makeText(context, "您的手機電量偏低,請及時充電", Toast.LENGTH_SHORT).show();
        }
        else if (intent.getAction().equals("android.provider.Telephony.SMS_RECEIVED"))
        {
            if (intent.getAction().equals("android.provider.Telephony.SMS_RECEIVED"))
            {
                Bundle bundle = intent.getExtras();
                if (bundle != null)
                {//如果資料不為空
                    //獲得收到的簡訊資料
                    Object[] objArray = (Object[]) bundle.get("pdus");
                    //根據objArray的大小建立一個SmsMessage陣列,用於封裝簡訊內容
                    SmsMessage[] smsMessage = new SmsMessage[objArray.length];
                    StringBuffer sb = new StringBuffer();
                    sb.append("時間:" + new DateFormat().format("yyyy - MM - dd hh.mm.ss", new Date()));

                    //遍歷smsMessage陣列取出所有簡訊
                    for (int i = 0; i < smsMessage.length; i++)
                    {
                        //將每條位元組型別的簡訊資料轉換成SmsMessage物件
                        smsMessage[i] = SmsMessage.createFromPdu((byte[]) objArray[i]);
                        //獲取簡訊傳送地址
                        sb.append("傳送者:" + smsMessage[i].getOriginatingAddress());
                        //獲取簡訊內容
                        sb.append("簡訊內容:" + smsMessage[i].getDisplayMessageBody() + "\n");
                    }

                    DialogUtil.showPrompt(context,sb.toString());
                    Toast.makeText(context, sb.toString(), Toast.LENGTH_LONG).show();
                }
            }
        }
        else if(intent.getAction().equals("android.hardware.usb.action.USB_STATE"))
        {
            if (intent.getExtras().getBoolean("connected"))
            {
                Toast.makeText(context, "USB插入", Toast.LENGTH_LONG).show();
            }
            else
            {
                Toast.makeText(context, "USB拔出", Toast.LENGTH_LONG).show();
            }
        }
    }
}
RequestPermissionType.java是許可權請求的時候,Qequest Code(請求碼)
package com.nii.receiver.type;

/**
 * Created by wzj on 2017/2/19.
 */
public interface RequestPermissionType
{
    /**
     * 請求打電話的許可權碼
     */
    int REQUEST_CODE_ASK_CALL_PHONE = 100;

    /**
     * 請求接收簡訊息
     */
    int REQUEST_CODE_ASK_RECEIVE_SMS = 101;

    /**
     * 請求讀簡訊
     */
    int REQUEST_CODE_ASK_READ_SMS = 102;
}

DialogUtil.java是介面彈窗工具類
package com.nii.receiver.util;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.view.WindowManager;

/**
 * 對話方塊工具箱
 *
 * @author xiaopan
 */
public class DialogUtil
{
    /**
     * 顯示一個對話方塊
     *
     * @param context                    上下文物件,最好給Activity,否則需要android.permission.SYSTEM_ALERT_WINDOW
     * @param title                      標題
     * @param message                    訊息
     * @param confirmButton              確認按鈕
     * @param confirmButtonClickListener 確認按鈕點選監聽器
     * @param centerButton               中間按鈕
     * @param centerButtonClickListener  中間按鈕點選監聽器
     * @param cancelButton               取消按鈕
     * @param cancelButtonClickListener  取消按鈕點選監聽器
     * @param onShowListener             顯示監聽器
     * @param cancelable                 是否允許通過點選返回按鈕或者點選對話方塊之外的位置關閉對話方塊
     * @param onCancelListener           取消監聽器
     * @param onDismissListener          銷燬監聽器
     * @return 對話方塊
     */
    public static AlertDialog showAlert(Context context, String title, String message,
                                        String confirmButton, DialogInterface.OnClickListener confirmButtonClickListener,
                                        String centerButton, DialogInterface.OnClickListener centerButtonClickListener,
                                        String cancelButton, DialogInterface.OnClickListener cancelButtonClickListener,
                                        DialogInterface.OnShowListener onShowListener, boolean cancelable,
                                        DialogInterface.OnCancelListener onCancelListener,
                                        DialogInterface.OnDismissListener onDismissListener)
    {
        AlertDialog.Builder promptBuilder = new AlertDialog.Builder(context);
        if (title != null)
        {
            promptBuilder.setTitle(title);
        }
        if (message != null)
        {
            promptBuilder.setMessage(message);
        }
        if (confirmButton != null)
        {
            promptBuilder.setPositiveButton(confirmButton, confirmButtonClickListener);
        }
        if (centerButton != null)
        {
            promptBuilder.setNeutralButton(centerButton, centerButtonClickListener);
        }
        if (cancelButton != null)
        {
            promptBuilder.setNegativeButton(cancelButton, cancelButtonClickListener);
        }
        promptBuilder.setCancelable(true);
        if (cancelable)
        {
            promptBuilder.setOnCancelListener(onCancelListener);
        }

        AlertDialog alertDialog = promptBuilder.create();
        if (!(context instanceof Activity))
        {
            alertDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
        }
        alertDialog.setOnDismissListener(onDismissListener);
        alertDialog.setOnShowListener(onShowListener);
        alertDialog.show();
        return alertDialog;
    }


    /**
     * 顯示一個對話方塊
     *
     * @param context                    上下文物件,最好給Activity,否則需要android.permission.SYSTEM_ALERT_WINDOW
     * @param title                      標題
     * @param message                    訊息
     * @param confirmButtonClickListener 確認按鈕點選監聽器
     * @param cancelButtonClickListener  取消按鈕點選監聽器
     * @return 對話方塊
     */
    public static AlertDialog showConfirm(Context context, String title, String message,
                                        DialogInterface.OnClickListener confirmButtonClickListener,
                                        DialogInterface.OnClickListener cancelButtonClickListener)
    {
        return showAlert(context, title, message, "Yes",
                confirmButtonClickListener, null, null, "No", cancelButtonClickListener, null, true, null, null);
    }


    /**
     * 顯示一個提示框
     *
     * @param context       上下文物件,最好給Activity,否則需要android.permission.SYSTEM_ALERT_WINDOW
     * @param message       提示的訊息
     * @param confirmButton 確定按鈕的名字
     */
    public static AlertDialog showPrompt(Context context, String message, String confirmButton)
    {
        return showAlert(context, null, message, confirmButton, null, null, null, null, null, null, true, null, null);
    }



    /**
     * 顯示一個提示框
     *
     * @param context 上下文物件,最好給Activity,否則需要android.permission.SYSTEM_ALERT_WINDOW
     * @param message 提示的訊息
     */
    public static AlertDialog showPrompt(Context context, String message)
    {
        return showAlert(context, null, message, "OK", null, null, null, null, null, null, true, null, null);
    }
}

PermissionUtil.java是許可權申請工具類
package com.nii.receiver.util;

import android.Manifest;
import android.app.Activity;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.Build;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;

/**
 * Created by wzj on 2017/2/19.
 */
public abstract class PermissionUtil
{
    /**
     * 請求許可權
     * @param mContext mContext
     * @param permission  permission
     * @param requestCode requestCode
     */
    public static void requestPermission(Context mContext,String permission,int requestCode)
    {
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M)
        {
            return;
        }

        int checkCallPhonePermission = ContextCompat.checkSelfPermission(mContext,permission);

        if (checkCallPhonePermission != PackageManager.PERMISSION_GRANTED)
        {
            ActivityCompat.requestPermissions((Activity) mContext, new String[]{permission},requestCode);
        }
    }
}