2013-08-14 13 views
6

Mój statyczny nośnik ma WeakReference do mojego Activity (ma to zapobiec dobrze udokumentowanemu problemowi wycieku pamięci).Android Handler zmiana WeakReference

Wysyłam długi, opóźniony komunikat i chcę, aby ta wiadomość została dostarczona do mojej aktywności (która powinna znajdować się na pierwszym planie).

Moją obawą jest to, że podczas zmiany orientacji moja działalność ulega zniszczeniu, a przewodnik ma odniesienie do starej działalności, która powinna zostać zniszczona.

Aby to zrobić w moim onCreate dla tego działania, robię to.

if(mHandler == null) 
     mHandler = new LoginHandler(this); 
    else { 
     mHandler.setTarget(this); 
    } 

A moja obsługi jest zadeklarowana jako statyczna zmienna globalna:

private static LoginHandler  mHandler   = null; 

i klasy wykonawczego jest statyczna jak poniżej:

private static class LoginHandler extends Handler { 

    private WeakReference<LoginActivity> mTarget; 

    LoginHandler(LoginActivity target) { 
     mTarget = new WeakReference<LoginActivity>(target); 
    } 

    public void setTarget(LoginActivity target) { 
     mTarget = new WeakReference<LoginActivity>(target); 
    } 

    @Override 
    public void handleMessage(Message msg) { 
     // process incoming messages here 
     LoginActivity activity = mTarget.get(); 
     switch (msg.what) { 
      case Constants.SUCCESS: 
       activity.doSomething(); 
       break; 

      default: 
       activity.setStatusMessage("failed " + msg.obj, STATUS_TYPE_DONE); 
     } 
    } 
} 

Co chcę wiedzieć jest, jeśli jest coś złego w zmianie WeakReference na onCreate lub jest coś jeszcze nie tak z tym podejściem?

Dzięki,

+0

@CommonsWare jakąkolwiek opinię na ten temat? – Ali

Odpowiedz

5

Więc napisałem następujący test, aby dowiedzieć się, czy miałem rację, czy nie i wydaje się, że m podejście jest poprawne. W onCreate zmieniamy WeakReference, a wysłana wiadomość zawsze zostanie dostarczona do działania, które jest na pierwszym planie. Jeśli zmienisz ten kod, aby zawsze tworzyć nowy Handler w onCreate, zauważysz, że wiadomości aktualizacji nie zostaną dostarczone.

public class MainActivity extends Activity { 

    private static int COUNT = 0; 

    static LoginHandler mHandler; 

    private static class LoginHandler extends Handler { 

     private WeakReference<MainActivity> mTarget; 

     LoginHandler(MainActivity target) { 
      mTarget = new WeakReference<MainActivity>(target); 
     } 

     public void setTarget(MainActivity target) { 
      mTarget.clear(); 
      mTarget = new WeakReference<MainActivity>(target); 
     } 

     @Override 
     public void handleMessage(Message msg) { 
      // int duration = Toast.LENGTH_LONG; 
      // process incoming messages here 
      MainActivity activity = mTarget.get(); 
      activity.update(msg.arg1); 
     } 
    } 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.activity_main); 

     if(mHandler == null) 
      mHandler = new LoginHandler(this); 
     else 
      mHandler.setTarget(this); 

     ((Button)findViewById(R.id.button)).setOnClickListener(new View.OnClickListener() { 

      @Override 
      public void onClick(View v) { 
       Message msg = new Message(); 
       msg.arg1 = COUNT++; 
       mHandler.sendMessageDelayed(msg, 3000); 

      } 
     }); 

    } 

    @Override 
    public boolean onCreateOptionsMenu(Menu menu) { 
     // Inflate the menu; this adds items to the action bar if it is present. 
     getMenuInflater().inflate(R.menu.main, menu); 
     return true; 
    } 

    private void update(int count) { 
     ((TextView) findViewById(R.id.hello_world)).setText("Hello World @ "+ count); 
    } 

} 
0

Rozwiązaniem problemu ucieczki z działalnością niszczenia i tworzenia cyklu życia, jeśli chcesz zatrzymać aktywne obiekty, jest skorzystanie z "Fragmentów retencji".

Pomysł jest prosty, mówisz systemowi Android, aby "zatrzymał" twój fragment, gdy jego powiązane działanie jest niszczone i ponownie tworzone. I upewnij się, że pobieramy kontekst bieżącego działania w podpowiedzi onAttach() fragmentu, więc zawsze aktualizujesz poprawną aktywność.

poniższego linku ma więcej szczegółów: http://www.androiddesignpatterns.com/2013/04/retaining-objects-across-config-changes.html