간단하고 우아한 방법을 찾았습니다.
- 소포 없음
- 직렬화 불가능
- 정적 필드 없음
- 이벤트 버스 없음
방법 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 참조를 생성하고이 자바 객체에 대한 참조가 없을 때이 글로벌 JNI 참조를 해제합니다. 바인더는이 글로벌 JNI 참조를 바인더 오브젝트에 저장합니다.
*주의 :이 메소드는 두 활동이 동일한 프로세스에서 실행되지 않는 한 작동합니다. 그렇지 않으면 (ObjectWrapperForBinder) getIntent (). getExtras (). getBinder ( "object_value")에서 ClassCastException을 발생시킵니다.
ObjectWrapperForBinder 정의 클래스
public class ObjectWrapperForBinder extends Binder {
private final Object mData;
public ObjectWrapperForBinder(Object data) {
mData = data;
}
public Object getData() {
return mData;
}
}
방법 2
- 발신자에게
- 사용자 정의 원시 메소드를 사용하여 JNI 글로벌 참조 테이블에 Java 오브젝트를 추가하십시오 (JNIEnv :: NewGlobalRef를 통해)
- 반환 정수를 넣습니다 (실제로 JNIEnv :: NewGlobalRef 반환 jobject, 포인터입니다, 안전하게 int로 캐스트 할 수 있습니다) intent (Intent :: putExtra를 통해)
- 수신기
- Intent에서 정수 가져 오기 (Intent :: getInt를 통해)
- JNI 글로벌 참조 테이블에서 JNIEnv :: NewLocalRef를 통해 Java 오브젝트를 복원하려면 사용자 정의 고유 메소드 사용
- JNI 글로벌 참조 테이블에서 항목 제거 (JNIEnv :: DeleteGlobalRef를 통해),
그러나 방법 2에는 수신자가 java 오브젝트를 복원하지 못하면 (예를 들어, java 오브젝트를 복원하기 전에 일부 예외가 발생하거나 수신자 활동이 전혀 존재하지 않는 경우) 약간의 심각한 문제가 있습니다. 그러면 java 오브젝트는 안드로이드 바인더 가이 예외를 처리하기 때문에 고아 또는 메모리 누수, 방법 1에는이 문제가 없습니다
방법 3
java 객체를 원격으로 호출하기 위해 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);
두 번째 활동을위한 코드 :
두 번째 활동이 다른 프로세스에서 실행되도록 AndroidManifest.xml의 android : process 속성을 비어 있지 않은 프로세스 이름으로 변경하십시오.
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는 Handler에서 비동기 적으로 순차적으로 실행됩니다.
실제로 android.os.Messenger는 보조 인터페이스입니다 .Android 소스 코드가 있으면 IMessenger.aidl이라는 파일을 찾을 수 있습니다.
package android.os;
import android.os.Message;
/** @hide */
oneway interface IMessenger {
void send(in Message msg);
}