我在远程服务中遇到回调问题,在注册回调轮换后导致活动泄漏。你能否给我一些建议我做错了什么。
IRemoteApi.aidl
import com.example.remoteservice.IRemoteListener;
interface IRemoteApi{
void addListener(IRemoteListener listener);
void removeListener(IRemoteListener listener);
void sendRequest(String msg);
}
IRemoteListener.aidl
interface IRemoteListener {
void onMessage(String text);
}
RemoteService.java
public class RemoteService extends Service {
private static final String TAG = RemoteService.class.getSimpleName();
final RemoteCallbackList<IRemoteListener> mCallbacks = new RemoteCallbackList<IRemoteListener>();
@Override
public void onCreate() {
super.onCreate();
Log.e(TAG, "Create service...");
}
@Override
public void onDestroy() {
super.onDestroy();
mCallbacks.kill();
}
private void dumpMethod(String msg){
if(msg.equals("OK")){
final int N = mCallbacks.beginBroadcast();
for (int i=0; i<N; i++) {
try {
mCallbacks.getBroadcastItem(i).onMessage("Voila!");
} catch (RemoteException e) {}
}
mCallbacks.finishBroadcast();
}
}
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
private IRemoteApi.Stub mBinder = new IRemoteApi.Stub() {
@Override
public void addListener(IRemoteListener listener) throws RemoteException {
if (listener != null) mCallbacks.register(listener);
}
@Override
public void removeListener(IRemoteListener listener) throws RemoteException {
if (listener != null) mCallbacks.unregister(listener);
}
@Override
public void sendRequest(String msg) throws RemoteException {
dumpMethod(msg);
}
};
}
MainActivity.java
public class MainActivity extends ActionBarActivity {
private static final String TAG = MainActivity.class.getSimpleName();
IRemoteApi mService;
boolean isBound = false;
private ServiceConnection mServiceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mService = IRemoteApi.Stub.asInterface(service);
isBound = true;
Log.e("merhold", "Bound to service");
try {
mService.addListener(serviceListener);
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
getApplicationContext().startService(new Intent(RemoteService.class.getName()));
getApplicationContext().bindService(new Intent(RemoteService.class.getName()), mServiceConnection, Context.BIND_AUTO_CREATE);
}
@Override
protected void onDestroy() {
super.onDestroy();
if(isBound){
try {
mService.removeListener(serviceListener);
getApplicationContext().unbindService(mServiceConnection);
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
public void sendRequest(View view) {
try {
mService.sendRequest("OK");
} catch (RemoteException e) {
e.printStackTrace();
}
}
private IRemoteListener serviceListener = new IRemoteListener.Stub(){
@Override
public void onMessage(String text) throws RemoteException {
Log.e(TAG, "Message from listener: "+text);
}
};
}
答案 0 :(得分:5)
因为有两个进程,所以还有两个垃圾收集器。
服务和客户端垃圾收集器。该服务处理小型IBinder 对象(IRemoteListener)对垃圾快速收集并不那么重要。来自客户 这些IBinder对象包含对大活动的引用。
在服务收集垃圾之前,活动不能被垃圾收集 IBinder对象因此会泄露直到发生这种情况。解决方案是改变 监听器进入静态内部类。如果您想访问活动中的某些内容 你必须使用弱引用。
以下是Dianne Hackborn的相关问题和解释; https://stackoverflow.com/a/12206516/1035854
一些代码:
private static class MyRemoteListener extends IRemoteListener.Stub {
private final WeakReference<Activity> mWeakActivity;
public MyRemoteListener(Activity activity) {
mWeakActivity = new WeakReference<Activity>(activity);
}
@Override
public void onMessage(String text) throws RemoteException {
Activity activity = mWeakActivity.get();
if (activity != null) {
// ((MainActivity)activity).handleOnMessage(text);
}
}
}