远程服务,旋转时泄漏活动 [英] Remote service, leaks activity when rotating

查看:251
本文介绍了远程服务,旋转时泄漏活动的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在注册回调循环导致活动泄漏后,远程服务中的回调存在问题.您能给我一些建议吗,我在做错什么.

I've got a problem with a callbacks in remote service, after register a callback rotation cause an activity leak. Can You give me some suggestion what I'm doing wrong.

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

}

推荐答案

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

Because there are two processes there are also two garbage collectors involved.

服务和客户端垃圾收集器.服务处理小IBinder 对垃圾收集不是很重要的对象(IRemoteListener)可以快速收集.来自客户 这些IBinder对象拥有对大型活动的引用.

The service and client garbage collector. The service handles small IBinder objects (IRemoteListener) which are not so important to garbage collect fast. From the client side these IBinder objects holds a reference to an activity which is big.

在服务对垃圾桶进行垃圾收集之前,无法对垃圾收集器进行活动 IBinder对象,因此它将被泄漏,直到发生这种情况.解决方案是更改 侦听器转换为静态内部类.如果您想访问活动中的某些内容 您必须使用弱引用.

The activity can't be garbage collected until the service have garbage collected the IBinder objects so it will be leaked until that happens. The solution is to change the listener into a static inner class. If you want to access something in the activity you have to use a weak reference.

以下是相关问题和戴安娜·哈克伯恩(Dianne Hackborn)的解释; https://stackoverflow.com/a/12206516/1035854

Here's a related question and an explanation by 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);
        }
    }
}

这篇关于远程服务,旋转时泄漏活动的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆