為什么用Service
回顧Activity
說(shuō)起Service
之前先來(lái)看看四個(gè)卵胞兄弟痊臭,因?yàn)?code>ContentProvider和BroadcastReceiver
和Service
沒(méi)有太大關(guān)聯(lián)倚搬,所以重點(diǎn)看一下卵胞兄弟Activity
即可丧蘸,老規(guī)矩,還是read the fucking source code
開(kāi)始斗搞,代碼從startActivity
開(kāi)始。
public class MainActivity extends ActionBarActivity
{
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
...
startActivity(new Intent(this, TabActivity.class));
}
}
上面這處代碼再熟悉不過(guò)了慷妙,我們跟下去看看究竟僻焚。
@Override
public void startActivity(Intent intent) {
this.startActivity(intent, null);
}
繼續(xù)跟下去會(huì)進(jìn)入到接口IActivityManager
public interface IActivityManager extends IInterface {
public int startActivity(IApplicationThread caller, String callingPackage, Intent intent,
String resolvedType, IBinder resultTo, String resultWho, int requestCode, int flags,
ProfilerInfo profilerInfo, Bundle options) throws RemoteException;
}
進(jìn)入到實(shí)現(xiàn)類ActivityManagerNative
public int startActivity(IApplicationThread caller, String callingPackage, Intent intent,
String resolvedType, IBinder resultTo, String resultWho, int requestCode,
int startFlags, ProfilerInfo profilerInfo, Bundle options) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
data.writeStrongBinder(caller != null ? caller.asBinder() : null);
data.writeString(callingPackage);
intent.writeToParcel(data, 0);
data.writeString(resolvedType);
data.writeStrongBinder(resultTo);
data.writeString(resultWho);
data.writeInt(requestCode);
data.writeInt(startFlags);
if (profilerInfo != null) {
data.writeInt(1);
profilerInfo.writeToParcel(data, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
} else {
data.writeInt(0);
}
if (options != null) {
data.writeInt(1);
options.writeToParcel(data, 0);
} else {
data.writeInt(0);
}
mRemote.transact(START_ACTIVITY_TRANSACTION, data, reply, 0);
reply.readException();
int result = reply.readInt();
reply.recycle();
data.recycle();
return result;
}
這個(gè)方法簡(jiǎn)單分析一下,L27之前都是數(shù)據(jù)在跨進(jìn)程之前需要進(jìn)行打包處理景殷,然后L27調(diào)用transact方法溅呢,進(jìn)入NDK方法澡屡,最后從replay中取得返回結(jié)果。
重回Service
上面跟了這么多代碼咐旧,最重要的一點(diǎn)就是Activity組件的跳轉(zhuǎn)是完全解耦的驶鹉,說(shuō)的更直接一點(diǎn)是只需要Context上下文即可完成跳轉(zhuǎn),意即無(wú)論再任何場(chǎng)景下铣墨,只要有Context上下文室埋,想怎么跳轉(zhuǎn)就怎么跳轉(zhuǎn),這么好的特性伊约,是不是在剩下的四個(gè)卵胞兄弟中也有這樣的特性姚淆?帶著這個(gè)疑問(wèn)我們繼續(xù)跟一下startService
public class MainActivity extends ActionBarActivity
{
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
...
startService(new Intent(this, TabService.class));
}
}
跟下去,進(jìn)入ContextWrapper
類
@Override
public ComponentName startService(Intent service) {
return mBase.startService(service);
}
進(jìn)入實(shí)現(xiàn)類ContextImpl
類
@Override
public ComponentName startService(Intent service) {
warnIfCallingFromSystemProcess();
return startServiceCommon(service, mUser);
}
第一行就是個(gè)warning屡律,第二行繼續(xù)跟下去進(jìn)入ActivityManagerProxy
代理類
public ComponentName startService(IApplicationThread caller, Intent service,
String resolvedType, int userId) throws RemoteException
{
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
data.writeStrongBinder(caller != null ? caller.asBinder() : null);
service.writeToParcel(data, 0);
data.writeString(resolvedType);
data.writeInt(userId);
mRemote.transact(START_SERVICE_TRANSACTION, data, reply, 0);
reply.readException();
ComponentName res = ComponentName.readFromParcel(reply);
data.recycle();
reply.recycle();
return res;
}
這個(gè)方法整體上是不是似曾相識(shí)腌逢,里面的具體流程就不作贅述了。
通過(guò)上面的源碼對(duì)比超埋,發(fā)現(xiàn)Service和Activity如此的想象搏讶,那既然Service和Activity這么像,為啥還多此一舉多弄出來(lái)一個(gè)Service干什么霍殴?原因其實(shí)很簡(jiǎn)單媒惕,因?yàn)榻怦睿钥梢钥鐖?chǎng)景来庭,然后就有一堆理由需要使用Service了妒蔚,比如:
一些應(yīng)用程序,始終需要與服務(wù)器之間始終保持著心跳連接月弛,就可以使用Service來(lái)實(shí)現(xiàn)肴盏。即使Activity被銷毀,或者程序被關(guān)閉尊搬,只要進(jìn)程還在叁鉴,Service就可以繼續(xù)運(yùn)行。而且重要的是這個(gè)Service可以被任何可以獲取Context的地方控制
接下來(lái)我們說(shuō)一下如何控制Service佛寿,由前面可知幌墓,只要獲取Context就可以對(duì)Service為所欲為了,以下為實(shí)例代碼
public void onClick(View v) {
switch (v.getId()) {
case R.id.start_service:
Intent startIntent = new Intent(this, MyService.class);
startService(startIntent);
break;
case R.id.stop_service:
Log.d("MyService", "click Stop Service button");
Intent stopIntent = new Intent(this, MyService.class);
stopService(stopIntent);
break;
case R.id.bind_service:
Intent bindIntent = new Intent(this, MyService.class);
bindService(bindIntent, connection, BIND_AUTO_CREATE);
break;
case R.id.unbind_service:
Log.d("MyService", "click Unbind Service button");
unbindService(connection);
break;
default:
break;
}
}
這里需要注意一點(diǎn)冀泻,控制總是成對(duì)出現(xiàn)常侣,比如:
第一種情況
startService
stopService
第二種情況
bindService
unbindService
第三種情況
startService
bindService
unbindService
stopService
Service和Thread以及Process區(qū)別
不少Android初學(xué)者都可能會(huì)有這樣的疑惑,Service和Thread到底有什么關(guān)系呢弹渔?什么時(shí)候應(yīng)該用Service胳施,什么時(shí)候又應(yīng)該用Thread?答案可能會(huì)有點(diǎn)讓你吃驚肢专,因?yàn)镾ervice和Thread之間沒(méi)有任何關(guān)系舞肆!
之所以有不少人會(huì)把它們聯(lián)系起來(lái)焦辅,主要就是因?yàn)镾ervice的后臺(tái)概念。Thread我們大家都知道椿胯,是用于開(kāi)啟一個(gè)子線程筷登,在這里去執(zhí)行一些耗時(shí)操作就不會(huì)阻塞主線程的運(yùn)行。而Service我們最初理解的時(shí)候哩盲,總會(huì)覺(jué)得它是用來(lái)處理一些后臺(tái)任務(wù)的前方,一些比較耗時(shí)的操作也可以放在這里運(yùn)行,這就會(huì)讓人產(chǎn)生混淆了廉油。但是惠险,如果我告訴你Service其實(shí)是運(yùn)行在主線程里的,你還會(huì)覺(jué)得它和Thread有什么關(guān)系嗎抒线?
這里不再做實(shí)驗(yàn)去驗(yàn)證了班巩,如果你感興趣的話可以自己去驗(yàn)證。所以說(shuō)白了十兢,Service既不是線程更不是進(jìn)程趣竣,他只是Android提供給我方便使用的組件而已,千萬(wàn)別聯(lián)想多了旱物。
本地Service
Service根據(jù)功能不同,可以分為本地Service和遠(yuǎn)程Service卫袒,當(dāng)然還有前臺(tái)Service和后臺(tái)Service宵呛,后臺(tái)Service見(jiàn)怪不怪,那么前臺(tái)Service是什么鬼夕凝?這里僅僅舉個(gè)例子宝穗,不做深入,比如墨跡天氣码秉,默認(rèn)顯示在通知欄里面逮矛,那么如何做到的,你可以Google一下列子很多转砖,我們回歸本地和遠(yuǎn)程Service须鼎,有些人可能會(huì)聯(lián)想很多,其實(shí)這個(gè)本地和遠(yuǎn)程是相對(duì)進(jìn)程來(lái)說(shuō)的府蔗,在同一個(gè)進(jìn)程里就是本地Service晋控,不在同一個(gè)進(jìn)程里就是遠(yuǎn)程Service。我們知道不同進(jìn)程間通信和相同進(jìn)程間通信有著很大區(qū)別姓赤,最直白的表象就是復(fù)雜程度不同赡译,我們先看本地Service如何通信。
[引用代碼]
public class MyService extends Service {
public static final String TAG = "MyService";
private MyBinder mBinder = new MyBinder();
@Override
public void onCreate() {
super.onCreate();
Log.d(TAG, "onCreate() executed");
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(TAG, "onStartCommand() executed");
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
super.onDestroy();
Log.d(TAG, "onDestroy() executed");
}
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
class MyBinder extends Binder {
public void startDownload() {
Log.d("TAG", "startDownload() executed");
// 執(zhí)行具體的下載任務(wù)
}
}
}
注意這里MyBinder類繼承自Binder類不铆,在其中添加了一個(gè)startDownload()公有方法用于在后臺(tái)執(zhí)行下載任務(wù)蝌焚。然后這個(gè)類的實(shí)例mBinder在重載方法onBind中作為返回值返回裹唆,這個(gè)實(shí)例就是Activity和Service之間聯(lián)系最為緊密的橋梁。
public class MainActivity extends Activity implements OnClickListener {
private Button bindService;
private Button unbindService;
private MyService.MyBinder myBinder;
private ServiceConnection connection = new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName name) {
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
myBinder = (MyService.MyBinder) service;
myBinder.startDownload();
}
};
@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;
}
}
}
可以看到只洒,這里我們首先創(chuàng)建了一個(gè)ServiceConnection的匿名類许帐,在里面重寫(xiě)了onServiceConnected()方法和onServiceDisconnected()方法,這兩個(gè)方法分別會(huì)在Activity與Service建立關(guān)聯(lián)和解除關(guān)聯(lián)的時(shí)候調(diào)用红碑。在onServiceConnected()方法中舞吭,我們又通過(guò)向下轉(zhuǎn)型得到了MyBinder的實(shí)例,有了這個(gè)實(shí)例析珊,Activity和Service之間的關(guān)系就變得非常緊密了羡鸥。
現(xiàn)在我們可以在Activity中根據(jù)具體的場(chǎng)景來(lái)調(diào)用MyBinder中的任何public方法,即實(shí)現(xiàn)了Activity指揮Service干什么Service就去干什么的功能忠寻。
當(dāng)然惧浴,現(xiàn)在Activity和Service其實(shí)還沒(méi)關(guān)聯(lián)起來(lái)了呢,這個(gè)功能是在Bind Service按鈕的點(diǎn)擊事件里完成的奕剃≈月茫可以看到,這里我們?nèi)匀皇菢?gòu)建出了一個(gè)Intent對(duì)象纵朋,然后調(diào)用bindService()方法將Activity和Service進(jìn)行綁定柿顶。bindService()方法接收三個(gè)參數(shù),第一個(gè)參數(shù)就是剛剛構(gòu)建出的Intent對(duì)象操软,第二個(gè)參數(shù)是前面創(chuàng)建出的ServiceConnection的實(shí)例嘁锯,第三個(gè)參數(shù)是一個(gè)標(biāo)志位,這里傳入BIND_AUTO_CREATE表示在Activity和Service建立關(guān)聯(lián)后自動(dòng)創(chuàng)建Service聂薪,這會(huì)使得MyService中的onCreate()方法得到執(zhí)行家乘,但onStartCommand()方法不會(huì)執(zhí)行。
然后如何我們想解除Activity和Service之間的關(guān)聯(lián)怎么辦呢藏澳?調(diào)用一下unbindService()方法就可以了仁锯,這也是Unbind Service按鈕的點(diǎn)擊事件里實(shí)現(xiàn)的邏輯。
遠(yuǎn)程Service
首先我們比較關(guān)系如何實(shí)現(xiàn)遠(yuǎn)程Service
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.servicetest"
android:versionCode="1"
android:versionName="1.0" >
......
<service
android:name="com.example.servicetest.MyService"
android:process=":remote" >
</service>
</manifest>
通過(guò)上面的配置文件翔悠,我們知道應(yīng)該是Service和APP從屬于不同的進(jìn)程业崖,然后比較復(fù)雜的就是進(jìn)程間通信了。
那么如何才能讓Activity與一個(gè)遠(yuǎn)程Service建立關(guān)聯(lián)呢凉驻?這就要使用AIDL來(lái)進(jìn)行跨進(jìn)程通信了(IPC)腻要。
AIDL(Android Interface Definition Language)是Android接口定義語(yǔ)言的意思,它可以用于讓某個(gè)Service與多個(gè)應(yīng)用程序組件之間進(jìn)行跨進(jìn)程通信涝登,從而可以實(shí)現(xiàn)多個(gè)應(yīng)用程序共享同一個(gè)Service的功能雄家。
接下來(lái)不準(zhǔn)備詳細(xì)些如何實(shí)現(xiàn)進(jìn)程間通信了,因?yàn)锳ndroid SDK里面有很多例子可以參考胀滚,另外如果對(duì)AIDL一點(diǎn)也不熟悉趟济,可以通過(guò)Android Service完全解析乱投,關(guān)于服務(wù)你所需知道的一切(下)這篇文章了解一下.
另外還有一篇博客寫(xiě)的不錯(cuò)Android 中的 Service 全面總結(jié) 。