Исправить утечку активности, когда слушатель сохраняет неявную ссылку - PullRequest
2 голосов
/ 24 апреля 2020

В методе MessageFeedActivity onCreate он загружает каналы, вызывая getMessageTypes метод CTFeedAPI класса.

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 класс делает сетевой запрос, вызывая executeRequest метод NetworkRequest класса как

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 response

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». И, к сожалению, поскольку фоновый поток (метод executeRequest в классе NetworkRequest) по-прежнему сохраняет ссылку на него, возникает утечка.

Итак, как реализовать ссылку CTFeedAPIListener в MessageFeedActivity для устранения утечки.

Ответы [ 2 ]

2 голосов
/ 24 апреля 2020

В этом проекте не только вы потеряете память, но и ваш код будет сильно связан и очень сложен для тестирования; склонны к ошибкам, которые трудно обнаружить. Я бы предложил вам реализовать MVP или аналогичную архитектуру. Ваша деятельность никогда не должна знать ничего о вашем сетевом уровне. Добавьте слой докладчика, который отвечает за запрос чего-либо от имени вашей деятельности, и используйте интерфейс для обновления вашей активности. Ваш докладчик должен получить доступ к бизнес-объекту, который сопоставлен с ответом уровня хранилища, который отвечает за доступ к сети или базе данных и возвращает значения представителю клиента. Таким образом, слои вашего докладчика и бизнес-логики c будут отделены и легко протестированы независимо. В будущем, если бизнес-требования изменятся, ваши изменения не затронут другие уровни. Пожалуйста, смотрите эту статью для получения дополнительной информации по теме .

1 голос
/ 03 мая 2020

Слабые ссылочные объекты, которые не мешают делать их референты финализируемыми, финализированными и затем возвращаемыми. Слабые ссылки чаще всего используются для реализации канонизирующих отображений.

Предположим, что сборщик мусора в определенный момент времени определяет, что объект слабо доступен. В это время он будет атомарно очищать все слабые ссылки на этот объект и все слабые ссылки на любые другие слабо достижимые объекты, из которых этот объект доступен через цепочку сильных и мягких ссылок. В то же время он объявит, что все ранее слабо достижимые объекты были завершены. В то же время или в более позднее время он будет ставить в очередь те недавно очищенные слабые ссылки, которые зарегистрированы в очередях ссылок.

Вы можете использовать Слабую ссылку:

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

сохранить CTFeedAPI и CTFeedAPIListener в качестве переменной экземпляра 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();
 }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...