开发者

passing custom object to android service in different process

I have a service that is set to start in a separate process:

<service android:name=".services.UploadService"
          android:process=":UploadServiceProcess" />

And I can successfully bind to it using b开发者_开发问答indService(). My issue occurs when I try to send a message by calling Messenger.send():

service.send(Message.obtain(null, UploadService.MESSAGE_UPLOAD_REQUEST, uploadRequest));

where uploadRequest is a custom object that implements Parcelable

public class UploadRequest implements Parcelable {
    public File file;
    public boolean deleteOnUpload;

public UploadRequest(File file, boolean deleteOnUpload) {
    this.file = file;
    this.deleteOnUpload = deleteOnUpload;
}

private UploadRequest(Parcel in) {
    this.file = new File(in.readString());
}

public int describeContents() {
    return 0;
}

public void writeToParcel(Parcel dest, int flags) {
    dest.writeString(this.file.getPath());
}

public static final Parcelable.Creator<UploadRequest> CREATOR = new Parcelable.Creator<UploadRequest>() {
    public UploadRequest createFromParcel(Parcel in) {
        return new UploadRequest(in);
    }
    public UploadRequest[] newArray(int size) {
        return new UploadRequest[size];
    }
};

}

I set a breakpoint in my services handleMessage, but my app never gets to the breakpoint. However, if instead of using my custom UploadRequest object I send null, I get to the handleMessage breakpoint like I'd expect, but obviously I can't do anything at that point. I've verified file.getPath() when calling writeToParcel returns a non null String. This leads me to believe that something is off in my UploadRequest class, but from googling I can't see anything wrong with my class. Any ideas?


The documentation of Message member obj says:

An arbitrary object to send to the recipient. When using Messenger to send the message across processes this can only be non-null if it contains a Parcelable of a framework class (not one implemented by the application). For other data transfer use setData(Bundle). Note that Parcelable objects here are not supported prior to the FROYO release.

My guess is you are seeing an issue because you are creating your own parcelable which is not allowed when crossing the process boundary. Instead, you'll have to package your object into a bundle. This also means your object will need to implement Serializable but will not need to be Parcelable.


tried this just now.

Message.obj can transfer a framework class, such as ContentValues.

and Message.SetData can transfer a Bundle across processes and you can put any Parcelable objects into the bundle.

just remember to call setClassLoader on bundle, when received the Messag.

send side

        Message localMsg = Message.obtain();
        localMsg.what = TPServiceConnection.MSG_REPLY_SERVICE_HELLO;

        Bundle data = new Bundle();

        ContentValues cv = new ContentValues();
        cv.put("KEY", mRand.nextInt());
        data.putParcelable("KEY", cv);

        TPServiceDataModal modal = new TPServiceDataModal(mRand.nextInt());
        data.putParcelable("KEY2", modal);

        localMsg.setData(data);

receive side

        Bundle data = msg.getData();
        data.setClassLoader(this.getClass().getClassLoader());

        Parcelable parcelable = data.getParcelable("KEY");
        if (parcelable instanceof ContentValues) {
            ContentValues cv = (ContentValues) parcelable;
            Log.d(TAG, "reply content: " + cv.getAsInteger("KEY"));
        }

        Parcelable parcelable2 = data.getParcelable("KEY2");
        if (parcelable2 instanceof TPServiceDataModal) {
            TPServiceDataModal modal = (TPServiceDataModal) parcelable2;
            Log.d(TAG, "reply modal: " + modal.mData);
        }

where TPServiceDataModal is a Parcelable calss.


Example to pass parcelable object via Bundle, remember to use classLoader and define object with correct package

Client app

val msg: Message = Message.obtain(null, MSG_SAY_HELLO)
msg.data = Bundle().apply {
    putParcelable("KEY_MY_OBJECT", MyObject("an", 12))
}
mService?.send(msg)

.

package com.example.androidmessengerclient    
@Parcelize
class MyObject(val name: String, val age: Int) : Parcelable

Server app

override fun handleMessage(msg: Message) {
            when (msg.what) {
                123 -> {

                     msg.data.classLoader = MyObject::class.java.classLoader
                     val o = msg.data.getParcelable<MyObject>("KEY_MY_OBJECT")
                }
            }
}

. The model in the Server app needs to have the the same package like the Client app

package com.example.androidmessengerclient    
@Parcelize
class MyObject(val name: String, val age: Int) : Parcelable
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜