亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 系統 > Android > 正文

Android 進程間通信實現原理分析

2020-04-11 12:16:22
字體:
來源:轉載
供稿:網友

Android Service是分為兩種:
  本地服務(Local Service): 同一個apk內被調用
  遠程服務(Remote Service):被另一個apk調用
遠程服務需要借助AIDL來完成。

AIDL 是什么
  AIDL (Android Interface Definition Language) 是一種IDL 語言,用于生成可以在Android設備上兩個進程之間進行進程間通信(interprocess communication, IPC)的代碼。如果在一個進程中(例如Activity)要調用另一個進程中(例如Service)對象的操作,就可以使用AIDL生成可序列化的參數。
  AIDL IPC機制是面向接口的,像COM或Corba一樣,但是更加輕量級。它是使用代理類在客戶端和實現端傳遞數據。

AIDL 的作用
  由于每個應用程序都運行在自己的進程空間,并且可以從應用程序UI運行另一個服務進程,而且經常會在不同的進程間傳遞對象。在Android平臺,一個進程通常不能訪問另一個進程的內存空間,所以要想對話,需要將對象分解成操作系統可以理解的基本單元,并且有序的通過進程邊界。
  通過代碼來實現這個數據傳輸過程是冗長乏味的,Android提供了AIDL工具來處理這項工作。

選擇AIDL的使用場合
  官方文檔特別提醒我們何時使用AIDL是必要的:只有你允許客戶端從不同的應用程序為了進程間的通信而去訪問你的service,以及想在你的service處理多線程。
  如果不需要進行不同應用程序間的并發通信(IPC),you should create your interface by implementing a Binder;或者你想進行IPC,但不需要處理多線程的,則implement your interface using a Messenger。無論如何,在使用AIDL前,必須要理解如何綁定service――bindService。

下面將要講到的這個例子來自:http://www.cnblogs.com/lonkiss/archive/2012/10/23/2735548.html

下面用一個客戶端Activity操作服務端Service播放音樂的實例演示AIDL的使用。

服務端代碼結構(左)                                 客戶端代碼結構(右)
被標記的就是需要動手的。
服務端

新建一個android application project,命名為PlayerServer。 在res下的raw文件夾里面放入一個音樂文件,我這里放入的是Delta Goodrem的《Lost Without You》片段。如果不存在raw這個文件夾就自己新建一個,命名為raw。這個文件夾在raw文件夾下,與layout文件夾平級。raw中的文件遵守標識符的命名規則,不要出現中文和空格,多個單詞可以用下劃線連接。
  
新建一個IRemoteServiice.aidl 文件,加入如下代碼

復制代碼 代碼如下:

package pandafang.demo.playerserver;
interface IRemoteService {
 void play();
 void stop();
}

可見aidl文件的代碼跟java的interface一樣,但是aidl中不能加public等修飾符。Ctrl + S 保存后 ADT 會根據這個IRemoteService.aidl文件自動生成IRemoteService.java文件。如同R.java文件一樣在“gen/包名”下,代碼是自動生成的,不要手動修改。
  
接下來就是bound service的知識了。IRemoteService.java 中有一個Stub靜態抽象類extends Binder implements IRemoteService。自己動手寫一個PlayerService 用來播放音樂,播放音樂需要使用

android.media.MediaPlayer類。代碼如下

復制代碼 代碼如下:

/**
 * 播放音樂的服務
 */
public class PlayerService extends Service {

 public static final String TAG = "PlayerService";

 private MediaPlayer mplayer;

 @Override
 public IBinder onBind(Intent intent) {
  Log.i(TAG,"service onbind");
  if(mplayer==null){
   // 方法一說明
   // 此方法實例化播放器的同時指定音樂數據源 ,若用此方法在,mplayer.start() 之前不需再調用mplayer.prepare()
   // 官方文檔有說明 :On success, prepare() will already have been called and must not be called again.
   // 譯文:一旦create成功,prepare已被調用,勿再調用 。查看源代碼可知create方法內部已經調用prepare方法。
   // 方法一開始
   // mplayer = MediaPlayer.create(this, R.raw.lost);
   // 方法一結束

   // 方法二說明
   // 若用此方法,在mplayer.start() 之前需要調用mplayer.prepare()
   // 方法二開始
   mplayer = new MediaPlayer();
   try {
    FileDescriptor fd = getResources().openRawResourceFd(R.raw.lost).getFileDescriptor(); // 獲取音樂數據源
    mplayer.setDataSource(fd); // 設置數據源
    mplayer.setLooping(true); // 設為循環播放
   } catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   }
   // 方法二結束
   Log.i(TAG,"player created");
  }
  return mBinder;
 }

 // 實現aidl文件中定義的接口
 private IBinder mBinder = new IRemoteService.Stub() {

  @Override
  public void stop() throws RemoteException {
   try {
    if (mplayer.isPlaying()) {
     mplayer.stop();
    }
   } catch (Exception e) {
    // TODO: handle exception
    e.printStackTrace();
   }
  }

  @Override
  public void play() throws RemoteException {
   try {
    if (mplayer.isPlaying()) {
     return;
    }
    // start之前需要prepare。
    // 如果前面實例化mplayer時使用方法一,則第一次play的時候直接start,不用prepare。
    // 但是stop一次之后,再次play就需要在start之前prepare了。
    // 前面使用方法二 這里就簡便了, 不用判斷各種狀況
    mplayer.prepare();
    mplayer.start();
   } catch (Exception e) {
    // TODO: handle exception
    e.printStackTrace();
   }
  }
 };
 @Override
 public boolean onUnbind(Intent intent) {
  if (mplayer != null) {
   mplayer.release();
  }
  Log.i(TAG,"service onUnbind");
  return super.onUnbind(intent);
 }
}

服務編寫好以后,按照慣例在AndroidManifest.xml中加入聲明,代碼如下
復制代碼 代碼如下:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="pandafang.demo.playerserver"
    android:versionCode="1"
    android:versionName="1.0" >
    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="15" />
    <application
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <service android:name=".PlayerService" android:process=":remote">
            <intent-filter >
                <action android:name="com.example.playerserver.PlayerService"/>
            </intent-filter>
         </service>
    </application>
</manifest>

需要加入的只是<service>...</service>那段,要注意的是 android:process=":remote" 和 intent-filter 。
  運行服務端到設備上,準備給客戶端調用
客戶端
  新建一個android application project,命名為PlayerClient。將服務端放有aidl文件的包直接copy到客戶
端src目錄下,保留包中的aidl文件,其他刪除。
 編寫MainActivity.java 代碼如下
復制代碼 代碼如下:

/**
 * 客戶端控制界面
 */
public class MainActivity extends Activity {

 public static final String TAG = "MainActivity";

 // 服務端 AndroidManifest.xml中的intent-filter action聲明的字符串
 public static final String ACTION = "com.example.playerserver.PlayerService";

 private Button playbtn, stopbtn;

 private IRemoteService mService;

 private boolean isBinded = false;

 private ServiceConnection conn = new ServiceConnection() {

  @Override
  public void onServiceDisconnected(ComponentName name) {
   isBinded = false;
   mService = null;
  }

  @Override
  public void onServiceConnected(ComponentName name, IBinder service) {
   mService = IRemoteService.Stub.asInterface(service);
   isBinded = true;
  }
 };
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        doBind();
        initViews();
    }
    private void initViews() {
     playbtn = (Button) findViewById(R.id.button1);
        stopbtn = (Button) findViewById(R.id.button2);
        playbtn.setOnClickListener(clickListener);
        stopbtn.setOnClickListener(clickListener);
    }
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.activity_main, menu);
        return true;
    }
    @Override
    protected void onDestroy() {
  doUnbind();
     super.onDestroy();
    }
    public void doBind() {
     Intent intent = new Intent(ACTION);
     bindService(intent, conn, Context.BIND_AUTO_CREATE);
    }
    public void doUnbind() {
     if (isBinded) {
      unbindService(conn);
         mService = null;
         isBinded = false;
     }

    }
    private OnClickListener clickListener = new OnClickListener() {

  @Override
  public void onClick(View v) {
   if (v.getId() == playbtn.getId()) {
    // play
    Log.i(TAG,"play button clicked");
    try {
     mService.play();
    } catch (RemoteException e) {
     // TODO Auto-generated catch block
     e.printStackTrace();
    }
   } else {
    // stop
    Log.i(TAG,"stop button clicked");
    try {
     mService.stop();
    } catch (RemoteException e) {
     // TODO Auto-generated catch block
     e.printStackTrace();
    }
   }
  }
 };
}

MainActivity是根據向導自動生成的,不需要在AndroidManifest.xml中注冊聲明了
運行客戶端到設備,按下按鈕可以播放/停止 效果如圖

如果想對更加詳細的實現原理進行研究,可以參見這篇文章:
http://www.cnblogs.com/over140/archive/2011/03/08/1976890.html

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
国产自产女人91一区在线观看| xxx一区二区| 国产精品一区二区三区免费视频| 欧美整片在线观看| 一区二区三区黄色| 精品国模在线视频| 国产精品69久久久久| 国产精品第100页| 国产在线98福利播放视频| 国产精品高清在线观看| 成人天堂噜噜噜| 国产欧美精品在线| 久久免费视频观看| 欧美电影在线观看网站| 亚洲老司机av| 国产精品天天狠天天看| 欧美性视频网站| 一区二区三欧美| 亚洲最大激情中文字幕| 日韩激情在线视频| 午夜精品久久久久久99热软件| 亚洲a区在线视频| 国产精品久久91| 欧美电影免费观看高清完整| 欧美激情久久久久| 欧美精品18videos性欧美| 久久精品久久久久久| 亚洲男人天堂久| 亚洲剧情一区二区| 久久精品中文字幕电影| 色哟哟亚洲精品一区二区| 国产亚洲精品久久久久久牛牛| 日韩视频精品在线| 国产福利成人在线| 久久97久久97精品免视看| 久久国产精品99国产精| 亚洲成色777777女色窝| 日韩中文字幕国产精品| 日韩亚洲欧美中文高清在线| 精品久久中文字幕久久av| 91地址最新发布| 国产日韩在线免费| 一区二区欧美在线| 国产日韩中文字幕在线| 日本高清不卡在线| 色小说视频一区| 最近中文字幕日韩精品| 精品视频9999| 国产精品日韩在线一区| 国产精品狠色婷| 国产一区香蕉久久| 亚洲精品自拍第一页| 日韩欧美一区视频| 日韩精品丝袜在线| 亚洲欧美在线一区二区| 米奇精品一区二区三区在线观看| 97不卡在线视频| 日韩成人xxxx| 久久国产精品视频| 国产精品一区二区三区久久久| 亚洲第一免费播放区| 成人精品视频久久久久| 日韩精品视频免费在线观看| 欧美人在线观看| 啊v视频在线一区二区三区| 日韩av综合网站| 久热在线中文字幕色999舞| 亚洲国产精品一区二区久| 69视频在线播放| 亚洲韩国青草视频| 亚洲国产欧美一区二区三区久久| 欧美成人一区二区三区电影| 亚洲成年网站在线观看| 日韩在线观看精品| 亚洲精品网址在线观看| 国产视频综合在线| 日韩电影中文字幕在线| 欧美中文在线字幕| 欧美诱惑福利视频| 欧美日韩高清区| 亚洲精品丝袜日韩| 日本亚洲欧美三级| 日韩精品有码在线观看| 国产精品十八以下禁看| 国产精品久久在线观看| 国产精品美女主播在线观看纯欲| 亚洲成色999久久网站| xxx一区二区| 亚洲色图第三页| 欧美国产日韩一区二区三区| 国模极品一区二区三区| 中文字幕v亚洲ⅴv天堂| 日韩在线视频免费观看高清中文| 精品久久久久久中文字幕| 色偷偷av一区二区三区| 日韩av在线网页| 欧美成人黑人xx视频免费观看| 欧美激情在线有限公司| 国产精品极品在线| 亚洲国内精品在线| 亚洲区一区二区| 欧美性生交大片免网| 性欧美激情精品| 国产精品一区二区性色av| 国产成人免费av电影| 黄色成人av网| 国产成人一区二| 亚洲精品第一国产综合精品| 久久视频在线播放| 亚洲一级免费视频| 91最新国产视频| 日韩电影免费在线观看| 国产精品91免费在线| 国产深夜精品福利| 国产精品自产拍在线观| 日韩网站免费观看| 欧美精品激情blacked18| 久久青草精品视频免费观看| 久久免费精品视频| 欧洲成人免费aa| 高清一区二区三区四区五区| 欧美美最猛性xxxxxx| 欧美另类交人妖| 久久影视电视剧凤归四时歌| 中文字幕在线国产精品| 日韩欧美一区二区在线| 久久久久久久久久久免费| 国产精品久久久亚洲| 欧美日韩国产综合视频在线观看中文| 成人日韩在线电影| 57pao精品| 亚洲人高潮女人毛茸茸| 亚洲男人天堂久| 日韩午夜在线视频| 国产一区二区三区久久精品| 国产精品色午夜在线观看| 国产视频亚洲精品| 亚洲视频在线观看网站| 欧美亚洲另类激情另类| 国产中文字幕日韩| 国产精品日本精品| 97精品在线视频| 亚洲精品福利在线观看| 国产999精品久久久| 日韩视频免费中文字幕| 自拍偷拍亚洲一区| 欧美精品第一页在线播放| 色中色综合影院手机版在线观看| 亚洲男人的天堂在线| 欧美性黄网官网| 精品国产乱码久久久久久婷婷| 欧美性少妇18aaaa视频| 欧美亚洲日本黄色| 一本色道久久88综合日韩精品| 亚洲欧美日韩一区二区在线| 九九视频这里只有精品| 久久精品成人欧美大片古装| 日韩国产精品亚洲а∨天堂免| 久久影院资源网| 精品国产精品自拍| 久久成人这里只有精品| 亚洲欧美日韩一区在线| 欧美日韩高清区| 欧美一性一乱一交一视频|