四大組件之Service
Service是Android開(kāi)發(fā)的基礎(chǔ)之一煤蚌,但是在實(shí)際項(xiàng)目開(kāi)發(fā)中用到較少岳瞭,有必要梳理一下仁烹,就先篇文章記錄下欠痴。
Service的啟動(dòng)方式
與Activity一樣迄靠,service需要在manifest.xml 中進(jìn)行注冊(cè)
<service android:name=".service.TestService" />
Service的啟動(dòng)方式有兩種,接下來(lái)分別進(jìn)行介紹
方式一
方法一使用上也與Activity跳轉(zhuǎn)相似喇辽,通過(guò)Intent的方式進(jìn)行啟動(dòng)掌挚。
startService(new Intent(ServiceActivity.this, TestService.class));
我們?cè)谙嚓P(guān)生命周期中打印日志觀察啟動(dòng)流程。
@Override
public void onCreate() {
Log.e(TAG, "onCreate:");
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.e(TAG, "onStartCommand:");
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
Log.e(TAG, "onDestroy:");
super.onDestroy();
}
當(dāng)?shù)谝淮吸c(diǎn)擊按鈕觸發(fā)startService時(shí)菩咨,
service.TestService: onCreate:
service.TestService: onStartCommand:
第二次點(diǎn)擊觸發(fā)
service.TestService: onStartCommand:
發(fā)現(xiàn)后面start多少次都只會(huì)走onStartCommand函數(shù)吠式,可以與Activity的onNewIntent進(jìn)行類(lèi)比舅世,已經(jīng)初始化的Service不需要被重復(fù)創(chuàng)建。
接著觸發(fā)stopService后再啟動(dòng)Service奇徒,則會(huì)從OnCreate開(kāi)始雏亚。
方式二
若要Activity與Service之間有交互,就需要通過(guò)方法二bindService的方式摩钙。創(chuàng)建ServiceConnection對(duì)象進(jìn)行關(guān)聯(lián)罢低。
private ServiceConnection connection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
bindService(new Intent(ServiceActivity.this, TestService.class),connection, 1);
通過(guò)bindService的方式只會(huì)綁定一次
service.TestService: onCreate:
service.TestService: onBind:
同樣的通過(guò)unbindService之后重復(fù)創(chuàng)建綁定流程。
Service的使用
相對(duì)于Activity來(lái)說(shuō)胖笛,Service并沒(méi)有頁(yè)面网持,也就沒(méi)有控件上的交互,單純用于處理邏輯长踊。
現(xiàn)在我們通過(guò)方式一執(zhí)行下1s的耗時(shí)任務(wù)功舀,使用Sleep進(jìn)行模擬,然后進(jìn)行Toast身弊。
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
try {
Thread.sleep(1000);
Toast.makeText(getBaseContext(), "任務(wù)完成", Toast.LENGTH_LONG).show();
} catch (InterruptedException e) {
e.printStackTrace();
}
Log.e(TAG, "onStartCommand:");
return super.onStartCommand(intent, flags, startId);
}
但是如果任務(wù)時(shí)間過(guò)長(zhǎng)辟汰,由于處于主線(xiàn)程中,就會(huì)造成ANR的現(xiàn)象阱佛。這個(gè)時(shí)候就可以創(chuàng)建一個(gè)線(xiàn)程執(zhí)行帖汞,或者使用IntentService的方式。
IntentService封裝了HandlerThread凑术,創(chuàng)建啟動(dòng)線(xiàn)程并進(jìn)行Loop翩蘸。Handler接收消息處理任務(wù)后直接關(guān)閉Service。
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
onHandleIntent((Intent)msg.obj);
stopSelf(msg.arg1);
}
}
另一種通過(guò)Bind的方式更加的靈活淮逊,可以根據(jù)需要執(zhí)行任務(wù)催首。在TestService中定義LocalBinder類(lèi),在創(chuàng)建Service時(shí)進(jìn)行初始化泄鹏,執(zhí)行bindService后返回該對(duì)象郎任。
private LocalBinder mbinder = new LocalBinder();
@Nullable
@Override
public IBinder onBind(Intent intent) {
Log.e(TAG, "onBind:");
return mbinder;
}
public class LocalBinder extends Binder {
public TestService getservices() {
return TestService.this;
}
public void method1() {
Toast.makeText(getBaseContext(), "method1", Toast.LENGTH_LONG).show();
Log.e(TAG, "start:");
}
public void method2() {
Toast.makeText(getBaseContext(), "method2", Toast.LENGTH_LONG).show();
Log.e(TAG, "start:");
}
}
在Activity中的onServiceConnected時(shí)保存對(duì)象。
private TestService.LocalBinder localBinder;
private ServiceConnection connection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
localBinder = (TestService.LocalBinder) service;
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
即可根據(jù)需要調(diào)用localBinder.method1()命满。
Service的跨進(jìn)程通信
IBinder這個(gè)東西是用來(lái)實(shí)現(xiàn)跨進(jìn)程通信的涝滴,像上面那樣使用簡(jiǎn)直是殺雞用牛刀。
使用Messenger來(lái)發(fā)送跨進(jìn)程消息
首先在Manifest中將TestService設(shè)置其他進(jìn)程
<service android:name=".service.TestService"
android:process=":remote"/>
在TestService中創(chuàng)建Messenger對(duì)象胶台,在onBind中返回
private Messenger messenger = new Messenger(new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case 1:
Log.e(TAG, "remoteService接收到了Activity發(fā)送的消息");
break;
default:
super.handleMessage(msg);
break;
}
}
});
@Nullable
@Override
public IBinder onBind(Intent intent) {
Log.e(TAG, "onBind:");
return messenger.getBinder();
}
在Activity中使用通過(guò)onBind返回的IBinder對(duì)象創(chuàng)建Messenger發(fā)送遠(yuǎn)程消息。
private Messenger mMessenger;
private ServiceConnection connection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mMessenger = new Messenger(service);
Message message = Message.obtain(null, 1);
try {
mMessenger.send(message);
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
運(yùn)行觀察結(jié)果
service.TestService: remoteService接收到了Activity發(fā)送的消息
也可以設(shè)置message.replyTo 為本地的Messenger 杂抽,接收遠(yuǎn)程的消息诈唬。
Activity中
private Messenger remoteMessenger;
private Messenger localMessenger;
private ServiceConnection connection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
remoteMessenger = new Messenger(service);
localMessenger = new Messenger(new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case 1:
Log.e(TAG, "Activity接收到了remoteService返回的消息");
break;
default:
super.handleMessage(msg);
break;
}
}
});
Message message = Message.obtain(null, 1);
message.replyTo = localMessenger;
try {
remoteMessenger.send(message);
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
Service中
private Messenger messenger = new Messenger(new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case 1:
Log.e(TAG, "remoteService接收到了Activity發(fā)送的消息");
Message message = Message.obtain(null, 1);
try {
msg.replyTo.send(message);
} catch (RemoteException e) {
e.printStackTrace();
}
break;
default:
super.handleMessage(msg);
break;
}
}
});
就實(shí)現(xiàn)了遠(yuǎn)程與本地的跨進(jìn)程雙端通信。
使用AIDL來(lái)發(fā)送跨進(jìn)程消息
首先創(chuàng)建一個(gè)RemoteServer的aidl文件缩麸,點(diǎn)擊錘子編譯一下铸磅。在debug中會(huì)生成對(duì)應(yīng)RemoteServer.java類(lèi),生成的文件中有對(duì)應(yīng)的Stub、Proxy和在aidl中寫(xiě)的request方法阅仔。
// RemoteServer.aidl
interface RemoteServer {
void request();
}
在Service中實(shí)現(xiàn)Binder方法
IBinder RemoteServer = new RemoteServer.Stub() {
@Override
public void request() throws RemoteException {
Log.e(TAG, "RemoteServer接收到了Activity發(fā)送的消息");
}
};
@Nullable
@Override
public IBinder onBind(Intent intent) {
Log.e(TAG, "onBind:");
return RemoteServer;
}
在Activity中使用與Messenger類(lèi)似吹散,通過(guò)IBinder創(chuàng)建代理對(duì)象進(jìn)行調(diào)用。
private ServiceConnection connection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
try {
RemoteServer.Stub.asInterface(service).request();
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
本文以Service的創(chuàng)建使用為主八酒,AIDL以及binder通信的底層原理還在學(xué)習(xí)中空民。。羞迷。