Ich habe eine einfache und elegante Methode gefunden:
- KEIN Paket
- NEIN Serialisierbar
- KEIN statisches Feld
- Kein Ereignisbus
Methode 1
Code für die erste Aktivität:
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);
Code für die zweite Aktivität:
final Object objReceived = ((ObjectWrapperForBinder)getIntent().getExtras().getBinder("object_value")).getData();
Log.d(TAG, "received object=" + objReceived);
Sie werden das gleiche finden objSent
und objReceived
habenhashCode
, so dass sie identisch sind.
Aber warum können wir auf diese Weise ein Java-Objekt übergeben?
Tatsächlich erstellt Android Binder eine globale JNI-Referenz für das Java-Objekt und gibt diese globale JNI-Referenz frei, wenn für dieses Java-Objekt keine Referenz vorhanden ist. Binder speichert diese globale JNI-Referenz im Binder-Objekt.
* VORSICHT: Diese Methode funktioniert NUR, es sei denn, die beiden Aktivitäten werden im selben Prozess ausgeführt. Andernfalls wird ClassCastException unter (ObjectWrapperForBinder) getIntent (). GetExtras (). GetBinder ("object_value") ausgelöst. *
Klasse ObjectWrapperForBinder Definition
public class ObjectWrapperForBinder extends Binder {
private final Object mData;
public ObjectWrapperForBinder(Object data) {
mData = data;
}
public Object getData() {
return mData;
}
}
Methode 2
- für den Absender
- Verwenden Sie eine benutzerdefinierte native Methode, um Ihr Java-Objekt zur globalen JNI-Referenztabelle hinzuzufügen (über JNIEnv :: NewGlobalRef).
- Setzen Sie die Rückgabe-Ganzzahl (eigentlich JNIEnv :: NewGlobalRef return jobject, ein Zeiger, den wir sicher in int umwandeln können) in Ihre Absicht (über Intent :: putExtra).
- für den Empfänger
- Ganzzahl von Intent abrufen (über Intent :: getInt)
- Verwenden Sie eine benutzerdefinierte native Methode, um Ihr Java-Objekt aus der globalen JNI-Referenztabelle wiederherzustellen (über JNIEnv :: NewLocalRef).
- Element aus der globalen JNI-Referenztabelle entfernen (über JNIEnv :: DeleteGlobalRef),
Methode 2 hat jedoch ein kleines, aber schwerwiegendes Problem: Wenn der Empfänger das Java-Objekt nicht wiederherstellen kann (z. B. tritt vor der Wiederherstellung des Java-Objekts eine Ausnahme auf oder die Empfängeraktivität überhaupt nicht vorhanden ist), wird das Java-Objekt zu einem Orphan oder Speicherverlust, Methode 1 hat dieses Problem nicht, da Android Binder diese Ausnahme behandelt
Methode 3
Um das Java-Objekt remote aufzurufen, erstellen wir einen Datenvertrag / eine Datenschnittstelle zur Beschreibung des Java-Objekts. Wir verwenden die Hilfedatei
IDataContract.aidl
package com.example.objectwrapper;
interface IDataContract {
int func1(String arg1);
int func2(String arg1);
}
Code für die erste Aktivität
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);
Code für die zweite Aktivität:
Ändern Sie das android: process-Attribut in AndroidManifest.xml in einen nicht leeren Prozessnamen, um sicherzustellen, dass die zweite Aktivität in einem anderen Prozess ausgeführt wird
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();
}
Auf diese Weise können wir eine Schnittstelle zwischen zwei Aktivitäten übergeben, obwohl diese in unterschiedlichen Prozessen ausgeführt werden, und die Schnittstellenmethode remote aufrufen
Methode 4
Methode 3 scheint nicht einfach genug zu sein, da wir eine Hilfeschnittstelle implementieren müssen. Wenn Sie nur eine einfache Aufgabe ausführen möchten und der Rückgabewert der Methode nicht erforderlich ist, können wir android.os.Messenger verwenden
Code für die erste Aktivität (Absender):
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)));
}
}
Code für die zweite Aktivität (Empfänger):
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();
}
}
}
Alle Messenger.send werden asynchron und sequentiell in einem Handler ausgeführt.
Tatsächlich ist android.os.Messenger auch eine Hilfeschnittstelle. Wenn Sie den Android-Quellcode haben, finden Sie eine Datei mit dem Namen IMessenger.aidl
package android.os;
import android.os.Message;
/** @hide */
oneway interface IMessenger {
void send(in Message msg);
}