- 服務(Service)是 Android 中實現(xiàn)程序后臺運行的解決方案戏羽,它非常適合用于去執(zhí)行那些不需要和用戶交互而且還要求長期運行的任務。
- 服務并不是運行在一個獨立的進程當中的刀荒,而是依賴于創(chuàng)建服務時所在的應用程序進程首懈。當某個應用程序進程被殺掉時看成,所有依賴于該進程的服務也會停止運行。
- 服務并不會自動開啟線程鹏秋,所有的代碼都是默認運行在主線程當中的尊蚁。也就是說,我們需要在服務的內(nèi)部手動創(chuàng)建子線程侣夷,并在這里執(zhí)行具體的任務横朋。
一、定義服務
public class MyService extends Service {
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
super.onDestroy();
}
}
- **onBind() **方法百拓,用于活動和服務進行通信琴锭。
- **onCreate() **方法會在服務創(chuàng)建的時候調用。
- **onStartCommand() **方法會在每次服務啟動的時候調用衙传。
- **onDestroy() **方法會在服務銷毀的時候調用决帖。
- 需要在 AndroidManifest.xml 文件中進行注冊:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.servicetest"
android:versionCode="1"
android:versionName="1.0" >
......
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
......
<service android:name=".MyService" >
</service>
</application>
</manifest>
二、啟動和停止服務
1. 創(chuàng)建 Intent蓖捶,再在活動中用 startService() 方法啟動服務地回。
Intent startIntent = new Intent(this, MyService.class);
startService(startIntent); // 啟動服務
- 服務還未創(chuàng)建過,onCreate()俊鱼、**onStartCommand() **兩個方法都會執(zhí)行落君。
- 服務已經(jīng)創(chuàng)建過,則只有 **onStartCommand() **方法可以得到執(zhí)行了亭引。
2. 創(chuàng)建 Intent,再在活動中用 stopService() 方法停止服務皮获。
Intent stopIntent = new Intent(this, MyService.class);
stopService(stopIntent); // 停止服務
- 若要服務自己停止焙蚓,只需要在服務類的任何一個位置調用 **stopSelf() **方法就行。
三洒宝、活動和服務進行通信
在 MyService 中:
1. 創(chuàng)建內(nèi)部類 MyBinder 繼承自 Binder购公,里面是活動需要調用的內(nèi)容。
2. 在 MyService 中創(chuàng)建 MyBinder 的實例雁歌。
3. 在 onBind() 方法里返回這個實例 mBinder宏浩。
public class MyService extends Service {
private DownloadBinder mBinder = new DownloadBinder();
class DownloadBinder extends Binder {
public void startDownload() {
Log.d("MyService", "startDownload executed");
}
public int getProgress() {
Log.d("MyService", "getProgress executed");
return 0;
}
}
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
.....
}
在 MainActivity 中:
1. 創(chuàng)建 ServiceConnection 的匿名類實例,重寫 onServiceConnected() 方法和 onServiceDisconnected() 方法靠瞎。
- 這兩個方法分別會在活動與服務成功綁定以及解除綁定的時候調用比庄。
2. 在 onServiceConnected() 方法中求妹,通過向下轉型得到 MyBinder 的實例。
- 有了這個實例佳窑,可以在活動中根據(jù)具體的場景來調用 MyBinder 中的任何 public 方法制恍。
綁定活動和服務:
1. 創(chuàng)建 Intent。
2. 用 bindService() 方法綁定活動和服務神凑。
- 第一個參數(shù):Intent净神。
- 第二個參數(shù):ServiceConnection 的實例。
- 第三個參數(shù):這里傳入** BIND_AUTO_CREATE** 表示在活動和服務進行綁定后自動創(chuàng)建服務溉委,即執(zhí)行 onCreate() 方法鹃唯。
3. 用 unbindService() 方法解除綁定。
- 參數(shù):ServiceConnection 的實例瓣喊。
public class MainActivity extends Activity implements OnClickListener {
private Button startService;
private Button stopService;
private Button bindService;
private Button unbindService;
private MyService.DownloadBinder downloadBinder;
private ServiceConnection connection = new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName name) {
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
downloadBinder = (MyService.DownloadBinder) service;
downloadBinder.startDownload();
downloadBinder.getProgress();
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
......
bindService = (Button) findViewById(R.id.bind_service);
unbindService = (Button) findViewById(R.id.unbind_service);
bindService.setOnClickListener(this);
unbindService.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
......
case R.id.bind_service:
Intent bindIntent = new Intent(this, MyService.class);
bindService(bindIntent, connection, BIND_AUTO_CREATE); // 綁定服務
break;
case R.id.unbind_service:
unbindService(connection); // 解綁服務
break;
default:
break;
}
}
}
四坡慌、服務的生命周期
- 調用 **startService() 方法,相應的服務就會啟動起來型宝,并回調 onStartCommand() 方法八匠。如果這個服務之前還沒有創(chuàng)建過,onCreate() 方法會先于 onStartCommand() **方法執(zhí)行趴酣。
- 服務啟動了之后會一直保持運行狀態(tài)梨树,直到 stopService() 或 **stopSelf() **方法被調用。
- 還可以調用** bindService() 來獲取一個服務的持久連接岖寞,這時就會回調服務中的 onBind() 方法抡四。如果這個服務之前還沒有創(chuàng)建過,onCreate()** 方法會**先于 onBind() **方法執(zhí)行仗谆。
- 當調用了** startService() **方法后土匀,又去調用 stopService() 方法,這時服務中的 onDestroy() 方法就會執(zhí)行棱诱,表示服務已經(jīng)銷毀了雕崩。
- 當調用了 **bindService() **方法后,又去調用 unbindService() 方法狸吞,onDestroy() 方法也會執(zhí)行勉耀。
- 需要注意的是,當對一個服務既調用了 startService() 方法蹋偏,又調用了 bindService() 方法便斥,一個服務只要被啟動或者被綁定了之后,就會一直處于運行狀態(tài)威始,必須要讓以上兩種條件同時不滿足枢纠,服務才能被銷毀。所以黎棠,這種情況下要同時調用 stopService() 和 unbindService() 方法晋渺,onDestroy() 方法才會執(zhí)行镰绎。
五、服務的更多技巧
1. 使用前臺服務
- 前臺服務會一直有一個正在運行的圖標在系統(tǒng)的狀態(tài)欄顯示些举,下拉狀態(tài)欄后可以看到更加詳細的信息跟狱,非常類似于通知的效果。如天氣應用經(jīng)常要用到户魏。
- 希望服務可以一直保持運行狀態(tài)驶臊,而不會由于系統(tǒng)內(nèi)存不足的原因導致被回收,就可以考慮使用前臺服務叼丑。
Notification.Builder builder = new Notification.Builder(MainActivity.this);
builder.setSmallIcon(R.drawable.ic_launcher);
builder.setContentTitle("title");
builder.setContentText("text");
builder.setWhen(System.currentTimeMillis()); // 顯示時間
Intent intent=new Intent(MainActivity.this,Main2Activity.class);
PendingIntent pi=PendingIntent.getActivity(MainActivity.this,0,intent,PendingIntent.FLAG_CANCEL_CURRENT);
builder.setContentIntent(pi);
Notification notification = builder.build();
startForeground(1, notification);
使用很簡單关翎,就是把創(chuàng)建 Notification 方法里的 manager.notify(1, notification); 換成 startForeground(1, notification);。
2. 使用 IntentService
- 服務中的代碼都是默認運行在主線程當中的鸠信,如果直接在服務里去處理一些耗時的邏輯纵寝,就很容易出現(xiàn) ANR(Application Not Responding)的情況。
- 所以對于一些耗時操作星立,需要在服務中開啟子線程執(zhí)行爽茴。
- 因為服務啟動后會一直處于開啟狀態(tài),有時也會希望服務在執(zhí)行完畢后自動停止绰垂∈易啵可以這樣寫。
public class MyService extends Service {
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
new Thread(new Runnable() {
@Override
public void run() {
// 處理具體的邏輯
stopSelf();
}
}).start();
return super.onStartCommand(intent, flags, startId);
}
}
- 為了可以簡單地創(chuàng)建一個異步的劲装、會自動停止的服務胧沫,Android 專門提供了一個 IntentService 類:
public class MyIntentService extends IntentService {
public MyIntentService() {
super("MyIntentService"); // 調用父類的有參構造函數(shù)
}
@Override
protected void onHandleIntent(Intent intent) {
// 打印當前線程的id
Log.d("MyIntentService", "Thread id is " + Thread.currentThread().getId());
}
@Override
public void onDestroy() {
super.onDestroy();
Log.d("MyIntentService", "onDestroy executed");
}
}
- 首先要提供一個無參的構造函數(shù),并且必須在其內(nèi)部調用父類的有參構造函數(shù)占业。
- 在子類中去實現(xiàn)** onHandleIntent()** 這個抽象方法绒怨,這個方法已經(jīng)是在子線程中運行的了。
- 根據(jù) IntentService 的特性谦疾,這個服務在運行結束后應該是會自動停止的南蹂,即執(zhí)行** onDestroy()** 方法。