Mer*_*old 5 service android memory-leaks callback aidl
在注册回调轮换导致活动泄漏后,我在远程服务中遇到了回调问题.你能给我一些建议吗我做错了什么.
IRemoteApi.aidl
import com.example.remoteservice.IRemoteListener;
interface IRemoteApi{
void addListener(IRemoteListener listener);
void removeListener(IRemoteListener listener);
void sendRequest(String msg);
}
Run Code Online (Sandbox Code Playgroud)
IRemoteListener.aidl
interface IRemoteListener {
void onMessage(String text);
}
Run Code Online (Sandbox Code Playgroud)
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);
}
};
}
Run Code Online (Sandbox Code Playgroud)
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);
}
};
}
Run Code Online (Sandbox Code Playgroud)
因为有两个进程,所以还涉及两个垃圾收集器.
服务和客户端垃圾收集器.该服务处理小型IBinder对象(IRemoteListener),这对快速垃圾收集并不重要.从客户端来看,这些IBinder对象包含对大活动的引用.
在服务有垃圾收集IBinder对象之前,活动不能被垃圾收集,因此它将被泄露直到发生这种情况.解决方案是将侦听器更改为静态内部类.如果要访问活动中的某些内容,则必须使用弱引用.
这是Dianne Hackborn的一个相关问题和解释; /sf/answers/854456151/
一些代码:
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);
}
}
}
Run Code Online (Sandbox Code Playgroud)