標籤:android des style blog class code
Android間的進程通訊(傳遞複雜物件)完成對複雜物件的序列化
在Android中傳遞複雜資料類型的時候要通過將序列化,在Android中提供了一個介面Parcelable來實現對對象的序列化。
下面對需要傳輸的對象進行序列化操作,首先看自訂的類Person。
package com.example.service_parcelable_conmmute.bean;import android.graphics.Bitmap;/** * 用來傳輸的對象結構 * @author Xinyuyu * */public class Person { private String name; private String age; private Bitmap figure; public Person(){ } public Person(String name, String age, Bitmap figure){ this.name = name; this.age = age; this.figure =figure; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getAge() { return age; } public void setAge(String age) { this.age = age; } public Bitmap getFigure() { return figure; } public void setFigure(Bitmap figure) { this.figure = figure; }}
這個類就是一般的JavaBean包含了一些get/set方法,我們要做的就是在進程之間傳遞該對象的值。所以就要將該對象進行序列化,下面實現一個類來完成該任務。
建立ParcelablePerson類,來完成對Person的序列化和還原序列化的操作。其代碼如下:
public class ParcelablePerson implements Parcelable { Person person = new Person(); public Person getPerson() { return person; } public void setPerson(Person person) { this.person = person; } public ParcelablePerson(Person person){ this.person = person; } public ParcelablePerson(Parcel source){ person.setName(source.readString()); person.setAge(source.readString()); person.setFigure((Bitmap)source.readParcelable(Bitmap.class.getClassLoader())); } @Override public int describeContents() { return 0; } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeString(person.getName()); dest.writeString(person.getAge()); dest.writeParcelable(person.getFigure(), PARCELABLE_WRITE_RETURN_VALUE); } public static final Parcelable.Creator<ParcelablePerson> CREATOR = new Parcelable.Creator<ParcelablePerson>(){ @Override public ParcelablePerson createFromParcel(Parcel source) { return new ParcelablePerson(source); } @Override public ParcelablePerson[] newArray(int size) { return new ParcelablePerson[size]; } };}
這段代碼中完成了對Person對象的序列化與還原序列化,實現Parcelable介面要做的就是來重寫幾個方法(分別完成序列化和還原序列化),writeToParcel(Parcel dest, int flags)完成的就是對對象的序列化
其中的參數Parcel是一個容器,將對象放入其中就是序列化的過程。而CREATOR中的createFormParcel(Parcel source)來完成的就是還原序列化,可以返回一個複雜的對象。實現了這寫,就完成了對複雜物件的序列化和還原序列化操作,這樣我們就可以對它進行傳輸了。
完成綁定服務,完成進程中的通訊
以上我們只是完成了對一個複雜物件的序列化,下面我們要做的是建立服務,並且完成傳輸。
首先我們要做的是建立一個服務,在Android中建立一個服務要做的就是去實現Service介面。下面是發送對象的一個服務代碼
public class ServiceForSendObject extends Service { private static final String MSG = "MESSAGE"; private ParcelablePerson parcelablePerson; private Person person; // ===================================== SendObject.Stub sendBinder = new Stub(){ @Override public ParcelablePerson getPersonInfo() throws RemoteException { Log.i(MSG, "調用getPersonInfo()介面實現,返回一個序列化的對象"); return parcelablePerson; }}; // ===================================== @Override public void onCreate() { person = new Person("xinyuyu", "25", BitmapFactory.decodeStream(getResources().openRawResource(R.drawable.ic_launcher))); parcelablePerson = new ParcelablePerson(person); super.onCreate(); Log.i(MSG, "回調onCreate()建立服務"); } @Override public int onStartCommand(Intent intent, int flags, int startId) { Log.i(MSG, "回調onStartCommand()啟動服務"); return super.onStartCommand(intent, flags, startId); } @Override public boolean onUnbind(Intent intent) { Log.i(MSG, "回調onUnbind解除綁定服務"); return super.onUnbind(intent); } @Override public void onDestroy() { Log.i(MSG, "回調onDestroy銷毀服務"); super.onDestroy(); } @Override public IBinder onBind(Intent intent) { Log.i(MSG, "回調onBind()方法綁定服務"); return sendBinder; }}
在該段代碼中輸出各個階段的一些資訊,關鍵是在onCreat()方法中完成執行個體化一個對象,並且對該對象完成序列化操作。在分割線之間的代碼是關鍵代碼,注意在IBinder()中返回的是一個SendObject.Stub對象。而這個類是如何產生的呢?我們在完成進程間傳輸的時候需要用到Android中的AIDL語言來定義一個介面,下面我們來建立一個名為SendObject的aidl檔案,SendObject.aidl
package com.example.service_parcelable_conmmute_service.aidl;import com.example.service_parcelable_conmmute.bean.ParcelablePerson;interface SendObject { ParcelablePerson getPersonInfo();}
這個介面中的import會報錯,這時候需要在建立一個AIDL檔案,將其名字設定為和序列化類別一樣,這裡就起做ParcelablePerson.aidl。其內容如下
package com.example.service_parcelable_conmmute.bean;
parcelable ParcelablePerson;
完成這些就不會有錯誤了。
這時候你會發現在gen目錄下有一個和你的aidl名字一樣Java檔案即SendObject.java。而我們使用的SendObject.Stub就在其中。開啟這個檔案看一下,你會發現SendObject.Stub是這樣一個類,實現了SendObject介面並且繼承了android.os.Binder類。這樣我們就重寫SendObject方法,將其實現功能。就是分割線直接的代碼。
public static abstract class Stub extends android.os.Binder implements com.example.service_parcelable_conmmute_service.aidl.SendObject
還要注意一點進程間的服務通訊應該更改AndroidManifest.xml檔案的屬性,如下
<service android:name="com.example.service_parcelable_conmmute.service.ServiceForSendObject"android:process=":remote"><intent-filter> <action android:name="com.example.service_parcelable_conmmute.service.SEND_OBJECT"/> <category android:name="android.intent.category.DEFAULT" /> </intent-filter></service>
這樣可以完成隱式的傳遞Intent。完成了這些,服務端就完成了。這個時候可以運行下代碼。
啟動介面
點擊初始化服務後,可以看到服務開始運行
紅色框中為我們的服務。
點擊兩按鈕後LogCat輸出的資訊
從中可以看出來這個服務的生命週期。
以上我們就完成了服務端的工作了,下面來進行用戶端的完成。
在用戶端我們首先需要的是將服務端寫好的那些AIDL檔案和實體類拷貝到該工程下(連同包名進行拷貝)如
然後我們所要完成的就是完成用戶端的activity程式了。將倆個程式進行聯絡的就是我們的SendObject介面。看下面代碼
public class A extends Activity { private Button show_button; private TextView show_name_age; private ImageView show_image; private Button unbind_ser; private SendObject sendObject; private ParcelablePerson parcelablePerson; private Person person; private ServiceConnection connection = new ServiceConnection(){ // 建立綁定後service程式調用onBind()方法,返回一個IBinder對象 @Override public void onServiceConnected(ComponentName name, IBinder service) { sendObject = SendObject.Stub.asInterface(service); try { parcelablePerson = sendObject.getPersonInfo(); person = parcelablePerson.getPerson(); Log.i("", person.getName()); show_name_age.setText(person.getName() + "\n" + person.getAge()); show_image.setImageBitmap(person.getFigure()); } catch (RemoteException e) { e.printStackTrace(); } } @Override public void onServiceDisconnected(ComponentName name) { Log.i("", "error"); } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.a); show_button = (Button)this.findViewById(R.id.button1); show_name_age = (TextView)this.findViewById(R.id.textView1); show_image = (ImageView)this.findViewById(R.id.imageView1); unbind_ser = (Button)this.findViewById(R.id.button2); show_button.setOnClickListener(new OnClickListener(){ @Override public void onClick(View v) { // 隱式傳遞intent Intent intent = new Intent(); intent.setAction("com.example.service_parcelable_conmmute.service.SEND_OBJECT"); bindService(intent, connection, BIND_AUTO_CREATE); }}); // 解除綁定(服務會在activity銷毀後自動銷毀) unbind_ser.setOnClickListener(new OnClickListener(){ @Override public void onClick(View v) { unbindService(connection); } }); }}
將該程式與服務進行綁定就用到了bindService()方法,看該方法中的參數,第一個是一個intent,第二個是一個ServiceConnection類,與服務建立串連,接收到onBind()傳輸的資料。從這個方法中我們就得到了傳遞過來的對象。運行用戶端程式
點擊第一個按鈕後會顯示出來一個Person對象的資訊。這就說明資料從服務端傳輸了過來。
LogCat輸出的資訊