繁体   English   中英

修复侦听器保留隐式引用时的活动泄漏

[英]Fix activity leak when listener keeps implicit reference

MessageFeedActivity onCreate方法中,它通过调用CTFeedAPI class 的getMessageTypes方法加载提要。

public class MessageFeedActivity extends AppCompatActivity {
 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);

  //Setting the listener
  CTFeedAPI ctFeedAPI = new CTFeedAPI(new CTFeedAPI.CTFeedAPIListener() {
   @Override
   public void feedAPISuccessListener(Object object) {
    // Handle Success
   }

   @Override
   public void feedAPIErrorListener(int error) {
    // Handle Error
   }
  });

  ctFeedAPI.getMessageTypes();
 }

 @Override
 protected void onDestroy() {
  super.onDestroy();
 }
}

并等待CTFeedAPIListener响应。 CTFeedAPI class make.network 请求通过调用NetworkRequest class 的performRequest方法作为

public class CTFeedAPI implements NetworkListener {
 private CTFeedAPIListener apiListener;

 public CTFeedAPI(CTFeedAPIListener feedAPIListener) {
  apiListener = feedAPIListener;
 }

 public void getMessageTypes() {
  Map < String, String > params = new HashMap < > ();
  params.put("f", "GetMessageTypes");

  NetworkRequest networkRequest = new NetworkRequest(this);
  networkRequest.performRequest();
 }

 public interface CTFeedAPIListener {
  void feedAPISuccessListener(Object object);

  void feedAPIErrorListener(int error);
 }
}

并等待NetworkListener响应

public class NetworkRequest {
 private NetworkListener mListener;

 public interface NetworkListener {

  void networkReqSuccessListener(String cacheKey, String tag, String response);

  void networkReqErrorListener(String tag, int error);
 }
 public NetworkRequest(NetworkListener listener) {
  this.mListener = listener;
 }

 public void performRequest(
  // Perform Network Requests and respond as
  if (mListener != null) {
   if (success) {
    mListener.networkReqSuccessListener(getUrl(), getTag(), response);
   } else {
    mListener.networkReqErrorListener(getTag(), err_msg);
   }
  }
 }

当用户按下返回键时,在销毁 MessageFeedActivity 之前,系统调用 'onDestroy' 方法。 不幸的是,由于后台线程(NetworkRequest 类中的 performRequest 方法)仍然保留对它的引用,因此发生了泄漏。

那么如何在 MessageFeedActivity 中实现CTFeedAPIListener引用来消除泄漏。

在这种设计中,您不仅会泄漏 memory,而且您的代码也会高度耦合并且很难测试; 容易出现难以检测的错误。 我建议您实施 MVP 或类似架构。 你的活动不应该知道任何关于你的网络层的信息。 添加一个表示层,负责代表您的活动请求某些内容,并使用界面更新您的活动。 您的演示者应该访问从存储库层的响应映射的业务实体,该实体负责.network 或 Db 访问并将值返回给客户端演示者。 这样,您的演示者和业务逻辑层将解耦并且易于独立测试。 将来如果业务需求发生变化,您的更改不会影响其他层。 有关该主题的更多信息,请参阅本文

弱引用对象,不阻止其引用对象可终结、终结,然后回收。 弱引用最常用于实现规范化映射。

假设垃圾收集器在某个时间点确定 object 是弱可达的。 届时,它将自动清除对 object 的所有弱引用,以及对任何其他弱可达对象的所有弱引用,而 object 可通过强引用链和软引用链从中访问。 同时,它会声明所有以前的弱可达对象是可终结的。 同时或在稍后的某个时间,它会将那些在引用队列中注册的新清除的弱引用排入队列。

您可以使用弱引用:

import java.lang.ref.WeakReference;

public class NetworkRequest {
 public interface NetworkListener {
      void networkReqSuccessListener(String cacheKey, String tag, String response);
      void networkReqErrorListener(String tag, int error);
 }

 private WeakReference<NetworkListener> mListener;

 public NetworkRequest(NetworkListener listener) {
      this.mListener = new WeakReference<NetworkListener>(listener);
 }

 public void performRequest(){
  // Perform Network Requests and respond as
  NetworkListener listener = mListener.get();
  if (listener != null) {
     if (success) listener.networkReqSuccessListener(getUrl(), getTag(), response);
     else listener.networkReqErrorListener(getTag(), err_msg);
   }
  }
}

public class CTFeedAPI implements NetworkListener {
 private WeakReference<CTFeedAPIListener> apiListener;

 public CTFeedAPI(CTFeedAPIListener feedAPIListener) {
  apiListener = new WeakReference<>(feedAPIListener);
 }

 public void getMessageTypes() {
  Map < String, String > params = new HashMap < > ();
  params.put("f", "GetMessageTypes");

  NetworkRequest networkRequest = new NetworkRequest(this);
  networkRequest.performRequest();
 }

 public interface CTFeedAPIListener {
  void feedAPISuccessListener(Object object);

  void feedAPIErrorListener(int error);
 }
}

CTFeedAPICTFeedAPIListener保存为MessageFeedActivity的实例变量,以防止GC在出现活动时收集它们:

public class MessageFeedActivity extends AppCompatActivity {

private CTFeedAPI ctFeedAPI = null;// keeping a reference to CTFeedAPI
private CTFeedAPIListener listener = null;// keeping a reference to listener
 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);

  //Setting the listener
  listener = new CTFeedAPI.CTFeedAPIListener() {
   @Override
   public void feedAPISuccessListener(Object object) {
    // Handle Success
   }

   @Override
   public void feedAPIErrorListener(int error) {
    // Handle Error
   }
  });
  ctFeedAPI = new CTFeedAPI(listener);
  ctFeedAPI.getMessageTypes();
 }

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM