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ù)是一個無界面化的應(yīng)用程序組件
- 服務(wù)一般用于后臺進行耗時操作
Service的生命周期:
![Upload service_lifecycle.png failed. Please try again.]
startService方式開啟服務(wù):
-
startService(Intent service)
,通過intent值來指定啟動哪個Service,可以直接指定目標(biāo)Service的名,也可以通過Intent的action屬性來啟動設(shè)置了相應(yīng)action屬性的Service,使用這種方式啟動的Service,當(dāng)啟動它的Activity被銷毀時,是不會影響到它的運行的,這時它仍然繼續(xù)在后臺運行它的工作。直至調(diào)用StopService(Intent service)
方法時或者是當(dāng)系統(tǒng)資源非常緊缺時,這個服務(wù)才會調(diào)用onDestory()方法停止運行。所以這種Service一般可以用做,處理一些耗時的工作。 - 四大組件默認(rèn)都是和activity運行在同一個主線程中的,那就是說activity通過startservice方法啟動一個服務(wù)后,被啟動的服務(wù)和activity都是在同一個線程中的。所以當(dāng)我主動銷毀了這個activity,但是他所在的線程還是存在的,只不過是這個activity他所占用的資源被釋放掉了,這個activity所在的主線程只有當(dāng)android內(nèi)存不足才會被殺死掉,否則一般的情況下這個activity所在的應(yīng)用程序的線程始終存在,也就是這個activity所啟動的服務(wù)也會一直運行下去。
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);
}
}
運行結(jié)果:
![Upload start_service_lifecycle.png failed. Please try again.]
Service 可以被開啟多次,但是只會創(chuàng)建一次.
bindService方式開啟服務(wù)
- bindService開啟的服務(wù),可以調(diào)用到服務(wù)中的方法.
- 啟動的LifeService是和MainActivity在同一個進程里的,因為在注冊服務(wù)時,沒有配置它的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();
}
}
運行結(jié)果
![Upload bind_service_1.png failed. Please try again.]
出現(xiàn)一個有意思的現(xiàn)象: 當(dāng)解綁服務(wù)后,service已經(jīng)onDestroy(),但是還是能調(diào)用服務(wù)中的方法.運行圖如下:
![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ù)能在后臺長期運行,不能調(diào)用服務(wù)中方法.
- bindService開啟服務(wù): 能調(diào)用服務(wù)中的方法,但是不能在后臺長期運行.
- 混合方式開啟服務(wù): 保證服務(wù)后臺長期運行, 還能調(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();
}
}
運行結(jié)果
![Upload mix_start_service.png failed. Please try again.]
注意幾點:
- 以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)部實現(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對象
mIService = (IService) service;
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
}
IntentService 類
Service 的子類,它使用工作線程逐一處理所有啟動請求。如果您不要求服務(wù)同時處理多個請求,這是最好的選擇。 您只需實現(xiàn) onHandleIntent() 方法即可,該方法會接收每個啟動請求的 Intent,使您能夠執(zhí)行后臺工作。由于大多數(shù)啟動服務(wù)都不必同時處理多個請求(實際上,這種多線程情況可能很危險),因此使用 IntentService 類實現(xiàn)服務(wù)也許是最好的選擇。
IntentService 執(zhí)行以下操作:
- 創(chuàng)建默認(rèn)的工作線程,用于在應(yīng)用的主線程外執(zhí)行傳遞給 onStartCommand() 的所有 Intent。
- 創(chuàng)建工作隊列,用于將 Intent 逐一傳遞給 onHandleIntent() 實現(xiàn),這樣您就永遠(yuǎn)不必?fù)?dān)心多線程問題。
- 在處理完所有啟動請求后停止服務(wù),因此您永遠(yuǎn)不必調(diào)用 stopSelf()。
- 提供 onBind() 的默認(rèn)實現(xiàn)(返回 null)。
- 提供 onStartCommand() 的默認(rèn)實現(xiàn),可將 Intent 依次發(fā)送到工作隊列和 onHandleIntent() 實現(xiàn)。
綜上所述,您只需實現(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òu)造函數(shù)和一個 onHandleIntent() 實現(xiàn)即可。如果您決定還重寫其他回調(diào)方法(如 onCreate()、onStartCommand() 或 onDestroy()),請確保調(diào)用超類實現(xiàn),以便 IntentService 能夠妥善處理工作線程的生命周期。
執(zhí)行多線程耗時操作Service
正如上一部分中所述,使用 IntentService 顯著簡化了啟動服務(wù)的實現(xiàn)。但是,若要求服務(wù)執(zhí)行多線程(而不是通過工作隊列處理啟動請求),則可擴展 Service 類來處理每個 Intent。
為了便于比較,以下提供了 Service 類實現(xiàn)的代碼示例,該類執(zhí)行的工作與上述使用 IntentService 的示例完全相同。也就是說,對于每個啟動請求,它均使用工作線程執(zhí)行作業(yè),且每次僅處理一個請求。
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í)行更多工作。
但是,因為是由您自己處理對 onStartCommand() 的每個調(diào)用,因此可以同時執(zhí)行多個請求。此示例并未這樣做,但如果您希望如此,則可為每個請求創(chuàng)建一個新線程,然后立即運行這些線程(而不是等待上一個請求完成)。
請注意,onStartCommand() 方法必須返回整型數(shù)。整型數(shù)是一個值,用于描述系統(tǒng)應(yīng)該如何在服務(wù)終止的情況下繼續(xù)運行服務(wù)(如上所述,IntentService 的默認(rèn)實現(xiàn)將為您處理這種情況,不過您可以對其進行修改)。從 onStartCommand() 返回的值必須是以下常量之一:
-
START_NOT_STICKY
如果系統(tǒng)在 onStartCommand() 返回后終止服務(wù),則除非有掛起 Intent 要傳遞,否則系統(tǒng)不會重建服務(wù)。這是最安全的選項,可以避免在不必要時以及應(yīng)用能夠輕松重啟所有未完成的作業(yè)時運行服務(wù)。
-
START_STICKY
如果系統(tǒng)在 onStartCommand() 返回后終止服務(wù),則會重建服務(wù)并調(diào)用 onStartCommand(),但不會重新傳遞最后一個 Intent。相反,除非有掛起 Intent 要啟動服務(wù)(在這種情況下,將傳遞這些 Intent ),否則系統(tǒng)會通過空 Intent 調(diào)用 onStartCommand()。這適用于不執(zhí)行命令、但無限期運行并等待作業(yè)的媒體播放器(或類似服務(wù))。
-
START_REDELIVER_INTENT
如果系統(tǒng)在 onStartCommand() 返回后終止服務(wù),則會重建服務(wù),并通過傳遞給服務(wù)的最后一個 Intent 調(diào)用 onStartCommand()。任何掛起 Intent 均依次傳遞。這適用于主動執(zhí)行應(yīng)該立即恢復(fù)的作業(yè)(例如下載文件)的服務(wù)。
前臺服務(wù)
public class ForegroundService extends Service {
@Override
public void onCreate() {
super.onCreate();
showNotification();
}
private void showNotification() {
//創(chuàng)建點擊跳轉(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ù),具體大家可以自信查詢文檔,這里舉例幾個常見的服務(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();