Service的概念
1.Service作為安卓的四大組件之一,固然是每一位安卓開(kāi)發(fā)者必須掌握的一個(gè)知識(shí)點(diǎn)。雖然它沒(méi)有Activity的使用頻繁,但也是日常開(kāi)發(fā)經(jīng)常用到的涩蜘。
2.通過(guò)名字我們知道,它是服務(wù)的意思锋边。而且通常是"默默"的為我們服務(wù)的皱坛。為什么說(shuō)是默默,因?yàn)樗⒉幌馎ctivity一樣豆巨,能夠被我們看到剩辟。通常,它用于在后臺(tái)為我們執(zhí)行一些耗時(shí)往扔,或者需要長(zhǎng)時(shí)間執(zhí)行的一些操作的贩猎。下面讓我們來(lái)看看它的基本用法。
Service的創(chuàng)建
- 1.任何一個(gè)對(duì)象萍膛,想要發(fā)揮其作用吭服,那么就應(yīng)該首先創(chuàng)建出來(lái)。Service的創(chuàng)建和Activity類似蝗罗,也是通過(guò)Intent來(lái)實(shí)現(xiàn)的艇棕。而且既然是安卓四大組件之一,那么它也需要在清單文件中進(jìn)行注冊(cè)的串塑。下面沼琉,看一下一個(gè)簡(jiǎn)單的創(chuàng)建Service的例子:
public class SimpleService extends Service {
public static final String TAG = "SimpleService";
@Override
public void onCreate() {
super.onCreate();
Log.d(TAG, "onCreate");
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(TAG, "onStartCommand");
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
super.onDestroy();
Log.d(TAG, "onDestroy");
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
}
- 2.首先,創(chuàng)建一個(gè)類SimpleService繼承自Service,然后重寫(xiě)它的onCreate桩匪,onStartCommand打瘪,onDestroy方法,并分別在它們的方法體中打入Log日志。其中onBind方法是默認(rèn)實(shí)現(xiàn)的闺骚,具體作用后面會(huì)講到彩扔。然后呢,千萬(wàn)不要忘記要在清單文件中注冊(cè)它僻爽,其實(shí)如果你是通過(guò)Android Studio直接new了一個(gè)Service的話虫碉,Android Studio會(huì)默認(rèn)幫助你在清單文件中添加對(duì)該Service的注冊(cè),代碼如下:
<service android:name=".ui.main.SimpleService"
android:enabled="true"
android:exported="true"/>
我直接在我之前做的一個(gè)項(xiàng)目中新建的进泼,所以不要在意包路徑的命名蔗衡,就是包名點(diǎn)類名纤虽。細(xì)心的朋友可能看到了下面還有兩個(gè)屬性乳绕。其中enabled屬性,是指該服務(wù)是否能夠被實(shí)例化逼纸。如果設(shè)置為true洋措,則能夠被實(shí)例化,否則不能被實(shí)例化杰刽,默認(rèn)值是true菠发。一般情況下,我們都會(huì)需要實(shí)例化贺嫂,所以也可以選擇不設(shè)置滓鸠。而exported屬性用于指示該服務(wù)是否能夠被其他應(yīng)用程序組件調(diào)用或跟它交互。如果設(shè)置為true第喳,則能夠被調(diào)用或交互(通常如果一個(gè)服務(wù)需要跨進(jìn)程使用需要這么設(shè)置)糜俗,否則不能。設(shè)置為false時(shí)曲饱,只有同一個(gè)應(yīng)用程序的組件或帶有相同用戶ID的應(yīng)用程序才能啟動(dòng)或綁定該服務(wù)悠抹。
- 3.接下來(lái)創(chuàng)建一個(gè)StartActivity,用于在其中創(chuàng)建SimpleService對(duì)象扩淀。代碼如下:
public class StartActivity extends AppCompatActivity implements View.OnClickListener {
private Button startBtn, stopBtn;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_start);
startBtn = (Button) findViewById(R.id.btn_start_service);
stopBtn = (Button) findViewById(R.id.btn_stop_service);
startBtn.setOnClickListener(this);
stopBtn.setOnClickListener(this);
}
@Override
public void onClick(View v) {
if (v != null) {
switch (v.getId()) {
case R.id.btn_start_service:
Intent startIntent = new Intent(this, SimpleService.class);
startService(startIntent);
break;
case R.id.btn_stop_service:
Intent stopIntent = new Intent(this, SimpleService.class);
stopService(stopIntent);
break;
}
}
}
}
StartActivity的xml文件如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.kitty.android.ui.main.StartActivity">
<Button
android:id="@+id/btn_start_service"
android:layout_width="match_parent"
android:layout_height="50dp"
android:text="Start Service"/>
<Button
android:id="@+id/btn_destroy_service"
android:layout_width="match_parent"
android:layout_height="50dp"
android:text="Destroy Service"/>
</LinearLayout>
- 4.很簡(jiǎn)單楔敌,就是添加兩個(gè)按鈕,分別用于啟動(dòng)Service和停止Service驻谆÷汛眨可以看到,創(chuàng)建一個(gè)Service的方法非常簡(jiǎn)單胜臊,就是和創(chuàng)建Activity類似勺卢,創(chuàng)建一個(gè)Intent對(duì)象,然后通過(guò)startService方法開(kāi)啟一個(gè)服務(wù)区端。然后同樣的值漫,通過(guò)stopService方法來(lái)停止一個(gè)服務(wù)。為了證明方法的正確性织盼,我們先點(diǎn)擊startBtn杨何,看一下Logcat中的日志截圖酱塔,如下所示:
由此可以看出,當(dāng)通過(guò)startService方法開(kāi)啟一個(gè)服務(wù)的時(shí)候危虱,會(huì)執(zhí)行Service的onCreate和onStartCommand方法羊娃。接下來(lái),我們?cè)俅吸c(diǎn)擊一下 start按鈕埃跷,再來(lái)看一下Loacat的日志:
這一次蕊玷,只執(zhí)行了onStartCommand方法,由此我們可以得出結(jié)論弥雹,當(dāng)一個(gè)Service被創(chuàng)建以后垃帅,再次調(diào)用startService方法,Service是不會(huì)被重新創(chuàng)建的剪勿,而是會(huì)重新執(zhí)行onStartCommand方法贸诚。無(wú)論我們點(diǎn)擊多少次start按鈕,始終只會(huì)執(zhí)行onStartCommand方法厕吉。
以上是服務(wù)的創(chuàng)建酱固。接下來(lái),我們點(diǎn)擊stop按鈕头朱,logcat日志如下:
可以看到运悲,Service執(zhí)行了onDestroy方法,這時(shí)服務(wù)就已經(jīng)停止了项钮。
以上就是簡(jiǎn)單的創(chuàng)建一個(gè)服務(wù)的流程班眯。然而,在我們?nèi)粘i_(kāi)發(fā)中寄纵,我們經(jīng)常需要在服務(wù)中做一些邏輯操作鳖敷,然后將結(jié)果返回給一個(gè)Activity,即要實(shí)現(xiàn)Service和Activity的通信程拭,接下來(lái)定踱,讓我們看看如何讓二者建立起聯(lián)系。
Service與Activity之間的通信
在上面的介紹中恃鞋,我們只是實(shí)現(xiàn)了在Activity中開(kāi)啟一個(gè)服務(wù)崖媚,然而服務(wù)開(kāi)啟了就和這個(gè)Activity沒(méi)什么聯(lián)系了。其實(shí)二者是可以繼續(xù)保持聯(lián)絡(luò)的恤浪,還記得前面提到的一個(gè)onBind方法吧畅哑,其實(shí)它就是Service與Activity之間建立通信的橋梁。現(xiàn)在我們修改一下前面的代碼水由,SimpleService代碼修改如下:
public class SimpleService extends Service {
public static final String TAG = "SimpleService";
private SimpleBinder mBinder;
@Override
public void onCreate() {
super.onCreate();
Log.d(TAG, "onCreate");
mBinder = new SimpleBinder();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(TAG, "onStartCommand");
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
super.onDestroy();
Log.d(TAG, "onDestroy");
}
@Override
public IBinder onBind(Intent intent) {
if (mBinder != null) {
return mBinder;
}
return null;
}
class SimpleBinder extends Binder {
public void doTask() {
Log.d(TAG, "doTask");
}
}
}
現(xiàn)在荠呐,我們?cè)赟impleService中創(chuàng)建了一個(gè)SimpleBinder類,繼承自Binder。然后泥张,在里面創(chuàng)建了一個(gè)doTask方法呵恢,模擬執(zhí)行一個(gè)任務(wù)。然后媚创,我們?cè)僭赟tartActivity中加入兩個(gè)按鈕渗钉,分別用于綁定服務(wù)和解綁服務(wù),XML文件代碼我就不貼了钞钙,就是添兩個(gè)按鈕鳄橘,下面是StartActivity的更改后的代碼:
public class StartActivity extends AppCompatActivity implements View.OnClickListener {
public static final String TAG = "SimpleService";
private Button startBtn, stopBtn, bindBtn, unBindBtn;
private SimpleService.SimpleBinder mBinder;
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.d(TAG, name.toString());
mBinder = (SimpleService.SimpleBinder) service;
mBinder.doTask();
}
@Override
public void onServiceDisconnected(ComponentName name) {
Log.d(TAG, name.toString());
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_start);
startBtn = (Button) findViewById(R.id.btn_start_service);
stopBtn = (Button) findViewById(R.id.btn_stop_service);
bindBtn = (Button) findViewById(R.id.btn_bind_service);
unBindBtn = (Button) findViewById(R.id.btn_un_bind_service);
startBtn.setOnClickListener(this);
stopBtn.setOnClickListener(this);
bindBtn.setOnClickListener(this);
unBindBtn.setOnClickListener(this);
}
@Override
public void onClick(View v) {
if (v != null) {
switch (v.getId()) {
case R.id.btn_start_service:
Intent startIntent = new Intent(this, SimpleService.class);
startService(startIntent);
break;
case R.id.btn_stop_service:
Intent stopIntent = new Intent(this, SimpleService.class);
stopService(stopIntent);
break;
case R.id.btn_bind_service:
Intent bindIntent = new Intent(this, SimpleService.class);
bindService(bindIntent, mConnection, BIND_AUTO_CREATE);
break;
case R.id.btn_un_bind_service:
unbindService(mConnection);
break;
}
}
}
}
這里,我們創(chuàng)建了一個(gè)ServiceConnection的匿名內(nèi)部類芒炼,并實(shí)現(xiàn)了onServiceConnected和onServiceDisconnected兩個(gè)方法瘫怜。ServiceConnection可以看做是一個(gè)由Activity操作的代表,負(fù)責(zé)與Service進(jìn)行連接焕议,當(dāng)Activity與Service連接成功時(shí)宝磨,會(huì)執(zhí)行onServiceConnected方法弧关,相反的盅安,當(dāng)二者斷開(kāi)連接的時(shí)候,會(huì)執(zhí)行onServiceDisconnected方法世囊。當(dāng)二者連接成功時(shí)别瞭,在onServiceConnected方法中,我們可以獲取到SimpleService中的SimpleBinder的實(shí)例對(duì)象株憾,然后我們就可以調(diào)用其所有的公共方法來(lái)實(shí)現(xiàn)我們想要做的事了蝙寨。
現(xiàn)在我們來(lái)看一下綁定一個(gè)服務(wù)的方法,也是先創(chuàng)建一個(gè)Intent嗤瞎,然后將其作為bindService的第一個(gè)參數(shù)墙歪,第二個(gè)參數(shù)就是我們剛才說(shuō)到的那個(gè)代表ServiceConnection,而第三個(gè)參數(shù)是一個(gè)標(biāo)記贝奇,這里我們傳入BIND_AUTO_CREATE標(biāo)記虹菲,此標(biāo)記表示在Activity和Service建立關(guān)聯(lián)后自動(dòng)創(chuàng)建Service,并執(zhí)行Service中的onCreate方法掉瞳,并不會(huì)執(zhí)行onStartCommand方法毕源。(標(biāo)記不只這一個(gè),可以自行去查閱其他flag的含義)
為了驗(yàn)證剛剛我所說(shuō)的陕习,我們點(diǎn)擊bind按鈕霎褐,并查看logcat日志,如下:
可以看到该镣,確實(shí)只執(zhí)行了onCreate方法冻璃,并且在ServiceConnection的onServiceConnected中的第一個(gè)參數(shù)返回的其實(shí)就是SimpleService的具體包名路徑。然后接著就執(zhí)行了SimpleBinder中的doTask方法。當(dāng)我們?cè)俅吸c(diǎn)擊bind按鈕省艳,會(huì)發(fā)現(xiàn)歌粥,并沒(méi)有執(zhí)行任何的方法,說(shuō)明了服務(wù)如果一旦與一個(gè)Activity綁定后拍埠,如果沒(méi)有解綁的話失驶,它是不會(huì)重新與這個(gè)Activity進(jìn)行綁定的。
綁定完了枣购,最終我們肯定是需要解綁的嬉探,來(lái)看一下unBind按鈕的操作方法,只有一個(gè)unbindService方法棉圈,需要傳入一個(gè)ServiceConnection參數(shù)涩堤,即我們前面創(chuàng)建的mConnection實(shí)例。點(diǎn)擊unbind按鈕分瘾,看到logcat日志如下:
執(zhí)行了onDestroy方法胎围,這是剛剛通過(guò)bindService方法創(chuàng)建的Service就已經(jīng)被摧毀了。
Service創(chuàng)建與摧毀方式的混淆
通過(guò)剛剛上述的描述德召,我們現(xiàn)在知道創(chuàng)建一個(gè)Service的方式有兩種白魂,即通過(guò)startService和bindService的方式。而二者對(duì)Service的摧毀方式分別為stopService和unBindService上岗。那么可能很多人會(huì)疑問(wèn)如果我選擇startService的方式創(chuàng)建福荸,然后選擇unbindService的方式摧毀‰戎溃或者說(shuō)我采用bindService方式創(chuàng)建敬锐,stopService方式摧毀呢。那么我們來(lái)對(duì)每種情況分別驗(yàn)證一下會(huì)發(fā)生什么樣的結(jié)果呆瞻。
我們首先現(xiàn)將SimpleService中的代碼還原成如下?tīng)顟B(tài)台夺。StartActivity中還是四個(gè)按鈕分別對(duì)應(yīng)四個(gè)方法。
public class SimpleService extends Service {
public static final String TAG = "SimpleService";
private SimpleBinder mBinder;
@Override
public void onCreate() {
super.onCreate();
Log.d(TAG, "onCreate");
mBinder = new SimpleBinder();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(TAG, "onStartCommand");
new Thread(new Runnable() {
@Override
public void run() {
// 任務(wù)邏輯
}
}).start();
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
super.onDestroy();
Log.d(TAG, "onDestroy");
}
@Override
public IBinder onBind(Intent intent) {
if (mBinder != null) {
return mBinder;
}
return null;
}
class SimpleBinder extends Binder {
public void doTask() {
Log.d(TAG, "doTask");
}
}
}
- 1.我們首先點(diǎn)擊一下start按鈕痴脾,然后點(diǎn)擊unbind按鈕颤介,結(jié)果會(huì)發(fā)現(xiàn)程序崩了。
崩潰日志如下明郭,提示非法狀態(tài)異常买窟,接著后面又說(shuō),Service沒(méi)有被注冊(cè)薯定。其實(shí)始绍,很容易理解,就是不看崩潰日志话侄,估計(jì)很多人也猜到了亏推,Service根本就沒(méi)有與任何東西綁定学赛,又何談解綁呢。所以吞杭,這里需要注意盏浇,在使用unbindService方法關(guān)閉一個(gè)服務(wù)時(shí),為防止出現(xiàn)以上的情況芽狗,我們需要在調(diào)用比方法前判斷一下當(dāng)前的Service是否已經(jīng)被綁定绢掰。
針對(duì)這一判斷谷歌并沒(méi)有提供專門(mén)的Api,而我們可以通過(guò)在本地創(chuàng)建一個(gè)變量童擎,當(dāng)服務(wù)被綁定的時(shí)候滴劲,在ServiceConnection的onServiceConnected方法中將其設(shè)為true, 在onServiceDisconnected方法中將其設(shè)為false。這樣的話顾复,如果服務(wù)未被綁定的話班挖,這個(gè)值會(huì)永遠(yuǎn)為false,這樣我們就直接在調(diào)用unbindService方法前做出相應(yīng)的提示芯砸,以防止崩潰產(chǎn)生萧芙。
- 2.點(diǎn)擊bind按鈕后,再點(diǎn)擊stop按鈕假丧。同樣双揪,看一下logcat日志:
請(qǐng)相信我,我真的點(diǎn)擊了stop按鈕虎谢,而且不止點(diǎn)擊了一次盟榴。可以看到婴噩,Service并沒(méi)有被摧毀。而當(dāng)我再次點(diǎn)擊unbind按鈕時(shí)羽德,Service才被摧毀几莽。其實(shí)這也很好解釋,舉個(gè)例子吧宅静,施瓦星格拍的終結(jié)者(第二部)不知道大家有沒(méi)有看過(guò)章蚣,施瓦星格扮演的終結(jié)者的使命是保護(hù)男主,他的程序一旦被啟動(dòng)姨夹,就會(huì)一直以保護(hù)男主(完成使命)為目的纤垂,只有消滅了敵人,確保男主可以平安無(wú)事了磷账,他才會(huì)停止保護(hù)男主的行為峭沦。Service就相當(dāng)于施瓦星格,它一旦被綁定逃糟,必須等到一個(gè)結(jié)果來(lái)告訴它"使命"完成了(解綁了)吼鱼,它才會(huì)停止下來(lái)蓬豁。
3.點(diǎn)擊start按鈕后,接著點(diǎn)擊bind按鈕菇肃,然后呢地粪,我們分別單獨(dú)點(diǎn)擊stop和unbind按鈕,發(fā)現(xiàn)Service都不會(huì)被摧毀琐谤,只有在我們兩個(gè)按鈕都點(diǎn)擊了以后(兩個(gè)按鈕的點(diǎn)擊順序無(wú)所謂)蟆技,Service才會(huì)被摧毀。通過(guò)這一樣一個(gè)結(jié)論斗忌,我們可以得出叉瘩,一個(gè)Service,只有在即沒(méi)有和任何Activity綁定又處于停止?fàn)顟B(tài)下的時(shí)候项棠,才可以被摧毀肃廓。
4.最后,還要大家清楚一個(gè)問(wèn)題就是陈哑。當(dāng)你通過(guò)start按鈕妻坝,開(kāi)啟一個(gè)Service后,再次點(diǎn)擊bind按鈕惊窖,只會(huì)執(zhí)行服務(wù)的doTask方法刽宪,也就是Service綁定的方法回調(diào),而不會(huì)執(zhí)行onCreate方法再次創(chuàng)建一個(gè)Service界酒。而同樣的當(dāng)通過(guò)點(diǎn)擊bind按鈕開(kāi)啟一個(gè)服務(wù)后圣拄,再點(diǎn)擊start按鈕,也不會(huì)執(zhí)行onCreate方法毁欣,只會(huì)每次點(diǎn)擊都執(zhí)行onstartCommand方法庇谆,這里在前面也提到過(guò)。
Service的執(zhí)行線程
很多對(duì)Service了解的不是很透徹的同學(xué)凭疮,當(dāng)被問(wèn)到Service運(yùn)行在什么線程中饭耳,很多人都會(huì)第一反應(yīng)是子線程。原因呢执解,因?yàn)榇蠖鄶?shù)人都知道Service通常用來(lái)執(zhí)行一些比較耗時(shí)的后臺(tái)任務(wù)寞肖,既然提到了耗時(shí),那么肯定不會(huì)運(yùn)行在主線程啊衰腌,因?yàn)槟菢拥脑挄?huì)阻塞線程的啊新蟆。其實(shí)呢,并不是這樣的右蕊,Service其實(shí)是運(yùn)行在主線程的琼稻。為了證明我所說(shuō)的,我分別在StartActivity的onCreate方法和SimpleService的onCreate方法中獲取當(dāng)前運(yùn)行的線程的名字和id尤泽,代碼如下:
// Activity的onCreate方法
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_start);
Log.d(TAG, "StartActivity-----" + Thread.currentThread().getName() + "--" + Thread.currentThread().getId());
}
// Service的onCreate方法
@Override
public void onCreate() {
super.onCreate();
Log.d(TAG, "SimpleService-----" + Thread.currentThread().getName() + "--"Thread.currentThread().getId());
}
分別啟動(dòng)Activity和Service,Logcat日志如下:
可以看到欣簇,Service真的和Activity一樣规脸,是運(yùn)行在主線程的。到這估計(jì)好多人就懵逼了熊咽,這到底是個(gè)什么鬼啊莫鸭,明明是用來(lái)執(zhí)行一些后臺(tái)的耗時(shí)任務(wù)的啊,怎么還運(yùn)行在主線程啊横殴。
其實(shí)被因,這就是不會(huì)融會(huì)貫通的表現(xiàn)。Service確實(shí)運(yùn)行在主線程衫仑,但是我們?nèi)绻麍?zhí)行耗時(shí)操作梨与,我們可以在Service里面開(kāi)啟一個(gè)子線程來(lái)執(zhí)行耗時(shí)任務(wù)啊。那么問(wèn)題又來(lái)了文狱,我們?cè)贏ctivity中就可以創(chuàng)建子線程何必還費(fèi)二遍事開(kāi)始一個(gè)服務(wù)來(lái)創(chuàng)建一個(gè)子線程呢粥鞋。這里就不得不說(shuō)出Service的一個(gè)特性了,那就是不管創(chuàng)建Service的Activity是否被摧毀瞄崇,或者說(shuō)即使退出了應(yīng)用程序呻粹,但只要應(yīng)用的進(jìn)程沒(méi)有被殺死,這個(gè)Service就還會(huì)在運(yùn)行著苏研。而對(duì)于Activity來(lái)說(shuō)等浊,一旦Activity被摧毀,那么在它里面創(chuàng)建的線程也就不存在摹蘑,這樣一來(lái)執(zhí)行的任務(wù)也就停止了筹燕。而如果放在Service中執(zhí)行,即便是關(guān)聯(lián)的Activity被摧毀了衅鹿,那么只要重新與Service進(jìn)行關(guān)聯(lián)撒踪,那么它還是會(huì)獲得原有Service中的Binder實(shí)例的。舉出這樣一個(gè)需求塘安,假設(shè)應(yīng)用需要在進(jìn)程未被殺死的情況下時(shí)刻保持著從服務(wù)器讀取一個(gè)狀態(tài)糠涛,很明顯這時(shí)候就可以用Service來(lái)實(shí)現(xiàn)了啊。
現(xiàn)在兼犯,是不是明白了為什么通常在Service中執(zhí)行一些后臺(tái)的耗時(shí)操作了吧。下面我列舉出一個(gè)例子來(lái)掩飾在Service中開(kāi)啟一個(gè)線程來(lái)執(zhí)行操作:
public class SimpleService extends Service {
private SimpleBinder mBinder;
@Override
public void onCreate() {
super.onCreate();
mBinder = new SimpleBinder();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
new Thread(new Runnable() {
@Override
public void run() {
// 任務(wù)邏輯
}
}).start();
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
super.onDestroy();
}
@Override
public IBinder onBind(Intent intent) {
if (mBinder != null) {
return mBinder;
}
return null;
}
class SimpleBinder extends Binder {
public void doTask() {
new Thread(new Runnable() {
@Override
public void run() {
// 任務(wù)邏輯
}
}).start();
}
}
}
看到了吧集漾,是不是很簡(jiǎn)單切黔!