Я знайшов простий і елегантний метод:
- НЕ Розділяється
- НЕ Серіалізується
- НЕТ статичного поля
- Немає автобусів подій
Спосіб 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 таким чином?
Насправді, андроїдне в'яжуче створить глобальну посилання 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)
- покладіть ціле число return (власне, JNIEnv :: NewGlobalRef return taskject, який є вказівником, ми можемо передати його до int безпечно) у свій намір (через Intent :: putExtra)
- для приймача
- отримати ціле число від наміру (через Intent :: getInt)
- використовувати власний нативний метод для відновлення вашого об'єкта Java з глобальної довідкової таблиці JNI (через JNIEnv :: NewLocalRef)
- видалити елемент із глобальної довідкової таблиці JNI (через JNIEnv :: DeleteGlobalRef),
Але у способу 2 є невелика, але серйозна проблема, якщо приймач не зможе відновити об'єкт java (наприклад, якийсь виняток трапиться до відновлення об'єкта java, або активність приймача взагалі не існує), то об'єкт java стане сирота або витік пам’яті, метод 1 не має цієї проблеми, оскільки андроїдне в’яжуче обробляє цей виняток
Спосіб 3
Для віддаленого виклику об’єкта java ми створимо контракт / інтерфейс даних для опису об’єкта java, використовуємо файл helpl
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: process в 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);
}