讀前思考
學習一門技術或者看一篇文章最好的方式就是帶著問題去學習,這樣才能在過程中有茅塞頓開、燈火闌珊的感覺,記憶也會更深刻。
- 談一談 Service 的生命週期?
- Service的兩種啟動方式?區別在哪?
- 一個 Activty 先 start 一個 Service 後,再 bind 時會回撥什麼方法?
- Service 如何和 Activity 進行通訊?
- 是否能在 Service 進行耗時操作?如果非要可以怎麼做?
- 前臺服務是什麼?和普通服務的不同?如何去開啟一個前臺服務?
建立服務
- 建立一個類繼承 Service ,重寫 onBind( )方法 .
public class Part1aService extends Service {
private static final String CHANNEL_ID_STRING = "KEVEN_JIANSHU";
public Part1aService() {
}
@Override
public IBinder onBind(Intent intent) {
LogUtils.i("Service 執行了 onBind( )");
return null;
}
複製程式碼
- 在清單檔案中註冊 Service .
<service android:name=".part1.Part1aService"></service>
複製程式碼
啟動服務
啟動服務有兩種方式,一種是 startService( ) ,一種是 bindService( ) .
startService( )
特點: 一旦服務開啟就跟呼叫者(開啟者)沒有任何關係了。開啟者退出了,開啟者掛了,服務還在後臺長期的執行,開啟者不能呼叫服務裡面的方法。
使用如下程式碼進行服務開啟
Intent intent = new Intent(Part1aActivity.this, Part1aService.class);
startService(intent);
複製程式碼
使用如下程式碼進行服務關閉(或者 Service 呼叫 stopSelf( ) )
Intent intent = new Intent(Part1aActivity.this, Part1aService.class);
stopService(intent);
複製程式碼
生命週期回撥
com.keven.jianshu I/TAG: Service 執行了 onCreate( )
com.keven.jianshu I/TAG: Service 執行了 onStartCommand( )
com.keven.jianshu I/TAG: Service 執行了 onDestroy( )
複製程式碼
Android 8.0 + ,對後臺服務進行了限制了,官網如下所述。
Android 8.0 還對特定函式做出了以下變更:
如果針對 Android 8.0 的應用嘗試在不允許其建立後臺服務的情況下使用 startService() 函式,則該函式將引發一個 IllegalStateException。
新的 Context.startForegroundService() 函式將啟動一個前臺服務。現在,即使應用在後臺執行,系統也允許其呼叫 Context.startForegroundService()。
不過,應用必須在建立服務後的五秒內呼叫該服務的 startForeground() 函式。
所以,啟動程式碼就可以針對文件所述進行適配。
//進行8.0+ 以上啟動服務的適配
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
Intent intent = new Intent(Part1aActivity.this, Part1aService.class);
startForegroundService(intent);
} else {
Intent intent = new Intent(Part1aActivity.this, Part1aService.class);
startService(intent);
}
複製程式碼
在 Service 中的 onCreate( ) 方法中做如下修改。
@Override
public void onCreate() {
LogUtils.i("Service 執行了 onCreate( )");
super.onCreate();
//適配8.0+service
NotificationManager notificationManager = (NotificationManager) MyApp.getInstance().getSystemService(Context.NOTIFICATION_SERVICE);
NotificationChannel mChannel = null;
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
mChannel = new NotificationChannel(CHANNEL_ID_STRING, "Keven 簡書", NotificationManager.IMPORTANCE_HIGH);
notificationManager.createNotificationChannel(mChannel);
Notification notification = new Notification.Builder(getApplicationContext(), CHANNEL_ID_STRING).build();
startForeground(1, notification);
}
}
複製程式碼
bindService( )
特點:bind 的方式開啟服務,繫結服務,呼叫者掛了,服務也會跟著掛掉。繫結者可以呼叫服務裡面的方法。
使用 bind 方式開啟與關閉服務的程式碼如下
//繫結服務
Intent intent = new Intent(Part1aActivity.this, Part1aService.class);
bindService(intent, connection, BIND_AUTO_CREATE);
//解綁服務
Intent intent = new Intent(Part1aActivity.this, Part1aService.class);
unbindService(connection);
複製程式碼
生命週期呼叫如下
com.keven.jianshu I/TAG: Service 執行了 onCreate( )
com.keven.jianshu I/TAG: Service 執行了 onBind( )
com.keven.jianshu I/TAG: Service 執行了 onUnbind( )
com.keven.jianshu I/TAG: Service 執行了 onDestroy( )
複製程式碼
一個 Activty 先 start 一個 Service 後,再 bind 時會回撥 onBind( ) 方法,不會呼叫 onCreate( ) 方法,因為服務已經啟動了。
Service 和 Activity 進行通訊
方式一:廣播
這種方式比較簡單,用 Android 四大元件之一的廣播即可實現通訊。
方式二:針對 bindService( ) 啟動方式的通訊
- 在 Service 中建立類繼承 Binder,並在其中編寫需要 Activity 呼叫的方法。
class MyBinder extends Binder {
public void getServiceMethod() {
LogUtils.e("呼叫了 Part1aService 的 getServiceMethod( ) 方法");
}
}
複製程式碼
- 在 Service 中建立上述類的物件。
private MyBinder binder = new MyBinder();
複製程式碼
- 在 Service 中的 onBind( ) 方法中返回建立的物件。
@Override
public IBinder onBind(Intent intent) {
LogUtils.i("Service 執行了 onBind( )");
return binder;
}
複製程式碼
- 在 Activity 中建立 ServiceConnection 類,並重寫它的 onServiceConnected( ) 和 onServiceDisconnected( ) 方法,並將 onServiceConnected( ) 方法中的 IBinder 型別的物件強轉為 Service 中類的型別,之後就可以呼叫其中的方法進行通訊了。
ServiceConnection connection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Part1aService.MyBinder myBinder = (Part1aService.MyBinder) service;
myBinder.getServiceMethod();
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
複製程式碼
耗時操作
因為服務也是執行在 UI 執行緒的,所以不能再服務中執行耗時操作,如果需要執行耗時操作,可以有如下兩種方式。
方式一: 開啟子執行緒執行耗時操作;
方式二: 使用 IntentService 。
IntentService 是 Android 系統提供的類,可在其中執行耗時任務,當任務執行完後,服務會自動銷燬,無需操作。
通過檢視原始碼可以知道 IntentService 繼承 Service,在它的 onCreate( ) 方法中建立了 HandlerThread,Looper,ServiceHandler ,所以其內部有訊息機制和執行緒,可以在 onHandleIntent( ) 方法中執行耗時操作。
我們可以新建一個類繼承 IntentService,重寫它的 onHandleIntent( ) 方法,並在其中執行耗時操作,然後在清單檔案中註冊這個服務即可。
文章已經讀到末尾了,不知道最初的幾個問題你都會了嗎?如果不會的話?可以再針對不會的問題進行精讀哦!答案都在文中,相信你肯定可以解決的!