編輯:關於Android編程
在這裡 篇文章裡面我將總結廣播接收器(Broadcast Receiver)方面的知識。首先我們來了解下andorid中廣播的類型,android中的廣播可以分為2種,標准廣播和有序廣播。
標准廣播:是一種完全異步執行的廣播,在廣播發出後,所有廣播接收器幾乎都會同一時刻接收到這條廣播消息,因此它們之間沒有任何先後順序可言。這種廣播的效率比較高,但同時也意味著它無法被截斷的。
有序廣播:則是一種同步機制的廣播,在廣播發出之後,同一時刻只會有一個廣播接收器能夠接收到這條廣播信息,當這個廣播接收器中邏輯執行完畢後,廣播才會繼續傳遞。所以此時的廣播接收器是有先後順序的,優先級高的廣播接收器就可以先收到廣播信息,並且前面的廣播接收器還可以截斷正在傳遞的廣播,這樣後面的廣播接收器就無法收到廣播消息了。
接收系統廣播
廣播接收器可以自由的對自己感興趣的廣播進行注冊,這樣當有相應的廣播發出時,廣播接收器就能夠收到該廣播,並在內部處理相應的邏輯。注冊廣播的方式一般有2種,在代碼中和在AndroidManifest.xml中注冊,其中前者也被稱為動態注冊,後者也被稱為靜態注冊。
那麼該如何創建一個廣播接收器?其實只要新建一個類,讓它繼承自BroadcastReceiver,並重寫父類的onReceiver方法就行了。這樣當有廣播到來時,onReceiver方法就會得到執行,具體的邏輯處理就可以在這個方法中處理。
下面我們就先通過動態注冊的方式來編寫一個能夠監聽網絡變化的程序。新建一個項目,項目為BroadcastTest。修改MainActivity中的代碼,如下所示:
package com.wj.broadcasttest; import android.os.Bundle; import android.app.Activity; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.view.Menu; import android.widget.Toast; public class MainActivity extends Activity { 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_CHANGE"); networkChangeReceiver=new NetworkChangeReceiver(); registerReceiver(networkChangeReceiver, intentFilter); } @Override protected void onDestroy() { // TODO Auto-generated method stub super.onDestroy(); unregisterReceiver(networkChangeReceiver); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.main, menu); return true; } //繼承BroadcastReceiver,重寫onReceiver方法,進行廣播接收處理。 class NetworkChangeReceiver extends BroadcastReceiver{ @Override public void onReceive(Context context, Intent intent) { // TODO Auto-generated method stub Toast.makeText(context, "network changes", Toast.LENGTH_SHORT).show(); } } }
可以看到,MainActivity中定義了一個內部類NetworkChangeReceiver,這個類是繼承自BroadcastReceiver的,並重寫了父類的onReceiver方法,這樣每當網絡狀態發送變化時,onReceiver方法就會得到執行,這裡只是簡單的使用Toast提示了一段文本信息。
在onCreate方法中,首先我們創建了一個IntentFilter的實例,並給它添加了一個值為android.net.conn.CONNECTIVITY_CHANGE的action,為什麼要添加這個值呢?因為當網絡狀態發送變化時,系統發出的正是一條值為android.net.conn.CONNECTIVITY_CHANGE的廣播,也就是說我們的廣播接收器想要監聽的廣播,就在這裡添加相應的action就行了。接著創建了一個NetworkChangeReceiver實例,然後調用registerReceiver(networkChangeReceiver, intentFilter);方法進行注冊,將NetworkChangeReceiver實例和IntentFilter實例都傳了進去,這樣NetworkChangeReceiver就會收到所有值為android.net.conn.CONNECTIVITY_CHANGE的廣播,也就實現了監聽網絡變化的功能。
最後要記得,動態注冊的廣播接收器一定都要取消注冊才行,這裡我們是在onDestroy方法中通過調用unregisterReceiver(networkChangeReceiver)方法來實現的。
首先你會在注冊完成的時候收到一條廣播,然後按下home鍵回到主界面(注意不能按back鍵,否則onDestroy方法會執行),接著按下menu鍵--》System settings---》Data usage進入到數據使用詳情界面,然後嘗試著打開Mobile Data來啟動和禁用網絡,你就會看到有Toast提醒你網絡發生了變化。
上面只是提醒網絡變化了還不夠人性化,最好是能夠准確的告訴用戶當前是有網絡還是沒有網絡,所以我們對onReceiver的代碼進行修改,代碼如下:
//繼承BroadcastReceiver,重寫onReceiver方法,進行廣播接收處理。 class NetworkChangeReceiver extends BroadcastReceiver{ @Override public void onReceive(Context context, Intent intent) { // TODO Auto-generated method stub ConnectivityManager connectivityManager=(ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE); NetworkInfo networkInfo=connectivityManager.getActiveNetworkInfo(); if(networkInfo!=null&&networkInfo.isAvailable()){ Toast.makeText(context, "network is Available", Toast.LENGTH_LONG).show(); }else{ Toast.makeText(context, "network is unAvailable", Toast.LENGTH_LONG).show(); } } }
android系統為了保證應用程序的安全性能做了規定,如果程序需要訪問一些系統的關鍵信息,必須在配置文件中聲明權限才可以,否則程序將會崩潰,比如這裡查詢網絡狀態就是需要生命權限的。給程序添加權限,代碼如下:
重寫運行程序,然後按下home鍵---》按下menu鍵---》System settings --》Data usage(沒的Data usage,你就找到手機的網絡設置也一樣),運行程序結果如下:
<喎?/kf/ware/vc/" target="_blank" class="keylink">vcD4KPHA+PGltZyBzcmM9"/uploadfile/Collfiles/20141110/20141110083632105.jpg" alt="\">
靜態注冊實現開機啟動
動態注冊的廣播可以自由地控制注冊與注銷,在靈活性方面有很大的優勢,但是存在的缺點是,必須要在程序啟動之後才能接收到廣播,因為注冊的邏輯是寫在onCreate方法中的。如果要程序在未啟動的情況下就能接收到廣播,這就需要使用靜態注冊的方式了。
下面准備讓程序接收一條開機廣播,當收到這條廣播時就可以在onReciver方法裡執行相應的邏輯,從而實現開機啟動的功能。新建BootCompleteReceiver,繼承BroadcastReceiver,代碼如下:
package com.wj.broadcasttest; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.widget.Toast; public class BootCompleteReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { // TODO Auto-generated method stub Toast.makeText(context, "Boot Complete", Toast.LENGTH_LONG).show(); } }
在AndroidMainifest.xml中將上面的廣播進行注冊,代碼如下:
另外監聽系統開機廣播需要聲明權限,所以使用了
把監聽網絡變化的Toast顯示注釋掉,然後關閉模擬器,並重寫啟動,運行程序,將看到Boot Complete彈出來了。
注意:不要在onReceiver方法中添加過多的邏輯或者進行任何的耗時操作,因為在廣播接收器中是不允許開啟線程的,當onReceiver方法運行了較長時間,而沒有結束時,程序就會報錯。因此廣播接收器更多的是扮演一種打開程序其他組件的角色,比如創建一條狀態通知,或者啟動一個服務等。
發送自定義廣播
發送標准廣播
新建一個MyBroadcastReceiver類繼承BroadcastReceiver,代碼如下所示:
package com.wj.broadcasttest; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.widget.Toast; public class MyBroadcastReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { // TODO Auto-generated method stub Toast.makeText(context, "received in MyBroadcastReceiver", Toast.LENGTH_SHORT).show(); } }
修改MainActivity裡面的代碼,代碼如下:
package com.wj.broadcasttest; import android.net.ConnectivityManager; import android.net.NetworkInfo; import android.os.Bundle; import android.app.Activity; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.view.Menu; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.Toast; public class MainActivity extends Activity { private IntentFilter intentFilter; private NetworkChangeReceiver networkChangeReceiver; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Button button1=(Button) findViewById(R.id.button1); button1.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub Intent intent=new Intent("com.wj.broadcasttest.MY_BROADCAST"); sendBroadcast(intent); } }); intentFilter=new IntentFilter(); intentFilter.addAction("android.net.conn.CONNECTIVITY_CHANGE"); networkChangeReceiver=new NetworkChangeReceiver(); registerReceiver(networkChangeReceiver, intentFilter); } @Override protected void onDestroy() { // TODO Auto-generated method stub super.onDestroy(); unregisterReceiver(networkChangeReceiver); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.main, menu); return true; } //繼承BroadcastReceiver,重寫onReceiver方法,進行廣播接收處理。 class NetworkChangeReceiver extends BroadcastReceiver{ @Override public void onReceive(Context context, Intent intent) { // TODO Auto-generated method stub ConnectivityManager connectivityManager=(ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE); NetworkInfo networkInfo=connectivityManager.getActiveNetworkInfo(); if(networkInfo!=null&&networkInfo.isAvailable()){ /*Toast.makeText(context, "network is Available", Toast.LENGTH_LONG).show();*/ }else{ Toast.makeText(context, "network is unAvailable", Toast.LENGTH_LONG).show(); } } } }
在按鈕的點擊事件裡面加入了發送自定義廣播的邏輯。首先構建出了一個Intent對象,並把要發送的廣播值傳入,然後調用了Context的sendBroadcast方法將廣播發送出去。這樣所有監聽com.wj.broadcasttest.MY_BROADCAST這條廣播的廣播接收器就會收到消息。此時發送出去的廣播就是一條標准廣播。運行程序,並點擊send broadcast按鈕,運行結果如下:
當然廣播發送的時候也可以攜帶一些數據在Intent中進行傳送。
發送有序廣播
廣播是一種跨進程的通信方式,這一點從前面接收系統廣播的時候就可以看出來。因此在我們應用程序內發出的廣播,其他的應用程序也是可以接收到的。為了驗證這一點,我們在建立一個BroadcastTest2項目。將項目創建好之後,還需要在這個項目下定義一個廣播接收器,用於接收上面的自定義廣播。
在上面的項目BroadcastTest2中新建AnotherBroadcastReceiver類繼承,BroadcastReceiver。代碼如下:
package com.wj.broadcasttest2; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.widget.Toast; public class AnotherBroadcastReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { // TODO Auto-generated method stub Toast.makeText(context, "received in AnotherBroadcastReceiver", Toast.LENGTH_SHORT).show(); } }
上面的代碼,只為了在收到廣播的時候,彈出一段文本信息。然後在AndroidManifest.xml文件中對上面的廣播進行注冊,代碼如下:
AnotherBroadcastReceiver同樣接收的是com.wj.broadcasttest.MY_BROADCAST這條廣播。
現在運行BroadcastTest2項目將這個程序安裝到模擬器上,然後回到BroadcastTest項目的主界面,並點擊send broadcast按鈕,會彈出下面的信息:
上面的這個小案例,就證明了我們應用程序發出的廣播是可以被其他應用程序接收到的。不過到目前為止我們發送的廣播都還是標准廣播,現在我們來嘗試下發送有序廣播。
修改BroadcastTest項目的MainActivity裡面的代碼,代碼如下:
package com.wj.broadcasttest; import android.net.ConnectivityManager; import android.net.NetworkInfo; import android.os.Bundle; import android.app.Activity; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.view.Menu; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.Toast; public class MainActivity extends Activity { private IntentFilter intentFilter; private NetworkChangeReceiver networkChangeReceiver; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Button button1=(Button) findViewById(R.id.button1); button1.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub Intent intent=new Intent("com.wj.broadcasttest.MY_BROADCAST"); //sendBroadcast(intent); /*將sendBroadcast(intent)方法改成sendOrderedBroadcast(intent, null) * 就可以發送有序廣播了。sendOrderedBroadcast(intent, null)方法接收兩個參數 * ,第一個參數是仍然是Intent,第二參數是一個與權限相關的字符串,這裡傳入的是null。 * */ sendOrderedBroadcast(intent, null);//發送有序廣播。 } }); intentFilter=new IntentFilter(); intentFilter.addAction("android.net.conn.CONNECTIVITY_CHANGE"); networkChangeReceiver=new NetworkChangeReceiver(); registerReceiver(networkChangeReceiver, intentFilter); } @Override protected void onDestroy() { // TODO Auto-generated method stub super.onDestroy(); unregisterReceiver(networkChangeReceiver); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.main, menu); return true; } //繼承BroadcastReceiver,重寫onReceiver方法,進行廣播接收處理。 class NetworkChangeReceiver extends BroadcastReceiver{ @Override public void onReceive(Context context, Intent intent) { // TODO Auto-generated method stub ConnectivityManager connectivityManager=(ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE); NetworkInfo networkInfo=connectivityManager.getActiveNetworkInfo(); if(networkInfo!=null&&networkInfo.isAvailable()){ /*Toast.makeText(context, "network is Available", Toast.LENGTH_LONG).show();*/ }else{ Toast.makeText(context, "network is unAvailable", Toast.LENGTH_LONG).show(); } } } }
sendOrderedBroadcast(intent, null);//發送有序廣播。發送有序廣播,運行程序,點擊send broadcast按鈕,你會發現這2個應用程序仍然都會接收到這條廣播。看上去好像和標准廣播沒什麼區別,不過別忘了,這個時候的廣播接收器是有先後順序的,而且前面的廣播接收器還可以將廣播截斷,以阻止其繼續傳播。
那麼該如何設定廣播接收器的先後順序了?這個是在注冊的時候進行設定的,代碼如下:
android:priority="100"屬性給廣播接收器設置了優先級,優先級比較高廣播接收器就可以先收到廣播。這裡把MyBroadcastReceiver的優先級設置為100,以保證它一定會在AnotherBroadcastReceiver之前收到廣播。
既然已經獲得了接收廣播的優先權,那麼MyBroadcastReceiver就可以選擇釋放允許廣播繼續傳遞了,修改MyBroadcastReceiver的代碼如下所示:
package com.wj.broadcasttest; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.widget.Toast; public class MyBroadcastReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { // TODO Auto-generated method stub Toast.makeText(context, "received in MyBroadcastReceiver", Toast.LENGTH_SHORT).show(); abortBroadcast();//該方法攔截了有序廣播,後面的廣播就無法在接收到這條廣播了 } }
在運行程序,這時候就只有MyBroadcastReceiver能收到廣播了,彈出信息提示。
使用本地廣播
前面發送和接收的廣播全部是屬於系統全局廣播,即發出的廣播可以被其他任何的應用程序接收到,並且我們也可以接收到來自於其他任何應用程序的廣播。這樣很容易引起安全問題。為了解決廣播的安全問題,android引入了一套本地廣播機制,使用這個機制發出的廣播只能夠在應用程序的內部進行傳遞。並且廣播接收器也只能接收來自應用程序發出的廣播,這樣所有的安全問題就都不存在了。在本地廣播的使用主要是使用了LocalBroadcastManager來對廣播進行管理。並提供了發送廣播和注冊廣播接收器的方法,下面是具體的實例。修改BroadcastTest項目的MainActivity的代碼。
package com.wj.broadcasttest; import android.net.ConnectivityManager; import android.net.NetworkInfo; import android.os.Bundle; import android.app.Activity; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.support.v4.content.LocalBroadcastManager; import android.view.Menu; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.Toast; public class MainActivity extends Activity { private IntentFilter intentFilter; private NetworkChangeReceiver networkChangeReceiver; private LocalReceiver localReceiver; private LocalBroadcastManager localBroadcastManager; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //獲取LocalBroadcastManager的實例 localBroadcastManager=LocalBroadcastManager.getInstance(this); Button button1=(Button) findViewById(R.id.button1); button1.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub /*Intent intent=new Intent("com.wj.broadcasttest.MY_BROADCAST");*/ //sendBroadcast(intent); /*將sendBroadcast(intent)方法改成sendOrderedBroadcast(intent, null) * 就可以發送有序廣播了。sendOrderedBroadcast(intent, null)方法接收兩個參數 * ,第一個參數是仍然是Intent,第二參數是一個與權限相關的字符串,這裡傳入的是null。 * */ /*sendOrderedBroadcast(intent, null);//發送有序廣播。*/ //發送本地廣播 Intent intent=new Intent("com.wj.broadcasttest.LOCAL_BROADCAST"); localBroadcastManager.sendBroadcast(intent);//發送本地廣播 } }); /*intentFilter=new IntentFilter(); intentFilter.addAction("android.net.conn.CONNECTIVITY_CHANGE"); networkChangeReceiver=new NetworkChangeReceiver(); registerReceiver(networkChangeReceiver, intentFilter);*/ //注冊本地廣播 intentFilter=new IntentFilter(); intentFilter.addAction("com.wj.broadcasttest.LOCAL_BROADCAST"); localReceiver=new LocalReceiver(); localBroadcastManager.registerReceiver(localReceiver, intentFilter); } @Override protected void onDestroy() { // TODO Auto-generated method stub super.onDestroy(); /*unregisterReceiver(networkChangeReceiver);*/ localBroadcastManager.unregisterReceiver(localReceiver); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.main, menu); return true; } class LocalReceiver extends BroadcastReceiver{ @Override public void onReceive(Context context, Intent intent) { // TODO Auto-generated method stub Toast.makeText(context, "receiver local broadcast", Toast.LENGTH_SHORT).show(); } } //繼承BroadcastReceiver,重寫onReceiver方法,進行廣播接收處理。 class NetworkChangeReceiver extends BroadcastReceiver{ @Override public void onReceive(Context context, Intent intent) { // TODO Auto-generated method stub ConnectivityManager connectivityManager=(ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE); NetworkInfo networkInfo=connectivityManager.getActiveNetworkInfo(); if(networkInfo!=null&&networkInfo.isAvailable()){ /*Toast.makeText(context, "network is Available", Toast.LENGTH_LONG).show();*/ }else{ Toast.makeText(context, "network is unAvailable", Toast.LENGTH_LONG).show(); } } } }
上面的代碼和前面學的動態注冊廣播以及發送廣播的代碼是一樣的。只不過現在首先是通LocalBroadcastManager
的getInstance方法得到它的一個實例,然後在注冊廣播接收器的時候調用的是LocalBroadcastManager的registerReceiver方法,在發送廣播的時候調用的是LocalBroadcastManager的sendBroadcast方法。
運行程序,效果如下:
漏洞的問題。
3.發送本地廣播比發送系統全局廣播將會更加高效。
最後注意的是:在廣播接收器中啟動活動,因此一定要給Intent加FLAG_ACTIVITY_NEW_TASK這個標志。最後當在廣播中要彈出一個一個對話框的時候,需要給對話框設置alertDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT),不然對話框將無法在廣播接收器中彈出。
轉載請注明來至:http://blog.csdn.net/j903829182/article/details/40713385
時隔5個月時間,即6月14日,紅米3S作為紅米3的升級版,配備了高通骁龍430八核處理器,配備4100毫安時電池,定價699元起。紅米3S相對於紅米3的售價
https://github.com/daimajia/AndroidViewHover import android.support.v8.renderscrip
Fragment的地位在開發中可是舉足輕重的,掌握它的的生命周期以及使用特性是非常重要的,例如在開發中常使用的模板: FragmentTransaction tran
一、為什麼要進行屏幕適配某廠商統計如下數據2012年,支持Android的設備共有3997種 2013年,支持Android的設備共有11868種 2014年,支持And