Tôi tìm thấy một phương pháp đơn giản và thanh lịch:
- KHÔNG có bưu kiện
- KHÔNG nối tiếp
- KHÔNG trường tĩnh
- Không có xe buýt sự kiện
Phương pháp 1
Mã cho hoạt động đầu tiên:
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);
Mã cho hoạt động thứ hai:
final Object objReceived = ((ObjectWrapperForBinder)getIntent().getExtras().getBinder("object_value")).getData();
Log.d(TAG, "received object=" + objReceived);
bạn sẽ tìm thấy objSent
và objReceived
có cùnghashCode
, vì vậy chúng giống hệt nhau.
Nhưng tại sao chúng ta có thể vượt qua một đối tượng java theo cách này?
Trên thực tế, binder android sẽ tạo tham chiếu JNI toàn cầu cho đối tượng java và phát hành tham chiếu JNI toàn cầu này khi không có tham chiếu cho đối tượng java này. Binder sẽ lưu tham chiếu JNI toàn cầu này trong đối tượng Binder.
* THẬN TRỌNG: phương pháp này CHỈ hoạt động trừ khi hai hoạt động chạy trong cùng một quy trình, nếu không thì ném ClassCastException vào (ObjectWrapperForBinder) getIntent (). GetExtras (). GetBinder ("object_value") *
lớp định nghĩa ObjectWrapperForBinder
public class ObjectWrapperForBinder extends Binder {
private final Object mData;
public ObjectWrapperForBinder(Object data) {
mData = data;
}
public Object getData() {
return mData;
}
}
Cách 2
- cho người gửi
- sử dụng phương thức gốc tùy chỉnh để thêm đối tượng java của bạn vào bảng tham chiếu toàn cầu JNI (thông qua JNIEnv :: NewGlobalRef)
- đặt số nguyên trả về (thực ra là JNIEnv :: NewGlobalRef công việc trả về, là một con trỏ, chúng ta có thể chuyển nó thành int một cách an toàn) cho Intent của bạn (thông qua Intent :: putExtra)
- cho người nhận
- lấy số nguyên từ Intent (thông qua Intent :: getInt)
- sử dụng phương thức gốc tùy chỉnh để khôi phục đối tượng java của bạn từ bảng tham chiếu toàn cầu JNI (thông qua JNIEnv :: NewLocalRef)
- xóa mục khỏi bảng tham chiếu toàn cầu của JNI (thông qua JNIEnv :: DeleteGlobalRef),
Nhưng Phương thức 2 có một vấn đề nhỏ nhưng nghiêm trọng, nếu người nhận không khôi phục được đối tượng java (ví dụ: một số ngoại lệ xảy ra trước khi khôi phục đối tượng java hoặc Hoạt động của người nhận hoàn toàn không tồn tại), thì đối tượng java sẽ trở thành Trẻ mồ côi hoặc rò rỉ bộ nhớ, Phương pháp 1 không có vấn đề này, vì trình kết nối Android sẽ xử lý ngoại lệ này
Phương pháp 3
Để gọi đối tượng java từ xa, chúng tôi sẽ tạo một hợp đồng / giao diện dữ liệu để mô tả đối tượng java, chúng tôi sẽ sử dụng tệp hỗ trợ
IDataContract.aidl
package com.example.objectwrapper;
interface IDataContract {
int func1(String arg1);
int func2(String arg1);
}
Mã cho hoạt động đầu tiên
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);
Mã cho hoạt động thứ hai:
thay đổi thuộc tính android: process trong AndroidManifest.xml thành tên quy trình không trống để đảm bảo hoạt động thứ hai chạy trong quy trình khác
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();
}
Theo cách này, chúng ta có thể chuyển giao diện giữa hai hoạt động mặc dù chúng chạy trong quy trình khác nhau và gọi phương thức giao diện từ xa
Phương pháp 4
Phương pháp 3 dường như không đủ đơn giản vì chúng ta phải thực hiện giao diện viện trợ. Nếu bạn chỉ muốn thực hiện tác vụ đơn giản và giá trị trả về của phương thức là không cần thiết, chúng ta có thể sử dụng android.os.Mesbah
Mã cho hoạt động đầu tiên (người gửi):
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)));
}
}
Mã cho hoạt động thứ hai (người nhận):
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();
}
}
}
Tất cả Messenger.send sẽ thực thi trong Trình xử lý không đồng bộ và tuần tự.
Trên thực tế, android.os.Mesbah cũng là một giao diện hỗ trợ, nếu bạn có mã nguồn Android, bạn có thể tìm thấy một tệp có tên IMesbah.aidl
package android.os;
import android.os.Message;
/** @hide */
oneway interface IMessenger {
void send(in Message msg);
}