描述
Service通程溃總是稱之為“后臺(tái)服務(wù)”么夫,其中“后臺(tái)”一詞是相對(duì)于前臺(tái)而言的盐茎,具體是指其本身的運(yùn)行并不依賴于用戶可視的UI界面兴垦;
因此,從實(shí)際業(yè)務(wù)需求上來(lái)理解字柠,Service的適用場(chǎng)景應(yīng)該具備以下條件:
1探越、并不依賴于用戶可視的UI界面(當(dāng)然,這一條其實(shí)也不是絕對(duì)的窑业,如前臺(tái)Service就是與Notification界面結(jié)合使用的)钦幔;
2、具有較長(zhǎng)時(shí)間的運(yùn)行特性常柄。
Service特性
1鲤氢、Service本身都是運(yùn)行在其所在進(jìn)程的主線程(如果Service與Clinet同屬于一個(gè)進(jìn)程,則是運(yùn)行于UI線程)西潘,但Service一般都是需要進(jìn)行”長(zhǎng)期“操作铜异,所以經(jīng)常寫(xiě)法是在自定義Service中處理”長(zhǎng)期“操作時(shí)需要新建線程,以免阻塞UI線程或?qū)е翧NR秸架;
2揍庄、Service一旦創(chuàng)建,需要停止時(shí)都需要顯示調(diào)用相應(yīng)的方法(startService需要調(diào)用stopService()或Service本身調(diào)用stopSelf(..);
bindService需要調(diào)用unbindService()东抹,否則對(duì)于startService將處于一直運(yùn)行狀態(tài)蚂子,對(duì)于bindService沃测,當(dāng)Client生命周期結(jié)束時(shí)也將因此問(wèn)題。也就是說(shuō)食茎,Service執(zhí)行完畢后蒂破,必須人為的去停止它。
startService
startService()啟動(dòng)Service后别渔,此時(shí)Service的生命周期與Client本身的什么周期是沒(méi)有任何關(guān)系的;
使用步驟如下:
1附迷、創(chuàng)建Service子類,繼承自Service
2哎媚、在AndroidManifest文件中注冊(cè)Service:
項(xiàng)目中的每一個(gè)Service都必須在AndroidManifest.xml中注冊(cè)才能生效喇伯。
3、啟動(dòng)Service:
當(dāng)?shù)谝淮螁?dòng)Service的時(shí)候拨与,會(huì)調(diào)用該Service中的onCreate()和onStartCommand(Intent intent, int flags, int startId)方法稻据。若再次啟動(dòng)Service,onCreate()不會(huì)被調(diào)用买喧,只有onStartCommand(Intent intent, int flags, int startId)方法才會(huì)調(diào)用捻悯。其中參數(shù)flags默認(rèn)情況下是0,對(duì)應(yīng)的常量名為START_STICKY_COMPATIBILITY淤毛。startId是一個(gè)唯一的整型今缚,用于表示此次Client執(zhí)行startService(...)的請(qǐng)求請(qǐng)求標(biāo)識(shí),在多次startService(...)的情況下低淡,呈現(xiàn)0,1,2....遞增姓言。
4、銷毀Service:
無(wú)論多少次的startService查牌,只需要一次stopService()即可將此Service終止事期,執(zhí)行onDestroy()函數(shù)(其實(shí)很好理解滥壕,因?yàn)閛nDestroy()與onCreate()回調(diào)是相對(duì)的)纸颜。
5、注意點(diǎn):
5.1绎橘、當(dāng)用戶強(qiáng)制kill掉進(jìn)程時(shí)胁孙,onDestroy()是不會(huì)執(zhí)行的。
5.2称鳞、對(duì)于同一個(gè)Service涮较,Service實(shí)例一次永遠(yuǎn)只存在一個(gè),而不管Client是否是相同的組件冈止,也不管Client是否處于相同的進(jìn)程中狂票。
5.3、Service通過(guò)startService(..)啟動(dòng)Service后熙暴,此時(shí)Service的生命周期與Client本身的什么周期是沒(méi)有任何關(guān)系的闺属,只有Client調(diào)用stopService(..)或Service本身調(diào)用stopSelf(..)才能停止此Service慌盯。當(dāng)然,當(dāng)用戶強(qiáng)制kill掉Service進(jìn)程或系統(tǒng)因內(nèi)存不足也可能kill掉此Service掂器。
5.4亚皂、Client A 通過(guò)startService()啟動(dòng)Service后,可以在其他Client(如Client B国瓮、Client C)通過(guò)調(diào)用stopService()結(jié)束此Service灭必。
5.5、Client調(diào)用stopService()時(shí)乃摹,如果當(dāng)前Service沒(méi)有啟動(dòng)禁漓,也不會(huì)出現(xiàn)任何報(bào)錯(cuò)或問(wèn)題,也就是說(shuō)峡懈,stopService()無(wú)需做當(dāng)前Service是否有效的判斷璃饱。
5.6、當(dāng)Service需要運(yùn)行在單獨(dú)的進(jìn)程中肪康,AndroidManifest.xml聲明時(shí)需要通過(guò)android:process指明此進(jìn)程名稱荚恶,當(dāng)此Service需要對(duì)其他App開(kāi)放時(shí),android:exported屬性值需要設(shè)置為true(當(dāng)然磷支,在有intent-filter時(shí)默認(rèn)值就是true)谒撼。
自定義Service
public class MyService extends Service {
public static final String TAG = "MyService";
@Override
public void onCreate() {
super.onCreate();
Log.e(TAG, "onCreate() executed");
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.e(TAG, "onStartCommand() executed");
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
super.onDestroy();
Log.e(TAG, "onDestroy() executed");
}
//返回具體的IBind對(duì)象
@Override
public IBinder onBind(Intent intent) {
return null;
}
}
在AndroidManifest文件中注冊(cè)Service
<service
android:name=".MyService"
android:exported="false">
</service>
startService
public class ServiceTestOneActivity extends BaseActivity
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_service_test);
Log.e("ServiceTestOneActivity",
"ServiceTestOneActivity thread id is " + Thread.currentThread().getId());
findViewById(R.id.bt_start).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent startIntent = new Intent(ServiceTestOneActivity.this, MyService.class);
startService(startIntent);
}
});
findViewById(R.id.bt_stop).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent stopIntent = new Intent(ServiceTestOneActivity.this, MyService.class);
stopService(stopIntent);
}
});
}
@Override
protected void onDestroy() {
super.onDestroy();
}
}
bindService
bindService的主要特性在于Service的生命周期是依附于Client的生命周期的,當(dāng)Client銷毀時(shí)雾狈,bindService將執(zhí)行onDestroy廓潜。
同時(shí)通過(guò)Service中的Binder對(duì)象可以較為方便進(jìn)行Client-Service通信。bindService一般使用過(guò)程如下:
1善榛、創(chuàng)建Service子類辩蛋,繼承自Service,并重寫(xiě)onBind(Intent intent)方法移盆,此方法中需要返回具體的Binder對(duì)象悼院。
2、Client通過(guò)實(shí)現(xiàn)ServiceConnection接口來(lái)自定義ServiceConnection咒循,并通過(guò)bindService (Intent service, ServiceConnection sc, int flags)方法將Service綁定到此Client上据途;
3、自定義的 ServiceConnection 中實(shí)現(xiàn) onServiceConnected(ComponentName name, IBinder binder)方法叙甸,獲取Service端Binder實(shí)例颖医;
4、通過(guò)獲取的Binder實(shí)例進(jìn)行Service端其他公共方法的調(diào)用裆蒸,以完成Client-Service通信熔萧;
5、當(dāng)Client在恰當(dāng)?shù)纳芷冢ㄈ鏾nDestroy等)時(shí),此時(shí)需要解綁之前已經(jīng)綁定的Service佛致,通過(guò)調(diào)用函數(shù)unbindService(ServiceConnection sc)遂赠。
6、注意點(diǎn)
6.1晌杰、bindService()會(huì)調(diào)用Service的與onCreate()和 onBind()方法跷睦,不會(huì)調(diào)用onStartCommand()方法,但是會(huì)調(diào)用ServiceConnection中的onServiceConnected()方法肋演。
6.2抑诸、unbindService()銷毀服務(wù)會(huì)調(diào)用Service的onUnBind()方法。
6.3爹殊、如果關(guān)閉當(dāng)前Activity蜕乡,必須在Activity的 onDestroy()中取消綁定Service。
6.4梗夸、不可重復(fù)調(diào)用unbindService()取消綁定层玲,否則會(huì)出現(xiàn) Service not registered 異常。
6.5反症、當(dāng)Activity關(guān)閉后辛块,如果沒(méi)有調(diào)用unbindService()取消綁定服務(wù),此Service會(huì)自動(dòng)調(diào)用 onDestroy()方法铅碍,但是這種方式是不安全的润绵,建議主動(dòng)取消綁定。
自定義BinderService
public class MyService extends Service {
public static final String TAG = "MyService";
public boolean isServiceBind = false;
public MyBinder myBind = new MyBinder();
@Override
public void onCreate() {
super.onCreate();
Log.e(TAG, "MyService thread id is " + Thread.currentThread().getId());
Log.e(TAG, "onCreate() executed");
createForegroundService();
}
//創(chuàng)建前臺(tái)服務(wù)
private void createForegroundService() {
Intent notificationIntent = new Intent(this, MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this,0,notificationIntent,0);
Notification.Builder builder = new Notification.Builder(getApplicationContext());
builder.setContentTitle("***服務(wù)");
builder.setContentText("請(qǐng)勿關(guān)閉胞谈,***");
builder.setSmallIcon(R.mipmap.service_icon);
builder.setContentIntent(pendingIntent);
Notification notification = builder.build();
//啟動(dòng)前臺(tái)服務(wù)
startForeground(1,notification);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.e(TAG, "onStartCommand() executed");
return super.onStartCommand(intent, flags, startId);
}
// 返回具體的IBind對(duì)象
@Override
public IBinder onBind(Intent intent) {
Log.e(TAG, "onBind() executed");
isServiceBind = true;
return myBind;
}
@Override
public boolean onUnbind(Intent intent) {
isServiceBind = false;
Log.e(TAG, "onUnbind() executed");
return super.onUnbind(intent);
}
@Override
public void onDestroy() {
super.onDestroy();
//停止前臺(tái)服務(wù)
stopForeground(true);
Log.e(TAG, "onDestroy() executed");
}
public void doSomeThing() {
Log.e(TAG, "doSomeThing() executed");
}
public class MyBinder extends Binder {
public MyService getService() {
return MyService.this;
}
public void doWork() {
Log.e("MyBind", "doWork() executed");
}
}
}
使用bindService啟動(dòng)
public class ServiceTestOneActivity extends BaseActivity {
private MyService myService;
private MyService.MyBinder myBinder;
private MyReceiver myReceiver;
private ServiceConnection connection = new ServiceConnection() {
public static final String TAG = "ServiceConnection";
@Override
public void onServiceDisconnected(ComponentName name) {
// 服務(wù)斷開(kāi)連接
Log.e(TAG, "onServiceDisconnected() executed");
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
// 服務(wù)連接成功尘盼,可得到IBinder對(duì)象,也可以通過(guò)IBinder得到Service實(shí)例
Log.e(TAG, "onServiceConnected() executed");
myBinder = (MyService.MyBinder) service;
myService = myBinder.getService();
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_service_test);
Log.e("ServiceTestOneActivity",
"ServiceTestOneActivity thread id is " + Thread.currentThread().getId());
initBroadcast();
findViewById(R.id.bt_start).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent startIntent = new Intent(ServiceTestOneActivity.this, MyService.class);
startService(startIntent);
}
});
findViewById(R.id.bt_stop).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent stopIntent = new Intent(ServiceTestOneActivity.this, MyService.class);
stopService(stopIntent);
}
});
findViewById(R.id.bt_bind).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// 這里傳入BIND_AUTO_CREATE表示在Activity和Service建立關(guān)聯(lián)后自動(dòng)創(chuàng)建Service,
// 這會(huì)使得MyService中的onCreate()方法得到執(zhí)行烦绳,但onStartCommand()方法不會(huì)執(zhí)行卿捎。
Intent bindIntent = new Intent(ServiceTestOneActivity.this, MyService.class);
bindService(bindIntent, connection, Context.BIND_AUTO_CREATE);
}
});
findViewById(R.id.bt_unbind).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
checkServiceIsBind();
}
});
findViewById(R.id.bt_do_work).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (null != myService && null != myBinder) {
myService.doSomeThing();
myBinder.doWork();
}
}
});
}
private void checkServiceIsBind() {
if (null != myService && myService.isServiceBind) {
myService = null;
myBinder = null;
unbindService(connection);
}
}
@Override
protected void onDestroy() {
super.onDestroy();
checkServiceIsBind();
}
}
startService和bindService交叉使用
如果既點(diǎn)擊了Start Service按鈕,又點(diǎn)擊了Bind Service按鈕會(huì)怎么樣呢径密?
這個(gè)時(shí)候你會(huì)發(fā)現(xiàn)午阵,不管你是單獨(dú)點(diǎn)擊Stop Service按鈕還是Unbind Service按鈕,Service都不會(huì)被銷毀睹晒,必需將兩個(gè)按鈕都點(diǎn)擊一下趟庄,Service才會(huì)被銷毀括细。也就是說(shuō)伪很,點(diǎn)擊Stop Service按鈕只會(huì)讓Service停止,點(diǎn)擊Unbind Service按鈕只會(huì)讓Service和Activity解除關(guān)聯(lián)奋单, 一個(gè)Service必須要在既沒(méi)有和任何Activity關(guān)聯(lián)又處于停止?fàn)顟B(tài)的時(shí)候才會(huì)被銷毀锉试。
Service和Thread
實(shí)際上Service和Thread是沒(méi)有任何關(guān)系的,Service實(shí)際上就運(yùn)行在主線程上览濒。
1呆盖、Android的后臺(tái)就是指拖云,它的運(yùn)行是完全不依賴UI的。即使Activity被銷毀应又,或者程序被關(guān)閉宙项,只要進(jìn)程還在,Service就可以繼續(xù)運(yùn)行株扛。
比如說(shuō)一些應(yīng)用程序尤筐,始終需要與服務(wù)器之間始終保持著心跳連接,就可以使用Service來(lái)實(shí)現(xiàn)洞就∨璺保可以在Service中再創(chuàng)建一個(gè)子線程,然后在這里去處理耗時(shí)邏輯就沒(méi)問(wèn)題了旬蟋。
2油昂、Activity很難對(duì)Thread進(jìn)行控制,當(dāng)Activity被銷毀之后倾贰,就沒(méi)有任何其它的辦法可以再重新獲取到之前創(chuàng)建的子線程的實(shí)例冕碟。而且在一個(gè)Activity中創(chuàng)建的子線程,另一個(gè)Activity無(wú)法對(duì)其進(jìn)行操作匆浙。但是Service就不同了鸣哀,所有的Activity都可以與Service進(jìn)行關(guān)聯(lián),然后可以很方便地操作其中的方法吞彤,即使Activity被銷毀了我衬,之后只要重新與Service建立關(guān)聯(lián),就又能夠獲取到原有的Service中Binder的實(shí)例饰恕。 因此挠羔,使用Service來(lái)處理后臺(tái)任務(wù),Activity就可以放心地finish埋嵌,完全不需要擔(dān)心無(wú)法對(duì)后臺(tái)任務(wù)進(jìn)行控制的情況破加。
3、一個(gè)比較標(biāo)準(zhǔn)的Service就可以寫(xiě)成:
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
new Thread(new Runnable() {
@Override
public void run() {
// 開(kāi)始執(zhí)行后臺(tái)任務(wù)
}
}).start();
return super.onStartCommand(intent, flags, startId);
}
//或者
class MyBinder extends Binder {
public void startDownload() {
new Thread(new Runnable() {
@Override
public void run() {
// 執(zhí)行具體的下載任務(wù)
}
}).start();
}
}
創(chuàng)建前臺(tái)Service
前臺(tái)服務(wù)是那些被認(rèn)為用戶知道(用戶所認(rèn)可的)且在系統(tǒng)內(nèi)存不足的時(shí)候不允許系統(tǒng)殺死的服務(wù)雹嗦。前臺(tái)服務(wù)必須給狀態(tài)欄提供一個(gè)通知范舀,它被放到正在運(yùn)行(Ongoing)標(biāo)題之下——這就意味著通知只有在這個(gè)服務(wù)被終止或從前臺(tái)主動(dòng)移除通知后才能被解除。
Service幾乎都是在后臺(tái)運(yùn)行的了罪,Service的系統(tǒng)優(yōu)先級(jí)還是比較低的,當(dāng)系統(tǒng)出現(xiàn)內(nèi)存不足情況時(shí)锭环,就有可能會(huì)回收掉正在后臺(tái)運(yùn)行的Service。
如果你希望Service可以一直保持運(yùn)行狀態(tài)泊藕,而不會(huì)由于系統(tǒng)內(nèi)存不足的原因?qū)е卤换厥崭ū纾涂梢钥紤]使用前臺(tái)Service。
前臺(tái)Service和普通Service最大的區(qū)別就在于,它會(huì)一直有一個(gè)正在運(yùn)行的圖標(biāo)在系統(tǒng)的狀態(tài)欄顯示玫锋,下拉狀態(tài)欄后可以看到更加詳細(xì)的信息蛾茉,非常類似于通知的效果。
ex:App中的音樂(lè)播放服務(wù)應(yīng)被設(shè)置在前臺(tái)運(yùn)行(前臺(tái)服務(wù))——在App后臺(tái)運(yùn)行時(shí)撩鹿,便于用戶明確知道它的當(dāng)前操作谦炬、在狀態(tài)欄中指明當(dāng)前歌曲信息、提供對(duì)應(yīng)操作节沦。
//創(chuàng)建前臺(tái)服務(wù)
private void createForegroundService() {
Intent notificationIntent = new Intent(this, MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this,0,notificationIntent,0);
Notification.Builder builder = new Notification.Builder(getApplicationContext());
builder.setContentTitle("***服務(wù)");
builder.setContentText("請(qǐng)勿關(guān)閉吧寺,***");
builder.setSmallIcon(R.mipmap.service_icon);
builder.setContentIntent(pendingIntent);
Notification notification = builder.build();
//啟動(dòng)前臺(tái)服務(wù)
startForeground(1,notification);
}
@Override
public void onDestroy() {
super.onDestroy();
//停止前臺(tái)服務(wù)
stopForeground(true);
}
IntentService
1、IntentService是繼承于Service并處理異步請(qǐng)求的一個(gè)類散劫。
注意這句話——“繼承于Service”和“處理異步請(qǐng)求”稚机。
“繼承于Service”表示他是一個(gè)服務(wù),我們知道Service是存在于主線程的获搏,它之中不能存在耗時(shí)操作赖条,否則的話回應(yīng)起ANR,因此便有了IntentService——這個(gè)封裝了HandlerThread和Handler的特殊Service常熙。
2纬乍、特性:
2.1、IntentService中只有“一個(gè)”默認(rèn)的HandlerThread線程用來(lái)處理異步任務(wù);
2.2裸卫、默認(rèn)直接實(shí)現(xiàn)了onBind()方法仿贬,直接返回null,并定義了抽象方法onHandlerIntent()墓贿,用戶自定義子類時(shí)茧泪,需要實(shí)現(xiàn)此方法;
2.3聋袋、onHandlerIntent()主要就是用來(lái)處于相應(yīng)的“長(zhǎng)期”任務(wù)的队伟,并且已經(jīng)自動(dòng)在新的線程中,用戶無(wú)語(yǔ)自定義新線程幽勒;
2.4嗜侮、當(dāng)“長(zhǎng)期”任務(wù)執(zhí)行完畢后(也就是onHandlerIntent()執(zhí)行完畢后),此IntentService將自動(dòng)結(jié)束啥容,無(wú)需人為調(diào)用方法使其結(jié)束锈颗;
2.5、IntentService處理任務(wù)時(shí)咪惠,也是按照隊(duì)列的方式一個(gè)個(gè)去處理击吱,而非真正意義上的多線程并發(fā)方式。
2.6硝逢、onHandleIntent(Intent)發(fā)生在子線程姨拥,不能直接更新UI,需要先把結(jié)果發(fā)到Activity中
2.7渠鸽、提交的任務(wù)順序執(zhí)行叫乌,如果一個(gè)任務(wù)A正在IntentService中執(zhí)行,此時(shí)發(fā)送另一個(gè)異步任務(wù)B到IntentService中徽缚,那么必須等到任務(wù)A執(zhí)行完之后任務(wù)B才會(huì)開(kāi)始執(zhí)行
3憨奸、使用IntentService的好處:
3.1、我們省去了在 Service 中手動(dòng)開(kāi)線程的麻煩凿试,
3.2排宰、當(dāng)操作完成時(shí),我們不用手動(dòng)停止 Service那婉。
自定義IntentService
public class MyIntentService extends IntentService {
public static final String TAG = "MyIntentService";
public static final String ACTION_ONE = "action_one";
public static final String ACTION_TWO = "action_two";
public static final String ACTION_BROADCAST = "action_broad";
private int progressOne, progressTwo;
//無(wú)參的構(gòu)造方法板甘,指定線程名稱
public MyIntentService() {
// 線程的名稱
super("MyIntentService");
}
@Override
public void onCreate() {
super.onCreate();
Log.e(TAG, "onCreate() executed");
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.e(TAG, "onStartCommand() executed");
return super.onStartCommand(intent, flags, startId);
}
//實(shí)現(xiàn)此方法,處理異步任務(wù)详炬,此方法運(yùn)行在子線程(即HandlerThread)
@Override
protected void onHandleIntent(Intent intent) {
if (intent != null && intent.getAction() != null) {
switch (intent.getAction()) {
case ACTION_ONE:
while (progressOne < 100) {
progressOne++;
//發(fā)送廣播通知UI線程更新UI
sendBroadcast(getUpdateIntent(0, progressOne));
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
break;
case ACTION_TWO:
while (progressTwo < 100) {
progressTwo++;
//發(fā)送廣播通知UI線程更新UI
sendBroadcast(getUpdateIntent(1, progressTwo));
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
break;
}
}
}
@Override
public void onDestroy() {
super.onDestroy();
Log.e(TAG, "onDestroy() executed");
}
private Intent getUpdateIntent(int i, int progress) {
Intent intent = new Intent(ACTION_BROADCAST);
intent.putExtra("type", i);
intent.putExtra("progress", progress);
return intent;
}
}
啟動(dòng)IntentService
public class ServiceTestOneActivity extends BaseActivity {
private TextView textViewOne;
private TextView textViewTwo;
private MyReceiver myReceiver;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_service_test);
textViewOne = findViewById(R.id.tv_one);
textViewTwo = findViewById(R.id.tv_two);
initBroadcast();
findViewById(R.id.bt_intent_one).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(ServiceTestOneActivity.this, MyIntentService.class);
intent.setAction(MyIntentService.ACTION_ONE);
startService(intent);
}
});
findViewById(R.id.bt_intent_two).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(ServiceTestOneActivity.this, MyIntentService.class);
intent.setAction(MyIntentService.ACTION_TWO);
startService(intent);
}
});
}
// 注冊(cè)廣播
private void initBroadcast() {
myReceiver = new MyReceiver();
registerReceiver(myReceiver, new IntentFilter(MyIntentService.ACTION_BROADCAST));
}
@Override
protected void onDestroy() {
super.onDestroy();
}
public class MyReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
switch (action) {
case MyIntentService.ACTION_BROADCAST:
if (intent.getIntExtra("type", 0) == 0) {
textViewOne.setText(intent.getIntExtra("progress", 0) + "");
} else {
textViewTwo.setText(intent.getIntExtra("progress", 0) + "");
}
break;
}
}
}
}
遠(yuǎn)程服務(wù)盐类,即AIDL實(shí)現(xiàn)進(jìn)程間通信
Android Interface Definition Language,也就是Android接口定義語(yǔ)言呛谜。是的在跳,首先我們知道的第一點(diǎn)就是:AIDL是一種語(yǔ)言。
實(shí)現(xiàn)步驟:
1隐岛、創(chuàng)建AIDL文件猫妙,會(huì)自動(dòng)生成aidl文件。創(chuàng)建成功后再/main目錄下自動(dòng)創(chuàng)建aidl文件夾聚凹。
// IMyAIDLService.aidl
package com.android.pkqup.androidnote.service_test;
// Declare any non-default types here with import statements
interface IMyAIDLService {
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
double aDouble, String aString);
int plus(int a, int b);
String toUpperCase(String str);
}
2割坠、創(chuàng)建Service,以IMyAIDLService.Stub()實(shí)例作為IBinder對(duì)象在onBind()方法中返回妒牙。
public class RemoteService extends Service {
public static final String TAG = "RemoteService";
@Override
public void onCreate() {
super.onCreate();
Log.e(TAG, "onCreate() executed");
Log.e(TAG, "ServiceTestOneActivity process id is " + Process.myPid());
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.e(TAG, "onStartCommand() executed");
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
super.onDestroy();
Log.e(TAG, "onDestroy() executed");
}
// 返回具體的IBind對(duì)象
@Override
public IBinder onBind(Intent intent) {
//以AIDL的Stub作為IBinder返回
return binder;
}
IMyAIDLService.Stub binder = new IMyAIDLService.Stub() {
@Override
public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
double aDouble, String aString) throws RemoteException {
}
// 相加
@Override
public int plus(int a, int b) throws RemoteException {
return a + b;
}
// 轉(zhuǎn)大寫(xiě)
@Override
public String toUpperCase(String str) throws RemoteException {
if (str != null) {
return str.toUpperCase();
}
return null;
}
};
}
3韭脊、在AndroidManifest文件中注冊(cè)遠(yuǎn)程Service。
注意:android:process=":remote"
<service
android:exported="true"
android:name=".service_test.RemoteService"
android:process=":remote">
<!--給遠(yuǎn)程service創(chuàng)建一個(gè)意圖過(guò)濾器 提供給其他應(yīng)用做隱式意圖-->
<intent-filter>
<action android:name="com.android.pkqup.androidnote.remote.service" />
</intent-filter>
</service>
4单旁、復(fù)制整個(gè)aidl文件夾到第三方工程的 /main 目錄下沪羔。
5、在第三方應(yīng)用中bindService象浑。
private ServiceConnection serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
IMyAIDLService myAIDLService = IMyAIDLService.Stub.asInterface(service);
try {
int result = myAIDLService.plus(50, 50);
String upperStr = myAIDLService.toUpperCase("comes from ClientTest");
Log.d("TAG", "result is " + result);
Log.d("TAG", "upperStr is " + upperStr);
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
private void bindService() {
Intent intent = new Intent("com.android.pkqup.androidnote.remote.service");
//Android5.0之后服務(wù)必須顯性聲明蔫饰,所以在調(diào)用其他應(yīng)用的遠(yuǎn)程服務(wù)時(shí)必須加上包名,
intent.setPackage("com.android.pkqup.androidnote");
bindService(intent, serviceConnection, BIND_AUTO_CREATE);
}