2015年8月22日 星期六

Activityc和Service之間的值傳遞

StartService這種方式是無法將Service運算的數據返回給Activity,也就是說Activity丟指令給Service去做,但Service做到什麼程度,做完了還是正在做...等這些訊息,Activity是無法得知的,所以就需要用bound service來解決這問題的,下面是基本使用方法:

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="com.example.binderservice01.MainActivity" >

    <Button
        android:id="@+id/btn1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="綁定完成操作" />

</RelativeLayout>

MainActivity.java:

public class MainActivity extends Activity {
private Button btn1 ;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn1 = (Button)findViewById(R.id.btn1);
btn1.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent();
intent.setClass(MainActivity.this, SecondService.class);
bindService(intent, conn, BIND_AUTO_CREATE);
}
});
}
//接下來用匿名內部類來生成一個ServiceConnection對象。他是一個接口
ServiceConnection conn = new ServiceConnection(){
//當如果調用上面的bindService去綁定service成功的話,就會去調用                                                 onServiceConnected
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
FirstBinder binder = (FirstBinder)service;
String data = binder.getData();
System.out.println("得到Service 的binder的值data--->"+data);
}
//當綁定service斷開時候,就會調用onServiceDisconnected
@Override
public void onServiceDisconnected(ComponentName name) {
// TODO Auto-generated method stub
}
};
}

SecondService.java:

public class SecondService extends Service {

//當其他的應用程序組件(Activity)綁定至當前的Service,就會調用這方法
@Override
public IBinder onBind(Intent intent) {
//因為FirstBinder繼承了Binder,Binder又是IBinder的子類
//,所以我們也可以認為FirstBinder是IBinder的子類,就可以return binder
IBinder binder = new FirstBinder();
return binder;
}

class FirstBinder extends Binder{
public String getData(){
return "test data";
}
}
}

08-23 13:57:28.947: I/System.out(19095): 得到Service 的binder的值data--->test data

總結: 首先在Service裡面先定義一個class Binder的實現類,然後裡面去添加一個方法,然後在
onBind這個方法去返回這個FirstBinder對象,之後在Activity去調用bindService,在調用時要先實現一個ServiceConnection這個接口。當綁定成功時候就會通過ServiceConnection來調用
onServiceConnected來取得Service裡binder對象的數據取出來,透過這個機制就可以讓Activity去調用Service的方法得到Service的數據資訊。

-----------------------------------分隔線-----------------------------------------------

Service功能主要是在後台處理一些比較耗時的操作,譬如說網路連接、資料下載、播放mp3...等等,所以用戶是看不到service的存在的,用戶只能透過Activity去對Service發送指令,Serviec接到指令後,就會去執行一些操作,所以Service不能夠與用戶做基本的溝通,這就是Service的特點

如何讓Activity能夠從Service那裏取的目前Service運行的狀態的基本使用法:

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="com.example.binderservice02.MainActivity" >

    <Button
        android:id="@+id/bt1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="綁定Service" />

    <Button
        android:id="@+id/bt2"
        android:layout_below="@+id/bt1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="發送請求" />

</RelativeLayout>

MainActivity.java:

public class MainActivity extends Activity {
private Button btn1;
private Button btn2;
private IBinder binder;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

btn1 = (Button) findViewById(R.id.bt1);
btn2 = (Button) findViewById(R.id.bt2);
btn1.setOnClickListener(new OnClickListener() {

@Override
public void onClick(View v) {
//當點擊btn1會先綁定Activity和Service的binder關係
Intent intent = new Intent();
intent.setClass(MainActivity.this, SecondService.class);
bindService(intent, conn, BIND_AUTO_CREATE);
                                System.out.println("綁定binder");
}

});

btn2.setOnClickListener(new OnClickListener() {

@Override
public void onClick(View v) {
// 當點擊btn2馬上會調用SecondService的onTransact方法
//data是由Activity傳送過去的資料,reply是Service經由計算後傳回的資料,code和flags可設0
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInt(5);
try {
binder.transact(0, data, reply, 0);
int i = reply.readInt();
System.out.println("Activity的reply值是------>"+i);
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

}
});
}

ServiceConnection conn = new ServiceConnection() {

@Override
public void onServiceConnected(ComponentName componentName,
IBinder binder) {
MainActivity.this.binder = binder;
}

@Override
public void onServiceDisconnected(ComponentName componentName) {

}

};

}
SecondService.java:

public class SecondService extends Service{

@Override
public IBinder onBind(Intent intent) {
return new MyBinder();
}

class MyBinder extends Binder {

@Override
protected boolean onTransact(int code, Parcel data, Parcel reply,
int flags) throws RemoteException {

int i = data.readInt(); //data是從Activity傳過來的
System.out.println("Service的data是 ----->" +i);

i = i +10;
reply.writeInt(i);

return super.onTransact(code, data, reply, flags);
}

}

}

Manifest.xml:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.binderservice02"
    android:versionCode="1"
    android:versionName="1.0" >

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

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name=".MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
    <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

印出結果:
08-23 13:05:50.217: I/System.out(16821): Service的data是 ----->5
08-23 13:05:50.217: I/System.out(16821): Activity的reply值是------>15