類型和區(qū)別
- 特點(diǎn):沒有UI,后臺(tái)運(yùn)行
- Started
- 啟動(dòng)方式startSevice()
- 一旦啟動(dòng),在后臺(tái)永遠(yuǎn)運(yùn)行,除非主動(dòng)停止或者被kill
- 通常不返回值(可發(fā)一個(gè)PendingIntent, 用廣播返回值)
- Bound
- 啟動(dòng)方式bindService()
- 只要有應(yīng)用綁定到它,就在運(yùn)行。當(dāng)沒有應(yīng)用綁定時(shí),service被摧毀。
- 多個(gè)應(yīng)用可以綁定到一個(gè)bind service.
- BroadcastReceiver不能綁定到服務(wù)
- 可以返回值,以及做進(jìn)程間通信(IPC)
- 一個(gè)service可以同時(shí)實(shí)現(xiàn)onStartCommand()和onBind()
-
注意:Service是在主線程上運(yùn)行,不要進(jìn)行耗時(shí)操作
image.png
創(chuàng)建一個(gè)新的service
-
重寫父類方法
- onStartCommand(). 被startService()調(diào)用,需要用stopSelf() or stopService()手動(dòng)停用
- onBind(),當(dāng)調(diào)用bindSerivce()的時(shí)候會(huì)調(diào)用,需要返回一個(gè)IBinder
- onCreate(). 一次性,如service已經(jīng)在運(yùn)行,則不再調(diào)用
- onDestroy(). 前臺(tái)服務(wù)>綁定到活動(dòng)的服務(wù)>后臺(tái)服務(wù)>長(zhǎng)時(shí)間運(yùn)行的后臺(tái)服務(wù). 服務(wù)會(huì)被kill,當(dāng)有資源時(shí),會(huì)嘗試恢復(fù)。對(duì)于started服務(wù),需要考慮當(dāng)系統(tǒng)自動(dòng)恢復(fù)時(shí)的處理。這根據(jù)onStartCommand()時(shí)的返回值有所不同:
- START_STICKY, 重新啟動(dòng)時(shí),傳入的intent是null
- START_STICKY_COMPATIBILITY, 不保證會(huì)重新調(diào)用onStartCommand()
- START_NOT_STICKY, 不自動(dòng)重啟
- START_REDELIVER_INTENT, 總是重新發(fā)送上次的intent
- 可以通過flag來判斷服務(wù)的性質(zhì)START_FLAG_REDELIVERY, START_FLAG_RETRY
-
修改Manifest
- android:enabled=["true" | "false"]
- android:exported=[“true” | “false”],如果為false,只有相同userID的能訪問。如果有intent filter,默認(rèn)為true,如果沒有,默認(rèn)為false
- android:icon="drawable resource“
- android:isolatedProcess=[“true” | “false”], 為true時(shí),將運(yùn)行在獨(dú)立進(jìn)程中
- android:label="string resource“
- android:name="string“
- android:permission=“string“,如果設(shè)置,只有擁有權(quán)限的才能訪問
- android:process=“string”
IntentService & Stop Service &前臺(tái)服務(wù)
- Intent Service
- Service的子類,推薦的實(shí)現(xiàn)Started Service的方法。會(huì)自動(dòng)為每個(gè)request創(chuàng)建worker thread.
- 自動(dòng)創(chuàng)建隊(duì)列進(jìn)行處理,不用擔(dān)心線程沖突
- 隊(duì)列處理完畢自動(dòng)stopSelf()
- 自動(dòng)為不可bind的(可以通過重寫來實(shí)現(xiàn)可bind)
- 只需要兩點(diǎn):
- 構(gòu)造函數(shù)中調(diào)用父類
- 實(shí)現(xiàn)onHandleIntent()方法
- 可以重寫其它方法,但要記得返回父類函數(shù)
- 停止Service
- 當(dāng)stop service時(shí),如果多個(gè)request同時(shí)在處理,stopSelf()可能會(huì)把新發(fā)起的request結(jié)束掉,所以推薦使用stopSelf(int),這樣會(huì)比較當(dāng)前正在處理的request是不是結(jié)束的目標(biāo)。
- 記得stopSelf(),這是消耗系統(tǒng)資源的。
- 前臺(tái)Service
- 提供必需的notification和id, 用startForeground(ONGOING_NOTIFICATION_ID, notification) 啟動(dòng),用stopForeground(boolean removeNotification)停止
- stopForeground并不停止服務(wù),而只是會(huì)讓前臺(tái)notification消失
Bounded Service
創(chuàng)建bounded service的三種方式
- 擴(kuò)展Binder類,如果只是自己的應(yīng)用內(nèi)使用,用這種方式。
- 使用Messenger,可實(shí)現(xiàn)IPC的最簡(jiǎn)單(?)的方法,線程安全,C/S端都用Handler來處理消息
- 使用AIDL,優(yōu)點(diǎn)是可以同時(shí)處理多個(gè)請(qǐng)求,對(duì)于大部分的app,Google并不推薦使用這種方式(但是在framework里面有很多)
onBind()只在第一次綁定時(shí)執(zhí)行一次,后續(xù)再綁定時(shí)返回第一次的Ibinder對(duì)象
當(dāng)調(diào)用服務(wù)的方法時(shí),要捕獲DeadObjectException異常,這個(gè)異常標(biāo)明service不存在了 - bindServices的flag
- BIND_AUTO_CREATE
- BIND_DEBUG_UNBIND,只用于調(diào)試。當(dāng)設(shè)置時(shí),以后的unbind請(qǐng)求的callstack會(huì)被保存
- BIND_IMPORTANT,允許客戶端把服務(wù)升級(jí)為“前臺(tái)”優(yōu)先級(jí),一般只能升級(jí)到“可見”優(yōu)先級(jí)
- BIND_NOT_FOREGROUND,不允許把被綁定的服務(wù)升級(jí)為“前臺(tái)”優(yōu)先級(jí)。
- BIND_ABOVE_CLIENT,道友比貧道更重要
- BIND_ADJUST_WITH_ACTIVITY,如從activity發(fā)起,那么允許優(yōu)先級(jí)隨其可見性來調(diào)整
- BIND_ALLOW_OOM_MANAGEMENT, 讓擁有該服務(wù)的進(jìn)程來自己管理優(yōu)先級(jí)
- BIND_WAIVE_PRIORITY,放棄調(diào)整優(yōu)先級(jí),讓系統(tǒng)像對(duì)待普通應(yīng)用一樣對(duì)待
擴(kuò)展Binder類方式
- Service端
- 實(shí)現(xiàn)一個(gè)Binder實(shí)例,其中包含可調(diào)用的方法或者其它包含可調(diào)用方法的類示例(包括當(dāng)前的service類)
- 在onBind()時(shí)返回該實(shí)例
- Client端
- 綁定時(shí)傳入connection參數(shù)(一個(gè)ServiceConnection的實(shí)例),綁定是異步的,并不返回Binder
- 在connection的onServiceConnected()方法中接收實(shí)例,并轉(zhuǎn)換類型為Binder類型,然后調(diào)用需要的方法
- 實(shí)現(xiàn)connection的onServiceDisconnected()方法,處理服務(wù)crash和被kill時(shí)的情況
- 示例代碼
//服務(wù)端:
public class LocalService extends Service {
// Binder given to clients
private final IBinder mBinder = new LocalBinder();//實(shí)例化
// Random number generator
private final Random mGenerator = new Random();
/**
* Class used for the client Binder. Because we know this service always
* runs in the same process as its clients, we don't need to deal with IPC.
*/
public class LocalBinder extends Binder {//實(shí)現(xiàn)Binder,其中有可返回當(dāng)前service的方法
LocalService getService() {
// Return this instance of LocalService so clients can call public methods
return LocalService.this;
}
}
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
/** method for clients */
public int getRandomNumber() {
return mGenerator.nextInt(100);
}
}
//客戶端:
public class BindingActivity extends Activity {
LocalService mService;
boolean mBound = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
@Override
protected void onStart() {
super.onStart();
// Bind to LocalService
Intent intent = new Intent(this, LocalService.class);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);//開啟Activity時(shí)綁定service,綁定后立即返回,connection作為參數(shù)傳入
//綁定完成后,將會(huì)調(diào)用connection的onServiceConnected方法,客戶端將在
//那里接收Binder,并轉(zhuǎn)型,然后得到要可調(diào)用方法的類,或者該Binder就包含可調(diào)方法
}
@Override
protected void onStop() {
super.onStop();
// Unbind from the service
if (mBound) {
unbindService(mConnection);
mBound = false;
}
}
/** Called when a button is clicked (the button in the layout file attaches to
* this method with the android:onClick attribute) */
public void onButtonClick(View v) {
if (mBound) {
// Call a method from the LocalService.
// However, if this call were something that might hang, then this request should
// occur in a separate thread to avoid slowing down the activity performance.
int num = mService.getRandomNumber();
Toast.makeText(this, "number: " + num, Toast.LENGTH_SHORT).show();
}
}
/** Defines callbacks for service binding, passed to bindService() */
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName className,
IBinder service) {
// We've bound to LocalService, cast the IBinder and get LocalService instance
LocalBinder binder = (LocalBinder) service;
mService = binder.getService();
mBound = true;
}
@Override
public void onServiceDisconnected(ComponentName arg0) {
mBound = false;
}
};
}
使用Messenger方式
- Service端
- 創(chuàng)建Handler來處理消息
- 用Handler創(chuàng)建一個(gè)Messenger
- 在onBind()中返回Messenger創(chuàng)建的IBinder
- Client端
- 用得到的IBinder去創(chuàng)建Messenger
- 用Messenger發(fā)消息指揮Service的Handler運(yùn)行
- (如需要回復(fù)),創(chuàng)建Client端的Messenger,在send()命令的replyTo參數(shù)中傳入這個(gè)Messenger
- Sample:
//服務(wù)端:
public class MessengerService extends Service {
/** Command to the service to display a message */
static final int MSG_SAY_HELLO = 1;
/**
* Handler of incoming messages from clients.
*/
class IncomingHandler extends Handler {//定義一個(gè)Handler
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_SAY_HELLO:
Toast.makeText(getApplicationContext(), "hello!", Toast.LENGTH_SHORT).show();
break;
default:
super.handleMessage(msg);
}
}
}
/**
* Target we publish for clients to send messages to IncomingHandler.
*/
final Messenger mMessenger = new Messenger(new IncomingHandler());//用Handler創(chuàng)建一個(gè)Messenger
/**
* When binding to the service, we return an interface to our messenger
* for sending messages to the service.
*/
@Override
public IBinder onBind(Intent intent) {
Toast.makeText(getApplicationContext(), "binding", Toast.LENGTH_SHORT).show();
return mMessenger.getBinder();//返回用Messenger創(chuàng)建的IBinder
}
}
//客戶端:
public class ActivityMessenger extends Activity {
/** Messenger for communicating with the service. */
Messenger mService = null;
/** Flag indicating whether we have called bind on the service. */
boolean mBound;
/**
* Class for interacting with the main interface of the service.
*/
private ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
// This is called when the connection with the service has been
// established, giving us the object we can use to
// interact with the service. We are communicating with the
// service using a Messenger, so here we get a client-side
// representation of that from the raw IBinder object.
mService = new Messenger(service);//用IBinder創(chuàng)建Messenger
mBound = true;
}
public void onServiceDisconnected(ComponentName className) {
// This is called when the connection with the service has been
// unexpectedly disconnected -- that is, its process crashed.
mService = null;
mBound = false;
}
};
public void sayHello(View v) {
if (!mBound) return;
// Create and send a message to the service, using a supported 'what' value
Message msg = Message.obtain(null, MessengerService.MSG_SAY_HELLO, 0, 0);
try {
mService.send(msg);
} catch (RemoteException e) {//記得Catch Exception
e.printStackTrace();
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
@Override
protected void onStart() {
super.onStart();
// Bind to the service
bindService(new Intent(this, MessengerService.class), mConnection,
Context.BIND_AUTO_CREATE); //實(shí)際應(yīng)用中,這里應(yīng)該是隱式intent
}
@Override
protected void onStop() {
super.onStop();
// Unbind from the service
if (mBound) {
unbindService(mConnection);
mBound = false;
}
}
}
AIDL方式
-
服務(wù)端
- 創(chuàng)建AIDL
- 創(chuàng)建接口定義和方法簽名
- 可識(shí)別的數(shù)據(jù)類型包括基本類型(int,long,boolean),String,CharSequence,List(支持泛型,對(duì)端接收到的總是一個(gè)arrayList),Map接口(不支持泛型,對(duì)端接收到的總是一個(gè)HashMap),List和Map必須加in/out/inout參數(shù)(in:參數(shù)會(huì)傳輸?shù)椒?wù)端,out:參數(shù)只是用來獲取輸出值,沒有傳輸,inout:兩者結(jié)合)
- 只能有方法,不能有靜態(tài)域
- 實(shí)現(xiàn)接口,SDK自動(dòng)生成名為Stub的抽象函數(shù)(派生于Binder),我們需要派生這個(gè)Stub類并實(shí)現(xiàn)它的抽象方法
- 調(diào)用通常是以同步方式執(zhí)行,所以注意不要在調(diào)用方的主線程調(diào)用,可能引起調(diào)用方的ANR
- 在服務(wù)端發(fā)出的exception并不會(huì)被返回到調(diào)用方。
實(shí)現(xiàn)服務(wù),在onBind()中將stub的實(shí)例返回去
- 創(chuàng)建AIDL
-
客戶端
- 也要導(dǎo)入AIDL
- 調(diào)用bind之后,在onServiceConnected()中用IRemoteService.Stub.asInterface(service)將Binder轉(zhuǎn)換為接口,就可以直接使用了
本地調(diào)用發(fā)生在與調(diào)用方相同的線程,遠(yuǎn)程調(diào)用發(fā)生在一個(gè)系統(tǒng)維護(hù)的線程池中(這里,跟Service在主線程上運(yùn)行是有出入的)
example:
AIDL:
package com.example.testservice;
interface ITestAidl {
List<String> testListGeneric();
List testListNoGeneric();//支持泛型List
//List testListWithGeneric1(in List param); //不支持非泛型參數(shù)
List testListWithGeneric(in List<String> param);
//Map<String,String> testMap1(); //不支持泛型Map
//Map testMap(out Map param);//Map做參數(shù),gen里面會(huì)報(bào)錯(cuò),原因應(yīng)該是因?yàn)椴恢С址欠盒蛥?shù)
Map testMap(String Param);
List testIn(in List<String> param);//in:參數(shù)會(huì)被輸送到服務(wù)端
//@Override public java.util.List testIn(java.util.List<java.lang.String> param) throws android.os.RemoteException
//{
//android.os.Parcel _data = android.os.Parcel.obtain();
//android.os.Parcel _reply = android.os.Parcel.obtain();
//java.util.List _result;
//try {
//_data.writeInterfaceToken(DESCRIPTOR);
//_data.writeStringList(param);
//mRemote.transact(Stub.TRANSACTION_testIn, _data, _reply, 0);
//_reply.readException();
//java.lang.ClassLoader cl = (java.lang.ClassLoader)this.getClass().getClassLoader();
//_result = _reply.readArrayList(cl);
//}
//finally {
//_reply.recycle();
//_data.recycle();
//}
//return _result;
//}
List testOut(out List<String> param);//out:參數(shù)只是用來獲取輸出值
//{
//android.os.Parcel _data = android.os.Parcel.obtain();
//android.os.Parcel _reply = android.os.Parcel.obtain();
//java.util.List _result;
//try {
//_data.writeInterfaceToken(DESCRIPTOR);
//mRemote.transact(Stub.TRANSACTION_testOut, _data, _reply, 0);
//_reply.readException();
//java.lang.ClassLoader cl = (java.lang.ClassLoader)this.getClass().getClassLoader();
//_result = _reply.readArrayList(cl);
//_reply.readStringList(param);
//}
//finally {
//_reply.recycle();
//_data.recycle();
//}
//return _result;
//}
List testInOut(inout List<String> param);//參數(shù)會(huì)被傳輸,處理后成為輸出值
//{
//android.os.Parcel _data = android.os.Parcel.obtain();
//android.os.Parcel _reply = android.os.Parcel.obtain();
//java.util.List _result;
//try {
//_data.writeInterfaceToken(DESCRIPTOR);
//_data.writeStringList(param);
//mRemote.transact(Stub.TRANSACTION_testInOut, _data, _reply, 0);
//_reply.readException();
//java.lang.ClassLoader cl = (java.lang.ClassLoader)this.getClass().getClassLoader();
//_result = _reply.readArrayList(cl);
//_reply.readStringList(param);
//}
//finally {
//_reply.recycle();
//_data.recycle();
//}
//return _result;
//}
}
Service:
package com.example.testservice;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
public class SampleService extends Service {
@Override
public IBinder onBind(Intent arg0) {
return mBinder;
}
private ITestAidl.Stub mBinder = new ITestAidl.Stub() {
@Override
public List testOut(List<String> param) throws RemoteException {
for (String s : param) {
Log.i("TestAIDL", "Before manipulate,param is:" + s);
}
param.add("5");
param.add("6");
param.add("7");
return param;
}
@Override
public Map testMap(String Param) throws RemoteException {
Map<Integer, String> myMap = new Hashtable<Integer, String>();
myMap.put(1, Param);
myMap.put(2, Param + " " + Param);
return myMap;
}
@Override
public List testListWithGeneric(List<String> param)
throws RemoteException {
for (String s : param) {
Log.d("TestAIDL", "Received:" + s);
}
return param;
}
@Override
public List testListNoGeneric() throws RemoteException {
List<String> myList = new ArrayList<String>();
myList.add("A");
myList.add("B");
return myList;
}
@Override
public List<String> testListGeneric() throws RemoteException {
List<String> myList = new ArrayList<String>();
myList.add("A");
myList.add("B");
return myList;
}
@Override
public List testInOut(List<String> param) throws RemoteException {
for (String s : param) {
Log.i("TestAIDL", "Before manipulate,param is:" + s);
}
param.add("5");
param.add("6");
param.add("7");
return param;
}
@Override
public List testIn(List<String> param) throws RemoteException {
for (String s : param) {
Log.i("TestAIDL", "Before manipulate,param is:" + s);
}
param.add("5");
param.add("6");
param.add("7");
return param;
}
};
}
Client:
package com.example.testserviceclient;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import android.view.View;
import com.example.testservice.ITestAidl;
import com.example.zzp.IMyinterface;
public class TestServiceClient extends Activity {
public static final String ActionName = "com.zzp.test.TESTSERVICE";
public static final String ActionNameUseJar = "com.zzp.test.USEJAR";
private ITestAidl myService;
private IMyinterface myJarService;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_ttest_service);
}
@Override
protected void onStart() {
bindService(new Intent(ActionName), myConnection,
Context.BIND_AUTO_CREATE);
bindService(new Intent(ActionNameUseJar), myJarConnection,
Context.BIND_AUTO_CREATE);
super.onStart();
}
@Override
protected void onStop() {
unbindService(myConnection);
unbindService(myJarConnection);
super.onStop();
}
private ServiceConnection myConnection = new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName arg0) {
return;
}
@Override
public void onServiceConnected(ComponentName arg0, IBinder arg1) {
myService = ITestAidl.Stub.asInterface(arg1);
}
};
private ServiceConnection myJarConnection = new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName arg0) {
return;
}
@Override
public void onServiceConnected(ComponentName arg0, IBinder arg1) {
myJarService = (IMyinterface) arg1;
}
};
public void onTestLG(View view) {
try {
List<String> myList = myService.testListGeneric();
for (String s : myList) {
Log.d("TestAIDL-Client", "Test List Generic:" + s);
// D/TestAIDL-Client(20810): Test List Generic:A
// D/TestAIDL-Client(20810): Test List Generic:B
}
} catch (RemoteException e) {
Log.e("TestAIDL-Client", e.getMessage());
e.printStackTrace();
}
}
public void onTestLNG(View view) {
try {
// List<String> myList = myService.testListNoGeneric();
List myList = myService.testListNoGeneric();
for (Object s : myList) {
Log.d("TestAIDL-Client",
"Test List Non Generic:" + s.toString());
// D/TestAIDL-Client(25015): Test List Non Generic:A
// D/TestAIDL-Client(25015): Test List Non Generic:B
}
} catch (RemoteException e) {
Log.e("TestAIDL-Client", e.getMessage());
e.printStackTrace();
}
}
public void TestLwG(View view) {
try {
// List<String> myList = myService.testListNoGeneric();
ArrayList<String> param = new ArrayList<String>();
param.add("Client-A");
param.add("Client-B");
List myList = myService.testListWithGeneric(param);
for (Object s : myList) {
Log.d("TestAIDL-Client",
"Test List With Generic:" + s.toString());
// D/TestAIDL(27513): Received:Client-A
// D/TestAIDL(27513): Received:Client-B
// D/TestAIDL-Client(27500): Test List With Generic:Client-A
// D/TestAIDL-Client(27500): Test List With Generic:Client-B
}
} catch (RemoteException e) {
Log.e("TestAIDL-Client", e.getMessage());
e.printStackTrace();
}
}
public void TestM(View view) {
try {
Map<Integer, String> myMap = myService.testMap("ABC");
for (Entry<Integer, String> s : myMap.entrySet()) {
Log.d("TestAIDL-Client",
"Test Map:" + s.getKey() + "_" + s.getValue());
// D/TestAIDL-Client(29739): Test Map:1_ABC
// D/TestAIDL-Client(29739): Test Map:2_ABC ABC
}
} catch (RemoteException e) {
Log.e("TestAIDL-Client", e.getMessage());
e.printStackTrace();
}
}
public void TestIn(View view) {
try {
// List<String> myList = myService.testListNoGeneric();
ArrayList<String> param = new ArrayList<String>();
param.add("Client-A");
param.add("Client-B");
for (String s : param) {
Log.d("TestAIDL-Client", "Test In, param:" + s.toString());
}
List myList = myService.testIn(param);
for (String s : param) {
Log.d("TestAIDL-Client", "Test In, param:" + s.toString());
}
for (Object s : myList) {
Log.d("TestAIDL-Client",
"Test In, return value:" + s.toString());
}
// D/TestAIDL-Client(31223): Test In, param:Client-A
// D/TestAIDL-Client(31223): Test In, param:Client-B
// I/TestAIDL(29511): Before manipulate,param is:Client-A
// I/TestAIDL(29511): Before manipulate,param is:Client-B
// D/TestAIDL-Client(31223): Test In, param:Client-A
// D/TestAIDL-Client(31223): Test In, param:Client-B
// D/TestAIDL-Client(31223): Test In, return value:Client-A
// D/TestAIDL-Client(31223): Test In, return value:Client-B
// D/TestAIDL-Client(31223): Test In, return value:5
// D/TestAIDL-Client(31223): Test In, return value:6
// D/TestAIDL-Client(31223): Test In, return value:7
} catch (RemoteException e) {
Log.e("TestAIDL-Client", e.getMessage());
e.printStackTrace();
}
}
public void TestOut(View view) {
try {
// List<String> myList = myService.testListNoGeneric();
ArrayList<String> param = new ArrayList<String>();
param.add("Client-A");
param.add("Client-B");
for (String s : param) {
Log.d("TestAIDL-Client", "Test Out, param:" + s.toString());
}
List myList = myService.testOut(param);
for (String s : param) {
Log.d("TestAIDL-Client", "Test Out, param:" + s.toString());
}
for (Object s : myList) {
Log.d("TestAIDL-Client",
"Test Out, return value:" + s.toString());
}
// D/TestAIDL-Client( 2359): Test Out, param:Client-A
// D/TestAIDL-Client( 2359): Test Out, param:Client-B
// 這里,服務(wù)端并沒有收到param
// D/TestAIDL-Client( 2359): Test Out, param:5
// D/TestAIDL-Client( 2359): Test Out, param:6
// D/TestAIDL-Client( 2359): Test Out, param:7
// D/TestAIDL-Client( 2359): Test Out, return value:5
// D/TestAIDL-Client( 2359): Test Out, return value:6
// D/TestAIDL-Client( 2359): Test Out, return value:7
} catch (RemoteException e) {
Log.e("TestAIDL-Client", e.getMessage());
e.printStackTrace();
}
}
public void TestInOut(View view) {
try {
// List<String> myList = myService.testListNoGeneric();
ArrayList<String> param = new ArrayList<String>();
param.add("Client-A");
param.add("Client-B");
for (String s : param) {
Log.d("TestAIDL-Client", "Test InOut, param:" + s.toString());
}
List myList = myService.testInOut(param);
for (String s : param) {
Log.d("TestAIDL-Client", "Test InOut, param:" + s.toString());
}
for (Object s : myList) {
Log.d("TestAIDL-Client",
"Test InOut, return value:" + s.toString());
}
// D/TestAIDL-Client( 2359): Test InOut, param:Client-A
// D/TestAIDL-Client( 2359): Test InOut, param:Client-B
// I/TestAIDL(29511): Before manipulate,param is:Client-A
// I/TestAIDL(29511): Before manipulate,param is:Client-B
// D/TestAIDL-Client( 2359): Test InOut, param:Client-A
// D/TestAIDL-Client( 2359): Test InOut, param:Client-B
// D/TestAIDL-Client( 2359): Test InOut, param:5
// D/TestAIDL-Client( 2359): Test InOut, param:6
// D/TestAIDL-Client( 2359): Test InOut, param:7
// D/TestAIDL-Client( 2359): Test InOut, return value:Client-A
// D/TestAIDL-Client( 2359): Test InOut, return value:Client-B
// D/TestAIDL-Client( 2359): Test InOut, return value:5
// D/TestAIDL-Client( 2359): Test InOut, return value:6
// D/TestAIDL-Client( 2359): Test InOut, return value:7
} catch (RemoteException e) {
Log.e("TestAIDL-Client", e.getMessage());
e.printStackTrace();
}
}
// public void TestUseJar(View view) {
// Log.d("TestAIDL-Client", "Use Jar:" + myJarService.test());
// Log.d("TestAIDL-Client", "Static value:" + myJarService.DEFINE);
// Hashtable<Integer, String> param = new Hashtable<Integer, String>();
// param.put(5, "壹");
// param.put(6, "貳");
//
// Hashtable<Integer, String> myTable = myJarService.testGenericMap(param);
// for (Entry<Integer, String> s : myTable.entrySet()) {
// Log.d("TestAIDL-Client",
// "Use Jar Map:" + s.getKey() + "_" + s.getValue());
// }
//
// }
}
附:進(jìn)程優(yōu)先級(jí)
當(dāng)系統(tǒng)決定殺掉一個(gè)進(jìn)程的時(shí)候,會(huì)按照進(jìn)程優(yōu)先級(jí)的從低到高來決定先殺哪個(gè)。
- 前臺(tái)
- 擁有Activity并用戶正在交互(onResume)
- 擁有服務(wù)且服務(wù)與一個(gè)前臺(tái)頁面綁定
- 擁有服務(wù),且通過startForeground()調(diào)用
- 正在執(zhí)行服務(wù)的生命周期(onCreate等)
- 廣播正在執(zhí)行onReceive
- 可見
- 頁面已暫停
- 服務(wù)綁定到前臺(tái)或可見頁面
- 服務(wù)進(jìn)程
- 含有用Start方式啟動(dòng)的服務(wù)
- 后臺(tái)進(jìn)程
- 頁面已不再可見(onStop被調(diào)用)
- LRU (least recently used) list, 最早停止的最早kill
- 空進(jìn)程
- 不含有效組件,只為緩存
轉(zhuǎn)載請(qǐng)注明出處。

image
更多視頻教程請(qǐng)?jiān)?a target="_blank">網(wǎng)易云課堂搜索黑山老雕。
