ฉันพบวิธีการง่าย ๆ & หรูหรา:
- ไม่มีพัสดุ
- ไม่สามารถจัดลำดับได้
- ไม่มีสนามไฟฟ้าสถิต
- ไม่มี Event Bus
วิธีที่ 1
รหัสสำหรับกิจกรรมแรก:
final Object objSent = new Object();
final Bundle bundle = new Bundle();
bundle.putBinder("object_value", new ObjectWrapperForBinder(objSent));
startActivity(new Intent(this, SecondActivity.class).putExtras(bundle));
Log.d(TAG, "original object=" + objSent);
รหัสสำหรับกิจกรรมที่สอง:
final Object objReceived = ((ObjectWrapperForBinder)getIntent().getExtras().getBinder("object_value")).getData();
Log.d(TAG, "received object=" + objReceived);
คุณจะพบobjSent
และobjReceived
มีเหมือนกันhashCode
ดังนั้นจึงเหมือนกัน
แต่ทำไมเราสามารถส่งผ่านวัตถุ java ด้วยวิธีนี้
ที่จริงแล้ว Android binder จะสร้างการอ้างอิง JNI ทั่วโลกสำหรับวัตถุ Java และปล่อยการอ้างอิง JNI ทั่วโลกนี้เมื่อไม่มีการอ้างอิงสำหรับวัตถุ Java นี้ binder จะบันทึกการอ้างอิง JNI ทั่วโลกในวัตถุ Binder
* ข้อควรระวัง: วิธีนี้ใช้ได้เฉพาะกับสองกิจกรรมที่ดำเนินการในกระบวนการเดียวกันมิฉะนั้นให้โยน ClassCastException ที่ (ObjectWrapperForBinder) getIntent (). getExtras (). getBinder ("object_value") *
การกำหนดคลาส ObjectWrapperForBinder
public class ObjectWrapperForBinder extends Binder {
private final Object mData;
public ObjectWrapperForBinder(Object data) {
mData = data;
}
public Object getData() {
return mData;
}
}
วิธีที่ 2
- สำหรับผู้ส่ง
- ใช้วิธีเนทีฟแบบกำหนดเองเพื่อเพิ่มออบเจ็กต์ java ของคุณไปยังตารางอ้างอิงทั่วโลกของ JNI (ผ่าน JNIEnv :: NewGlobalRef)
- ใส่จำนวนเต็มคืน (ที่จริงแล้ว JNIEnv :: NewGlobalRef return jobject ซึ่งเป็นตัวชี้เราสามารถส่งมันไปยัง int อย่างปลอดภัย) เพื่อ Intent ของคุณ (ผ่าน Intent :: putExtra)
- สำหรับผู้รับ
- รับจำนวนเต็มจาก Intent (ผ่าน Intent :: getInt)
- ใช้วิธีเนทีฟแบบกำหนดเองเพื่อกู้คืนอ็อบเจ็กต์ java ของคุณจากตารางอ้างอิงโกลบอล JNI (ผ่าน JNIEnv :: NewLocalRef)
- ลบรายการออกจากตารางอ้างอิงทั่วโลกของ JNI (ผ่าน JNIEnv :: DeleteGlobalRef)
แต่วิธีที่ 2 มีปัญหาเล็กน้อย แต่ร้ายแรงหากผู้รับไม่สามารถกู้คืนออบเจ็กต์ java (ตัวอย่างเช่นมีข้อยกเว้นเกิดขึ้นก่อนที่จะกู้คืนออบเจ็กต์จาวาหรือกิจกรรมที่ผู้รับไม่มีอยู่เลย) จากนั้นวัตถุจาวาจะกลายเป็น เด็กกำพร้าหรือหน่วยความจำรั่ววิธีที่ 1 ไม่มีปัญหานี้เนื่องจาก Android binder จะจัดการข้อยกเว้นนี้
วิธีที่ 3
ในการเรียกใช้อ็อบเจกต์ java จากระยะไกลเราจะสร้าง data contract / interface เพื่ออธิบายอ็อบเจกต์ java เราจะใช้ไฟล์ aidl
IDataContract.aidl
package com.example.objectwrapper;
interface IDataContract {
int func1(String arg1);
int func2(String arg1);
}
รหัสสำหรับกิจกรรมแรก
final IDataContract objSent = new IDataContract.Stub() {
@Override
public int func2(String arg1) throws RemoteException {
// TODO Auto-generated method stub
Log.d(TAG, "func2:: arg1=" + arg1);
return 102;
}
@Override
public int func1(String arg1) throws RemoteException {
// TODO Auto-generated method stub
Log.d(TAG, "func1:: arg1=" + arg1);
return 101;
}
};
final Bundle bundle = new Bundle();
bundle.putBinder("object_value", objSent.asBinder());
startActivity(new Intent(this, SecondActivity.class).putExtras(bundle));
Log.d(TAG, "original object=" + objSent);
รหัสสำหรับกิจกรรมที่สอง:
เปลี่ยน android: attribute attribute ใน AndroidManifest.xml เป็นชื่อกระบวนการที่ไม่ว่างเปล่าเพื่อให้แน่ใจว่ากิจกรรมที่สองทำงานในกระบวนการอื่น
final IDataContract objReceived = IDataContract.Stub.asInterface(getIntent().getExtras().getBinder("object_value"));
try {
Log.d(TAG, "received object=" + objReceived + ", func1()=" + objReceived.func1("test1") + ", func2()=" + objReceived.func2("test2"));
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
ด้วยวิธีนี้เราสามารถผ่านส่วนต่อประสานระหว่างสองกิจกรรมแม้ว่าพวกเขาจะทำงานในกระบวนการที่แตกต่างกันและเรียกวิธีการอินเทอร์เฟซจากระยะไกล
วิธีที่ 4
วิธีที่ 3 ดูไม่ง่ายพอเพราะเราต้องใช้อินเตอร์เฟสช่วยเหลือ หากคุณต้องการทำงานง่ายๆและวิธีการคืนค่าเป็นสิ่งที่ไม่จำเป็นเราสามารถใช้ android.os.Messenger
รหัสสำหรับกิจกรรมแรก (ผู้ส่ง):
public class MainActivity extends Activity {
private static final String TAG = "MainActivity";
public static final int MSG_OP1 = 1;
public static final int MSG_OP2 = 2;
public static final String EXTRA_MESSENGER = "messenger";
private final Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
// TODO Auto-generated method stub
Log.e(TAG, "handleMessage:: msg=" + msg);
switch (msg.what) {
case MSG_OP1:
break;
case MSG_OP2:
break;
default:
break;
}
super.handleMessage(msg);
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
startActivity(new Intent(this, SecondActivity.class).putExtra(EXTRA_MESSENGER, new Messenger(mHandler)));
}
}
รหัสสำหรับกิจกรรมที่สอง (ผู้รับ):
public class SecondActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
final Messenger messenger = getIntent().getParcelableExtra(MainActivity.EXTRA_MESSENGER);
try {
messenger.send(Message.obtain(null, MainActivity.MSG_OP1, 101, 1001, "10001"));
messenger.send(Message.obtain(null, MainActivity.MSG_OP2, 102, 1002, "10002"));
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Messenger.send ทั้งหมดจะดำเนินการในตัวจัดการแบบอะซิงโครนัสและตามลำดับ
ที่จริงแล้ว android.os.Messenger ยังเป็นส่วนต่อประสานช่วยเหลือหากคุณมีซอร์สโค้ด android คุณสามารถค้นหาไฟล์ชื่อ IMessenger.aidl
package android.os;
import android.os.Message;
/** @hide */
oneway interface IMessenger {
void send(in Message msg);
}