極力推薦文章:歡迎收藏
Android 乾貨分享 java
本篇文章主要介紹 Android
開發中的部分知識點,經過閱讀本篇文章,您將收穫如下內容:android
- 廣播的生命週期
- 四大組件之一,必須在Androidmainfest.xml中註冊
- 廣播的註冊(靜態廣播、動態廣播)
- 廣播的發送(正常、有序、持續)
- 廣播接收(系統廣播、自定義廣播)
Broadcast
是 Android
四大組件之一,是一種普遍運用在應用程序之間異步傳輸信息的機制。Broadcast
本質上是一個Intent
對象,差異在於 Broadcast
能夠被多個 BroadcastReceiver
處理。BroadcastReceiver
是一個全局監聽器,經過它的 onReceive()
能夠過濾用戶想要的廣播,進而進行其它操做。程序員
BroadcastReceiver
默認是在主線程中執行,若是onReceiver()
方法處理事件超過10s
,則應用將會發生ANR(Application Not Responding)
,此時,若是創建工做線程並不能解決此問題,所以建議:如處理耗時操做,請用 Service
代替。微信
BroadcastReceiver
繼承關係 以下:網絡
java.lang.Object ↳ android.content.BroadcastReceiver
BroadcastReceiver
的主要聲明週期方法onReceiver()
,此方法執行完以後,BroadcastReceiver
實例將被銷燬。併發
<receiver android:name="ReceiverMethod" android:enabled="true" android:exported="true"> <intent-filter> <action android:name="String....." /> </intent-filter> </receiver>
注意:
如不註冊,將致使沒法接收處理廣播消息app
廣播的註冊分兩種,一種在ndroidMfest.xml
中靜態註冊,另外一種是在Java
代碼中動態註冊。異步
一些系統發送的廣播須要在Androidmainfest.xml
中靜態註冊,例如 開機廣播,apk狀態改變廣播,電量狀態改變廣播等。這些靜態註冊的廣播,一般在Androidmainfest.xml
中攔截特定的字符串。ide
靜態註冊廣播的方法以下:學習
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.programandroid" android:versionCode="1" android:versionName="1.0" > ... ... <receiver android:name="com.programandroid.BroadcastReceiver.NotificationReceived" android:enabled="true" android:exported="true" > <intent-filter> <action android:name="Notification_cancel" /> <action android:name="Notification_music_pre" /> <action android:name="Notification_music_play" /> <action android:name="Notification_music_next" /> </intent-filter> </receiver> ... ...
開機廣播比較特殊,須要在Androidmainfest.xml
中添加權限。不然,沒法獲取開機廣播。
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/> //靜態註冊廣播的方法 <receiver android:name=".component.BroadcastReceiver.BootReceiverMethod" android:enabled="true" android:exported="true"> <intent-filter> <action android:name="android.intent.action.BOOT_COMPLETED" /> </intent-filter> </receiver>
在Java中動態註冊廣播,一般格式以下:
//動態註冊廣播 registerReceiver(BroadcastReceiver, IntentFilter);
在廣播中動態註冊廣播請注意必定要使用context.getApplicationContext()
,防止context
爲空 ,引發空指針異常。
public class ScreenOnOffReceiver { public static void ReceiverScreenOnOff(Context context) { IntentFilter screenOffFilter = new IntentFilter(); screenOffFilter.addAction(Intent.ACTION_SCREEN_OFF); screenOffFilter.addAction(Intent.ACTION_SCREEN_ON); BroadcastReceiver mScreenOnOffReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { // TODO Auto-generated method stub String action = intent.getAction(); if (action.equals(Intent.ACTION_SCREEN_OFF)) { Toast.makeText(context, "接收屏幕熄滅廣播", Toast.LENGTH_SHORT).show(); } if (action.equals(Intent.ACTION_SCREEN_ON)) { Toast.makeText(context, "接收屏幕點亮廣播", Toast.LENGTH_SHORT).show(); } } }; /** * context.getApplicationContext() * 在廣播中註冊廣播時候須要注意,防止context 爲空 ,引發空指針異常 * **/ // 2.動態註冊廣播的方法 context.registerReceiver(mScreenOnOffReceiver, screenOffFilter); } }
發送無序廣播在Android
中很常見,是一種一對多的關係,主要經過 sendBroadcast(intent);
發送廣播。
廣播說白了就是一個帶Action
等字符串標記的Intent
。發送自定義廣播舉例以下:
Intent customIntent=new Intent(); customIntent.setAction("SendCustomBroadcast"); sendBroadcast(customIntent);
當用戶對某些廣播感興趣的話,此時能夠獲取此廣播,而後在onReceive
方法中處理接收廣播的一下操做。
public class CustomBroadcast extends BroadcastReceiver { public CustomBroadcast() { } @Override public void onReceive(Context context, Intent intent) { if (intent.getAction().equals("SendCustomBroadcast")){ Toast.makeText(context,"自定義廣播接收成功:Action:SendCustomBroadcast",Toast.LENGTH_SHORT).show(); } } }
注意自定義廣播是在
Androidmanfest.xml
中靜態註冊的。
廣播在Android
是有優先級的,優先級高的廣播能夠終止或修改廣播內容。發送有序廣播的方法以下sendOrderedBroadcast(intent,"str_receiver_permission");
Intent customOrderIntent=new Intent(); customOrderIntent.setAction("SendCustomOrderBroadcast"); customOrderIntent.putExtra("str_order_broadcast","老闆說:公司每人發 10 個 月餅"); sendOrderedBroadcast(customOrderIntent,"android.permission.ORDERBROADCAST");
廣播屬於四大組件,必定要在AndroidMainfest.xml
中註冊。
接收有序廣播的靜態註冊方法以下:
<receiver android:name=".component.BroadcastReceiver.CustomHightBrodcast" android:enabled="true" android:exported="true" > <intent-filter android:priority="1000"> <action android:name="SendCustomOrderBroadcast" /> </intent-filter> </receiver> <receiver android:name=".component.BroadcastReceiver.CustomMiddleBroadcast" android:enabled="true" android:exported="true" > <intent-filter android:priority="500"> <action android:name="SendCustomOrderBroadcast" /> </intent-filter> </receiver> <receiver android:name=".component.BroadcastReceiver.CustomLowerBroadcast" android:enabled="true" android:exported="true" > <intent-filter android:priority="100"> <action android:name="SendCustomOrderBroadcast" /> </intent-filter> </receiver>
public class CustomHightBrodcast extends BroadcastReceiver { public CustomHightBrodcast() { } @Override public void onReceive(Context context, Intent intent) { if (intent.getAction().equals("SendCustomOrderBroadcast")) { Toast.makeText(context, intent.getStringExtra("str_order_broadcast"), Toast.LENGTH_SHORT).show(); Bundle bundle=new Bundle(); bundle.putString("str_order_broadcast","經理說:公司每人發 5 個 月餅"); // 修改廣播傳輸數據 setResultExtras(bundle); } } }
public class CustomMiddleBroadcast extends BroadcastReceiver { public CustomMiddleBroadcast() { } @Override public void onReceive(Context context, Intent intent) { if (intent.getAction().equals("SendCustomOrderBroadcast")) { Toast.makeText(context, getResultExtras(true).getString("str_order_broadcast"), Toast.LENGTH_SHORT).show(); Bundle bundle=new Bundle(); bundle.putString("str_order_broadcast","主管說:公司每人發 2 個 月餅"); setResultExtras(bundle); } } }
public class CustomLowerBroadcast extends BroadcastReceiver { public CustomLowerBroadcast() { } @Override public void onReceive(Context context, Intent intent) { if (intent.getAction().equals("SendCustomOrderBroadcast")) { String notice= getResultExtras(true).getString("str_order_broadcast"); Toast.makeText(context,notice, Toast.LENGTH_SHORT).show(); // 終止廣播繼續傳播下去 abortBroadcast(); } } }
注意 :
有序廣播須要聲明並使用權限
<!-- 申請使用自定義 有序廣播的權限 --> <uses-permission > android:name="android.permission.ORDERBROADCAST" />
<!-- 自定義 有序廣播的權限 --> <permission> android:name="android.permission.ORDERBROADCAST"/>
在有序廣播中高優先級的廣播接收廣播,能夠修改數據,而後傳給低優先級的廣播。
粘性廣播會在Android
系統中一直存在,不過隨着 Android
系統的不斷更新,此方法逐漸被拋棄,使用方法以下:sendStickyBroadcast(intent);
當廣播發出後,如何接收廣播呢,下面將介紹接收廣播的方法。
接受廣播類 主要繼承 BroadcastReceiver
,而後在onReceive
方法,過濾廣播Action
中攜帶的Intent
,而後進行相關處理。
p ublic class BootReceiverMethod extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { // 接收開機廣播處理事情,好比啓動服務 Intent mStartIntent = new Intent(context, StartServiceMethods.class); context.startService(mStartIntent); } }
<receiver android:name=".component.BroadcastReceiver.BootReceiverMethod" android:enabled="true" android:exported="true"> <intent-filter> <action android:name="android.intent.action.BOOT_COMPLETED" /> </intent-filter> </receiver>
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
極力推薦文章:歡迎收藏
Android 乾貨分享
本篇文章主要介紹 Android
開發中的部分知識點,經過閱讀本篇文章,您將收穫如下內容:
- Service 簡介
- 四大組件之一,必須在Androidmainfest.xml 中註冊
- 啓動模式啓動服務
- 綁定模式綁定服務
- 前臺服務
- AIDL遠程服務
Service
是 Android
四大組件之一(Activity
活動,Service
服務,ContentProvider
內容提供者,BroadcastReceiver
廣播),與Activity
相比,Activity
是運行在前臺,用戶能夠看得見,Service
則是運行在後臺,無用戶界面,用戶沒法看到。
Service
主要用於組件之間交互(例如:與Activity
、ContentProvider
、BroadcastReceiver
進行交互)、後臺執行耗時操做等(例以下載文件,播放音樂等,但Service
在主線程運行時長不能超過20s
,不然會出現ANR
,耗時操做通常建議在子線程中進行操做)。
在瞭解Service
的生命週期的以前,咱們先了解一下Service
的繼承關係,方便咱們更好的瞭解Service
。
java.lang.Object ↳ android.content.Context ↳ android.content.ContextWrapper ↳ android.app.Service
Service
有兩種不一樣的啓動模式 ,不一樣的啓動模式對應不一樣生命週期.Service
啓動模式主要分兩種: 1. 啓動模式。 2. 綁定模式。
此模式經過 startService()
方法啓動,此服務能夠在後臺一直運行,不會隨啓動組件的消亡而消亡。只能執行單一操做,沒法返回結果給調用方,經常使用於網絡下載、上傳文件,播放音樂等。
此模式 經過綁定組件(Activity
等)調用 bindService()
啓動,此服務隨綁定組件的消亡而解除綁定。
若是此時沒有其它經過startService()
啓動,則此服務會隨綁定組件的消亡而消亡。
多個組件不只能夠同時綁定一個Service
,並且能夠經過進程間通訊(IPC)
執行跨進程操做等。
啓動模式與綁定模式的服務能夠同時運行,在銷燬服務時,只有兩種模式都不在使用Service
時候,才能夠銷燬服務,不然會引發異常。
兩種 Service
模式的生命週期以下:
<manifest ... > ... <application ... > <service android:name=".ServiceMethods" /> ... </application> </manifest>
Service
如不註冊 ,不會像Activity
那樣會致使App Crash
,Service
不註冊 不會報異常信息,可是服務會起不來,如不注意很容易迷惑。
經過啓動模式啓動的Service
,如不主動關閉,Service
會一直在。
Intent mBindIntent = new Intent(ServiceMethods.this, BindServiceMethods.class); startService(mStartIntent);
下面是驗證啓動模式啓動服務的生命週期的方法,詳細生命週期請查看上方Service
的生命週期圖。
01-03 17:16:36.147 23789-23789/com.android.program.programandroid I/StartService wjwj:: ----onCreate---- 01-03 17:16:36.223 23789-23789/com.android.program.programandroid I/StartService wjwj:: ----onStartCommand---- 01-03 17:16:38.174 23789-23789/com.android.program.programandroid I/StartService wjwj:: ----onDestroy----
此案例功能:啓動服務,在服務中建立通知
// Service 建立方法 @Override public void onCreate() { super.onCreate(); Log.i(TAG, "----onCreate----"); } // Service 啓動方法 @Override public int onStartCommand(Intent intent, int flags, int startId) { Log.i(TAG, "----onStartCommand----"); // 獲取NotificationManager實例 notifyManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); // 實例化NotificationCompat.Builder並設置相關屬性 NotificationCompat.Builder builder = new NotificationCompat.Builder( this) // 設置小圖標 .setSmallIcon(R.drawable.ic_launcher) .setLargeIcon( BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher)) // 設置通知標題 .setContentTitle("我是經過StartService服務啓動的通知") // 設置通知不能自動取消 .setAutoCancel(false).setOngoing(true) // 設置通知時間,默認爲系統發出通知的時間,一般不用設置 // .setWhen(System.currentTimeMillis()) // 設置通知內容 .setContentText("請使用StopService 方法中止服務"); // 經過builder.build()方法生成Notification對象,併發送通知,id=1 notifyManager.notify(1, builder.build()); return super.onStartCommand(intent, flags, startId); } // Service 銷燬方法 @Override public void onDestroy() { Log.i(TAG, "----onDestroy----"); notifyManager.cancelAll(); super.onDestroy(); }
綁定模式啓動的服務會隨着綁定逐漸的消亡而解除Service
綁定,若是此時Service
沒有經過啓動模式啓動,則此服務將會被銷燬。
綁定模式,是經過其餘組件啓動的Service
。
// 啓動綁定服務處理方法 public void BtnStartBindService(View view) { // 啓動綁定服務處理方法 bindService(mBindIntent, serviceConnection, Context.BIND_AUTO_CREATE); isBindService = true; Toast.makeText(ServiceMethod.this, "啓動 " + mBindCount + " 次綁定服務", Toast.LENGTH_SHORT).show(); } public void BtnSopBindService(View view) { if (isBindService) { // 解除綁定服務處理方法 unbindService(serviceConnection); Toast.makeText(ServiceMethod.this, "解除 " + mUnBindCount + " 次綁定服務", Toast.LENGTH_SHORT).show(); isBindService = false; } }
綁定服務 隨綁定組件的消亡而消亡
// Service 建立方法 @Override public void onCreate() { super.onCreate(); Log.i(TAG, "----onCreate----"); } // Service 綁定方法 @Override public IBinder onBind(Intent intent) { Log.i(TAG, "----onBind----"); MyBinder myBinder = new MyBinder(); return myBinder; } // Service 解除綁定方法 @Override public boolean onUnbind(Intent intent) { Log.i(TAG, "----onUnbind----"); return super.onUnbind(intent); } // Service 銷燬方法 @Override public void onDestroy() { Log.i(TAG, "----onDestroy----"); super.onDestroy(); }
綁定服務的生命週期代碼打印Log
信息以下:
01-03 20:32:59.422 13306-13306/com.android.program.programandroid I/BindService wjwj:: ----onCreate---- 01-03 20:32:59.423 13306-13306/com.android.program.programandroid I/BindService wjwj:: -----onBind----- 01-03 20:33:09.265 13306-13306/com.android.program.programandroid I/BindService wjwj:: ----onUnbind---- 01-03 20:33:09.266 13306-13306/com.android.program.programandroid I/BindService wjwj:: ----onDestroy----
功能:獲取綁定模式啓動 綁定服務及解除綁定服務的次數
package com.android.program.programandroid.component.Service; import android.app.Service; import android.content.Intent; import android.os.IBinder; import android.util.Log; public class BindServiceMethods extends Service { private static final String TAG = "BindService wjwj:"; public BindServiceMethods() { } @Override public void onCreate() { super.onCreate(); Log.i(TAG, "----onCreate----"); } @Override public IBinder onBind(Intent intent) { Log.i(TAG, "----onBind----"); MyBinder myBinder = new MyBinder(); return myBinder; } @Override public boolean onUnbind(Intent intent) { Log.i(TAG, "----onUnbind----"); return super.onUnbind(intent); } @Override public void onDestroy() { Log.i(TAG, "----onDestroy----"); super.onDestroy(); } }
// 啓動綁定服務處理方法 public void BtnStartBindService(View view) { bindService(mBindIntent, serviceConnection, Context.BIND_AUTO_CREATE); isBindService = true; Toast.makeText(ServiceMethods.this,"啓動 "+mBindCount+" 次綁定服務",Toast.LENGTH_SHORT).show(); } // 解除綁定服務處理方法 public void BtnSopBindService(View view) { if (isBindService) { unbindService(serviceConnection); Toast.makeText(ServiceMethods.this,"解除 "+mUnBindCount+" 次綁定服務",Toast.LENGTH_SHORT).show(); isBindService=false; } }
Binder
接口類/** * 該類提供 綁定組件與綁定服務提供接口 * */ public class MyBinder extends Binder { private int count = 0; public int getBindCount() { return ++count; } public int getUnBindCount() { return count> 0 ? count-- : 0; } }
服務默認啓動方式是後臺服務,可是能夠經過設置服務爲前臺服務,提升服務的優先級,進而避免手機內存緊張時,服務進程被殺掉。
1.設置爲前臺服務
//設置爲前臺服務 startForeground(int, Notification)
2.取消前臺服務
//取消爲前臺服務 stopForeground(true);
功能:前臺服務綁定通知信息,提升服務進程優先級,不然取消通知信息
package com.android.program.programandroid.component.Service; import android.app.NotificationManager; import android.app.Service; import android.content.Intent; import android.graphics.BitmapFactory; import android.os.IBinder; import android.support.v4.app.NotificationCompat; import com.android.program.programandroid.R; public class MyStartForcegroundService extends Service { public MyStartForcegroundService() { } @Override public IBinder onBind(Intent intent) { // TODO: Return the communication channel to the service. throw new UnsupportedOperationException("Not yet implemented"); } @Override public void onCreate() { super.onCreate(); } @Override public int onStartCommand(Intent intent, int flags, int startId) { if (intent.getAction().equals("start_forceground_service")) { // 獲取NotificationManager實例 NotificationManager notifyManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); // 實例化NotificationCompat.Builder並設置相關屬性 NotificationCompat.Builder builder = new NotificationCompat.Builder(this) // 設置小圖標 .setSmallIcon(R.mipmap.ic_launcher) .setLargeIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher)) // 設置通知標題 .setContentTitle("我是經過startForeground 啓動前臺服務通知") // 設置通知不能自動取消 .setAutoCancel(false) .setOngoing(true) // 設置通知時間,默認爲系統發出通知的時間,一般不用設置 // .setWhen(System.currentTimeMillis()) // 設置通知內容 .setContentText("請使用stopForeground 方法改成後臺服務"); //經過builder.build()方法生成Notification對象,併發送通知,id=1 // 設置爲前臺服務 startForeground(1, builder.build()); } else if (intent.getAction().equals("stop_forceground_service")) { stopForeground(true); } return super.onStartCommand(intent, flags, startId); } }
因爲內容較多,後續另開一篇詳細介紹。
至此,本篇已結束,若有不對的地方,歡迎您的建議與指正。同時期待您的關注,感謝您的閱讀,謝謝!