《Android深刻透析》之廣播(Broadcast)

1.     概述android

在android中,Broadcast做爲四大組件之一,被普遍的應用在android程序之間的數據傳遞。舉一個你們都比較熟悉的例子來講明。在車上的時候你們都有收聽廣播的習慣,廣播電臺經過發送不一樣頻率的信號,而後你們經過將各自頻率調成和電臺相同的頻率,就能夠接受到廣播內容了。在android中的廣播實際上是和這個是同樣的效果的。數組

2.     廣播機制安全

android中廣播機制體如今方方面面,各類廣播在android系統中運行,當系統、應用程序運行時便會向android註冊各類廣播,例如當開機完成後,系統會發送一條廣播,接受到這條廣播就能及時的做出提示和保存數據的動做;當你安裝卸載應用程序的時候系統都會發送廣播,來監聽這條廣播,就能夠做出相應的動做,一樣的廣播還有不少,好比電量多少,短信,來電等等。網絡

3.     發送和接收廣播app

3.1  廣播定義ide

關於廣播的定義,分爲兩種,動態註冊和靜態註冊。性能

動態註冊的廣播接收器永遠要快於靜態註冊的廣播接收器,無論靜態註冊的廣播接收器的優先級是否高於動態註冊的廣播接收器的優先級。google

動態註冊的廣播不是常駐型的,他是跟隨着activity的生命週期的。通常在開發中都會在onDestroy()方法中移除廣播。靜態註冊的廣播是常駐型的廣播,也就是說當應用程序關閉的時候,若是有信息廣播來,程序也會被系統調用。在同一優先級下,誰啓動的快,誰將先收到廣播。spa

3.2     靜態廣播3d

靜態廣播指的就是在AndroidManifest.xml配置文件中定義,

<receiver android:name=".DemoReceiver" android:exported="false">

     <intent-filter>

         <action android:name="com.example.broadcast1"/>

     </intent-filter>

</receiver>

 

android:name=".DemoReceiver"指的是靜態廣播的類名稱,

android:exported="false"設置的屬性,若是爲true的話則能夠容許被其餘應用接受,若是是false話,只能被本應用內的接收器接收

<action android:name="com.example.broadcast1"/>指的是定義的廣播的動做標準,就至關於廣播的頻率,只有當接收器指定相同的動做標準的時候,才能夠接收到發送的廣播內容

3.3     動態廣播

動態廣播須要經過代碼的方式註冊,註冊廣播接收器須要registerReceiver方法,註銷廣播接收器須要使用unregisterReceiver方法:

註冊:

IntentFilter filter = new IntentFilter();

       filter.addAction("com.example.broadcast2");

registerReceiver(broadcastReceiver, filter);

 

解除:

unregisterReceiver(broadcastReceiver);

其中broadcastReceiver 爲廣播接收器對象

3.4     廣播接收器

3.4.1 發送廣播

在說廣播接收器以前,首先說一下是怎麼發送廣播的。不管是動態註冊的仍是靜態註冊的廣播接收器,他的發送方法都是經過sendBroadcast方法來實現的,例以下代碼:

Intent intent = new Intent();

       intent.setAction("com.example.broadcast2");

       intent.putExtra("name", "動態註冊廣播");

sendBroadcast(intent);

 

sendBroadcast方法中的intent指定廣播接收器的動做,將要傳遞給廣播接收器的內容放入到intent中

3.4.2廣播接收

不論是動態廣播仍是靜態廣播,若是想接收到廣播,都須要定義廣播接收器,例如以下代碼:

private BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {

              @Override

              public void onReceive(Context context, Intent intent) {

                     String name = intent.getExtras().getString("name");

                     Toast.makeText(mContext, name, Toast.LENGTH_SHORT).show();

                    

              }

};

在廣播接收器中最重要的就是這個onReceive方法,其中在onReceive的intent參數中能夠攜帶發送廣播時所發送出來的參數,同這種intent.getExtras().getString("name")方法,經過intent的能夠傳遞各類類型的參數,包括對象.

3.4.3優先級

在註冊廣播的時候,能夠設定廣播的優先級,設置的數越大的越會在前面執行,這裏指的是同一級的廣播,好比幾個靜態註冊的廣播或者動態註冊的廣播,例如以下代碼,

<receiver android:name=".DemoReceiver1" android:exported="false">

            <intent-filter android:priority="500">

                <action android:name="com.example.broadcast1"/>

            </intent-filter>

 </receiver>

<receiver android:name=".DemoReceiver2" android:exported="false">

            <intent-filter android:priority="1000">

                <action android:name="com.example.broadcast1"/>

            </intent-filter>

 </receiver>

 

上面有兩個靜態註冊的廣播,第一個的優先級設置的500,第二個的優先級設置的1000,這樣設置優先級爲1000的就會先執行,而後纔會在優先級爲500的接收器裏收到信息,若是在優先級爲1000的接收器中設置abortBroadcast() 方法,那麼在同級別的優先級裏廣播將被終止,不在往下傳遞

 4.     系統廣播

廣播接收器有一個很大的用途就是接收系統廣播,根據系統廣播能夠作不少事情,下面就爲你們介紹幾種在開發過程當中常見的系統廣播

4.1開機啓動

在介紹開機啓動廣播以前,要先跟你們解釋一個問題,從android3.0系統以後,全部的android系統的機器在安裝完APP以後,必須手動啓動一次以後才能夠接收到開機啓動的廣播,不過google官方仍是給出瞭解釋,若是你能夠將本身的APP變成系統權限的話,那麼就能夠再任什麼時候候接到到系統的開機啓動廣播的。那麼如何將APP如何獲取系統權限哪,簡單的講就是把app放入到system/app目錄下,以下圖:

 

將app放入到system/app目錄下,系統會將該應用當作系統應用,獲取系統的最高權限,而且在未啓動過應用的前提下,就能夠獲取到任何的系統廣播。如下是接受到系統開機的廣播:

      @Override

       public void onReceive(Context context, Intent intent) {

              Intent intent = new Intent(context,MainActivity.class);

              intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

              context.startActivity(intent);

}

◊注意:

         在廣播接收器中經過intent打開activity,必需要設置intent的flags爲Intent.FLAG_ACTIVITY_NEW_TASK不然就會拋出android.util.AndroidRuntimeException: Calling startActivity() from outside of an Activity的異常,請讀者切記

須要在訂單文件中定義靜態接收器:

<receiver android:name=".BootReceiver" android:enabled="true">

            <intent-filter>

                <!-- 開機啓動 -->

                <action android:name="android.intent.action.BOOT_COMPLETED" />

            </intent-filter>

        </receiver>

 

在系統權限中須要加入下面的權限:

<!-- 開機自啓動權限 -->

    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" /> 4.2網絡狀態變動

在開發的過程當中都會遇到關於網絡的切換,好比wifi切換到3G,3G切換到無網絡,那麼咱們如何來得之當前的網絡狀態哪,下面經過一段代碼來給你們說明一下:

public class BootReceiver extends BroadcastReceiver{

        private ConnectivityManager connectivityManager;

           private NetworkInfo info;

       @Override

       public void onReceive(Context context, Intent intent) {

             

              if (ConnectivityManager.CONNECTIVITY_ACTION.equals(intent.getAction())) {

                      Log.d("mark", "網絡狀態已經改變");

                      connectivityManager = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);

                      info = connectivityManager.getActiveNetworkInfo(); 

                      if(info != null && info.isAvailable()) {

               String name = info.getTypeName();

               Log.d("mark", "當前網絡名稱:" + name);

                      } else {

               Log.d("mark", "沒有可用網絡");

                      }

             

              }

       }

 

}

    ConnectivityManager.CONNECTIVITY_ACTION當網絡狀態發生變化的時候,intent中的action就會收到當前狀態的監聽,而後獲取到ConnectivityManager對象,從ConnectivityManager對象中獲取NetworkInfo對象,NetworkInfo中能夠獲取到當前的網絡狀態是什麼形式

      

public class BootReceiver extends BroadcastReceiver{

        private ConnectivityManager connectivityManager;

           private NetworkInfo info;

       @Override

       public void onReceive(Context context, Intent intent) {

             

              if (ConnectivityManager.CONNECTIVITY_ACTION.equals(intent.getAction())) {

                      Log.d("mark", "網絡狀態已經改變");

                      connectivityManager = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);

                      info = connectivityManager.getActiveNetworkInfo(); 

                      if(info != null && info.isAvailable()) {

               String name = info.getTypeName();

               Log.d("mark", "當前網絡名稱:" + name);

                      } else {

               Log.d("mark", "沒有可用網絡");

                      }

             

              }

       }

 

}

 

           須要在清單文件中添加權限:
           <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>

 

4.3電量監聽

如何才能知道如今手機的電量是多少了哪?怎麼才能避免忽然沒電的尷尬?咱們能夠經過一個系統的廣播來查看電池的電量,下面咱們將經過一個動態註冊的方式來給你們寫一個例子:

     

  private BroadcastReceiver mBatteryChangeReceiver = new BroadcastReceiver() {

             

              @Override

              public void onReceive(Context context, Intent intent) {

                     if (Intent.ACTION_BATTERY_CHANGED.equals(intent.getAction())) {

                            //level表示當前電量的值

                            int level = intent.getIntExtra("level", 0);

                            //scale表示電量的總刻度

                            int scale = intent.getIntExtra("scale", 100);

                            //將當前的電量換算成百分比的形式

                            tvBattery.setText("電池用量:"+(level*100/scale)+"%");

                     }

                    

              }

       };

 

經過當前電量和總電量的計算,能夠獲得目前手機電池剩餘電量的一個百分比

下面是對定義的監聽器的註冊:

      

 private OnClickListener registerClickListener = new OnClickListener() {

             

              @Override

              public void onClick(View v) {

                     IntentFilter filter = new IntentFilter();

                     filter.addAction(Intent.ACTION_BATTERY_CHANGED);

                     registerReceiver(mBatteryChangeReceiver, filter);

                    

              }

       };

 

最後當再也不使用的時候,記得在onDestroy()方法中執行解除監聽的方法

4.4短信攔截

短信攔截廣播,顧名思義,就是當手機收到短信的時候能夠攔截電話號碼和短信內容,看下面的代碼實例:

public class ShortMessageReceiver extends BroadcastReceiver{

 

       @Override

       public void onReceive(Context context, Intent intent) {

              //經過廣播的方式獲取短信的內容

              Bundle bundle = intent.getExtras();

              if (bundle!=null) {

                     Set<String> keys = bundle.keySet();

                     //查看廣播中包含的數據項

                     for (String key:keys) {

                            Log.i("廣播中的數據項:", key);

                     }

                     //短信數據的獲取都用經過一個叫作pdus的key獲取

                     Object[] arrayObjects = (Object[])bundle.get("pdus");

                     //短信的數據內容都是封裝在SmsMessage對象中

                     SmsMessage[] msg = new SmsMessage[arrayObjects.length];

                     //循環處理收到的全部短信

                     for (int i = 0; i < arrayObjects.length; i++) {

                            //將每條短信數據賦值給SmsMessage對象

                            msg[i] = SmsMessage.createFromPdu((byte[])arrayObjects[i]);

                            //得到發送短信的電話號碼和短信內容

                            String s = "手機號:"+msg[i].getOriginatingAddress()+"\n";

                            s+= "短信內容:"+msg[i].getDisplayMessageBody();

                            //經過土司的方式把電話號碼和內容顯示出來

                            Toast.makeText(context, s, Toast.LENGTH_LONG).show();

                     }

                     abortBroadcast();

              }

             

       }
}

 

◊ 經過intent獲取短信內容項,短信的內容項存儲在Bundle中

◊ Bundle中存儲了一個set集合,能夠經過Log的方式循環查看短信中的每個數據項是什麼

◊ 收到的短信內容是以字節數組的形式保存的,爲了便於使用這些數據,因此要將這些字節數組經過

SmsMessage.createFromPdu((byte[])arrayObjects[i]);的方法轉換成SmsMessage對象。

◊ 爲何會用SmsMessage數組的形式存儲短信對象哪,由於短信息自己是有字數限制的,通常都是70個漢字左右,若是發送的短信字數過多,運營商就會把你發送的短信進行拆分來發送,好比說你發送了一天100個漢字的短信,運營商就會把短信拆分紅1條70字和一條30字的短信,爲了保證收到的短信的完整性,因此就須要以SmsMessage數組的形式來存儲接受短信內容。

 

廣播接收器須要在AndroidManifest.xml註冊,代碼以下:

<receiver android:name=".ShortMessageReceiver" android:enabled="true">

            <intent-filter>

                <action android:name="android.provider.Telephony.SMS_RECEIVED"/>

            </intent-filter>

</receiver>

 

       其中android:name="android.provider.Telephony.SMS_RECEIVED"是接收到短信的廣播動做,必須指定該動做,不然ShortMessageReceiver接收不到系統的短信廣播

因爲android的安全機制,必須在AndroidManifest.xml中指定權限,程序才能正常的接收短信廣播。

<uses-permission android:name="android.permission.RECEIVE_SMS" />

  1. 5.     小結

       本章節主要講解了android中的廣播接收器,介紹到這裏相信你們都對廣播就了一個大概的瞭解,廣播在android開發中應用很普遍,也很方便,包括他能夠傳遞數據給全局的各個類或者接收到的一些系統的廣播之類的機制。廣播至關於一個全局的事件,不論是否有接收器他都會根據條件去發送,去觸發,因此在性能方面來說,若是大量使用的話,可能會對應用形成性能損耗,因此你們在使用的時候,要通過深思熟慮以後在動手

相關文章
相關標籤/搜索