Jak poradzić sobie ze zmianą orientacji ekranu, gdy aktywne jest okno dialogowe postępu i wątek w tle?

Mój program wykonuje pewną aktywność sieciową w wątku w tle. Przed uruchomieniem wyskakuje okno dialogowe postępu. Okno dialogowe jest odrzucane przez opiekuna. To wszystko działa dobrze, z wyjątkiem sytuacji, gdy orientacja ekranu zmienia się, gdy okno dialogowe jest włączone(a wątek tła jest w trakcie). W tym momencie aplikacja zawiesza się lub blokuje lub wchodzi w dziwny etap, w którym aplikacja nie działa w ogóle, dopóki wszystkie wątki nie zostaną zabite.

Jak mogę poradzić sobie ze zmianą orientacji ekranu z wdziękiem?

Poniższy przykładowy kod pasuje mniej więcej do tego, co robi mój prawdziwy program:

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

Stos:

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)

Próbowałem odrzucić okno dialogowe postępu w onSaveInstanceState, ale to po prostu zapobiega natychmiastowej awarii. Wątek tła nadal działa, a interfejs użytkownika jest częściowo narysowany. Trzeba zabić całą aplikację, zanim zacznie działać ponownie.

Author: Alex Lockwood, 2009-07-11

26 answers

Gdy zmienisz orientację, Android utworzy nowy widok. Prawdopodobnie dostajesz awarie, ponieważ Twój wątek w tle próbuje zmienić stan na Starym. (Może to być również problem, ponieważ Twój wątek tła nie jest w wątku UI)

Proponuję uczynić ten mHandler niestabilnym i zaktualizować go, gdy zmieni się orientacja.

 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/doraprojects.net/template/agent.layouts/content.php on line 54
2009-07-12 19:34:27

Edit: inżynierowie Google nie zalecają takiego podejścia, jak opisuje to Dianne Hackborn (Alias hackbod ) w tym StackOverflow post. Zobacz też this blog post Więcej informacji.


Musisz dodać to do deklaracji aktywności w manifeście:

android:configChanges="orientation|screenSize"

Tak wygląda

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

Chodzi o to, że system niszczy aktywność, gdy nastąpi zmiana konfiguracji. Zobacz też ConfigurationChanges .

Więc umieszczenie tego w pliku konfiguracyjnym pozwala uniknąć zniszczenia Twojej aktywności przez system. Zamiast tego wywołuje metodę 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/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:10:30

Wymyśliłem solidne rozwiązanie tych problemów, które jest zgodne z "Androidowym sposobem" rzeczy. Wszystkie moje długotrwałe operacje są prowadzone według schematu IntentService.
To jest moje działania broadcast intents, IntentService wykonuje pracę, zapisuje dane w DB, a następnie nadaje STICKY intents.
Lepka część jest ważna, taka, że nawet jeśli aktywność została wstrzymana w czasie po rozpoczęciu pracy przez użytkownika i pomija transmisję w czasie rzeczywistym z ItentService nadal możemy odpowiedzieć i odebrać dane z aktywności wywołującej.
ProgressDialogs może pracować w tym wzorze całkiem ładnie z onSaveInstanceSate().
Zasadniczo musisz zapisać flagę, że w zapisanym pakiecie wystąpienia działa okno dialogowe postępu. Nie zapisuj obiektu okna dialogowego postęp, ponieważ spowoduje to wyciek całej aktywności.
Aby mieć trwały uchwyt do okna postępu, przechowuję go jako słabe odniesienie w obiekcie aplikacji.
Na zmianę orientacji lub cokolwiek innego powoduje to wstrzymanie aktywności (połączenie telefoniczne, użytkownik trafia do domu itp.), a następnie wznowienie, odrzucam stare okno dialogowe i odtwarzam nowe okno dialogowe w nowo utworzonej aktywności.
W przypadku nieokreślonych okien dialogowych postępu jest to łatwe. W przypadku stylu paska postępu musisz umieścić ostatni znany postęp w pakiecie i dowolne informacje, których używasz lokalnie w ćwiczeniu,aby śledzić postępy.
Po przywróceniu postępu będziesz używać tych informacji do ponownego wyświetlania paska postępu w tym samym stanie, co przed i następnie aktualizować na podstawie aktualnego stanu rzeczy.
Podsumowując, wprowadzenie długotrwałych zadań w IntentService w połączeniu z świadomym wykorzystaniem onSaveInstanceState() pozwala skutecznie śledzić okna dialogowe i przywracać następnie zdarzenia w cyklu życia aktywności. Odpowiednie bity kodu aktywności są poniżej. Będziesz również potrzebował logiki w BroadcastReceiver, aby odpowiednio obsłużyć lepkie intencje,ale to wykracza poza zakres tego.

   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/doraprojects.net/template/agent.layouts/content.php on line 54
2013-04-12 08:32:39

Spotkałem się z tym samym problemem. Moja aktywność musi analizować niektóre dane z adresu URL i jest powolna. Więc utworzyć wątek, aby to zrobić, a następnie pokazać progressdialog. Pozwoliłem wątkowi opublikować msg z powrotem do wątku interfejsu użytkownika poprzez Handler po zakończeniu. W Handlerze.handleMessage, pobieram obiekt danych (gotowy teraz) z wątku i wypełniam go do interfejsu użytkownika. Więc jest to bardzo podobne do twojego przykładu.

Po wielu próbach i błędach wygląda na to, że znalazłem rozwiązanie. Przynajmniej teraz mogę obracać ekran w każdej chwili, przed lub po wątek skończony. We wszystkich testach okno dialogowe jest prawidłowo zamknięte i wszystkie zachowania są zgodne z oczekiwaniami.

To, co zrobiłem, pokazano poniżej. Celem jest wypełnienie mojego modelu danych (mDataObject), a następnie wypełnienie go do interfejsu użytkownika. Powinien umożliwić obracanie ekranu w dowolnym momencie bez zaskoczenia.

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.
    }
}
To mi pasuje. Nie wiem, czy to jest "poprawna" metoda zaprojektowana przez Androida-twierdzą, że ta "destroy/recreate activity during screen rotation" faktycznie ułatwia sprawę, więc chyba to nie powinno być trudne. Daj mi znać, jeśli zobaczysz problem w moim kodzie. Jak wspomniano powyżej, tak naprawdę Nie wiem, czy jest jakiś efekt uboczny.
 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/doraprojects.net/template/agent.layouts/content.php on line 54
2010-02-19 18:23:56

Moim rozwiązaniem było rozszerzenie klasy ProgressDialog, Aby uzyskać własną MyProgressDialog.
Przedefiniowałem metody show() i dismiss(), Aby zablokować orientację przed pokazaniem Dialog i odblokować ją z powrotem po odrzuceniu Dialog. Kiedy więc Dialog jest pokazana i zmienia się orientacja urządzenia, orientacja ekranu pozostaje do wywołania dismiss(), a następnie orientacja ekranu zmienia się zgodnie z wartościami czujnika / orientacją urządzenia.

Oto Mój kod:

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/doraprojects.net/template/agent.layouts/content.php on line 54
2015-04-20 16:00:42

Początkowo postrzegany problem polegał na tym, że kod nie przetrwa zmiany orientacji ekranu. Widocznie zostało to "rozwiązane" poprzez zmianę orientacji ekranu przez program, zamiast pozwolić frameworkowi interfejsu użytkownika (poprzez wywołanie onDestroy)).

Chciałbym zgłosić, że jeśli podstawowym problemem jest to, że program nie przetrwa ondestroy (), to zaakceptowane rozwiązanie jest tylko obejściem, które pozostawia program z poważnymi innymi problemami i lukami. Pamiętaj, że struktura Androida wyraźnie stwierdza, że Twoja aktywność jest zagrożona zniszczeniem prawie w dowolnym momencie z powodu okoliczności poza Twoją kontrolą. Dlatego Twoja aktywność musi być w stanie przetrwać ondestroy() i kolejne OnCreate() z dowolnego powodu, a nie tylko zmiany orientacji ekranu.

Jeśli chcesz zaakceptować zmiany orientacji ekranu, aby rozwiązać problem OP, musisz sprawdzić, czy inne przyczyny ondestroy() nie skutkują tym samym błąd. Jesteś w stanie to zrobić? Jeśli nie, chciałbym zapytać, czy odpowiedź "przyjęta" jest naprawdę bardzo dobra.

 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/doraprojects.net/template/agent.layouts/content.php on line 54
2011-05-23 21:21:13

Miałem do czynienia z tym samym problemem, i wymyśliłem rozwiązanie, które nie involve za pomocą ProgressDialog i uzyskać szybsze wyniki.

To, co zrobiłem, to stworzenie układu, który ma pasek postępu w nim.

<?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>

Następnie w metodzie onCreate wykonaj następujące czynności

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

Następnie wykonaj długie zadanie w wątku, a kiedy to się skończy, Ustaw Widok zawartości na rzeczywisty układ, którego chcesz użyć do tej czynności.

Na przykład:

mHandler.post(new Runnable(){

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

This is what I czy, i odkryłem, że działa szybciej niż Pokazywanie Progresdialog i jest mniej natrętny i ma lepszy wygląd moim zdaniem.

Jeśli jednak chcesz skorzystać z ProgressDialog, to ta odpowiedź nie jest dla Ciebie.

 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/doraprojects.net/template/agent.layouts/content.php on line 54
2010-09-10 14:45:25

Odkryłem na to rozwiązanie, którego jeszcze nie widziałem gdzie indziej. Możesz użyć niestandardowego obiektu aplikacji, który wie, czy masz wykonywane zadania w tle, zamiast próbować to zrobić w ćwiczeniu, które zostanie zniszczone i odtworzone przy zmianie orientacji. Pisałem o tym w tutaj .

 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/doraprojects.net/template/agent.layouts/content.php on line 54
2010-05-17 16:20:12

Zamierzam przyczynić się do mojego podejścia do rozwiązania tego problemu rotacji. To może nie być istotne dla OP, ponieważ nie używa AsyncTask, ale może inni uznają to za przydatne. Jest to dość proste, ale wydaje się, że to działa za mnie:

Mam aktywność logowania z zagnieżdżoną AsyncTask klasą o nazwie BackgroundLoginTask.

W moim BackgroundLoginTask nie robię nic nadzwyczajnego poza dodaniem sprawdzania null przy wywołaniu ProgressDialog:

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

Służy do obsługi sprawy, w której zadanie tła kończy się, gdy {[10] } nie jest widoczny, a zatem okno dialogowe postępu zostało już odrzucone metodą onPause().

Następnie, w mojej klasie rodzica Activity, tworzę globalne statyczne Uchwyty do mojej klasy AsyncTask i mojej ProgressDialog (AsyncTask, będąc zagnieżdżonym, może uzyskać dostęp do tych zmiennych):

private static BackgroundLoginTask backgroundLoginTask;
private static ProgressDialog pleaseWaitDialog;

Służy to dwóm celom: po pierwsze, pozwala mojemu Activity zawsze uzyskać dostęp do AsyncTask obiektu nawet z nowej, poobrotowej aktywności. Po drugie, pozwala mojej BackgroundLoginTask na dostęp i odrzucenie ProgressDialog nawet po obróceniu.

Następnie dodaję to do onPause(), powodując, że okno postępu zniknie, gdy nasza Activity opuszcza pierwszy plan (zapobiegając tej brzydkiej awarii "force close"):

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

Wreszcie, mam następujące w mojej metodzie onResume():

if ((backgroundLoginTask != null) && (backgroundLoginTask.getStatus() == Status.RUNNING))
        {
           if (pleaseWaitDialog != null)
             pleaseWaitDialog.show();
        }
Pozwala to na ponowne pojawienie się Dialog po odtworzeniu Activity.

Oto cała klasa:

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

    }
}

W żadnym wypadku nie jestem doświadczonym programistą Androida, więc nie krępuj się komentować.

 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/doraprojects.net/template/agent.layouts/content.php on line 54
2015-04-20 16:18:52

Przenieś długie zadanie do oddzielnej klasy. Zaimplementuj to jako wzorzec podmiot-obserwator. Za każdym razem, gdy aktywność jest tworzona rejestruj i zamykaj ją za pomocą klasy task. Klasa Task może używać 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/doraprojects.net/template/agent.layouts/content.php on line 54
2009-07-11 04:56:07

Sztuką jest pokazanie / odrzucenie okna dialogowego w AsyncTask podczas onPreExecute/onPostExecute jak zwykle, jednak w przypadku orientacji-zmiana Utwórz / Pokaż nową instancję okna dialogowego w aktywności i przekaż jego odniesienie do zadania.

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/doraprojects.net/template/agent.layouts/content.php on line 54
2011-06-28 13:20:28

Zrobiłem to tak:

    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 {

                }
            }
        }

    }

Możesz też spróbować i dać mi znać, że to działa dla Ciebie, czy nie

 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/doraprojects.net/template/agent.layouts/content.php on line 54
2013-06-29 05:03:41

Jeśli utworzysz tło Service to sprawia, że wszystkie ciężkie podnoszenie (żądania/odpowiedź tcp, unmarshalling), View i Activity mogą być zniszczone i ponownie utworzone bez wycieku okna lub utraty danych. Pozwala to na zalecane zachowanie Androida, które polega na zniszczeniu aktywności przy każdej zmianie konfiguracji (np. dla każdej zmiany orientacji).

Jest to nieco bardziej skomplikowane, ale jest to najlepszy sposób na wywołanie żądania serwera, przetwarzanie danych przed / po, itd.

Możesz nawet użyć swojego Service do kolejkowania każdego żądania do serwera, dzięki czemu obsługa tych rzeczy jest łatwa i wydajna.

Poradnik dewelopera zawiera pełny rozdział na temat 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/doraprojects.net/template/agent.layouts/content.php on line 54
2011-03-10 17:11:08

Mam implementację, która pozwala na zniszczenie aktywności przy zmianie orientacji ekranu, ale nadal niszczy okno dialogowe w odtworzonej aktywności. Używam ...NonConfigurationInstance, aby dołączyć zadanie w tle do odtworzonej aktywności. Normalny Android Framework obsługuje odtwarzanie samego okna dialogowego, nic się tam nie zmienia.

Podklasowałem AsyncTask dodając pole dla aktywności' owning ' i metodę aktualizacji tego właściciela.

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

  ...
}

W mojej klasie aktywności I dodano pole backgroundTask odnoszące się do 'owned' backgroundtask, i aktualizuję to pole za pomocą onRetainNonConfigurationInstance i 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;
  }
  ...
}

Sugestie dotyczące dalszej poprawy:

  • Wyczyść odniesienie backgroundTask w aktywności po zakończeniu zadania, aby zwolnić pamięć lub inne zasoby z nią związane.
  • Wyczyść odniesienie ownerActivity w zadaniu backgroundtask przed zniszczeniem aktywności, na wypadek gdyby nie została natychmiast odtworzona.
  • utworzyć BackgroundTask interfejs i / lub zbiór pozwalający na uruchamianie różnych typów zadań z tego samego działania.
 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/doraprojects.net/template/agent.layouts/content.php on line 54
2011-04-29 13:56:09

Jeśli zachowasz dwa układy, wszystkie wątki interfejsu powinny zostać zakończone.

Jeśli używasz AsynTask, możesz łatwo wywołać metodę .cancel() wewnątrz metody onDestroy() bieżącej aktywności.

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

Dla AsyncTask, przeczytaj więcej w sekcji "anulowanie zadania" w tutaj .

Aktualizacja: Dodano warunek sprawdzania stanu, ponieważ może być anulowany tylko wtedy, gdy jest w stanie uruchomionym. Należy również pamiętać, że AsyncTask może być wykonany tylko jeden raz.

 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/doraprojects.net/template/agent.layouts/content.php on line 54
2011-08-03 10:04:11

Próbowałem zaimplementować rozwiązanie jfelectron , ponieważ jest to "solidne rozwiązanie tych problemów, które jest zgodne z'Android Way 'rzeczy ", ale zajęło trochę czasu, aby spojrzeć i poskładać wszystkie wymienione elementy. Skończyło się na tym nieco innym, a myślę, że bardziej eleganckim, rozwiązaniu zamieszczonym tutaj w całości.

Używa usługi IntentService uruchomionej z aktywności do wykonywania długotrwałego zadania w oddzielnym wątku. Serwis odpala Nadawanie intencji do działania, które aktualizują okno dialogowe. Działanie wykorzystuje metody showDialog (), onCreateDialog () i onPrepareDialog () w celu wyeliminowania konieczności przekazywania trwałych danych w obiekcie aplikacji lub pakiecie savedInstanceState. Powinno to działać bez względu na to, jak aplikacja zostanie przerwana.

Klasa Aktywności:

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

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

Wpisy w pliku manifestu:

Przed sekcją aplikacji:

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

Wewnątrz aplikacji Sekcja

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/doraprojects.net/template/agent.layouts/content.php on line 54
2012-04-27 04:50:27

Oto moje proponowane rozwiązanie:

  • Przenieś Asynktask lub wątek do zachowanego fragmentu, jak wyjaśniono tutaj . Uważam, że dobrą praktyką jest przenoszenie wszystkich połączeń sieciowych na fragmenty. Jeśli już używasz fragmentów, jeden z nich może być odpowiedzialny za połączenia. W przeciwnym razie możesz utworzyć fragment tylko do wykonania żądania, zgodnie z propozycją połączonego artykułu.
  • fragment użyje interfejsu słuchacza, aby zasygnalizować zakończenie/niepowodzenie zadania. Ty nie muszę się martwić o zmiany orientacji. Fragment zawsze będzie miał poprawny link do bieżącej aktywności, a okno dialogowe postępu można bezpiecznie wznowić.
  • Uczyń okno dialogowe postępów członkiem swojej klasy. W rzeczywistości powinieneś to zrobić dla wszystkich dialogów. W metodzie onPause powinieneś je odrzucić, w przeciwnym razie wycieknie okno na zmianę konfiguracji. Stan zajęty powinien być utrzymywany przez fragment. Gdy fragment jest dołączony do aktywności, możesz wywołać postęp okno dialogowe ponownie, jeśli połączenie jest nadal uruchomione. W tym celu można dodać metodę void showProgressDialog() do interfejsu fragment-activity listener.
 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/doraprojects.net/template/agent.layouts/content.php on line 54
2014-06-26 15:33:27

Próbowałem wszystkiego. Spędziłem dni eksperymentując. Nie chciałem blokować aktywności przed obrotem. Mój scenariusz był:

  1. okno dialogowe postępu pokazujące użytkownikowi dynamiczne informacje. Np.: "łączenie się z serwerem...", "Pobieranie danych...", itp.
  2. wątek robiący ciężkie rzeczy i aktualizujący okno dialogowe
  3. Aktualizacja interfejsu użytkownika z wynikami na końcu.

Problem polegał na tym, że podczas obracania ekranu każde rozwiązanie w książce zawiodło. Nawet z AsyncTask klasy, czyli prawidłowy sposób radzenia sobie z tą sytuacją. Podczas obracania ekranu aktualny kontekst, z którym pracuje wątek początkowy, zniknie, a to psuje wyświetlane okno dialogowe. Problemem zawsze było okno dialogowe, bez względu na to, ile sztuczek dodałem do kodu (przekazywanie nowych kontekstów do uruchomionych wątków, zachowywanie Stanów wątków przez rotacje itp...). Złożoność kodu na końcu była zawsze ogromna i zawsze było coś, co mogło pójść źle.

Jedynym rozwiązaniem, które zadziałało dla mnie, była sztuczka z aktywnością/dialogiem. To proste i genialne i to wszystko jest dowodem rotacji:

  1. Zamiast tworzyć okno dialogowe i poprosić o pokazanie go, Utwórz aktywność, która została ustawiona w manifeście za pomocą android: theme=" @ android: style / Theme.Dialog". Wygląda to na dialog.

  2. Zamień showDialog (DIALOG_ID) na startActivityForResult (yourActivityDialog, yourCode);

  3. Stosowanie onActivityResult w działanie wywołujące, aby uzyskać wyniki z wykonującego wątku (nawet błędy) i zaktualizować interfejs użytkownika.

  4. W "ActivityDialog", użyj wątków lub AsyncTask do wykonywania długich zadań i onRetainNonConfigurationInstance, aby zapisać stan "dialog" podczas obracania ekranu.

To jest szybkie i działa dobrze. Nadal używam okien dialogowych dla innych zadań i AsyncTask dla czegoś, co nie wymaga stałego okna dialogowego na ekranie. Ale z tym scenariuszem, zawsze idę na Wzór aktywności / okna dialogowego.

I, nie próbowałem, ale jest nawet możliwe, aby zablokować tę aktywność / okno z obracania, gdy wątek jest uruchomiony, przyspieszenie rzeczy, jednocześnie pozwalając na obracanie aktywności wywołania.

 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/doraprojects.net/template/agent.layouts/content.php on line 54
2010-03-07 17:47:21

W dzisiejszych czasach istnieje o wiele bardziej wyraźny sposób radzenia sobie z tego typu problemami. Typowe podejście to:

1. Upewnij się, że Twoje dane są prawidłowo oddzielone od interfejsu użytkownika:

Wszystko, co jest procesem w tle, powinno być zachowane Fragment (ustaw to za pomocą Fragment.setRetainInstance(). Staje się to Twoim "trwałym magazynem danych", w którym przechowywane są wszystkie dane, które chcesz zachować. Po zdarzeniu zmiana orientacji, Ta Fragment będzie nadal dostępna w oryginalnym stanie poprzez FragmentManager.findFragmentByTag() call (kiedy go tworzysz, powinieneś nadać mu tag , a nie ID , ponieważ nie jest dołączony do View).

Zobacz Handling Runtime Changes opracowany poradnik, aby dowiedzieć się, jak to zrobić poprawnie i dlaczego jest to najlepsza opcja.

2. Upewnij się, że poprawnie i bezpiecznie łączysz procesy w tle z interfejsem użytkownika:]}

Musisz odwrócić proces łączenia. W tej chwili twój proces w tle przywiązuje się do View - zamiast tego twój {[5] } powinien być dołączony do procesu w tle. To ma sens, prawda? Akcja View jest zależna od procesu w tle, podczas gdy proces w tle nie jest zależny od View.Oznacza to zmianę łącza na standardowy interfejs Listener. Powiedz swój proces (niezależnie od klasy - czy jest to AsyncTask, Runnable lub cokolwiek) definiuje OnProcessFinishedListener, gdy proces jest wykonywany, powinien wywołać ten listener, jeśli istnieje.

This answer is a ładny zwięzły opis jak zrobić niestandardowych słuchaczy.

3. Po utworzeniu interfejsu użytkownika (w tym zmianie orientacji) można połączyć interfejs użytkownika z procesem danych.]}

Teraz musisz się martwić o powiązanie zadania w tle z dowolną bieżącą strukturą View. Jeśli prawidłowo obsługujesz zmiany orientacji (Nie configChanges hakerzy zawsze polecają), to twój Dialog zostanie odtworzony przez system. Jest to ważne, oznacza to, że na Orientację zmień, wszystkie metody cyklu życia twojego Dialog zostaną odwołane. Tak więc w każdej z tych metod (onCreateDialog jest zwykle dobrym miejscem), można wykonać wywołanie w następujący sposób:

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

Zobacz Fragment lifecycle aby zdecydować, gdzie ustawienie słuchacza najlepiej pasuje do twojej indywidualnej implementacji.

Jest to ogólne podejście do zapewnienia solidnego i kompletnego rozwiązania ogólnego problemu zadanego w tym pytaniu. W tej odpowiedzi prawdopodobnie brakuje kilku drobnych elementów w zależności od indywidualnego scenariusza, ale jest to na ogół najbardziej poprawne podejście do prawidłowej obsługi zdarzeń zmiany orientacji.

 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/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:26:10

Stanąłem w tej samej sytuacji. To, co zrobiłem, to tylko jedna instancja dla mojego okna postępu w całej aplikacji.

Najpierw utworzyłem klasę DialogSingleton, aby uzyskać tylko jedną instancję (wzór Singletona)

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

Jak pokazuję w tej klasie, mam okno progress jako atrybut. Za każdym razem, gdy muszę pokazać okno postępu, dostaję unikalną instancję i tworzę nowy ProgressDialog.

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

Kiedy skończę zadanie w tle, ponownie wywołuję unikalny wystąpienie i odrzucenie jego okna dialogowego.

DialogSingleton.GetInstance().DialogDismiss(this);

Zapisuję status zadania w tle w moich współdzielonych preferencjach. Kiedy obracam ekran, pytam, Czy mam uruchomione zadanie dla tej czynności: (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).

Kiedy zaczynam uruchamiać zadanie w tle:

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

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

Kiedy skończę uruchamiać zadanie w tle:

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

DialogSingleton.GetInstance().DialogDismiss(ActivityName.this);
Mam nadzieję, że to pomoże.
 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/doraprojects.net/template/agent.layouts/content.php on line 54
2015-12-29 19:16:21

To bardzo stare pytanie, które pojawiło się na pasku bocznym z jakiegoś powodu.

Jeśli zadanie w tle musi przetrwać tylko wtedy, gdy aktywność jest na pierwszym planie, "nowym" rozwiązaniem jest hostowanie wątku w tle (lub, najlepiej, AsyncTask) w zachowanym fragmencie , jak opisano w tym przewodnik dla programistówi liczne Q&jako.

Zachowany fragment przetrwa, jeśli aktywność zostanie zniszczona w celu zmiany konfiguracji, ale Nie gdy aktywność jest niszczony w tle lub z tyłu stosu. Dlatego zadanie w tle powinno zostać przerwane, jeśli isChangingConfigurations() is false in 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/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:03:05

[1]}Jestem świeższy w Androidzie i próbowałem tego i to działa.

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/doraprojects.net/template/agent.layouts/content.php on line 54
2016-07-06 21:14:25

Wydaje się zbyt "szybkie i brudne", aby było prawdziwe, więc proszę wskazać wady, ale to, co znalazłem zadziałało...

W ramach metody onPostExecute mojej AsyncTask, po prostu owinąłem '.Odrzuć ' dla okna dialogowego postępu w bloku try/catch (z pustym catch), a następnie po prostu zignorował wyjątek, który został podniesiony. Wydaje się źle zrobić, ale wydaje się, że nie ma żadnych złych skutków (przynajmniej dla tego, co robię później, czyli rozpocząć kolejną aktywność przechodzącą w wyniku mojego długiego biegu zapytanie jako dodatkowe)

 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/doraprojects.net/template/agent.layouts/content.php on line 54
2010-11-10 10:58:12

Najprostszym i najbardziej elastycznym rozwiązaniem jest użycie AsyncTask ze statycznym odniesieniem do ProgressBar . Zapewnia to zamknięte, a tym samym wielokrotnego użytku rozwiązanie problemów ze zmianą orientacji. To rozwiązanie dobrze mi służyło do różnych asynchronicznych zadań, w tym pobierania plików z Internetu, komunikacji z usługami i skanowania systemu plików. Rozwiązanie zostało dobrze przetestowane na wielu wersjach Androida i modelach telefonów. Pełne demo można znaleźć tutaj ze szczególnym zainteresowaniem plik do pobrania.java

Poniżej przedstawiam jako przykład koncepcji

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();
        }
    }
}
Korzystanie z aplikacji na Androida jest proste]}
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/doraprojects.net/template/agent.layouts/content.php on line 54
2013-05-10 19:19:09

Znalazłem i łatwiejsze rozwiązanie do obsługi wątków przy zmianie orientacji. Możesz po prostu zachować statyczne odniesienie do swojej aktywności / fragmentu i sprawdzić, czy jego null przed uruchomieniem interfejsu użytkownika. Ja też proponuję spróbować złapać:

 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/doraprojects.net/template/agent.layouts/content.php on line 54
2015-10-02 15:11:31

Jeśli masz problemy z wykrywaniem zdarzeń zmiany orientacji w oknie dialogowym niezależnie od odniesienia do aktywności, ta metoda działa ekscytująco dobrze. Używam tego, ponieważ mam własną klasę dialog, która może być wyświetlana w wielu różnych działaniach, więc nie zawsze wiem, w której aktywności jest wyświetlana. Dzięki tej metodzie nie musisz zmieniać AndroidManifest, martwić się o odniesienia do aktywności i nie potrzebujesz niestandardowego okna dialogowego(jak mam). Potrzebujesz jednak niestandardowego Widok zawartości, dzięki czemu można wykryć zmiany orientacji za pomocą tego konkretnego widoku. Oto mój przykład:

Setup

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

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

        //DO SOMETHING HERE!! :D
    }
}

Implementacja 1-Dialog

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

Implementacja 2-AlertDialog.Budowniczy

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

Implementacja 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/doraprojects.net/template/agent.layouts/content.php on line 54
2015-11-18 18:13:32