2016-07-19 13 views
0

Ich verwende eine beibehaltenDialogFragment, die einen Fortschrittsdialog während einer TCP-Verbindung in einer AsyncTask ausgeführt. Die AsyncTask wird in der Methode onStart() von fragmebt ausgeführt und entweder abgebrochen, wenn die DialogFragment abgebrochen wird, oder in der onStop()-Methode des Fragments.Wann stoppen Sie eine AsyncTask in einem beibehaltenen DialogFragment?

Wenn meine Aufgabe abgeschlossen ist (d. H. TCP-Verbindung ist hergestellt oder fehlgeschlagen), oder abgebrochen wird, beende ich den Dialog mit der Methode dismiss().

Das Problem ist, wenn ich "Home" drücke, wenn die AsyncTask ausgeführt wird. In diesem Fall wird das Fragment onStop() Methode aufgerufen, die die AsyncTask storniert, und versuchen, den Dialog zu schließen, aber dann bekomme ich die folgende Fehlermeldung:

java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState 

Ich sah es ein Verfahren dismissAllowingStateLoss() benannt ist, die diese Ausnahme vermeiden aber ich bin mir nicht sicher, ob es die beste Lösung ist, ich möchte nicht, dass es ein Problem "versteckt".

Das erwartete Verhalten ist das folgende: Wenn der Benutzer die Aktivität verlässt, möchte ich die Verbindung abbrechen, deshalb stoppe ich es in onStop(). Hier

ist der Fragment-Code als Referenz:

public class TcpConnectionFragment extends DialogFragment { 

    private static final Logger logger = LoggerFactory.getLogger(TcpConnectionFragment.class); 

    private TcpConnectionTask connectionTask; 
    private String host; 
    private int port; 

    public static TcpConnectionFragment newInstance(String host, int port) { 
     Bundle bundle = new Bundle(); 
     bundle.putString("ADDRESS", host); 
     bundle.putInt("PORT", port); 
     TcpConnectionFragment fragment = new TcpConnectionFragment(); 
     fragment.setArguments(bundle); 
     return fragment; 
    } 

    private void startAsyncTask() { 
     logger.info("Starting asynchronous connection task"); 
     connectionTask = new TcpConnectionTask(this, host, port); 
     connectionTask.execute(); 
    } 

    private void stopAsyncTask() { 
     if (connectionTask == null) 
      return; 
     logger.info("Stopping asynchronous connection task"); 
     connectionTask.cancel(false); 
     try { 
      SocketChannel channel = connectionTask.getSocketChannel(); 
      if (channel != null) 
       channel.close(); 
     } catch (IOException ignored) { 
      // We don't care about this error here, we can't recover. 
     } 
    } 

    public TcpConnectionFragment() { 
     super(); 
    } 

    @Override 
    public void onCreate(@Nullable Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setRetainInstance(true); 
     if (getArguments() == null) 
      throw new IllegalArgumentException("Missing arguments"); 
     host = getArguments().getString("ADDRESS"); 
     port = getArguments().getInt("PORT"); 
    } 

    @Override 
    public void onActivityCreated(@Nullable Bundle savedInstanceState) { 
     super.onActivityCreated(savedInstanceState); 
    } 

    @NonNull 
    @Override 
    public Dialog onCreateDialog(Bundle savedInstanceState) { 
     return new MaterialDialog.Builder(getContext()) 
      .title(R.string.tcp_connect_dialog_title) 
      .content(R.string.tcp_connect_dialog_text, host, port) 
      .progress(true, 0) 
      .build(); 
    } 

    @Override 
    public void onStart() { 
     super.onStart(); 
     startAsyncTask(); 
    } 

    @Override 
    public void onStop() { 
     super.onStop(); 
     stopAsyncTask(); 
    } 

    @Override 
    public void onCancel(DialogInterface dialog) { 
     super.onCancel(dialog); 
     logger.info("Cancelled dialog."); 
     stopAsyncTask(); 
    } 

    /** 
    * This override is required to avoid a bug in the support library. 
    */ 
    @Override 
    public void onDestroyView() { 
     if (getDialog() != null && getRetainInstance()) 
      getDialog().setDismissMessage(null); 
     super.onDestroyView(); 
    } 

    /** 
    * Called by the {@link TcpConnectionTask} once connected. 
    * 
    * @param transport The transport created during the conenction. 
    */ 
    void onConnected(Transport transport) { 
     connectionTask = null; 
     dismiss(); 
    } 

    /** 
    * Called by the {@link TcpConnectionTask} once the connection is cancelled. 
    */ 
    void onConnectionCancelled() { 
     connectionTask = null; 
     dismiss(); 
    } 

    /* 
    * Called by the {@link TcpConnectionTask} if an error occurs during the connection. 
    */ 
    void onConnectionError(Exception error) { 
     connectionTask = null; 
     dismiss(); 
     if (getParentFragment() == null || getParentFragment().getView() == null) 
      return; 
     Snackbar.make(getParentFragment().getView().findViewById(R.id.frame_layout), 
       "Error: " + error.getMessage(), Snackbar.LENGTH_LONG).show(); 
    } 

} 

Antwort

0

Versuchen zu entlassen anrufen aus onPause() statt. Das sollte es tun.

prüfen die DialogFragment Diagramm von diesem Faden aus: In a DialogFragment, what should onCreate do?

Beispiel für die Rücknahme Rückruf:

mCancelObj = new CancellationObject(); 
new AsyncTask<Void, Void, Void>() {  
    // do something 
    // whenFinished check if !mCancelObj.isCancelled -> dialog.dismiss(); 
}.execute(); 

void onPause(){ 
mCancelObj.cancel(); 
} 
+0

Derzeit nennen I() von AsyncTask Rückrufe entlassen, was bedeutet, I zu entlassen(), um den Dialog, wenn te Verbindung wurde hergestellt, abgebrochen oder ein Fehler ist aufgetreten. Wenn ich es in onPause() tue, wird es für den Pausenfall funktionieren, aber ich könnte immer noch Probleme haben, wenn die Aufgabe zum gleichen Zeitpunkt beendet wird, wenn der Benutzer Home drückt, nein? –

+0

In diesem Fall würde ich ein Abbruchobjekt übergeben, das innerhalb der asynctask abgebrochen werden kann, so dass es möglich ist, etwas zu bereinigen, falls das Fragment stoppt. Ich benutze Bolts Tasks, das ist eine großartige Bibliothek zum Ausführen von asynchronen Aufgaben mit Abbruchobjekten. Überprüfen Sie es hier, wenn Sie es noch nicht wissen: https://github.com/BoltsFramework/Bolts-Android – miqueloi

+0

Es gibt keine Möglichkeit zu überprüfen, ob das Fragment in einem "gültigen" Zustand im Callback ist? Um zu überprüfen, ob kill() sicher aufgerufen werden kann? Wenn ich es vermeiden kann, eine riesige Bibliothek zu benutzen, wäre es gut :-) –