Service 服務(wù)
什么是服務(wù):
A service is not a separate process and A service is not thread; A Service is an application component that can perform long-running opreations in the background and doesnot provider a userinterface.
- 服務(wù)是一個(gè)無界面化的應(yīng)用程序組件
- 服務(wù)一般用于后臺(tái)進(jìn)行耗時(shí)操作
Service的生命周期:
![Upload service_lifecycle.png failed. Please try again.]
startService方式開啟服務(wù):
-
startService(Intent service)
,通過intent值來指定啟動(dòng)哪個(gè)Service,可以直接指定目標(biāo)Service的名,也可以通過Intent的action屬性來啟動(dòng)設(shè)置了相應(yīng)action屬性的Service,使用這種方式啟動(dòng)的Service,當(dāng)啟動(dòng)它的Activity被銷毀時(shí),是不會(huì)影響到它的運(yùn)行的,這時(shí)它仍然繼續(xù)在后臺(tái)運(yùn)行它的工作。直至調(diào)用StopService(Intent service)
方法時(shí)或者是當(dāng)系統(tǒng)資源非常緊缺時(shí),這個(gè)服務(wù)才會(huì)調(diào)用onDestory()方法停止運(yùn)行。所以這種Service一般可以用做,處理一些耗時(shí)的工作。 - 四大組件默認(rèn)都是和activity運(yùn)行在同一個(gè)主線程中的,那就是說activity通過startservice方法啟動(dòng)一個(gè)服務(wù)后,被啟動(dòng)的服務(wù)和activity都是在同一個(gè)線程中的。所以當(dāng)我主動(dòng)銷毀了這個(gè)activity,但是他所在的線程還是存在的,只不過是這個(gè)activity他所占用的資源被釋放掉了,這個(gè)activity所在的主線程只有當(dāng)android內(nèi)存不足才會(huì)被殺死掉,否則一般的情況下這個(gè)activity所在的應(yīng)用程序的線程始終存在,也就是這個(gè)activity所啟動(dòng)的服務(wù)也會(huì)一直運(yùn)行下去。
Service
public class LifeService extends Service {
private static final String TAG = "LifeService";
@Override
public void onCreate() {
Log.d(TAG, "服務(wù)------onCreate");
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(TAG, "服務(wù)------onStartCommand");
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
Log.d(TAG, "服務(wù)------onDestroy");
super.onDestroy();
}
}
Activity
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void startService(View view) {
Intent intent = new Intent(this, LifeService.class);
startService(intent);
}
public void stopService(View view) {
Intent intent = new Intent(this, LifeService.class);
stopService(intent);
}
}
運(yùn)行結(jié)果:
![Upload start_service_lifecycle.png failed. Please try again.]
Service 可以被開啟多次,但是只會(huì)創(chuàng)建一次.
bindService方式開啟服務(wù)
- bindService開啟的服務(wù),可以調(diào)用到服務(wù)中的方法.
- 啟動(dòng)的LifeService是和MainActivity在同一個(gè)進(jìn)程里的,因?yàn)樵谧?cè)服務(wù)時(shí),沒有配置它的android:process = "xxxx" 屬性。
Service
public class LifeService extends Service {
private static final String TAG = "LifeService";
@Override
public void onCreate() {
Log.d(TAG, "服務(wù)------onCreate");
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(TAG, "服務(wù)------onStartCommand");
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
Log.d(TAG, "服務(wù)------onDestroy");
super.onDestroy();
}
@Override
public boolean onUnbind(Intent intent) {
Log.d(TAG, "服務(wù)------onUnbind");
return super.onUnbind(intent);
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
Log.d(TAG, "服務(wù)------onBind");
return new Mybind();
}
public class Mybind extends Binder {
public void callMethodInService() {
methodInService();
}
}
public void methodInService() {
Toast.makeText(this, "服務(wù)里的方法被調(diào)用了", Toast.LENGTH_SHORT).show();
Log.d(TAG, "服務(wù)里的方法被調(diào)用了");
}
}
Activity
public class MainActivity extends AppCompatActivity {
private ServiceConnection conn;
private LifeService.Mybind mBinder;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
//綁定服務(wù)
public void bindService(View view) {
Intent intent = new Intent(this, LifeService.class);
conn = new MyServiceConnection();
bindService(intent, conn, BIND_AUTO_CREATE);
}
private class MyServiceConnection implements ServiceConnection {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mBinder = (LifeService.Mybind) service;
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
}
//解綁服務(wù)
public void unbindService(View view) {
unbindService(conn);
}
//調(diào)用服務(wù)里的方法
public void callMethodInService(View view) {
mBinder.callMethodInService();
}
}
運(yùn)行結(jié)果
![Upload bind_service_1.png failed. Please try again.]
出現(xiàn)一個(gè)有意思的現(xiàn)象: 當(dāng)解綁服務(wù)后,service已經(jīng)onDestroy(),但是還是能調(diào)用服務(wù)中的方法.運(yùn)行圖如下:
![Upload bind_service_2.png failed. Please try again.]
服務(wù)雖然是onDestroy了,但是MainActivity中還保留LifeService.Binder的引用,服務(wù)中的方法也保留了Service自身的引用,所以即便是Service onDestroy()了,但是還是可以調(diào)用到服務(wù)中的方法.
混合方式開啟服務(wù)
- startService開啟服務(wù): 服務(wù)能在后臺(tái)長(zhǎng)期運(yùn)行,不能調(diào)用服務(wù)中方法.
- bindService開啟服務(wù): 能調(diào)用服務(wù)中的方法,但是不能在后臺(tái)長(zhǎng)期運(yùn)行.
- 混合方式開啟服務(wù): 保證服務(wù)后臺(tái)長(zhǎng)期運(yùn)行, 還能調(diào)用服務(wù)中的方法.
![Upload service_binding_tree_lifecycle.png failed. Please try again.]
Service
public class LifeService extends Service {
private static final String TAG = "LifeService";
@Override
public void onCreate() {
Log.d(TAG, "服務(wù)------onCreate");
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(TAG, "服務(wù)------onStartCommand");
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
Log.d(TAG, "服務(wù)------onDestroy");
super.onDestroy();
}
@Override
public boolean onUnbind(Intent intent) {
Log.d(TAG, "服務(wù)------onUnbind");
return super.onUnbind(intent);
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
Log.d(TAG, "服務(wù)------onBind");
return new Mybind();
}
public class Mybind extends Binder {
public void callMethodInService() {
methodInService();
}
}
public void methodInService() {
Toast.makeText(this, "服務(wù)里的方法被調(diào)用了", Toast.LENGTH_SHORT).show();
Log.d(TAG, "服務(wù)里的方法被調(diào)用了");
}
}
Activity
public class MainActivity extends AppCompatActivity {
private ServiceConnection conn;
private LifeService.Mybind mBinder;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
//開啟服務(wù)
public void startService(View view) {
Intent intent = new Intent(this, LifeService.class);
startService(intent);
}
//停止服務(wù)
public void stopService(View view) {
Intent intent = new Intent(this, LifeService.class);
stopService(intent);
}
//綁定服務(wù)
public void bindService(View view) {
Intent intent = new Intent(this, LifeService.class);
conn = new MyServiceConnection();
bindService(intent, conn, BIND_AUTO_CREATE);
}
//解綁服務(wù)
public void unbindService(View view) {
unbindService(conn);
}
private class MyServiceConnection implements ServiceConnection {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mBinder = (LifeService.Mybind) service;
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
}
//調(diào)用服務(wù)中的方法
public void callMethodInService(View view) {
mBinder.callMethodInService();
}
}
運(yùn)行結(jié)果
![Upload mix_start_service.png failed. Please try again.]
注意幾點(diǎn):
- 以startService方式開啟的服務(wù), 解綁服務(wù),并不能使服務(wù)onDestroy
IBinder: the communication channel to the service,may return null if clients not connect to services.
unlike other application components, calls on to the IBinder interface returned here may not happen on the main thread of the process
接口
利用接口屏蔽方法內(nèi)部實(shí)現(xiàn)的細(xì)節(jié), 只暴露需要暴露的方法.
IService
public interface IService {
void callMethodInService();
}
Service
private class Mybind extends Binder implements IService {
public void callMethodInService() {
methodInService();
}
}
Activity
private class MyServiceConnection implements ServiceConnection {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
//轉(zhuǎn)化Iservice對(duì)象
mIService = (IService) service;
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
}
IntentService 類
Service 的子類,它使用工作線程逐一處理所有啟動(dòng)請(qǐng)求。如果您不要求服務(wù)同時(shí)處理多個(gè)請(qǐng)求,這是最好的選擇。 您只需實(shí)現(xiàn) onHandleIntent() 方法即可,該方法會(huì)接收每個(gè)啟動(dòng)請(qǐng)求的 Intent,使您能夠執(zhí)行后臺(tái)工作。由于大多數(shù)啟動(dòng)服務(wù)都不必同時(shí)處理多個(gè)請(qǐng)求(實(shí)際上,這種多線程情況可能很危險(xiǎn)),因此使用 IntentService 類實(shí)現(xiàn)服務(wù)也許是最好的選擇。
IntentService 執(zhí)行以下操作:
- 創(chuàng)建默認(rèn)的工作線程,用于在應(yīng)用的主線程外執(zhí)行傳遞給 onStartCommand() 的所有 Intent。
- 創(chuàng)建工作隊(duì)列,用于將 Intent 逐一傳遞給 onHandleIntent() 實(shí)現(xiàn),這樣您就永遠(yuǎn)不必?fù)?dān)心多線程問題。
- 在處理完所有啟動(dòng)請(qǐng)求后停止服務(wù),因此您永遠(yuǎn)不必調(diào)用 stopSelf()。
- 提供 onBind() 的默認(rèn)實(shí)現(xiàn)(返回 null)。
- 提供 onStartCommand() 的默認(rèn)實(shí)現(xiàn),可將 Intent 依次發(fā)送到工作隊(duì)列和 onHandleIntent() 實(shí)現(xiàn)。
綜上所述,您只需實(shí)現(xiàn) onHandleIntent() 來完成客戶端提供的工作即可。(不過,您還需要為服務(wù)提供小型構(gòu)造函數(shù)。)
public class HelloIntentService extends IntentService {
/**
* A constructor is required, and must call the super IntentService(String)
* constructor with a name for the worker thread.
*/
public HelloIntentService() {
super("HelloIntentService");
}
/**
* The IntentService calls this method from the default worker thread with
* the intent that started the service. When this method returns, IntentService
* stops the service, as appropriate.
*/
@Override
protected void onHandleIntent(Intent intent) {
// Normally we would do some work here, like download a file.
// For our sample, we just sleep for 5 seconds.
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
// Restore interrupt status.
Thread.currentThread().interrupt();
}
}
}
您只需要一個(gè)構(gòu)造函數(shù)和一個(gè) onHandleIntent() 實(shí)現(xiàn)即可。如果您決定還重寫其他回調(diào)方法(如 onCreate()、onStartCommand() 或 onDestroy()),請(qǐng)確保調(diào)用超類實(shí)現(xiàn),以便 IntentService 能夠妥善處理工作線程的生命周期。
執(zhí)行多線程耗時(shí)操作Service
正如上一部分中所述,使用 IntentService 顯著簡(jiǎn)化了啟動(dòng)服務(wù)的實(shí)現(xiàn)。但是,若要求服務(wù)執(zhí)行多線程(而不是通過工作隊(duì)列處理啟動(dòng)請(qǐng)求),則可擴(kuò)展 Service 類來處理每個(gè) Intent。
為了便于比較,以下提供了 Service 類實(shí)現(xiàn)的代碼示例,該類執(zhí)行的工作與上述使用 IntentService 的示例完全相同。也就是說,對(duì)于每個(gè)啟動(dòng)請(qǐng)求,它均使用工作線程執(zhí)行作業(yè),且每次僅處理一個(gè)請(qǐng)求。
public class HelloService extends Service {
private Looper mServiceLooper;
private ServiceHandler mServiceHandler;
// Handler that receives messages from the thread
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
// Normally we would do some work here, like download a file.
// For our sample, we just sleep for 5 seconds.
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
// Restore interrupt status.
Thread.currentThread().interrupt();
}
// Stop the service using the startId, so that we don't stop
// the service in the middle of handling another job
stopSelf(msg.arg1);
}
}
@Override
public void onCreate() {
// Start up the thread running the service. Note that we create a
// separate thread because the service normally runs in the process's
// main thread, which we don't want to block. We also make it
// background priority so CPU-intensive work will not disrupt our UI.
HandlerThread thread = new HandlerThread("ServiceStartArguments",
Process.THREAD_PRIORITY_BACKGROUND);
thread.start();
// Get the HandlerThread's Looper and use it for our Handler
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show();
// For each start request, send a message to start a job and deliver the
// start ID so we know which request we're stopping when we finish the job
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
mServiceHandler.sendMessage(msg);
// If we get killed, after returning from here, restart
return START_STICKY;
}
@Override
public IBinder onBind(Intent intent) {
// We don't provide binding, so return null
return null;
}
@Override
public void onDestroy() {
Toast.makeText(this, "service done", Toast.LENGTH_SHORT).show();
}
}
正如您所見,與使用 IntentService 相比,這需要執(zhí)行更多工作。
但是,因?yàn)槭怯赡约禾幚韺?duì) onStartCommand() 的每個(gè)調(diào)用,因此可以同時(shí)執(zhí)行多個(gè)請(qǐng)求。此示例并未這樣做,但如果您希望如此,則可為每個(gè)請(qǐng)求創(chuàng)建一個(gè)新線程,然后立即運(yùn)行這些線程(而不是等待上一個(gè)請(qǐng)求完成)。
請(qǐng)注意,onStartCommand() 方法必須返回整型數(shù)。整型數(shù)是一個(gè)值,用于描述系統(tǒng)應(yīng)該如何在服務(wù)終止的情況下繼續(xù)運(yùn)行服務(wù)(如上所述,IntentService 的默認(rèn)實(shí)現(xiàn)將為您處理這種情況,不過您可以對(duì)其進(jìn)行修改)。從 onStartCommand() 返回的值必須是以下常量之一:
-
START_NOT_STICKY
如果系統(tǒng)在 onStartCommand() 返回后終止服務(wù),則除非有掛起 Intent 要傳遞,否則系統(tǒng)不會(huì)重建服務(wù)。這是最安全的選項(xiàng),可以避免在不必要時(shí)以及應(yīng)用能夠輕松重啟所有未完成的作業(yè)時(shí)運(yùn)行服務(wù)。
-
START_STICKY
如果系統(tǒng)在 onStartCommand() 返回后終止服務(wù),則會(huì)重建服務(wù)并調(diào)用 onStartCommand(),但不會(huì)重新傳遞最后一個(gè) Intent。相反,除非有掛起 Intent 要啟動(dòng)服務(wù)(在這種情況下,將傳遞這些 Intent ),否則系統(tǒng)會(huì)通過空 Intent 調(diào)用 onStartCommand()。這適用于不執(zhí)行命令、但無限期運(yùn)行并等待作業(yè)的媒體播放器(或類似服務(wù))。
-
START_REDELIVER_INTENT
如果系統(tǒng)在 onStartCommand() 返回后終止服務(wù),則會(huì)重建服務(wù),并通過傳遞給服務(wù)的最后一個(gè) Intent 調(diào)用 onStartCommand()。任何掛起 Intent 均依次傳遞。這適用于主動(dòng)執(zhí)行應(yīng)該立即恢復(fù)的作業(yè)(例如下載文件)的服務(wù)。
前臺(tái)服務(wù)
public class ForegroundService extends Service {
@Override
public void onCreate() {
super.onCreate();
showNotification();
}
private void showNotification() {
//創(chuàng)建點(diǎn)擊跳轉(zhuǎn)Intent
Intent inten = new Intent(this, MainActivity.class);
//創(chuàng)建任務(wù)棧Builder
TaskStackBuilder taskStackBuilder = TaskStackBuilder.create(this);
taskStackBuilder.addParentStack(MainActivity.class);
taskStackBuilder.addNextIntent(inten);
PendingIntent pendingIntent = taskStackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);
//創(chuàng)建通知詳細(xì)信息
Notification notification = new NotificationCompat.Builder(this)
.setSmallIcon(R.mipmap.ic_launcher)
.setContentTitle("foreground service")
.setContentText("show details news")
.setWhen(System.currentTimeMillis())
.setContentIntent(pendingIntent)
.build();
NotificationManager nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
nm.notify(0, notification);
startForeground(0,notification);
}
}
系統(tǒng)服務(wù)
系統(tǒng)服務(wù)提供了很多便捷服務(wù),可以查詢Wifi、網(wǎng)絡(luò)狀態(tài)、查詢電量、查詢音量、查詢包名、查詢Application信息等等等相關(guān)多的服務(wù),具體大家可以自信查詢文檔,這里舉例幾個(gè)常見的服務(wù)
-
判斷Wifi是否開啟
WifiManager wm = (WifiManager) getSystemService(WIFI_SERVICE); boolean enabled = wm.isWifiEnabled();
獲取系統(tǒng)最大音量
```java
AudioManager am = (AudioManager) getSystemService(AUDIO_SERVICE);
int max = am.getStreamMaxVolume(AudioManager.STREAM_SYSTEM);
```
-
獲取當(dāng)前音量
AudioManager am = (AudioManager) getSystemService(AUDIO_SERVICE); int current = am.getStreamMaxVolume(AudioManager.STREAM_RING);
-
判斷網(wǎng)絡(luò)是否有連接
ConnectivityManager cm = (ConnectivityManager) getSystemService(CONNECTIVITY_SERVICE); NetworkInfo info = cm.getActiveNetworkInfo(); boolean isAvailable = info.isAvailable();