服務(wù)作為Android四大組件之一默终,是一種可在后臺(tái)執(zhí)行長(zhǎng)時(shí)間運(yùn)行操作而不提供界面的應(yīng)用組件椅棺。服務(wù)可由其他應(yīng)用組件啟動(dòng),而且即使用戶切換到其他應(yīng)用穷蛹,服務(wù)仍將在后臺(tái)繼續(xù)運(yùn)行土陪。需要注意的是服務(wù)并不會(huì)自動(dòng)開(kāi)啟線程,所有的代碼都是默認(rèn)運(yùn)行在主線程當(dāng)中的肴熏,所以需要在服務(wù)的內(nèi)部手動(dòng)創(chuàng)建子線程,并在這里執(zhí)行具體的任務(wù)顷窒,否則就有可能出現(xiàn)主線程被阻塞住的情況蛙吏。
Android多線程編程
異步消息機(jī)制
關(guān)于多線程編程其實(shí)和Java一致,無(wú)論是繼承Thread還是實(shí)現(xiàn)Runnable接口都可以實(shí)現(xiàn)鞋吉。在Android中需要掌握的就是在子線程中更新UI鸦做,UI是由主線程來(lái)控制的,所以主線程又稱為UI線程谓着。
Only the original thread that created a view hierarchy can touch its views.
雖然不允許在子線程中更新UI泼诱,但是Android提供了一套異步消息處理機(jī)制,完美解決了在子線程中操作UI的問(wèn)題赊锚,那就是使用Handler治筒。先來(lái)回顧一下使用Handler更新UI的用法:
public class MainActivity extends AppCompatActivity {
private static final int UPDATE_UI = 1001;
private TextView textView;
private Handler handler = new Handler(Looper.getMainLooper()){
@Override
public void handleMessage(@NonNull Message msg) {
if(msg.what == UPDATE_UI) textView.setText("Hello Thread!");
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = findViewById(R.id.tv_main);
}
public void updateUI(View view) {
// new Thread(()-> textView.setText("Hello Thread!")).start(); Error!
new Thread(()->{
Message message = new Message();
message.what = UPDATE_UI;
handler.sendMessage(message);
}).start();
}
}
使用這種機(jī)制就可以出色地解決掉在子線程中更新UI的問(wèn)題,下面就來(lái)分析一下Android異步消息處理機(jī)制到底的工作原理:Android中的異步消息處理主要由4個(gè)部分組成:Message舷蒲,Handler耸袜,MessageQueue和Looper。
1牲平、Message:線程之間傳遞的消息堤框,它可以在內(nèi)部攜帶少量的信息,用于在不同線程之間交換數(shù)據(jù)。
2蜈抓、Handler:處理者启绰,它主要是用于發(fā)送和處理消息的。發(fā)送消息一般是使用Handler的sendMessage()方法沟使,而發(fā)出的消息經(jīng)過(guò)一系列地輾轉(zhuǎn)處理后酬土,最終會(huì)傳遞到Handler的handleMessage()方法中。
3格带、MessageQueue:消息隊(duì)列撤缴,它主要用于存放所有通過(guò)Handler發(fā)送的消息。這部分消息會(huì)一直存在于消息隊(duì)列中叽唱,等待被處理屈呕。每個(gè)線程中只會(huì)有一個(gè)MessageQueue對(duì)象。
4棺亭、Looper是每個(gè)線程中的MessageQueue的管家虎眨,調(diào)用Looper的loop()方法后,就會(huì)進(jìn)入到一個(gè)無(wú)限循環(huán)當(dāng)中镶摘,然后每當(dāng)發(fā)現(xiàn) MessageQueue 中存在一條消息嗽桩,就會(huì)將它取出,并傳遞到Handler的handleMessage()方法中凄敢。每個(gè)線程中也只會(huì)有一個(gè)Looper對(duì)象碌冶。
異步消息處理整個(gè)流程:首先需要在主線程當(dāng)中創(chuàng)建一個(gè)Handler 對(duì)象,并重寫(xiě)handleMessage()方法涝缝。然后當(dāng)子線程中需要進(jìn)行UI操作時(shí)扑庞,就創(chuàng)建一個(gè)Message對(duì)象,并通過(guò)Handler將這條消息發(fā)送出去拒逮。之后這條消息會(huì)被添加到MessageQueue的隊(duì)列中等待被處理罐氨,而Looper則會(huì)一直嘗試從MessageQueue 中取出待處理消息,最后分發(fā)回 Handler 的handleMessage()方法中滩援。由于Handler是在主線程中創(chuàng)建的栅隐,所以此時(shí)handleMessage()方法中的代碼也會(huì)在主線程中運(yùn)行,于是我們?cè)谶@里就可以安心地進(jìn)行UI操作了玩徊。整個(gè)異步消息處理機(jī)制的流程如下圖所示:
AsyncTask
不過(guò)為了更加方便我們?cè)谧泳€程中對(duì)UI進(jìn)行操作租悄,Android還提供了另外一些好用的工具,比如AsyncTask佣赖。AsyncTask背后的實(shí)現(xiàn)原理也是基于異步消息處理機(jī)制恰矩,只是Android幫我們做了很好的封裝而已。首先來(lái)看一下AsyncTask的基本用法憎蛤,由于AsyncTask是一個(gè)抽象類外傅,所以如果我們想使用它纪吮,就必須要?jiǎng)?chuàng)建一個(gè)子類去繼承它。在繼承時(shí)我們可以為AsyncTask類指定3個(gè)泛型參數(shù)萎胰,這3個(gè)參數(shù)的用途如下:
Params:在執(zhí)行AsyncTask時(shí)需要傳入的參數(shù)碾盟,可用于在后臺(tái)任務(wù)中使用。
Progress:后臺(tái)任務(wù)執(zhí)行時(shí)技竟,如果需要在界面上顯示當(dāng)前的進(jìn)度冰肴,則使用這里指定的泛型作為進(jìn)度單位。
Result:當(dāng)任務(wù)執(zhí)行完畢后榔组,如果需要對(duì)結(jié)果進(jìn)行返回熙尉,則使用這里指定的泛型作為返回值類型。
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
private final int REQUEST_EXTERNAL_STORAGE = 1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void startDownload(View view) {
verifyStoragePermissions(this);
ProgressBar progressBar = findViewById(R.id.download_pb);
TextView textView = findViewById(R.id.download_tv);
new MyDownloadAsyncTask(progressBar, textView).execute("http://xxx.zip");
}
class MyDownloadAsyncTask extends AsyncTask<String, Integer, Boolean> {
private ProgressBar progressBar;
private TextView textView;
public MyDownloadAsyncTask(ProgressBar progressBar, TextView textView) {
this.progressBar = progressBar;
this.textView = textView;
}
@Override
protected Boolean doInBackground(String... strings) {
String urlStr = strings[0];
try {
URL url = new URL(urlStr);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
InputStream inputStream = conn.getInputStream();
// 獲取文件總長(zhǎng)度
int length = conn.getContentLength();
File downloadsDir = new File("...");
File descFile = new File(downloadsDir, "xxx.zip");
int downloadSize = 0;
int offset;
byte[] buffer = new byte[1024];
FileOutputStream fileOutputStream = new FileOutputStream(descFile);
while ((offset = inputStream.read(buffer)) != -1){
downloadSize += offset;
fileOutputStream.write(buffer, 0, offset);
// 拋出任務(wù)執(zhí)行的進(jìn)度
publishProgress((downloadSize * 100 / length));
}
fileOutputStream.close();
inputStream.close();
Log.i(TAG, "download: descFile = " + descFile.getAbsolutePath());
} catch (IOException e) {
e.printStackTrace();
return false;
}
return true;
}
// 在主線程中執(zhí)行結(jié)果處理
@Override
protected void onPostExecute(Boolean aBoolean) {
super.onPostExecute(aBoolean);
if(aBoolean){
textView.setText("下載完成搓扯,文件位于..xx.zip");
}else{
textView.setText("下載失敗");
}
}
// 任務(wù)進(jìn)度更新
@Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
// 收到新進(jìn)度检痰,執(zhí)行處理
textView.setText("已下載" + values[0] + "%");
progressBar.setProgress(values[0]);
}
@Override
protected void onPreExecute() {
super.onPreExecute();
textView.setText("未點(diǎn)擊下載");
}
}
}
1、onPreExecute():方法會(huì)在后臺(tái)任務(wù)開(kāi)始執(zhí)行之前調(diào)用锨推,用于進(jìn)行一些界面上的初始化操作铅歼,比如顯示一個(gè)進(jìn)度條對(duì)話框等。
2换可、doInBackground():方法中的所有代碼都會(huì)在子線程中運(yùn)行椎椰,我們應(yīng)該在這里去處理所有的耗時(shí)任務(wù)。任務(wù)一旦完成就可以通過(guò)return語(yǔ)句來(lái)將任務(wù)的執(zhí)行結(jié)果返回沾鳄,如果 AsyncTask的第三個(gè)泛型參數(shù)指定的是Void慨飘,就可以不返回任務(wù)執(zhí)行結(jié)果。注意洞渔,在這個(gè)方法中是不可以進(jìn)行UI操作的套媚,如果需要更新UI元素,比如說(shuō)反饋當(dāng)前任務(wù)的執(zhí)行進(jìn)度磁椒,可以調(diào)用publishProgress()方法來(lái)完成。
3玫芦、onProgressUpdate():當(dāng)在后臺(tái)任務(wù)中調(diào)用了publishProgress()方法后浆熔,onProgressUpdate()方法就會(huì)很快被調(diào)用,該方法中攜帶的參數(shù)就是在后臺(tái)任務(wù)中傳遞過(guò)來(lái)的桥帆。在這個(gè)方法中可以對(duì)UI進(jìn)行操作医增,利用參數(shù)中的數(shù)值就可以對(duì)界面元素進(jìn)行相應(yīng)的更新。
4老虫、onPostExecute():當(dāng)后臺(tái)任務(wù)執(zhí)行完畢并通過(guò)return語(yǔ)句進(jìn)行返回時(shí)叶骨,這個(gè)方法就很快會(huì)被調(diào)用。返回的數(shù)據(jù)會(huì)作為參數(shù)傳遞到此方法中祈匙,可以利用返回的數(shù)據(jù)來(lái)進(jìn)行一些UI操作忽刽,比如說(shuō)提醒任務(wù)執(zhí)行的結(jié)果天揖,以及關(guān)閉掉進(jìn)度條對(duì)話框等。
服務(wù)的基本用法
服務(wù)首先作為Android之一跪帝,自然也要在Manifest文件中聲明今膊,這是Android四大組件共有的特點(diǎn)。新建一個(gè)MyService類繼承自Service伞剑,然后再清單文件中聲明即可斑唬。
服務(wù)的創(chuàng)建與啟動(dòng)
MyService.java:
public class MyService extends Service {
private static final String TAG = "MyService";
public MyService() {
}
@Override
public IBinder onBind(Intent intent) {
Log.i(TAG, "onBind: ");
// TODO: Return the communication channel to the service.
throw new UnsupportedOperationException("Not yet implemented");
}
}
AndroidManifest.xml:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="cn.tim.basic_service">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<service
android:name=".MyService"
android:enabled="true"
android:exported="true" />
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
可以看到,MyService的服務(wù)標(biāo)簽中有兩個(gè)屬性黎泣,exported屬性表示是否允許除了當(dāng)前程序之外的其他程序訪問(wèn)這個(gè)服務(wù)恕刘,enabled屬性表示是否啟用這個(gè)服務(wù)。然后在MainActivity.java中啟動(dòng)這個(gè)服務(wù):
// 啟動(dòng)服務(wù)
startService(new Intent(this, MyService.class));
服務(wù)的停止(銷毀)
如何停止服務(wù)呢抒倚?在MainActivity.java中停止這個(gè)服務(wù):
Intent intent = new Intent(this, MyService.class);
// 啟動(dòng)服務(wù)
startService(intent);
// 停止服務(wù)
stopService(intent);
其實(shí)Service還可以重寫(xiě)其他方法:
public class MyService extends Service {
private static final String TAG = "MyService";
public MyService() {
}
// 創(chuàng)建
@Override
public void onCreate() {
super.onCreate();
Log.i(TAG, "onCreate: ");
}
// 啟動(dòng)
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i(TAG, "onStartCommand: ");
return super.onStartCommand(intent, flags, startId);
}
// 綁定
@Override
public IBinder onBind(Intent intent) {
Log.i(TAG, "onBind: ");
// TODO: Return the communication channel to the service.
throw new UnsupportedOperationException("Not yet implemented");
}
// 解綁
@Override
public void unbindService(ServiceConnection conn) {
super.unbindService(conn);
Log.i(TAG, "unbindService: ");
}
// 銷毀
@Override
public void onDestroy() {
super.onDestroy();
Log.i(TAG, "onDestroy: ");
}
}
其實(shí)onCreate()方法是在服務(wù)第一次創(chuàng)建的時(shí)候調(diào)用的褐着,而 onStartCommand()方法則在每次啟動(dòng)服務(wù)的時(shí)候都會(huì)調(diào)用,由于剛才我們是第一次點(diǎn)擊Start Service按鈕,服務(wù)此時(shí)還未創(chuàng)建過(guò)宫静,所以兩個(gè)方法都會(huì)執(zhí)行涨椒,之后如果再連續(xù)多點(diǎn)擊幾次 Start Service按鈕,就只有onStartCommand()方法可以得到執(zhí)行了:
服務(wù)綁定與解綁
在上面的例子中谴餐,雖然服務(wù)是在活動(dòng)里啟動(dòng)的,但在啟動(dòng)了服務(wù)之后呆抑,活動(dòng)與服務(wù)基本就沒(méi)有什么關(guān)系了岂嗓。這就類似于活動(dòng)通知了服務(wù)一下:你可以啟動(dòng)了!然后服務(wù)就去忙自己的事情了鹊碍,但活動(dòng)并不知道服務(wù)到底去做了什么事情厌殉,以及完成得如何。所以這就要借助服務(wù)綁定了侈咕。
比如在MyService里提供一個(gè)下載功能公罕,然后在活動(dòng)中可以決定何時(shí)開(kāi)始下載,以及隨時(shí)查看下載進(jìn)度耀销。實(shí)現(xiàn)這個(gè)功能的思路是創(chuàng)建一個(gè)專門的Binder對(duì)象來(lái)對(duì)下載功能進(jìn)行管理楼眷,修改MyService.java:
public class MyService extends Service {
private static final String TAG = "MyService";
private DownloadBinder mBinder = new DownloadBinder();
static class DownloadBinder extends Binder {
public void startDownload() {
// 模擬開(kāi)始下載
Log.i(TAG, "startDownload executed");
}
public int getProgress() {
// 模擬返回下載進(jìn)度
Log.i(TAG, "getProgress executed");
return 0;
}
}
public MyService() {}
// 創(chuàng)建
@Override
public void onCreate() {
super.onCreate();
Log.i(TAG, "onCreate: ");
}
// 啟動(dòng)
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i(TAG, "onStartCommand: ");
return super.onStartCommand(intent, flags, startId);
}
// 綁定
@Override
public IBinder onBind(Intent intent) {
Log.i(TAG, "onBind: ");
return mBinder;
}
// 解綁
@Override
public void unbindService(ServiceConnection conn) {
super.unbindService(conn);
Log.i(TAG, "unbindService: ");
}
// 銷毀
@Override
public void onDestroy() {
super.onDestroy();
Log.i(TAG, "onDestroy: ");
}
}
MainActivity.java如下:
public class MainActivity extends AppCompatActivity {
private MyService.DownloadBinder downloadBinder;
ServiceConnection connection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
downloadBinder = (MyService.DownloadBinder) service;
downloadBinder.startDownload();
downloadBinder.getProgress();
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void aboutService(View view) {
int id = view.getId();
Intent intent = new Intent(this, MyService.class);
switch (id){
case R.id.start_btn:
startService(intent);
break;
case R.id.stop_btn:
stopService(intent);
break;
case R.id.bind_btn:
// 這里傳入BIND_AUTO_CREATE表示在活動(dòng)和服務(wù)進(jìn)行綁定后自動(dòng)創(chuàng)建服務(wù)
bindService(intent, connection, BIND_AUTO_CREATE);
break;
case R.id.unbind_btn:
unbindService(connection);
break;
}
}
}
這個(gè)ServiceConnection的匿名類里面重寫(xiě)了onServiceConnected()方法和 onServiceDisconnected()方法,這兩個(gè)方法分別會(huì)在活動(dòng)與服務(wù)成功綁定以及解除綁定的時(shí)候調(diào)用熊尉。在 onServiceConnected()方法中罐柳,通過(guò)向下轉(zhuǎn)型得到DownloadBinder的實(shí)例,有了這個(gè)實(shí)例狰住,活動(dòng)和服務(wù)之間的關(guān)系就變得非常緊密了≌偶現(xiàn)在我們可以在活動(dòng)中根據(jù)具體的場(chǎng)景來(lái)調(diào)用DownloadBinder中的任何public()方法,即實(shí)現(xiàn)了指揮服務(wù)干什么服務(wù)就去干什么的功能(雖然實(shí)現(xiàn)startDownload與getProgress實(shí)現(xiàn)很簡(jiǎn)單)催植。
需要注意的是肮蛹,任何一個(gè)服務(wù)在整個(gè)應(yīng)用程序范圍內(nèi)都是通用的勺择,即 MyService不僅可以和MainActivity綁定,還可以和任何一個(gè)其他的活動(dòng)進(jìn)行綁定蔗崎,而且在綁定完成后它們都可以獲取到相同的DownloadBinder實(shí)例酵幕。
服務(wù)的生命周期
一旦調(diào)用了startServices()方法,對(duì)應(yīng)的服務(wù)就會(huì)被啟動(dòng)且回調(diào)onStartCommand()缓苛,如果服務(wù)未被創(chuàng)建芳撒,則會(huì)調(diào)用onCreate()創(chuàng)建Service對(duì)象。服務(wù)被啟動(dòng)后會(huì)一直保持運(yùn)行狀態(tài)未桥,直到stopService()或者stopSelf()方法被調(diào)用笔刹。不管startService()被調(diào)用了多少次,但是只要Service對(duì)象存在冬耿,onCreate()方法就不會(huì)被執(zhí)行舌菜,所以只需要調(diào)用一次stopService()或者stopSelf()方法就會(huì)停止對(duì)應(yīng)的服務(wù)。
在通過(guò)bindService()來(lái)獲取一個(gè)服務(wù)的持久連接的時(shí)候亦镶,這時(shí)就會(huì)回調(diào)服務(wù)中的 onBind()方法日月。類似地,如果這個(gè)服務(wù)之前還沒(méi)有創(chuàng)建過(guò)缤骨,oncreate()方法會(huì)先于onBind()方法執(zhí)行爱咬。之后,調(diào)用方可以獲取到onBind()方法里返回的IBinder對(duì)象的實(shí)例绊起,這樣就能自由地和服務(wù)進(jìn)行通信了精拟。只要調(diào)用方和服務(wù)之間的連接沒(méi)有斷開(kāi),服務(wù)就會(huì)一直保持運(yùn)行狀態(tài)虱歪。
那么即調(diào)用了startService()又調(diào)用了bindService()方法的蜂绎,這種情況下該如何才能讓服務(wù)銷毀掉呢?根據(jù)Android系統(tǒng)的機(jī)制笋鄙,一個(gè)服務(wù)只要被啟動(dòng)或者被綁定了之后师枣,就會(huì)一直處于運(yùn)行狀態(tài),必須要讓以上兩種條件同時(shí)不滿足萧落,服務(wù)才能被銷毀坛吁。所以,這種情況下要同時(shí)調(diào)用stopService()和 unbindService()方法铐尚,onDestroy()方法才會(huì)執(zhí)行。
服務(wù)的更多技巧
上面講述了服務(wù)最基本的用法哆姻,下面來(lái)看看關(guān)于服務(wù)的更高級(jí)的技巧宣增。
使用前臺(tái)服務(wù)
服務(wù)幾乎都是在后臺(tái)運(yùn)行的,服務(wù)的系統(tǒng)優(yōu)先級(jí)還是比較低的矛缨,當(dāng)系統(tǒng)出現(xiàn)內(nèi)存不足的情況時(shí)爹脾,就有可能會(huì)回收掉正在后臺(tái)運(yùn)行的服務(wù)帖旨。如果你希望服務(wù)可以一直保持運(yùn)行狀態(tài),而不會(huì)由于系統(tǒng)內(nèi)存不足的原因?qū)е卤换厥樟榉粒涂梢允褂们芭_(tái)服務(wù)解阅。比如QQ電話的懸浮窗口,或者是某些天氣應(yīng)用需要在狀態(tài)欄顯示天氣泌霍。
public class FrontService extends Service {
String mChannelId = "1001";
public FrontService() {
}
@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();
Intent intent = new Intent(this, MainActivity.class);
PendingIntent pi = PendingIntent.getActivity(this, 0, intent, 0);
Notification notification = new NotificationCompat.Builder(this, mChannelId)
.setContentTitle("This is content title.")
.setContentText("This is content text.")
.setWhen(System.currentTimeMillis())
.setSmallIcon(R.mipmap.ic_launcher)
.setLargeIcon(BitmapFactory.decodeResource(getResources(),
R.mipmap.ic_launcher))
.setContentIntent(pi)
.build();
startForeground(1, notification);
}
}
使用IntentService
服務(wù)中的代碼都是默認(rèn)運(yùn)行在主線程當(dāng)中的货抄,如果直接在服務(wù)里去處理一些耗時(shí)的邏輯,就很容易出現(xiàn)ANR的情況朱转。所以需要用到多線程編程蟹地,遇到耗時(shí)操作可以在服務(wù)的每個(gè)具體的方法里開(kāi)啟一個(gè)子線程,然后在這里去處理那些耗時(shí)的邏輯藤为。就可以寫(xiě)成如下形式:
public class OtherService extends Service {
public OtherService() {}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
new Thread(()->{
// TODO 執(zhí)行耗時(shí)操作
}).start();
return super.onStartCommand(intent, flags, startId);
}
...
}
但是怪与,這種服務(wù)一旦啟動(dòng)之后,就會(huì)一直處于運(yùn)行狀態(tài)缅疟,必須調(diào)用stopService()或者stopSelf()方法才能讓服務(wù)停止下來(lái)分别。所以,如果想要實(shí)現(xiàn)讓一個(gè)服務(wù)在執(zhí)行完畢后自動(dòng)停止的功能存淫,就可以這樣寫(xiě):
public class OtherService extends Service {
public OtherService() {}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
new Thread(()->{
// TODO 執(zhí)行耗時(shí)操作
stopSelf();
}).start();
return super.onStartCommand(intent, flags, startId);
}
...
}
雖然這種寫(xiě)法并不復(fù)雜耘斩,但是總會(huì)有一些程序員忘記開(kāi)啟線程,或者忘記調(diào)用stopSelf()方法纫雁。為了可以簡(jiǎn)單地創(chuàng)建一個(gè)異步的煌往、會(huì)自動(dòng)停止的服務(wù),Android 專門提供了一個(gè)IntentService類轧邪,這個(gè)類就很好地解決了前面所提到的兩種尷尬刽脖,下面我們就來(lái)看一下它的用法:
MyIntentService.java
public class MyIntentService extends IntentService {
private static final String TAG = "MyIntentService";
private int count = 0;
public MyIntentService() {
super("MyIntentService");
}
@Override
protected void onHandleIntent(Intent intent) {
count++;
Log.i(TAG, "onHandleIntent: count = " + count);
}
}
MainActivity.java:
for (int i = 0; i < 10; i++) {
Intent intent = new Intent(MainActivity.this, MyIntentService.class);
startService(intent);
}
參考資料:《第一行代碼》