远程服务,旋转时泄漏活动

时间:2013-11-12 17:53:00

标签: android service callback memory-leaks aidl

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

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

}

1 个答案:

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