首先引申下AIDL,什麼是AIDL呢?IPC? ------ Designing a Remote Interface Using AIDL
通常情況下,我們在同一進程內會使用Binder、BroadCastReciver讓Service跟Activity進行通信,數據交互,數據共享,但是跨進程呢?
IPC:IPC接口,IPC接口本地代理 ------ Implementing IPC Using AIDL
AIDL意爲:Android Interface Define Language 即 Android 接口描述語言
與J2ee的區別:Java中不允許跨進程內存共享,只傳遞對象,採用RMI方式,也可以通過序列化傳遞對象
Android AIDL: 採用AIDL方式,可以傳遞Bundle,實現起來稍微麻煩些
實現過程:在服務端定義AIDL文件,ADT插件編譯器將其編譯之後,會在R文件同級目錄文件下生成.java文件,輕量級,使用代理類在客戶端和實現層間傳
遞值
語法:可以申明接口和方法,參數和返回值不是任何類型,不需要申明import,String,charSequence等
AIDL使用起來也不是很麻煩,我個人感覺很實用!所以今天就說說關於AIDL的特性,很多朋友在自己的博客只是說它的理論而不是寫一些實例來講解,我個人感覺你只是說說他的
理論,一般人根本就看不懂,而且本來就是很抽象的東西,又摸不着,你們寫了也是白寫!
完全不顧新手的感受,應該是寫一些小例子,讓大家參與進來一起學習和探討效果才最佳!而且也不是一大堆的文字,看起來也不會那麼乏味,大家說是不?
下面就開始今天的AIDL/IPC講解與學習吧~,概念都講的差不多了,接下來就是實戰,代碼小例子給初學者細嚼慢嚥
從服務端線程開始寫,結構圖:
EngineerJspRemoteService.aidl 寫完之後保存,就會在gen文件自動創建一個.java文件
EngineerJspService.java
- package com.example.engineerjspserver;
- /**
- * AIDL/IPC
- * @author Engineer-Jsp
- * @date 2014.11.17
- * */
- import java.io.FileDescriptor;
- import android.app.Service;
- import android.content.Intent;
- import android.media.MediaPlayer;
- import android.os.IBinder;
- import android.os.RemoteException;
- import android.util.Log;
- public class EngineerJspService extends Service{
- private static final String TAG = "EngineerJspService";
- MediaPlayer player;
- @Override
- public IBinder onBind(Intent intent) {
- Log.d(TAG, "EngineerJspService is onBind..."+"\n來自客戶端的綁定操作已經完成...");
- if(player==null){
- player = MediaPlayer.create(this, R.raw.music);
- player = new MediaPlayer();
- try {
- FileDescriptor file = getResources().openRawResourceFd(R.raw.music).getFileDescriptor();
- player.setDataSource(file);
- player.setLooping(true);
- } catch (Exception e) {
- Log.d(TAG, e.toString());
- }
- Log.d(TAG, "player is created..."+"\n服務端播放器已經實例化,準備就緒...");
- }
- return binder;
- }
- private IBinder binder = new EngineerJspRemoteService.Stub() {
- @Override
- public void onStop() throws RemoteException {
- try {
- if(player.isPlaying()){
- Log.d(TAG, "客戶端進程對服務端進程執行了暫停操作...");
- player.stop();
- }
- } catch (Exception e) {
- Log.d(TAG, e.toString());
- }
- }
- @Override
- public void onPause() throws RemoteException {
- try {
- if(player.isPlaying()){
- return;
- }
- Log.d(TAG, "客戶端進程對服務端進程執行了開始操作...");
- player.prepare();
- player.start();
- } catch (Exception e) {
- Log.d(TAG, e.toString());
- }
- }
- };
- public boolean onUnbind(Intent intent) {
- if(player!=null){
- player.release();
- }
- Log.d(TAG, "EngineerJspService is onUnBind..."+"\n客戶端已經解綁斷線,服務停止了...");
- return super.onUnbind(intent);
- };
- }
- <?xml version="1.0" encoding="utf-8"?>
- <manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.example.engineerjspserver"
- android:versionCode="1"
- android:versionName="1.0" >
- <uses-sdk
- android:minSdkVersion="15"
- android:targetSdkVersion="18" />
- <application
- android:allowBackup="true"
- android:icon="@drawable/ic_launcher"
- android:label="@string/app_name"
- android:theme="@style/AppTheme" >
- <activity
- android:name="com.example.engineerjspserver.MainAcivity"
- android:label="@string/app_name" >
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity>
- <service android:name=".EngineerJspService" android:process=":remote">
- <intent-filter >
- <action android:name="com.example.engineerjspserver.EngineerJspService"/>
- </intent-filter>
- </service>
- </application>
- </manifest>
當完成上述操作之後,需要在res目錄下導入測試文件,比如我的測試文件一個music.mp3,需要與layout文件同級
搞定服務端之後,接下來就是客戶端線程編寫,之後進行進程通信測試
把服務端的aidl文件所在的包全部拷貝到客戶端的src下,把aidl文件除外的全部刪掉
EngineerJspActivity.java
- package com.example.engineerjspclient;
- /**
- * AIDL/IPC
- * @author Engineer-Jsp
- * @date 2014.11.17
- * */
- import com.example.engineerjspserver.EngineerJspRemoteService;
- import android.os.Bundle;
- import android.os.IBinder;
- import android.util.Log;
- import android.view.View;
- import android.view.View.OnClickListener;
- import android.widget.Button;
- import android.widget.Toast;
- import android.app.Activity;
- import android.content.ComponentName;
- import android.content.Intent;
- import android.content.ServiceConnection;
- public class EngineerJspActivity extends Activity {
- private static final String TAG = "EngineerJspActivity";
- private static final String ACTION = "com.example.engineerjspserver.EngineerJspService";
- private EngineerJspRemoteService EJService;
- private boolean isBind = false;
- private Button onPause,onStart;
- private ServiceConnection connection = new ServiceConnection() {
- @Override
- public void onServiceDisconnected(ComponentName name) {
- isBind = false;
- EJService = null;
- Log.d(TAG, "onServiceDisconnected" +
- "————"+"包名:"+name.getPackageName()+" "+"類名: "+name.getClassName()+"\n當客戶端線程斷線操作,服務將被清空...");
- }
- @Override
- public void onServiceConnected(ComponentName name, IBinder ibinder) {
- EJService = EngineerJspRemoteService.Stub.asInterface(ibinder);
- isBind = true;
- Log.d(TAG, "onServiceConnected————"+"包名:"+name.getPackageName()+" "+"類名: "+name.getClassName()+" "+"ibinder對象: "+ibinder.toString()+"\n客戶端線程與服務端線程連接中...");
- }
- };
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_engineer_jsp);
- Log.d(TAG, "客戶端線程Activity創建成功,初始化控件與綁定服務中...");
- Bind();
- intiView();
- }
- @Override
- protected void onDestroy() {
- UnBind();
- Log.d(TAG, "客戶端線程被銷燬,活動被解綁停止了...");
- super.onDestroy();
- }
- public void Bind(){
- Log.d(TAG, "Activity已經創建完成,執行綁定服務端線程活動中...");
- Intent intent = new Intent(ACTION);
- bindService(intent, connection, BIND_AUTO_CREATE);
- }
- public void UnBind(){
- if(isBind){
- Log.d(TAG, "Activity被銷燬了,與服務端線程的通信將被解綁停止...");
- unbindService(connection);
- EJService = null;
- isBind = false;
- }
- }
- private void intiView(){
- onPause = (Button)findViewById(R.id.onPause);
- onStart = (Button)findViewById(R.id.onStop);
- onPause.setOnClickListener(listener);
- onStart.setOnClickListener(listener);
- Log.d(TAG, "服務端線程的組件初始化完畢...");
- }
- private OnClickListener listener = new OnClickListener(){
- @Override
- public void onClick(View view) {
- if(view.getId()==R.id.onPause){
- try {
- EJService.onPause();
- Log.d(TAG, "客戶端線程對服務端線程執行了播放操作...");
- Toast.makeText(EngineerJspActivity.this,"客戶端線程對服務端線程執行了播放操作...", Toast.LENGTH_SHORT).show();
- } catch (Exception e) {
- Log.d(TAG, e.toString());
- }
- }else{
- try {
- EJService.onStop();
- Log.d(TAG, "客戶端線程對服務端線程執行了暫停操作...");
- Toast.makeText(EngineerJspActivity.this,"客戶端線程對服務端線程執行了暫停操作...", Toast.LENGTH_SHORT).show();
- } catch (Exception e) {
- Log.d(TAG, e.toString());
- }
- }
- }
- };
- }
activity_engineer_jsp.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=".EngineerJspActivity" >
- <Button
- android:id="@+id/onStop"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentLeft="true"
- android:layout_alignParentRight="true"
- android:layout_below="@+id/button1"
- android:layout_marginTop="42dp"
- android:text="onStop" />
- <Button
- android:id="@+id/onPause"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignLeft="@+id/onStop"
- android:layout_alignParentRight="true"
- android:layout_below="@+id/onStop"
- android:text="onPause" />
- </RelativeLayout>
- <?xml version="1.0" encoding="utf-8"?>
- <manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.example.engineerjspclient"
- android:versionCode="1"
- android:versionName="1.0" >
- <uses-sdk
- android:minSdkVersion="15"
- android:targetSdkVersion="18" />
- <application
- android:allowBackup="true"
- android:icon="@drawable/ic_launcher"
- android:label="@string/app_name"
- android:theme="@style/AppTheme" >
- <activity
- android:name="com.example.engineerjspclient.EngineerJspActivity"
- android:label="@string/app_name" >
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity>
- </application>
- </manifest>
啓動服務端進程與客戶端進程(不在同一個進程內,也就是不在同一個APK程序之內),在DDMS裏進行進程和堆棧查看
當服務端進程開啓之後,會等待客戶端進程接入與操作,類似c/s模式,Socket,客戶端進程開啓之後,服務端測試數據如下
客戶端測試數據:
服務測試:
客戶端進程對服務端進程執行了播放操作:
客戶端進程對服務端進程執行了暫停操作:
兩個進程項目圖結構:
AIDL這個小實例內容就這麼多,概念也說得差不多了,你們好好看看,消化消化~