¿Cómo manejar el cambio de orientación de la pantalla cuando el diálogo de progreso y el hilo de fondo están activos?


Mi programa realiza alguna actividad de red en un hilo en segundo plano. Antes de comenzar, aparece un cuadro de diálogo de progreso. El diálogo se descarta en el controlador. Todo esto funciona bien, excepto cuando la orientación de la pantalla cambia mientras el diálogo está activo (y el hilo de fondo está en marcha). En este punto, la aplicación se bloquea, o se bloquea, o entra en una etapa extraña en la que la aplicación no funciona hasta que todos los hilos han sido asesinados.

¿Cómo puedo manejar el cambio de orientación de la pantalla con gracia?

El siguiente código de ejemplo coincide aproximadamente con lo que hace mi programa real:

public class MyAct extends Activity implements Runnable {
    public ProgressDialog mProgress;

    // UI has a button that when pressed calls send

    public void send() {
         mProgress = ProgressDialog.show(this, "Please wait", 
                      "Please wait", 
                      true, true);
        Thread thread = new Thread(this);
        thread.start();
    }

    public void run() {
        Thread.sleep(10000);
        Message msg = new Message();
        mHandler.sendMessage(msg);
    }

    private final Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            mProgress.dismiss();
        }
    };
}

Pila:

E/WindowManager(  244): Activity MyAct has leaked window com.android.internal.policy.impl.PhoneWindow$DecorView@433b7150 that was originally added here
E/WindowManager(  244): android.view.WindowLeaked: Activity MyAct has leaked window com.android.internal.policy.impl.PhoneWindow$DecorView@433b7150 that was originally added here
E/WindowManager(  244):     at android.view.ViewRoot.<init>(ViewRoot.java:178)
E/WindowManager(  244):     at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:147)
E/WindowManager(  244):     at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:90)
E/WindowManager(  244):     at android.view.Window$LocalWindowManager.addView(Window.java:393)
E/WindowManager(  244):     at android.app.Dialog.show(Dialog.java:212)
E/WindowManager(  244):     at android.app.ProgressDialog.show(ProgressDialog.java:103)
E/WindowManager(  244):     at android.app.ProgressDialog.show(ProgressDialog.java:91)
E/WindowManager(  244):     at MyAct.send(MyAct.java:294)
E/WindowManager(  244):     at MyAct$4.onClick(MyAct.java:174)
E/WindowManager(  244):     at android.view.View.performClick(View.java:2129)
E/WindowManager(  244):     at android.view.View.onTouchEvent(View.java:3543)
E/WindowManager(  244):     at android.widget.TextView.onTouchEvent(TextView.java:4664)
E/WindowManager(  244):     at android.view.View.dispatchTouchEvent(View.java:3198)

He intentado descartar el diálogo de progreso en onaveinstancestate, pero eso solo evita un bloqueo inmediato. El hilo de fondo todavía está en marcha, y la interfaz de usuario está en estado parcialmente dibujado. Necesidad de matar a toda la aplicación antes de que comience a funcionar de nuevo.

Author: Alex Lockwood, 2009-07-11

26 answers

Al cambiar de orientación, Android creará una nueva vista. Es probable que tengas bloqueos porque tu subproceso en segundo plano está tratando de cambiar el estado del anterior. (También puede estar teniendo problemas porque su subproceso en segundo plano no está en el subproceso de interfaz de usuario)

Sugeriría hacer que mHandler sea volátil y actualizarlo cuando cambie la orientación.

 144
Author: haseman,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-07-12 19:34:27

Edit: Los ingenieros de Google no recomiendan este enfoque, como lo describe Dianne Hackborn (también conocido como hackbod ) en este StackOverflow post. Salida esta entrada del blog para más información.


Tienes que añadir esto a la declaración de actividad en el manifiesto:

android:configChanges="orientation|screenSize"

Así que parece que

<activity android:label="@string/app_name" 
        android:configChanges="orientation|screenSize|keyboardHidden" 
        android:name=".your.package">

La cuestión es que el sistema destruye la actividad cuando se produce un cambio en la configuración. Ver ConfigurationChanges.

Así que poner eso en el archivo de configuración evita que el sistema destruya tu actividad. En su lugar invoca el método onConfigurationChanged(Configuration).

 256
Author: sonxurxo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:10:30

Se me ocurrió una solución sólida como una roca para estos problemas que se ajusta a la 'Forma Android' de las cosas. Tengo todas mis operaciones de larga duración usando el patrón IntentService.
Eso es mis actividades de difusión intents, el IntentService hace el trabajo, guarda los datos en la base de datos y luego difunde STICKY intents.
La parte pegajosa es importante, de tal manera que incluso si la Actividad se detuvo durante durante el tiempo después de que el usuario inició el trabajo y pierde la transmisión en tiempo real desde el ItentService todavía podemos responder y recoger los datos de la actividad de llamada.
ProgressDialogs puede trabajar en este patrón bastante bien con onSaveInstanceSate().
Básicamente, debe guardar un indicador de que tiene un diálogo de progreso que se ejecuta en el paquete de instancias guardadas. NO guarde el objeto de diálogo de progreso porque esto filtrará toda la actividad.
Para tener un identificador persistente en el diálogo de progreso, lo almaceno como una referencia débil en el objeto de la aplicación.
En cambio de orientación o cualquier otra cosa eso hace que la Actividad se detenga (llamada telefónica, el usuario golpea inicio, etc.) y luego se reanude, descarto el diálogo anterior y recreo un nuevo diálogo en la actividad recién creada.
Para diálogos de progreso indefinidos esto es fácil. Para el estilo de la barra de progreso, debe poner el último progreso conocido en el paquete y cualquier información que esté utilizando localmente en la actividad para realizar un seguimiento del progreso.
Al restaurar el progreso, usarás esta información para volver a generar la barra de progreso en el mismo estado que antes y luego actualizar en función del estado actual de las cosas.
Así que para resumir, poner tareas de larga duración en un IntentService junto con el uso juidcious de onSaveInstanceState() le permite realizar un seguimiento eficiente de los diálogos y restaurar luego a través de los eventos del ciclo de vida de la actividad. Los bits relevantes del código de actividad están a continuación. También necesitarás lógica en tu BroadcastReceiver para manejar los intentos pegajosos apropiadamente, pero eso está más allá del alcance de esto.

   public void doSignIn(View view) {
        waiting=true;
        AppClass app=(AppClass) getApplication();
        String logingon=getString(R.string.signon);
        app.Dialog=new WeakReference<ProgressDialog>(ProgressDialog.show(AddAccount.this, "", logingon, true));
..}


@Override
    protected void onSaveInstanceState(Bundle saveState) {
        super.onSaveInstanceState(saveState);
        saveState.putBoolean("waiting",waiting);
    }

    @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            if(savedInstanceState!=null) {
                restoreProgress(savedInstanceState);

            }
...}


private void restoreProgress(Bundle savedInstanceState) {
        waiting=savedInstanceState.getBoolean("waiting");
        if (waiting) {
            AppClass app=(AppClass) getApplication();
            ProgressDialog refresher=(ProgressDialog) app.Dialog.get();
            refresher.dismiss();
            String logingon=getString(R.string.signon);
            app.Dialog=new WeakReference<ProgressDialog>(ProgressDialog.show(AddAccount.this, "", logingon, true));



        }

    }
 63
Author: jfelectron,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-04-12 08:32:39

Me encontré con el mismo problema. Mi actividad necesita analizar algunos datos de una URL y es lenta. Así que creo un hilo para hacerlo y luego mostrar un progressdialog. Dejo que el hilo publique un msg de nuevo en el hilo de la interfaz de usuario a través del Controlador cuando haya terminado. En Handler.handleMessage, obtengo el objeto de datos (listo ahora) de thread y lo lleno a UI. Así que es muy similar a su ejemplo.

Después de muchos ensayos y errores, parece que encontré una solución. Al menos ahora puedo rotar la pantalla en cualquier momento, antes o después el hilo está hecho. En todas las pruebas, el diálogo se cierra correctamente y todos los comportamientos son los esperados.

Lo que hice se muestra a continuación. El objetivo es llenar mi modelo de datos (mDataObject) y luego rellenarlo en UI. Debe permitir la rotación de la pantalla en cualquier momento sin sorpresa.

class MyActivity {

private MyDataObject mDataObject = null;
private static MyThread mParserThread = null; // static, or make it singleton

OnCreate() {
        ...
        Object retained = this.getLastNonConfigurationInstance();
        if(retained != null) {
            // data is already completely obtained before config change
            // by my previous self.
            // no need to create thread or show dialog at all
            mDataObject = (MyDataObject) retained;
            populateUI();
        } else if(mParserThread != null && mParserThread.isAlive()){
            // note: mParserThread is a static member or singleton object.
            // config changed during parsing in previous instance. swap handler
            // then wait for it to finish.
            mParserThread.setHandler(new MyHandler());
        } else {
            // no data and no thread. likely initial run
            // create thread, show dialog
            mParserThread = new MyThread(..., new MyHandler());
            mParserThread.start();
            showDialog(DIALOG_PROGRESS);
        }
}

// http://android-developers.blogspot.com/2009/02/faster-screen-orientation-change.html
public Object onRetainNonConfigurationInstance() {
        // my future self can get this without re-downloading
        // if it's already ready.
        return mDataObject;
}

// use Activity.showDialog instead of ProgressDialog.show
// so the dialog can be automatically managed across config change
@Override
protected Dialog onCreateDialog(int id) {
    // show progress dialog here
}

// inner class of MyActivity
private class MyHandler extends Handler {
    public void handleMessage(msg) {
        mDataObject = mParserThread.getDataObject();
        populateUI();
        dismissDialog(DIALOG_PROGRESS);
    }
}
}

class MyThread extends Thread {
    Handler mHandler;
    MyDataObject mDataObject;

    public MyHandler(..., Handler h) {...; mHandler = h;} // constructor with handler param
    public void setHandler(Handler h) { mHandler = h; } // for handler swapping after config change
    public MyDataObject getDataObject() { return mDataObject; } // return data object (completed) to caller
    public void run() {
        mDataObject = new MyDataObject();
        // do the lengthy task to fill mDataObject with data
        lengthyTask(mDataObject);
        // done. notify activity
        mHandler.sendEmptyMessage(0); // tell activity: i'm ready. come pick up the data.
    }
}

Eso es lo que funciona para mí. No se si este es el método "correcto" diseñado por Android claim afirman que este "destruir / recrear la actividad durante la rotación de la pantalla" en realidad hace las cosas más fáciles, así que supongo no debería ser demasiado complicado.

Avísame si ves algún problema en mi código. Como se dijo anteriormente, realmente no sé si hay algún efecto secundario.

 25
Author: samsonsu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-02-19 18:23:56

Mi solución fue extender la clase ProgressDialog para obtener mi propia MyProgressDialog.
He redefinido show() y dismiss() métodos para bloquear la orientación antes de mostrar el Dialog y desbloquearlo de nuevo cuando Dialog es despedido. Por lo tanto, cuando se muestra el Dialog y la orientación del dispositivo cambia, la orientación de la pantalla permanece hasta que se llama dismiss(), entonces la orientación de la pantalla cambia de acuerdo con los valores del sensor/orientación del dispositivo.

Aquí está mi código:

public class MyProgressDialog extends ProgressDialog {
private Context mContext;

public MyProgressDialog(Context context) {
    super(context);
    mContext = context;
}

public MyProgressDialog(Context context, int theme) {
    super(context, theme);
    mContext = context;
}

public void show() {
    if (mContext.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT)
        ((Activity) mContext).setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
    else
        ((Activity) mContext).setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
    super.show();
}

public void dismiss() {
    super.dismiss();
    ((Activity) mContext).setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR);
}

}
 14
Author: Oli,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-04-20 16:00:42

El problema original percibido era que el código no sobreviviría a un cambio de orientación de la pantalla. Aparentemente esto fue "resuelto" haciendo que el programa manejara el cambio de orientación de la pantalla por sí mismo, en lugar de dejar que el framework de UI lo hiciera (a través de llamar a onDestroy)).

Yo diría que si el problema subyacente es que el programa no sobrevivirá onDestroy(), entonces la solución aceptada es solo una solución alternativa que deja al programa con otros problemas y vulnerabilidades graves. Recuerda que el framework de Android indica específicamente que tu actividad corre el riesgo de ser destruida casi en cualquier momento debido a circunstancias fuera de tu control. Por lo tanto, tu actividad debe ser capaz de sobrevivir onDestroy() y subsecuente onCreate() por cualquier razón, no solo un cambio de orientación de la pantalla.

Si usted mismo va a aceptar el manejo de cambios de orientación de la pantalla para resolver el problema del OP, necesita verificar que otras causas de onDestroy () no resulten en lo mismo error. ¿Eres capaz de hacer esto? Si no, me preguntaría si la respuesta "aceptada" es realmente una muy buena.

 13
Author: gymshoe,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-05-23 21:21:13

Me enfrenté a este mismo problema, y se me ocurrió una solución que no involucraba el ProgressDialog y obtengo resultados más rápidos.

Lo que hice fue crear un diseño que tiene una barra de progreso en él.

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<ProgressBar
    android:id="@+id/progressImage"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_centerInParent="true"
    />
</RelativeLayout>

Luego en el método onCreate haga lo siguiente

public void onCreate(Bundle icicle) {
    super.onCreate(icicle);
    setContentView(R.layout.progress);
}

Luego haga la tarea larga en un hilo, y cuando haya terminado, haga que un Ejecutable establezca la vista de contenido en el diseño real que desea usar para esta actividad.

Por ejemplo:

mHandler.post(new Runnable(){

public void run() {
        setContentView(R.layout.my_layout);
    } 
});

Esto es lo que yo lo hice, y he encontrado que se ejecuta más rápido que mostrar el ProgressDialog y es menos intrusivo y tiene un mejor aspecto en mi opinión.

Sin embargo, si quieres usar ProgressDialog, entonces esta respuesta no es para ti.

 8
Author: Pzanno,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-09-10 14:45:25

Descubrí una solución a esto que aún no he visto en ningún otro lugar. Puede usar un objeto de aplicación personalizado que sepa si tiene tareas en segundo plano en marcha, en lugar de intentar hacer esto en la actividad que se destruye y se vuelve a crear al cambiar de orientación. Escribí sobre esto en aquí.

 7
Author: Heikki Toivonen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-05-17 16:20:12

Voy a contribuir con mi enfoque para manejar este problema de rotación. Esto puede no ser relevante para OP ya que no está usando AsyncTask, pero tal vez otros lo encuentren útil. Es bastante simple, pero parece hacer el trabajo para mí:

Tengo una actividad de inicio de sesión con una clase anidada AsyncTask llamada BackgroundLoginTask.

En mi BackgroundLoginTask no hago nada fuera de lo común excepto agregar un cheque nulo al llamar a ProgressDialog's dismiss:

@Override
protected void onPostExecute(Boolean result)
{    
if (pleaseWaitDialog != null)
            pleaseWaitDialog.dismiss();
[...]
}

Esto es para manejar el caso donde la tarea en segundo plano termina mientras el Activity no es visible y, por lo tanto, el diálogo de progreso ya ha sido descartado por el método onPause().

A continuación, en mi clase padre Activity, creo manejadores estáticos globales para mi clase AsyncTask y mi ProgressDialog (el AsyncTask, al estar anidado, puede acceder a estas variables):

private static BackgroundLoginTask backgroundLoginTask;
private static ProgressDialog pleaseWaitDialog;

Esto sirve para dos propósitos: Primero, le permite a mi Activity acceder siempre al objeto AsyncTask incluso desde una nueva actividad post-rotada. Segundo, permite a mi BackgroundLoginTask acceder y descartar el ProgressDialog incluso después de una rotación.

A continuación, añado esto a onPause(), haciendo que el diálogo de progreso desaparezca cuando nuestro Activity está dejando el primer plano (evitando que el feo "cierre de fuerza" se bloquee):

    if (pleaseWaitDialog != null)
    pleaseWaitDialog.dismiss();

Finalmente, tengo lo siguiente en mi onResume() método:

if ((backgroundLoginTask != null) && (backgroundLoginTask.getStatus() == Status.RUNNING))
        {
           if (pleaseWaitDialog != null)
             pleaseWaitDialog.show();
        }

Esto permite que el Dialog reaparezca después de que el Activity sea recreado.

Aquí está toda la clase:

public class NSFkioskLoginActivity extends NSFkioskBaseActivity {
    private static BackgroundLoginTask backgroundLoginTask;
    private static ProgressDialog pleaseWaitDialog;
    private Controller cont;

    // This is the app entry point.
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        if (CredentialsAvailableAndValidated())
        {
        //Go to main menu and don't run rest of onCreate method.
            gotoMainMenu();
            return;
        }
        setContentView(R.layout.login);
        populateStoredCredentials();   
    }

    //Save current progress to options when app is leaving foreground
    @Override
    public void onPause()
    {
        super.onPause();
        saveCredentialsToPreferences(false);
        //Get rid of progress dialog in the event of a screen rotation. Prevents a crash.
        if (pleaseWaitDialog != null)
        pleaseWaitDialog.dismiss();
    }

    @Override
    public void onResume()
    {
        super.onResume();
        if ((backgroundLoginTask != null) && (backgroundLoginTask.getStatus() == Status.RUNNING))
        {
           if (pleaseWaitDialog != null)
             pleaseWaitDialog.show();
        }
    }

    /**
     * Go to main menu, finishing this activity
     */
    private void gotoMainMenu()
    {
        startActivity(new Intent(getApplicationContext(), NSFkioskMainMenuActivity.class));
        finish();
    }

    /**
     * 
     * @param setValidatedBooleanTrue If set true, method will set CREDS_HAVE_BEEN_VALIDATED to true in addition to saving username/password.
     */
    private void saveCredentialsToPreferences(boolean setValidatedBooleanTrue)
    {
        SharedPreferences settings = getSharedPreferences(APP_PREFERENCES, MODE_PRIVATE);
        SharedPreferences.Editor prefEditor = settings.edit();
        EditText usernameText = (EditText) findViewById(R.id.editTextUsername);
        EditText pswText = (EditText) findViewById(R.id.editTextPassword);
        prefEditor.putString(USERNAME, usernameText.getText().toString());
        prefEditor.putString(PASSWORD, pswText.getText().toString());
        if (setValidatedBooleanTrue)
        prefEditor.putBoolean(CREDS_HAVE_BEEN_VALIDATED, true);
        prefEditor.commit();
    }

    /**
     * Checks if user is already signed in
     */
    private boolean CredentialsAvailableAndValidated() {
        SharedPreferences settings = getSharedPreferences(APP_PREFERENCES,
                MODE_PRIVATE);
        if (settings.contains(USERNAME) && settings.contains(PASSWORD) && settings.getBoolean(CREDS_HAVE_BEEN_VALIDATED, false) == true)
         return true;   
        else
        return false;
    }

    //Populate stored credentials, if any available
    private void populateStoredCredentials()
    {
        SharedPreferences settings = getSharedPreferences(APP_PREFERENCES,
            MODE_PRIVATE);
        settings.getString(USERNAME, "");
       EditText usernameText = (EditText) findViewById(R.id.editTextUsername);
       usernameText.setText(settings.getString(USERNAME, ""));
       EditText pswText = (EditText) findViewById(R.id.editTextPassword);
       pswText.setText(settings.getString(PASSWORD, ""));
    }

    /**
     * Validate credentials in a seperate thread, displaying a progress circle in the meantime
     * If successful, save credentials in preferences and proceed to main menu activity
     * If not, display an error message
     */
    public void loginButtonClick(View view)
    {
        if (phoneIsOnline())
        {
        EditText usernameText = (EditText) findViewById(R.id.editTextUsername);
        EditText pswText = (EditText) findViewById(R.id.editTextPassword);
           //Call background task worker with username and password params
           backgroundLoginTask = new BackgroundLoginTask();
           backgroundLoginTask.execute(usernameText.getText().toString(), pswText.getText().toString());
        }
        else
        {
        //Display toast informing of no internet access
        String notOnlineMessage = getResources().getString(R.string.noNetworkAccessAvailable);
        Toast toast = Toast.makeText(getApplicationContext(), notOnlineMessage, Toast.LENGTH_SHORT);
        toast.show();
        }
    }

    /**
     * 
     * Takes two params: username and password
     *
     */
    public class BackgroundLoginTask extends AsyncTask<Object, String, Boolean>
    {       
       private Exception e = null;

       @Override
       protected void onPreExecute()
       {
           cont = Controller.getInstance();
           //Show progress dialog
           String pleaseWait = getResources().getString(R.string.pleaseWait);
           String commWithServer = getResources().getString(R.string.communicatingWithServer);
            if (pleaseWaitDialog == null)
              pleaseWaitDialog= ProgressDialog.show(NSFkioskLoginActivity.this, pleaseWait, commWithServer, true);

       }

        @Override
        protected Boolean doInBackground(Object... params)
        {
        try {
            //Returns true if credentials were valid. False if not. Exception if server could not be reached.
            return cont.validateCredentials((String)params[0], (String)params[1]);
        } catch (Exception e) {
            this.e=e;
            return false;
        }
        }

        /**
         * result is passed from doInBackground. Indicates whether credentials were validated.
         */
        @Override
        protected void onPostExecute(Boolean result)
        {
        //Hide progress dialog and handle exceptions
        //Progress dialog may be null if rotation has been switched
        if (pleaseWaitDialog != null)
             {
            pleaseWaitDialog.dismiss();
                pleaseWaitDialog = null;
             }

        if (e != null)
        {
         //Show toast with exception text
                String networkError = getResources().getString(R.string.serverErrorException);
                Toast toast = Toast.makeText(getApplicationContext(), networkError, Toast.LENGTH_SHORT);
            toast.show();
        }
        else
        {
            if (result == true)
            {
            saveCredentialsToPreferences(true);
            gotoMainMenu();
            }
            else
            {
            String toastText = getResources().getString(R.string.invalidCredentialsEntered);
                Toast toast = Toast.makeText(getApplicationContext(), toastText, Toast.LENGTH_SHORT);
            toast.show();
            } 
        }
        }

    }
}

De ninguna manera soy un desarrollador de Android experimentado, así que siéntete libre de comentar.

 7
Author: Anders,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-04-20 16:18:52

Mueva la tarea larga a una clase separada. Implementarlo como un patrón sujeto-observador. Cada vez que se crea la actividad, regístrese y mientras cierra unregister con la clase task. La clase Task puede usar AsyncTask.

 4
Author: Vinay,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-07-11 04:56:07

El truco es mostrar/descartar el diálogo dentro de AsyncTask durante onPreExecute/onPostExecute como de costumbre, aunque en caso de orientation-change cree/muestre una nueva instancia del diálogo en la actividad y pase su referencia a la tarea.

public class MainActivity extends Activity {
    private Button mButton;
    private MyTask mTask = null;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        MyTask task = (MyTask) getLastNonConfigurationInstance();
        if(task != null){
            mTask = task;
            mTask.mContext = this;
            mTask.mDialog = ProgressDialog.show(this, "", "", true);        
        }

        mButton = (Button) findViewById(R.id.button1);
        mButton.setOnClickListener(new View.OnClickListener(){
            public void onClick(View v){
                mTask = new MyTask(MainActivity.this);
                mTask.execute();
            }
        });
    }


    @Override
    public Object onRetainNonConfigurationInstance() {
        String str = "null";
        if(mTask != null){
            str = mTask.toString();
            mTask.mDialog.dismiss();
        }
        Toast.makeText(this, str, Toast.LENGTH_SHORT).show();
        return mTask;
    }



    private class MyTask extends AsyncTask<Void, Void, Void>{
        private ProgressDialog mDialog;
        private MainActivity mContext;


        public MyTask(MainActivity context){
            super();
            mContext = context;
        }


        protected void onPreExecute() {
            mDialog = ProgressDialog.show(MainActivity.this, "", "", true);
        }

        protected void onPostExecute(Void result) {
            mContext.mTask = null;
            mDialog.dismiss();
        }


        @Override
        protected Void doInBackground(Void... params) {
            SystemClock.sleep(5000);
            return null;
        }       
    }
}
 4
Author: n224576,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-06-28 13:20:28

Lo he hecho así:

    package com.palewar;
    import android.app.Activity;
    import android.app.ProgressDialog;
    import android.os.Bundle;
    import android.os.Handler;
    import android.os.Message;

    public class ThreadActivity extends Activity {


        static ProgressDialog dialog;
        private Thread downloadThread;
        final static Handler handler = new Handler() {

            @Override
            public void handleMessage(Message msg) {

                super.handleMessage(msg);

                dialog.dismiss();

            }

        };

        protected void onDestroy() {
    super.onDestroy();
            if (dialog != null && dialog.isShowing()) {
                dialog.dismiss();
                dialog = null;
            }

        }

        /** Called when the activity is first created. */
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.main);

            downloadThread = (Thread) getLastNonConfigurationInstance();
            if (downloadThread != null && downloadThread.isAlive()) {
                dialog = ProgressDialog.show(ThreadActivity.this, "",
                        "Signing in...", false);
            }

            dialog = ProgressDialog.show(ThreadActivity.this, "",
                    "Signing in ...", false);

            downloadThread = new MyThread();
            downloadThread.start();
            // processThread();
        }

        // Save the thread
        @Override
        public Object onRetainNonConfigurationInstance() {
            return downloadThread;
        }


        static public class MyThread extends Thread {
            @Override
            public void run() {

                try {
                    // Simulate a slow network
                    try {
                        new Thread().sleep(5000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    handler.sendEmptyMessage(0);

                } finally {

                }
            }
        }

    }

También puedes intentar hacerme saber que funciona para ti o no

 4
Author: Sachin Gurnani,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-06-29 05:03:41

Si crea un fondo Service eso hace todo el trabajo pesado (solicitudes/respuestas tcp, sin marcar), el View y Activity pueden ser destruidos y recreados sin filtrar la ventana o perder datos. Esto permite el comportamiento recomendado de Android, que es destruir una Actividad en cada cambio de configuración (por ejemplo. para cada cambio de orientación).

Es un poco más complejo, pero es la mejor manera de invocar solicitudes del servidor, pre / post procesamiento de datos, sucesivamente.

Incluso puede usar su Service para poner en cola cada solicitud en un servidor, por lo que es fácil y eficiente manejar esas cosas.

La guía de desarrollo tiene un capítulo completo sobre Services.

 2
Author: acardenas89,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-03-10 17:11:08

Tengo una implementación que permite que la actividad se destruya en un cambio de orientación de la pantalla, pero aún así destruye el diálogo en la actividad recreada con éxito. Utilizo ...NonConfigurationInstance para adjuntar la tarea en segundo plano a la actividad recreada. El marco de trabajo normal de Android se encarga de recrear el diálogo en sí, no se cambia nada allí.

Subclase AsyncTask añadiendo un campo para la actividad 'owning', y un método para actualizar este propietario.

class MyBackgroundTask extends AsyncTask<...> {
  MyBackgroundTask (Activity a, ...) {
    super();
    this.ownerActivity = a;
  }

  public void attach(Activity a) {
    ownerActivity = a;
  }

  protected void onPostExecute(Integer result) {
    super.onPostExecute(result);
    ownerActivity.dismissDialog(DIALOG_PROGRESS);
  }

  ...
}

En mi clase de actividad I se agregó un campo backgroundTask que se refiere a la tarea de fondo 'poseída', y actualizo este campo usando onRetainNonConfigurationInstance y getLastNonConfigurationInstance.

class MyActivity extends Activity {
  public void onCreate(Bundle savedInstanceState) {
    ...
    if (getLastNonConfigurationInstance() != null) {
      backgroundTask = (MyBackgroundTask) getLastNonConfigurationInstance();
      backgroundTask.attach(this);
    }
  }

  void startBackgroundTask() {
    backgroundTask = new MyBackgroundTask(this, ...);
    showDialog(DIALOG_PROGRESS);
    backgroundTask.execute(...);
  }

  public Object onRetainNonConfigurationInstance() {
    if (backgroundTask != null && backgroundTask.getStatus() != Status.FINISHED)
      return backgroundTask;
    return null;
  }
  ...
}

Sugerencias para seguir mejorando:

  • Borre la referencia backgroundTask en la actividad después de que la tarea haya terminado para liberar cualquier memoria u otros recursos asociados con ella.
  • Borre la referencia ownerActivity en la tarea de fondo antes de que se destruya la actividad en caso de que no se vuelva a crear inmediatamente.
  • Crear una interfaz BackgroundTask y / o colección para permitir que diferentes tipos de tareas se ejecuten desde la misma actividad propietaria.
 2
Author: beetstra,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-04-29 13:56:09

Si mantiene dos diseños, todos los subprocesos de interfaz de usuario deben terminar.

Si usa AsinTask, entonces puede llamar fácilmente al método .cancel() dentro del método onDestroy() de la actividad actual.

@Override
protected void onDestroy (){
    removeDialog(DIALOG_LOGIN_ID); // remove loading dialog
    if (loginTask != null){
        if (loginTask.getStatus() != AsyncTask.Status.FINISHED)
            loginTask.cancel(true); //cancel AsyncTask
    }
    super.onDestroy();
}

Para AsyncTask, lea más en la sección "Cancelar una tarea" en aquí.

Actualización: Condición añadida para comprobar el estado, ya que solo se puede cancelar si está en estado de ejecución. También tenga en cuenta que la AsyncTask solo se puede ejecutar una vez.

 2
Author: Vikas,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-08-03 10:04:11

Intentó implementar la solución de jfelectronporque es una " solución sólida como una roca para estos problemas que se ajusta a la'Forma Android 'de las cosas", pero tomó algún tiempo buscar y reunir todos los elementos mencionados. Terminé con esta solución ligeramente diferente, y creo que más elegante, publicada aquí en su totalidad.

Utiliza un IntentService disparado desde una actividad para realizar la tarea de larga ejecución en un subproceso separado. El servicio dispara de nuevo pegajoso Broadcast intenta la actividad que actualiza el diálogo. La actividad utiliza ShowDialog (), onCreateDialog() y onPrepareDialog () para eliminar la necesidad de que se pasen datos persistentes en el objeto application o en el paquete savedInstanceState. Esto debería funcionar sin importar cómo se interrumpa su aplicación.

Clase de actividad:

public class TesterActivity extends Activity {
private ProgressDialog mProgressDialog;
private static final int PROGRESS_DIALOG = 0;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    Button b = (Button) this.findViewById(R.id.test_button);
    b.setOnClickListener(new OnClickListener() {
        public void onClick(View v) {
            buttonClick();
        }
    });
}

private void buttonClick(){
    clearPriorBroadcast();
    showDialog(PROGRESS_DIALOG);
    Intent svc = new Intent(this, MyService.class);
    startService(svc);
}

protected Dialog onCreateDialog(int id) {
    switch(id) {
    case PROGRESS_DIALOG:
        mProgressDialog = new ProgressDialog(TesterActivity.this);
        mProgressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
        mProgressDialog.setMax(MyService.MAX_COUNTER);
        mProgressDialog.setMessage("Processing...");
        return mProgressDialog;
    default:
        return null;
    }
}

@Override
protected void onPrepareDialog(int id, Dialog dialog) {
    switch(id) {
    case PROGRESS_DIALOG:
        // setup a broadcast receiver to receive update events from the long running process
        IntentFilter filter = new IntentFilter();
        filter.addAction(MyService.BG_PROCESS_INTENT);
        registerReceiver(new MyBroadcastReceiver(), filter);
        break;
    }
}

public class MyBroadcastReceiver extends BroadcastReceiver{
    @Override
    public void onReceive(Context context, Intent intent) {
        if (intent.hasExtra(MyService.KEY_COUNTER)){
            int count = intent.getIntExtra(MyService.KEY_COUNTER, 0);
            mProgressDialog.setProgress(count);
            if (count >= MyService.MAX_COUNTER){
                dismissDialog(PROGRESS_DIALOG);
            }
        }
    }
}

/*
 * Sticky broadcasts persist and any prior broadcast will trigger in the 
 * broadcast receiver as soon as it is registered.
 * To clear any prior broadcast this code sends a blank broadcast to clear 
 * the last sticky broadcast.
 * This broadcast has no extras it will be ignored in the broadcast receiver 
 * setup in onPrepareDialog()
 */
private void clearPriorBroadcast(){
    Intent broadcastIntent = new Intent();
    broadcastIntent.setAction(MyService.BG_PROCESS_INTENT);
    sendStickyBroadcast(broadcastIntent);
}}

Clase IntentService:

public class MyService extends IntentService {

public static final String BG_PROCESS_INTENT = "com.mindspiker.Tester.MyService.TEST";
public static final String KEY_COUNTER = "counter";
public static final int MAX_COUNTER = 100;

public MyService() {
  super("");
}

@Override
protected void onHandleIntent(Intent intent) {
    for (int i = 0; i <= MAX_COUNTER; i++) {
        Log.e("Service Example", " " + i);
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        Intent broadcastIntent = new Intent();
        broadcastIntent.setAction(BG_PROCESS_INTENT);
        broadcastIntent.putExtra(KEY_COUNTER, i);
        sendStickyBroadcast(broadcastIntent);
    }
}}

Entradas del archivo de manifiesto:

Antes de la sección de aplicación:

uses-permission android:name="com.mindspiker.Tester.MyService.TEST"
uses-permission android:name="android.permission.BROADCAST_STICKY"

Aplicación interna sección

service android:name=".MyService"
 2
Author: MindSpiker,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-04-27 04:50:27

Esta es mi solución propuesta:

  • Mueva la AsyncTask o Hilo a un Fragmento retenido, como se explica aquí. Creo que es una buena práctica mover todas las llamadas de red a fragmentos. Si ya está utilizando fragmentos, uno de ellos podría hacerse responsable de las llamadas. De lo contrario, puede crear un fragmento solo para hacer la solicitud, como propone el artículo vinculado.
  • El fragmento utilizará una interfaz de escucha para señalar la finalización/error de la tarea. No hay que preocuparse por los cambios de orientación allí. El fragmento siempre tendrá el enlace correcto a la actividad actual y el diálogo de progreso se puede reanudar de forma segura.
  • Haz de tu diálogo de progreso un miembro de tu clase. De hecho, usted debe hacer eso para todos los diálogos. En el método onPause debe descartarlos, de lo contrario se filtrará una ventana en el cambio de configuración. El estado ocupado debe ser mantenido por el fragmento. Cuando el fragmento se adjunta a la actividad, puede mostrar el progreso diálogo de nuevo, si la llamada todavía está en ejecución. Se puede agregar un método void showProgressDialog() a la interfaz de escucha de fragment-activity para este propósito.
 2
Author: kgiannakakis,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-06-26 15:33:27

Lo he intentado TODO. Pasé días experimentando. No quería bloquear la rotación de la actividad. Mi escenario fue:

  1. Un diálogo de progreso que muestra información dinámica al usuario. Por ejemplo: "Conexión al servidor...", "Descargando datos...", sucesivamente.
  2. Un hilo haciendo las cosas pesadas y actualizando el diálogo
  3. Actualizando la interfaz de usuario con los resultados al final.

El problema era que, al girar la pantalla, todas las soluciones del libro fallaban. Incluso con la AsyncTask clase, que es la forma correcta de Android de hacer frente a estas situaciones. Al girar la pantalla, el Contexto actual con el que está trabajando el hilo de inicio, se ha ido, y eso arruina el diálogo que se muestra. El problema siempre fue el Diálogo, sin importar cuántos trucos agregué al código (pasar nuevos contextos a subprocesos en ejecución, retener estados de subprocesos a través de rotaciones, etc.)...). La complejidad del código al final siempre fue enorme y siempre había algo que podía ir Equivocada.

La única solución que funcionó para mí fue el truco de la Actividad/Diálogo. Es simple y genial y es todo a prueba de rotación:

  1. En lugar de crear un diálogo y pedir que se muestre, cree una actividad que se haya establecido en el manifiesto con android:theme="@android:style/Theme.Diálogo". Por lo tanto, sólo parece un diálogo.

  2. Reemplazar ShowDialog (DIALOG_ID) con startActivityForResult (yourActivityDialog, yourCode);

  3. Uso onActivityResult in la actividad de llamada para obtener los resultados del subproceso de ejecución (incluso los errores) y actualizar la interfaz de usuario.

  4. En su 'ActivityDialog', use threads o AsyncTask para ejecutar tareas largas y onRetainNonConfigurationInstance para guardar el estado "dialog" cuando gire la pantalla.

Esto es rápido y funciona bien. Todavía uso diálogos para otras tareas y el AsyncTask para algo que no requiere un diálogo constante en la pantalla. Pero con este escenario, siempre voy por el Patrón de actividad / Diálogo.

Y, no lo intenté, pero incluso es posible bloquear esa Actividad/Diálogo de rotación, cuando el hilo se está ejecutando, acelerando las cosas, mientras que permite que la Actividad de llamada gire.

 1
Author: Rui,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-03-07 17:47:21

En estos días hay una manera mucho más distinta de manejar este tipo de problemas. El enfoque típico es:

1. Asegúrese de que sus datos estén separados correctamente de la interfaz de usuario:

Cualquier cosa que sea un proceso de fondo debe estar en un retained Fragment (establezca esto con Fragment.setRetainInstance(). Esto se convierte en su 'almacenamiento de datos persistentes' donde se guarda cualquier dato basado en que desee conservar. Después del evento de cambio de orientación, este Fragment seguirá siendo accesible en su estado original a través de un FragmentManager.findFragmentByTag() llamada (cuando la cree debe darle una etiqueta no un ID ya que no está adjunta a un View).

Consulte la guía desarrollada por Manejando los cambios en tiempo de ejecución para obtener información sobre cómo hacer esto correctamente y por qué es la mejor opción.

2. Asegúrese de que está interactuando de forma correcta y segura entre los procesos en segundo plano y su interfaz de usuario:

Debes invertir tu proceso de enlace. En el momento de su proceso de fondo se adhiere a un View - en su lugar, su View debe estar adjuntándose al proceso de fondo. Tiene más sentido, ¿verdad? La acción de View depende del proceso de fondo, mientras que el proceso de fondo no depende del View.Esto significa cambiar el enlace a una interfaz estándar Listener. Decir su proceso (sea cual sea la clase que es-si es un AsyncTask, Runnable o lo que sea) define un OnProcessFinishedListener, cuando el proceso se realiza debe llamar a ese oyente si existe.

Esta respuesta es una descripción concisa agradable de cómo hacer oyentes personalizados.

3. Vincule su IU al proceso de datos cada vez que se cree la IU (incluidos los cambios de orientación):

Ahora debe preocuparse por interconectar la tarea en segundo plano con cualquiera que sea su estructura actual View. Si está manejando sus cambios de orientación correctamente (no el configChanges hack que la gente siempre recomienda), entonces su Dialog será recreado por el sistema. Esto es importante, significa que en la orientación cambiar, todos los métodos de ciclo de vida de Dialog se recuperan. Así que en cualquiera de estos métodos (onCreateDialog suele ser un buen lugar), puedes hacer una llamada como la siguiente:

DataFragment f = getActivity().getFragmentManager().findFragmentByTag("BACKGROUND_TAG");
if (f != null) {
    f.mBackgroundProcess.setOnProcessFinishedListener(new OnProcessFinishedListener() {
        public void onProcessFinished() {
            dismiss();
        }
    });
 }

Consulte el ciclo de vida del fragmento para decidir dónde se ajusta mejor la configuración del oyente en su implementación individual.

Este es un enfoque general para proporcionar una solución sólida y completa al problema genérico planteado en esta pregunta. Probablemente faltan algunas piezas menores en esta respuesta dependiendo de su escenario individual, pero este es generalmente el enfoque más correcto para manejar adecuadamente los eventos de cambio de orientación.

 1
Author: B T,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:26:10

Me enfrenté a la misma situación. Lo que hice fue obtener solo una instancia para mi diálogo de progreso en toda la aplicación.

Primero, creé una clase DialogSingleton para obtener solo una instancia (patrón Singleton)

public class DialogSingleton
{
    private static Dialog dialog;

    private static final Object mLock = new Object();
    private static DialogSingleton instance;

    private DialogSingleton()
    {

    }

    public static DialogSingleton GetInstance()
    {
        synchronized (mLock)
        {
            if(instance == null)
            {
                instance = new DialogSingleton();
            }

            return instance;
        }
    }

    public void DialogShow(Context context, String title)
    {
        if(!((Activity)context).isFinishing())
        {
            dialog = new ProgressDialog(context, 2);

            dialog.setCanceledOnTouchOutside(false);

            dialog.setTitle(title);

            dialog.show();
        }
    }

    public void DialogDismiss(Context context)
    {
        if(!((Activity)context).isFinishing() && dialog.isShowing())
        {
            dialog.dismiss();
        }
    }
}

Como muestro en esta clase, tengo el diálogo de progreso como atributo. Cada vez que necesito mostrar un diálogo de progreso, obtengo la instancia única y creo un nuevo ProgressDialog.

DialogSingleton.GetInstance().DialogShow(this, "My title here!");

Cuando he terminado con la tarea de fondo, llamo de nuevo a la única instance and dismiss its dialog.

DialogSingleton.GetInstance().DialogDismiss(this);

Guardo el estado de la tarea en segundo plano en mis preferencias compartidas. Cuando giro la pantalla, pregunto si tengo una tarea ejecutándose para esta actividad: (onCreate)

if(Boolean.parseBoolean(preference.GetValue(IS_TASK_NAME_EXECUTED_KEY, "boolean").toString()))
{
    DialogSingleton.GetInstance().DialogShow(this, "Checking credentials!");
} // preference object gets the info from shared preferences (my own implementation to get and put data to shared preferences) and IS_TASK_NAME_EXECUTED_KEY is the key to save this flag (flag to know if this activity has a background task already running).

Cuando empiezo a ejecutar una tarea en segundo plano:

preference.AddValue(IS_TASK_NAME_EXECUTED_KEY, true, "boolean");

DialogSingleton.GetInstance().DialogShow(this, "My title here!");

Cuando termine de ejecutar una tarea en segundo plano:

preference.AddValue(IS_TASK_NAME_EXECUTED_KEY, false, "boolean");

DialogSingleton.GetInstance().DialogDismiss(ActivityName.this);

Espero que ayude.

 1
Author: deinier,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-12-29 19:16:21

Esta es una pregunta muy antigua que surgió en la barra lateral por alguna razón.

Si la tarea en segundo plano solo necesita sobrevivir mientras la actividad está en primer plano, la solución "nueva" es alojar el subproceso en segundo plano (o, preferiblemente, AsyncTask) en un fragmento retenido, como se describe en esta guía para desarrolladores y numerosas Preguntas y respuestas.

Un fragmento retenido sobrevive si la actividad se destruye por un cambio de configuración, pero no cuando la actividad se destruye en el fondo o pila posterior. Por lo tanto, la tarea en segundo plano debe interrumpirse si isChangingConfigurations() es falso en onPause().

 1
Author: Kevin Krumwiede,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:03:05

Soy un más fresco en Android y he probado esto y ha funcionado.

public class loadTotalMemberByBranch extends AsyncTask<Void, Void,Void> {
        ProgressDialog progressDialog = new ProgressDialog(Login.this);
        int ranSucess=0;
        @Override
        protected void onPreExecute() {
            // TODO Auto-generated method stub
            super.onPreExecute();
            progressDialog.setTitle("");    
            progressDialog.isIndeterminate();
            progressDialog.setCancelable(false);
            progressDialog.show();
            setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_NOSENSOR);

        }
        @Override
        protected Void doInBackground(Void... params) {
            // TODO Auto-generated method stub

            return null;
        }
        @Override
        protected void onPostExecute(Void result) {
            // TODO Auto-generated method stub
            super.onPostExecute(result);
            progressDialog.dismiss();
            setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_NOSENSOR);
        }
}
 1
Author: Cloy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-07-06 21:14:25

Parece demasiado 'rápido y sucio' para ser verdad, así que por favor señale los defectos, pero lo que encontré funcionó fue...

Dentro del método onPostExecute de mi AsyncTask, simplemente envolví el '.dismiss ' para el diálogo de progreso en un bloque try / catch (con un catch vacío) y luego simplemente ignoró la excepción que se planteó. Parece mal hacer, pero parece que no hay efectos nocivos (al menos para lo que estoy haciendo posteriormente, que es comenzar otra actividad que pasa en el resultado de mi larga carrera consulta como Extra)

 0
Author: Simon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-11-10 10:58:12

La solución más simple y flexible es usar un AsyncTask con una referencia estática a ProgressBar. Esto proporciona una solución encapsulada y por lo tanto reutilizable a los problemas de cambio de orientación. Esta solución me ha servido bien para diversas tareas asíncronas, incluidas descargas de Internet, comunicación con Servicios y análisis del sistema de archivos. La solución ha sido bien probada en múltiples versiones de Android y modelos de teléfonos. Una demostración completa se puede encontrar aquí con interés específico en DownloadFile.java

Presento lo siguiente como un ejemplo de concepto

public class SimpleAsync extends AsyncTask<String, Integer, String> {
    private static ProgressDialog mProgressDialog = null;
    private final Context mContext;

    public SimpleAsync(Context context) {
        mContext = context;
        if ( mProgressDialog != null ) {
            onPreExecute();
        }
    }

    @Override
    protected void onPreExecute() {
        mProgressDialog = new ProgressDialog( mContext );
        mProgressDialog.show();
    }

    @Override
    protected void onPostExecute(String result) {
        if ( mProgressDialog != null ) {
            mProgressDialog.dismiss();
            mProgressDialog = null;
        }
    }

    @Override
    protected void onProgressUpdate(Integer... progress) {
        mProgressDialog.setProgress( progress[0] );
    }

    @Override
    protected String doInBackground(String... sUrl) {
        // Do some work here
        publishProgress(1);
        return null;
    }

    public void dismiss() {
        if ( mProgressDialog != null ) {
            mProgressDialog.dismiss();
        }
    }
}

El uso en una actividad de Android es simple

public class MainActivity extends Activity {
    DemoServiceClient mClient = null;
    DownloadFile mDownloadFile = null;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate( savedInstanceState );
        setContentView( R.layout.main );
        mDownloadFile = new DownloadFile( this );

        Button downloadButton = (Button) findViewById( R.id.download_file_button );
        downloadButton.setOnClickListener( new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                mDownloadFile.execute( "http://www.textfiles.com/food/bakebred.txt");
            }
        });
    }

    @Override
    public void onPause() {
        super.onPause();
        mDownloadFile.dismiss();
    }
}
 0
Author: Derrick J Wippler,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-05-10 19:19:09

He encontrado una solución más fácil para manejar los hilos cuando cambia la orientación. Solo puede mantener una referencia estática a su actividad/fragmento y verificar si es nulo antes de actuar en la interfaz de usuario. Sugiero usar un try catch también:

 public class DashListFragment extends Fragment {
     private static DashListFragment ACTIVE_INSTANCE;

     @Override
     public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        ACTIVE_INSTANCE = this;

        new Handler().postDelayed(new Runnable() {
            public void run() {
                try {
                        if (ACTIVE_INSTANCE != null) {
                            setAdapter(); // this method do something on ui or use context
                        }
                }
                catch (Exception e) {}


            }
        }, 1500l);

    }

    @Override
    public void onDestroy() {
        super.onDestroy();

        ACTIVE_INSTANCE = null;
    }


}
 0
Author: sagits,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-10-02 15:11:31

Si está luchando con la detección de eventos de cambio de orientación de un diálogo INDEPENDIENTE DE UNA REFERENCIA DE ACTIVIDAD, este método funciona muy bien. Uso esto porque tengo mi propia clase de diálogo que se puede mostrar en múltiples Actividades diferentes, por lo que no siempre sé en qué Actividad se muestra. Con este método, no necesita cambiar el AndroidManifest, preocuparse por las referencias de actividad y no necesita un diálogo personalizado (como he hecho). Usted necesita, sin embargo, una costumbre vista de contenido para que pueda detectar los cambios de orientación utilizando esa vista en particular. Este es mi ejemplo:

Configuración

public class MyContentView extends View{
    public MyContentView(Context context){
        super(context);
    }

    @Override
    public void onConfigurationChanged(Configuration newConfig){
        super.onConfigurationChanged(newConfig);

        //DO SOMETHING HERE!! :D
    }
}

Implementación 1-Diálogo

Dialog dialog = new Dialog(context);
//set up dialog
dialog.setContentView(new MyContentView(context));
dialog.show();

Implementación 2-AlertDialog.Constructor

AlertDialog.Builder builder = new AlertDialog.Builder(context);
//set up dialog builder
builder.setView(new MyContentView(context));        //Can use this method
builder.setCustomTitle(new MycontentView(context)); // or this method
builder.build().show();

Implementación 3-ProgressDialog / AlertDialog

ProgressDialog progress = new ProgressDialog(context);
//set up progress dialog
progress.setView(new MyContentView(context));        //Can use this method
progress.setCustomTitle(new MyContentView(context)); // or this method
progress.show();
 0
Author: kpninja12,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-11-18 18:13:32