5

在注册回调轮换后,我在远程服务中遇到了回调问题,导致活动泄漏。你能给我一些建议我做错了什么。

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);
    }

远程服务.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);
        }
    };

}
4

1 回答 1

6

因为有两个进程,所以还涉及两个垃圾收集器。

服务和客户端垃圾收集器。该服务处理小型 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);
        }
    }
}
于 2014-06-25T18:18:53.517 回答