詳解Android 進(jìn)程間通信的幾種實(shí)現(xiàn)方式
一、概述
由于應(yīng)用程序之間不能共享內(nèi)存。在不同應(yīng)用程序之間交互數(shù)據(jù)(跨進(jìn)程通訊),在Android SDK中提供了4種用于跨進(jìn)程通訊的方式。
這4種方式正好對(duì)應(yīng)于android系統(tǒng)中4種應(yīng)用程序組件:Activity、Content Provider、Broadcast和Service。其中Activity可以跨進(jìn)程調(diào)用其他應(yīng)用程序的Activity;Content Provider可以跨進(jìn)程訪問其他應(yīng)用程序中的數(shù)據(jù)(以Cursor對(duì)象形式返回),當(dāng)然,也可以對(duì)其他應(yīng)用程序的數(shù)據(jù)進(jìn)行增、刪、改操 作;Broadcast可以向android系統(tǒng)中所有應(yīng)用程序發(fā)送廣播,而需要跨進(jìn)程通訊的應(yīng)用程序可以監(jiān)聽這些廣播;Service和Content Provider類似,也可以訪問其他應(yīng)用程序中的數(shù)據(jù),但不同的是,Content Provider返回的是Cursor對(duì)象,而Service返回的是Java對(duì)象,這種可以跨進(jìn)程通訊的服務(wù)叫AIDL服務(wù)。
Activity
Activity的跨進(jìn)程訪問與進(jìn)程內(nèi)訪問略有不同。雖然它們都需要Intent對(duì)象,但跨進(jìn)程訪問并不需要指定Context對(duì)象和Activity的 Class對(duì)象,而需要指定的是要訪問的Activity所對(duì)應(yīng)的Action(一個(gè)字符串)。有些Activity還需要指定一個(gè)Uri(通過 Intent構(gòu)造方法的第2個(gè)參數(shù)指定)。
在android系統(tǒng)中有很多應(yīng)用程序提供了可以跨進(jìn)程訪問的Activity,例如,下面的代碼可以直接調(diào)用撥打電話的Activity。
Intent callIntent = new Intent(Intent.ACTION_CALL, Uri.parse("tel:12345678" );
startActivity(callIntent);
Content Provider
Android應(yīng)用程序可以使用文件或SqlLite數(shù)據(jù)庫來存儲(chǔ)數(shù)據(jù)。Content Provider提供了一種在多個(gè)應(yīng)用程序之間數(shù)據(jù)共享的方式(跨進(jìn)程共享數(shù)據(jù))。應(yīng)用程序可以利用Content Provider完成下面的工作
1. 查詢數(shù)據(jù)
2. 修改數(shù)據(jù)
3. 添加數(shù)據(jù)
4. 刪除數(shù)據(jù)
雖然Content Provider也可以在同一個(gè)應(yīng)用程序中被訪問,但這么做并沒有什么意義。Content Provider存在的目的向其他應(yīng)用程序共享數(shù)據(jù)和允許其他應(yīng)用程序?qū)?shù)據(jù)進(jìn)行增、刪、改操作。
Android系統(tǒng)本身提供了很多Content Provider,例如,音頻、視頻、聯(lián)系人信息等等。我們可以通過這些Content Provider獲得相關(guān)信息的列表。這些列表數(shù)據(jù)將以Cursor對(duì)象返回。因此,從Content Provider返回的數(shù)據(jù)是二維表的形式。
廣播(Broadcast)
廣播是一種被動(dòng)跨進(jìn)程通訊的方式。當(dāng)某個(gè)程序向系統(tǒng)發(fā)送廣播時(shí),其他的應(yīng)用程序只能被動(dòng)地接收廣播數(shù)據(jù)。這就象電臺(tái)進(jìn)行廣播一樣,聽眾只能被動(dòng)地收聽,而不能主動(dòng)與電臺(tái)進(jìn)行溝通。
在應(yīng)用程序中發(fā)送廣播比較簡(jiǎn)單。只需要調(diào)用sendBroadcast方法即可。該方法需要一個(gè)Intent對(duì)象。通過Intent對(duì)象可以發(fā)送需要廣播的數(shù)據(jù)。
Service
1.利用AIDL Service實(shí)現(xiàn)跨進(jìn)程通信
這是我個(gè)人比較推崇的方式,因?yàn)樗啾菳roadcast而言,雖然實(shí)現(xiàn)上稍微麻煩了一點(diǎn),但是它的優(yōu)勢(shì)就是不會(huì)像廣播那樣在手機(jī)中的廣播較多時(shí)會(huì)有明顯的時(shí)延,甚至有廣播發(fā)送不成功的情況出現(xiàn)。
注意普通的Service并不能實(shí)現(xiàn)跨進(jìn)程操作,實(shí)際上普通的Service和它所在的應(yīng)用處于同一個(gè)進(jìn)程中,而且它也不會(huì)專門開一條新的線程,因此如果在普通的Service中實(shí)現(xiàn)在耗時(shí)的任務(wù),需要新開線程。
要實(shí)現(xiàn)跨進(jìn)程通信,需要借助AIDL(Android Interface Definition Language)。Android中的跨進(jìn)程服務(wù)其實(shí)是采用C/S的架構(gòu),因而AIDL的目的就是實(shí)現(xiàn)通信接口。
首先舉一個(gè)簡(jiǎn)單的栗子。
服務(wù)端代碼如下:
首先是aidl的代碼:
package com.android.service;
interface IData
{
int getRoomNum();
}
RoomService的代碼如下:
package com.android.service;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
public class RoomService extends Service{
private IData.Stub mBinder=new IData.Stub() {
@Override
public int getRoomNum() throws RemoteException {
return 3008;
}
};
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
}
AndroidManifest如下:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.aidlsampleservice"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="17" />
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme"
<service android:name="com.android.service.RoomService">
<intent-filter>
<action android:name="com.aidl.service.room"/>
</intent-filter>
</service>
</application>
</manifest>
然后運(yùn)行該Service所在的Project即可。
客戶端代碼如下:
注意客戶端也要有aidl文件,所以最簡(jiǎn)單的辦法就是將Service端中aidl所在的包直接復(fù)制過去。另外要注意的是在onDestroy中要解除和Service的綁定。
MainActivity.java的代碼如下:
package com.example.aidlsampleclient;
import com.android.service.IData;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.util.Log;
import android.view.Menu;
import android.widget.Button;
import android.widget.Toast;
import android.view.View;
public class MainActivity extends Activity implements View.OnClickListener{
private static final String TAG="MainActivity";
private static final String ROOM_SERVICE_ACTION="com.aidl.service.room";
private Button bindServiceButton;
private Button getServiceButton;
IData mData;
private ServiceConnection conn=new ServiceConnection()
{
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.i(TAG,"----------------onServiceConnected--------");
mData=IData.Stub.asInterface(service);
}
@Override
public void onServiceDisconnected(ComponentName name) {
Log.i(TAG,"----------------onServiceDisconnected-------------");
mData=null;
}
};
private void initView()
{
bindServiceButton=(Button)findViewById(R.id.bindServiceButton);
getServiceButton=(Button)findViewById(R.id.getServiceButton);
bindServiceButton.setOnClickListener(this);
getServiceButton.setOnClickListener(this);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
}
@Override
public void onClick(View v) {
switch(v.getId())
{
case R.id.bindServiceButton:
bindService();
break;
case R.id.getServiceButton:
getService();
break;
default:
break;
}
}
private void bindService()
{
Intent intent=new Intent();
intent.setAction(ROOM_SERVICE_ACTION);
bindService(intent,conn,BIND_AUTO_CREATE);
}
private void getService()
{
try
{
if(mData!=null)
{
int roomNum=mData.getRoomNum();
showLongToast("RoomNum:"+roomNum);
}
}
catch(RemoteException ex)
{
ex.printStackTrace();
}
}
private void showLongToast(String info)
{
Toast.makeText(getBaseContext(), info, Toast.LENGTH_LONG).show();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
@Override
protected void onDestroy() {
super.onDestroy();
unbindService(conn);
}
}
activity_main.xml的代碼如下:
<RelativeLayout 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:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".MainActivity" >
<Button
android:id="@+id/bindServiceButton"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="BindService"
/>
<Button
android:id="@+id/getServiceButton"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="GetService"
android:layout_below="@id/bindServiceButton"
/>
</RelativeLayout>
運(yùn)行結(jié)果如下:

然后舉一個(gè)稍微復(fù)雜一點(diǎn)的栗子,注意如果*.aidl文件中含有自定義的對(duì)象,那么該對(duì)象的類要實(shí)現(xiàn)Parcelable接口,并且要新建一個(gè)該類的aidl文件,否則會(huì)出現(xiàn)could not find import for class com.android.service.XX的錯(cuò)誤,其中XX為類名。還是上面的栗子,但是aidl文件中添加了一些新的方法。仍以上面的RoomService為例,
Service端的代碼如下:
Room類的代碼為:
package com.android.service;
import android.os.Parcel;
import android.os.Parcelable;
public class Room implements Parcelable{
//房間號(hào)
private int roomNum;
//房間大小
private float roomSpace;
//是否有空調(diào)
private boolean hasAirConditioner;
//是否有Wifi
private boolean hasWifi;
//房間內(nèi)的裝飾風(fēng)格
private String decorativeStyle;
public static final Parcelable.Creator<Room>CREATOR=new Parcelable.Creator<Room>() {
@Override
public Room createFromParcel(Parcel source) {
return new Room(source);
}
@Override
public Room[] newArray(int size) {
return null;
}
};
public Room(int roomNum,float roomSpace,boolean hasAirConditioner,boolean hasWifi,String decorativeStyle)
{
this.roomNum=roomNum;
this.roomSpace=roomSpace;
this.hasAirConditioner=hasAirConditioner;
this.hasWifi=hasWifi;
this.decorativeStyle=decorativeStyle;
}
private Room(Parcel source)
{
roomNum=source.readInt();
roomSpace=source.readFloat();
boolean[]tempArray=new boolean[2];
source.readBooleanArray(tempArray);
hasAirConditioner=tempArray[0];
hasWifi=tempArray[1];
decorativeStyle=source.readString();
}
@Override
public String toString()
{
StringBuilder sb=new StringBuilder();
sb.append("Basic info of room is as follows:\n");
sb.append("RoomNum:"+roomNum+"\n");
sb.append("RoomSpace:"+roomSpace+"\n");
sb.append("HasAirConditioner:"+hasAirConditioner+"\n");
sb.append("HasWifi:"+hasWifi+"\n");
sb.append("Decorative Style:"+decorativeStyle);
return sb.toString();
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest,int flags) {
dest.writeInt(roomNum);
dest.writeFloat(roomSpace);
dest.writeBooleanArray(new boolean[]{hasAirConditioner,hasWifi});
dest.writeString(decorativeStyle);
}
}
Room的聲明為:
package com.android.service; parcelable Room;
IRoom.aidl的代碼為:
package com.android.service;
import com.android.service.Room;
interface IRoom
{
Room getRoom();
}
RoomService的代碼為:
package com.android.service;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
public class RoomService extends Service{
private IRoom.Stub mBinder=new IRoom.Stub() {
@Override
public Room getRoom() throws RemoteException {
Room room=new Room(3008,23.5f,true,true,"IKEA");
return room;
}
};
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
}
由于AndroidManifest.xml的代碼不變,因而此處不再貼出。下面是客戶端的代碼:
package com.example.aidlsampleclient;
import com.android.service.IRoom;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.util.Log;
import android.view.Menu;
import android.widget.Button;
import android.widget.Toast;
import android.view.View;
public class MainActivity extends Activity implements View.OnClickListener{
private static final String TAG="MainActivity";
//private static final String SERVICE_ACTION="com.aidl.service.data";
private static final String ROOM_SERVICE_ACTION="com.aidl.service.room";
private Button bindServiceButton;
private Button getServiceButton;
IRoom mRoom;
private ServiceConnection conn=new ServiceConnection()
{
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.i(TAG,"----------------onServiceConnected--------");
showLongToast("onServiceConnected");
mRoom=IRoom.Stub.asInterface(service);
}
@Override
public void onServiceDisconnected(ComponentName name) {
Log.i(TAG,"----------------onServiceDisconnected-------------");
mRoom=null;
}
};
private void initView()
{
bindServiceButton=(Button)findViewById(R.id.bindServiceButton);
getServiceButton=(Button)findViewById(R.id.getServiceButton);
bindServiceButton.setOnClickListener(this);
getServiceButton.setOnClickListener(this);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
}
@Override
public void onClick(View v) {
switch(v.getId())
{
case R.id.bindServiceButton:
bindService();
break;
case R.id.getServiceButton:
getService();
break;
default:
break;
}
}
private void bindService()
{
Intent intent=new Intent();
intent.setAction(ROOM_SERVICE_ACTION);
bindService(intent,conn,BIND_AUTO_CREATE);
}
private void getService()
{
if(mRoom!=null)
{
try
{
showLongToast(mRoom.getRoom().toString());
}
catch (RemoteException e)
{
e.printStackTrace();
}
}
}
private void showLongToast(String info)
{
Toast.makeText(getBaseContext(), info, Toast.LENGTH_LONG).show();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
resent.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
@Override
protected void onDestroy() {
super.onDestroy();
unbindService(conn);
}
}
注意首先仍然是要將Room,IRoom的代碼復(fù)制過去,否則會(huì)出錯(cuò)。
運(yùn)行結(jié)果如下:

顯然,客戶端已經(jīng)成功讀取到服務(wù)信息。
注意,上面的所舉的栗子其實(shí)不只是跨進(jìn)程,還是跨應(yīng)用。要注意的是,跨應(yīng)用一定跨進(jìn)程,但是跨進(jìn)程不一定是跨應(yīng)用。對(duì)于跨應(yīng)用的情況,利用AIDL基本上是較好的解決了問題,但也只是“較好”而已,實(shí)際上并不完美,比如,如果要增加一個(gè)服務(wù),如果利用AIDL的話,那么又要改寫aidl文件,如果是涉及自定義對(duì)象,則還要增加自定義對(duì)象的聲明,而且這種改變不只是Service端的改變,客戶端也要跟著改變,顯然這種解決方案不夠優(yōu)雅。
那么,有沒有更優(yōu)雅的方法呢?
當(dāng)然有,那就是利用Service的onStartCommand(Intent intent, int flags, int startId)方法。
服務(wù)端代碼如下:
package com.android.service;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import android.widget.Toast;
public class RoomService extends Service{
private static final String TAG="RoomService";
private static final int CLEAN_SERVICE=0x1;
private static final int ORDER_SERVICE=0x2;
private static final int PACKAGE_SERVICE=0x3;
private static final String SERVICE_KEY="ServiceName";
@Override
public void onStart(Intent intent, int startId) {
showLog("onStart");
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
//String action=intent.getAction();
Log.i(TAG,"onStartCommand");
int actionFlag=intent.getIntExtra(SERVICE_KEY, -1);
switch(actionFlag)
{
case CLEAN_SERVICE:
showShortToast("Start Clean Service Right Now");
break;
case ORDER_SERVICE:
showShortToast("Start Order Service Right Now");
break;
case PACKAGE_SERVICE:
showShortToast("Start Package Service Right Now");
break;
default:
break;
}
return super.onStartCommand(intent, flags, startId);
}
private void showLog(String info)
{
Log.i(TAG,info);
}
private void showShortToast(String info)
{
Toast.makeText(getBaseContext(), info, Toast.LENGTH_SHORT).show();
}
@Override
public void onDestroy() {
showLog("onDestroy");
super.onDestroy();
}
@Override
public void onCreate() {
showLog("onCreate");
super.onCreate();
}
@Override
public IBinder onBind(Intent intent) {
showLog("onBind");
return null;
}
@Override
public boolean onUnbind(Intent intent) {
showLog("onUnbind");
return super.onUnbind(intent);
}
}
客戶端代碼如下:
package com.example.aidlsampleclient;
import com.android.service.IRoom;
import com.android.service.RoomService;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.util.Log;
import android.view.Menu;
import android.widget.Button;
import android.widget.Toast;
import android.view.View;
public class MainActivity extends Activity implements View.OnClickListener{
private static final String TAG="MainActivity";
private static final String ROOM_SERVICE_ACTION="com.aidl.service.room";
private static final int CLEAN_SERVICE=0x1;
private static final int ORDER_SERVICE=0x2;
private static final int PACKAGE_SERVICE=0x3;
private static final String SERVICE_KEY="ServiceName";
private Button cleanButton;
private Button orderButton;
private Button packageButton;
private void initView()
{
cleanButton=(Button)findViewById(R.id.cleanButton);
orderButton=(Button)findViewById(R.id.orderButton);
packageButton=(Button)findViewById(R.id.packageButton);
cleanButton.setOnClickListener(this);
orderButton.setOnClickListener(this);
packageButton.setOnClickListener(this);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
}
@Override
public void onClick(View v) {
switch(v.getId())
{
case R.id.cleanButton:
cleanAction();
break;
case R.id.orderButton:
orderAction();
break;
case R.id.packageButton:
packageAction();
break;
default:
break;
}
}
private void cleanAction()
{
startAction(ROOM_SERVICE_ACTION,CLEAN_SERVICE);
}
private void orderAction()
{
startAction(ROOM_SERVICE_ACTION,ORDER_SERVICE);
}
private void packageAction()
{
startAction(ROOM_SERVICE_ACTION,PACKAGE_SERVICE);
}
private void startAction(String actionName,int serviceFlag)
{
//Intent intent=new Intent(this,RoomService.class);
Intent intent=new Intent();
intent.setAction(actionName);
intent.putExtra(SERVICE_KEY, serviceFlag);
this.startService(intent);
}
private void showLongToast(String info)
{
Toast.makeText(getBaseContext(), info, Toast.LENGTH_LONG).show();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
resent.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
@Override
protected void onDestroy() {
super.onDestroy();
}
}
運(yùn)行結(jié)果如下:

顯然,此時(shí)客戶端順利獲取了服務(wù)。
上面舉的是跨應(yīng)用的例子,如果是在同一個(gè)應(yīng)用的不同進(jìn)程的話,則有更簡(jiǎn)單的實(shí)現(xiàn)方法。
RoomService的代碼如下:
package com.android.service;
import com.android.actions.Actions;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import android.widget.Toast;
public class RoomService extends Service{
private static final String TAG="RoomService";
@Override
public void onStart(Intent intent, int startId) {
showLog("onStart");
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
//String action=intent.getAction();
Log.i(TAG,"onStartCommand");
String action=intent.getAction();
if(Actions.CLEAN_ACTION.equals(action))
{
showShortToast("Start Clean Service Right Now");
}
else if(Actions.ORDER_ACTION.equals(action))
{
showShortToast("Start Order Service Right Now");
}
else if(Actions.PACKAGE_ACTION.equals(action))
{
showShortToast("Start Package Service Right Now");
}
else
{
showShortToast("Wrong action");
}
return super.onStartCommand(intent, flags, startId);
}
private void showLog(String info)
{
Log.i(TAG,info);
}
private void showShortToast(String info)
{
Toast.makeText(getBaseContext(), info, Toast.LENGTH_SHORT).show();
}
@Override
public void onDestroy() {
showLog("onDestroy");
super.onDestroy();
}
@Override
public void onCreate() {
showLog("onCreate");
super.onCreate();
}
@Override
public IBinder onBind(Intent intent) {
showLog("onBind");
return null;
}
@Override
public boolean onUnbind(Intent intent) {
showLog("onUnbind");
return super.onUnbind(intent);
}
}
MainActivity的代碼如下:
package com.android.activity;
import com.android.activity.R;
import com.android.service.RoomService;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.Menu;
import android.widget.Button;
import android.widget.Toast;
import android.view.View;
import com.android.actions.Actions;
public class MainActivity extends Activity implements View.OnClickListener{
private static final String TAG="MainActivity";
private static final String SERVICE_KEY="ServiceName";
private Button cleanButton;
private Button orderButton;
private Button packageButton;
private void initView()
{
cleanButton=(Button)findViewById(R.id.cleanButton);
orderButton=(Button)findViewById(R.id.orderButton);
packageButton=(Button)findViewById(R.id.packageButton);
cleanButton.setOnClickListener(this);
orderButton.setOnClickListener(this);
packageButton.setOnClickListener(this);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
}
@Override
public void onClick(View v) {
switch(v.getId())
{
case R.id.cleanButton:
cleanAction();
break;
case R.id.orderButton:
orderAction();
break;
case R.id.packageButton:
packageAction();
break;
default:
break;
}
}
private void cleanAction()
{
startAction(Actions.CLEAN_ACTION);
}
private void orderAction()
{
startAction(Actions.ORDER_ACTION);
}
private void packageAction()
{
startAction(Actions.PACKAGE_ACTION);
}
private void startAction(String actionName)
{
Intent intent=new Intent(this,RoomService.class);
intent.setAction(actionName);
this.startService(intent);
}
private void showLongToast(String info)
{
Toast.makeText(getBaseContext(), info, Toast.LENGTH_LONG).show();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
resent.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
@Override
protected void onDestroy() {
super.onDestroy();
}
}
從打印的log可看出,客戶端每調(diào)用一次Context.startService(Intent),Service就會(huì)重新執(zhí)行一次onStartCommand---->onStart;但是使用AIDL的話,綁定服務(wù)之后,不會(huì)重復(fù)執(zhí)行onStart,顯然后者的代價(jià)更小。
Service:前臺(tái)Service,像我們經(jīng)常用的天氣、音樂其實(shí)都利用了前臺(tái)Service來實(shí)現(xiàn)
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Android app應(yīng)用多語言切換功能實(shí)現(xiàn)
這篇文章主要為大家詳細(xì)介紹了Android app應(yīng)用多語言切換功能實(shí)現(xiàn)代碼,感興趣的小伙伴們可以參考一下2016-08-08
Android 如何保證service在后臺(tái)不被kill
本文主要介紹了Android 如何保證service在后臺(tái)不被kill的方法。具有很好的參考價(jià)值,下面跟著小編一起來看下吧2017-02-02
Android 判斷是開發(fā)debug模式,還是發(fā)布release模式的方法
下面小編就為大家?guī)硪黄狝ndroid 判斷是開發(fā)debug模式,還是發(fā)布release模式的方法。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2016-12-12
Android關(guān)于WebView中無法定位的問題解決
本篇文章主要介紹了Android關(guān)于WebView中無法定位的問題解決,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-10-10
解決Android WebView攔截url,視頻播放加載失敗的問題
這篇文章主要介紹了解決Android WebView攔截url,視頻播放加載失敗的問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-03-03
Android開發(fā)實(shí)現(xiàn)ListView和adapter配合顯示圖片和文字列表功能示例
這篇文章主要介紹了Android開發(fā)實(shí)現(xiàn)ListView和adapter配合顯示圖片和文字列表功能,涉及Android使用ListView結(jié)合adapter適配器實(shí)現(xiàn)圖文顯示功能相關(guān)的布局、解析、權(quán)限控制等操作技巧,需要的朋友可以參考下2019-04-04

