創作

2015年7月15日 星期三

Android AIDL/Service/Activity間的基本溝通

最近做到一個功能,需要一個一直存在的功能,然後不同App可以操作那個功能。

問了些前輩,他是推薦我試看看AIDL跟Service,當然我是都沒碰過。 

大約查了一下,整理出來。

 1.先來做一個Service。
      1.1 建立一個Android專案
     1.2 因為Service是要在背景執行,且沒打算給他畫面,所以把Layout跟Activity移除。
     1.3 建立一個Aidl的Package (這邊我稱之為窗口,跟這Service溝通用的窗口)
           並創建一個File,命名為DAidl.aidl
    1.4 DAidl.aidl
         
package com.doroto.aidl;
//做個CallBack
import com.doroto.aidl.DCallback;

interface DAidl
{
 int getINT();
 
 String getString();
 
 String getMsg(String msg);
 
 void setName(String name);
 
 void setData(String name,String parent,int count);
 
 void setListener(DCallback callback);

}

    1.5 在窗口DAidl裡面,有做個Callback事件,所以要在新增一個CallBack
    
    1.6DCallback.aidl

package com.doroto.aidl;

interface DCallback
{
 void onCallBack(String callBackMsg);
}

    1.7 好拉,窗口都好了,接下來就是做主要處理的Service
    1.8 建立一個Class 並繼承 App.Service
   


    1.9 DService.java
 
package com.doroto.aidlserviceexample;

import com.doroto.aidl.DAidl;
import com.doroto.aidl.DCallback;

import android.app.Service;
import android.content.Intent;
import android.os.Handler;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;

public class DService extends Service {
 private String TAG = "DService";
 
 //紀錄用
 private String mName = "service";
 private String mParent="";
 private String mString="Wellcome Dservice~";
 private int mCount = 0 ;
 private DCallback mCallback;
 

 @Override
 public IBinder onBind(Intent intent) {
  Log.println(Log.DEBUG, TAG, " onBind ");
  return mDail;
 } 
 
 @Override
 public void onCreate() {
  Log.println(Log.DEBUG, TAG, " onCreate() ");
  super.onCreate();
 }
 
 @Override
 public void onDestroy() {
  Log.println(Log.DEBUG, TAG, " onDestroy() ");
  super.onDestroy();
 }
 
 @Override
 public int onStartCommand(Intent intent, int flags, int startId) {
  Log.println(Log.DEBUG, TAG, " onStartCommand() ");
  return super.onStartCommand(intent, flags, startId);
 }
 
 
 /******************窗口********************/
 private DAidl.Stub mDail = new DAidl.Stub() {
  
  @Override
  public void setName(String name) throws RemoteException {
   Log.println(Log.DEBUG, TAG, "setName:"+name);
   mName = name;
   
  }
  
  @Override
  public void setListener(DCallback callback) throws RemoteException {
   Log.println(Log.DEBUG, TAG, "setListener");
   mCallback = callback;   
  }
  
  @Override
  public void setData(String name, String parent, int count)
    throws RemoteException {
   Log.println(Log.DEBUG, TAG, "setData:"+name+" "+parent+" "+count);
   mName = name;
   mParent = parent;
   mCount = count;
   
   //回傳CallBack
   if (mCallback!=null){
    
    try {
        Log.println(Log.DEBUG,TAG," onCallback! setData Delay 3s is Success!"); 
        mCallback.onCallBack("setData Delay 3s is Success!");
    } catch (RemoteException e) {
     Log.println(Log.ERROR,TAG," onCallback! Error:"+e); 
    }
    
   }
  }
  
  @Override
  public String getString() throws RemoteException {
   Log.println(Log.DEBUG, TAG, "getString:"+mString);
   return mString;
  }
  
  @Override
  public String getMsg(String msg) throws RemoteException {
   Log.println(Log.DEBUG, TAG, "getMsg:"+msg);
   return mString+" @ "+msg;
  }
  
  @Override
  public int getINT() throws RemoteException {
   Log.println(Log.DEBUG, TAG, "getINT:"+mCount);
   return mCount;
  }
 };

}

    1.10 最後,記得修正Manifest.xml,將Service做宣告
 
    1.11 Manifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.doroto.aidlserviceexample"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="18"
        android:targetSdkVersion="18" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <service android:name =".DService">
            <intent-filter>
                <action android:name="com.doroto.aidlserviceexample.dservice"/>  
            </intent-filter>
        </service>
        
    </application>

    1.12 最後發佈。出現說,沒有畫面,但是還是發佈成功的訊息。
            這就先別管他,我找時間再看看。

2.再來製作APP Connect端 。
    2.1 先建立一個Android專案,並把窗口複製一份過去。
 
    2.2  MainActivity.java
package com.example.aidlactivity2;

import android.app.Activity;
import android.content.ComponentName;
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 android.view.View.OnClickListener;
import android.widget.Button;

import com.doroto.aidl.DAidl;
import com.doroto.aidl.DCallback;
import com.example.aidlactivity2.R;

public class MainActivity extends Activity implements OnClickListener {

 private Button getIntBtn, getStrBtn, setNameBtn, setDataBtn, getMsgBtn;
 
 //窗口參數
 private DAidl dorotoAidl;
 private DorotoConnect dConnect = new DorotoConnect();
 
 private int addCount = 0;

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  
  //宣告按鈕
  getIntBtn = (Button) findViewById(R.id.GetInt);
  getStrBtn = (Button) findViewById(R.id.GetStr);
  getMsgBtn = (Button) findViewById(R.id.GetMsg);
  setNameBtn = (Button) findViewById(R.id.SetName);
  setDataBtn = (Button) findViewById(R.id.SetData);
  
  getIntBtn.setOnClickListener(this);
  getStrBtn.setOnClickListener(this);
  getMsgBtn.setOnClickListener(this);
  setNameBtn.setOnClickListener(this);
  setDataBtn.setOnClickListener(this);
   
  //加入窗口-Service
  Intent service = new Intent("com.doroto.aidlserviceexample.dservice");  
  //連接Service
     bindService(service, dConnect, BIND_AUTO_CREATE);  

 }

 @Override
 public void onClick(View v) {
  switch (v.getId()) {
  case R.id.GetInt:
   //呼叫窗口 getINT
   try {
    addCount=dorotoAidl.getINT();
   } catch (RemoteException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   }
   break;
  case R.id.GetStr:
   //呼叫窗口 getString
   try {
    dorotoAidl.getString();
   } catch (RemoteException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   }
   break;
  case R.id.GetMsg:
   //呼叫窗口 getMsg
   try {
    dorotoAidl.getMsg("Activity 1 GetMsg @@@@@");
   } catch (RemoteException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   }
   break;
  case R.id.SetName:
   //呼叫窗口 SetName
   try {
    dorotoAidl.setName("Activity1");
   } catch (RemoteException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   }
   break;
  case R.id.SetData:
   //呼叫窗口 SetData
   try {
    addCount+=5;
    dorotoAidl.setData("Activity1_Data", "Mama", addCount);
   } catch (RemoteException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   }
   break;

  default:
   break;
  }

 }
 
 
 /**連接訊息*/
 private  class DorotoConnect implements ServiceConnection{  
  @Override
  public void onServiceConnected(ComponentName name, IBinder service) {
   Log.println(Log.INFO,"Activity1","onServiceConnected");
   dorotoAidl = DAidl.Stub.asInterface(service);
   try {
    dorotoAidl.setListener(serviceCallBack);
   } catch (RemoteException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   }
  }

  @Override
  public void onServiceDisconnected(ComponentName name) {
   //斷開連結   
   dorotoAidl = null;
  }  
          
    }  
 
 /**CallBack*/
 private DCallback.Stub serviceCallBack = new DCallback.Stub() {
  @Override
  public void onCallBack(String callBackMsg) throws RemoteException {
   Log.println(Log.INFO,"Activity1","Get Service Callback");
  }
 };
 
}
2.3 發佈專案

3. 制做另一個專案,跟上個專案一樣。

4.Service內容是:每次SetData 之後 Count數量都會增加5。

5.這樣 A專案,跟B專案都可以呼叫到Service,而且Service中的變化,兩個都可以取得到了。

6.且AB專案關閉,Service還是存在著。 

如果要深入了解AIDL跟Service,可以先自行Google,因為我也是剛碰Service的新手,此篇也是紀錄用。

專案下載(GoogleDrive)









沒有留言:

張貼留言