2866 Stimmen

Wie kann ich einen Aktivitätsstatus mit der Funktion "Instanzstatus speichern" speichern?

Ich habe mit der Android-SDK-Plattform gearbeitet, und es ist ein wenig unklar, wie man den Status einer Anwendung speichert. Angesichts dieser geringfügigen Umrüstung des Beispiels "Hello, Android":

package com.android.hello;

import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;

public class HelloAndroid extends Activity {

  private TextView mTextView = null;

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

    mTextView = new TextView(this);

    if (savedInstanceState == null) {
       mTextView.setText("Welcome to HelloAndroid!");
    } else {
       mTextView.setText("Welcome back.");
    }

    setContentView(mTextView);
  }
}

Ich dachte, es würde für den einfachsten Fall ausreichen, aber es antwortet immer mit der ersten Nachricht, egal wie ich von der App weg navigiere.

Ich bin sicher, dass die Lösung so einfach ist wie das Aufheben von onPause oder so ähnlich, aber ich habe etwa 30 Minuten lang in der Dokumentation gestöbert und nichts Eindeutiges gefunden.

103voto

Fedor Punkte 43061

onSaveInstanceState wird aufgerufen, wenn das System Speicher benötigt und eine Anwendung beendet. Er wird nicht aufgerufen, wenn der Benutzer die Anwendung einfach schließt. Daher denke ich, dass der Anwendungsstatus auch in onPause .

Sie sollte in einem dauerhaften Speicher wie Preferences oder SQLite.

42 Stimmen

Entschuldigung, das ist nicht ganz korrekt. onSaveInstanceState wird aufgerufen, bevor die Aktivität neu erstellt werden muss, d.h. jedes Mal, wenn der Benutzer das Gerät dreht. Es ist für die Speicherung transienter View-Zustände gedacht. Wenn Android das Schließen der Anwendung erzwingt, wird onSaveInstanceState tatsächlich NICHT aufgerufen (weshalb es für die Speicherung wichtiger Anwendungsdaten unsicher ist). onPause wird jedoch garantiert aufgerufen, bevor die Aktivität beendet wird, daher sollte es verwendet werden, um permanente Informationen in Einstellungen oder Squlite zu speichern. Richtige Antwort, falsche Gründe.

79voto

David Punkte 801

Beide Methoden sind nützlich und gültig, und beide eignen sich am besten für unterschiedliche Szenarien:

  1. Der Benutzer beendet die Anwendung und öffnet sie zu einem späteren Zeitpunkt erneut, aber die Anwendung muss die Daten der letzten Sitzung erneut laden - dies erfordert einen Ansatz zur dauerhaften Speicherung, z. B. mit SQLite.
  2. Der Benutzer wechselt die Anwendung und kehrt dann zur ursprünglichen Anwendung zurück und möchte dort weitermachen, wo er aufgehört hat - Speichern und Wiederherstellen von Bündeldaten (z. B. Anwendungsstatusdaten) in onSaveInstanceState() y onRestoreInstanceState() ist in der Regel ausreichend.

Wenn Sie die Zustandsdaten persistent speichern, können sie in einem der folgenden Fälle wieder geladen werden onResume() o onCreate() (oder eigentlich bei jedem Lebenszyklusaufruf). Dies kann das gewünschte Verhalten sein oder auch nicht. Wenn Sie es in einem Bundle in einer InstanceState dann ist sie flüchtig und eignet sich nur für die Speicherung von Daten zur Verwendung in derselben "Sitzung" des Benutzers (ich verwende den Begriff "Sitzung" sehr großzügig), aber nicht zwischen "Sitzungen".

Es ist nicht so, dass der eine Ansatz besser ist als der andere, es ist nur wichtig zu verstehen, welches Verhalten Sie benötigen und den am besten geeigneten Ansatz zu wählen.

78voto

Mike A. Punkte 1403

Die Rettung des Staates ist in meinen Augen bestenfalls eine Flickschusterei. Wenn Sie persistente Daten speichern müssen, verwenden Sie einfach eine SQLite Datenbank. Android macht es SOOO einfach.

Etwa so:

import java.util.Date;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;

public class dataHelper {

    private static final String DATABASE_NAME = "autoMate.db";
    private static final int DATABASE_VERSION = 1;

    private Context context;
    private SQLiteDatabase db;
    private OpenHelper oh ;

    public dataHelper(Context context) {
        this.context = context;
        this.oh = new OpenHelper(this.context);
        this.db = oh.getWritableDatabase();
    }

    public void close() {
        db.close();
        oh.close();
        db = null;
        oh = null;
        SQLiteDatabase.releaseMemory();
    }

    public void setCode(String codeName, Object codeValue, String codeDataType) {
        Cursor codeRow = db.rawQuery("SELECT * FROM code WHERE codeName = '"+  codeName + "'", null);
        String cv = "" ;

        if (codeDataType.toLowerCase().trim().equals("long") == true){
            cv = String.valueOf(codeValue);
        }
        else if (codeDataType.toLowerCase().trim().equals("int") == true)
        {
            cv = String.valueOf(codeValue);
        }
        else if (codeDataType.toLowerCase().trim().equals("date") == true)
        {
            cv = String.valueOf(((Date)codeValue).getTime());
        }
        else if (codeDataType.toLowerCase().trim().equals("boolean") == true)
        {
            String.valueOf(codeValue);
        }
        else
        {
            cv = String.valueOf(codeValue);
        }

        if(codeRow.getCount() > 0) //exists-- update
        {
            db.execSQL("update code set codeValue = '" + cv +
                "' where codeName = '" + codeName + "'");
        }
        else // does not exist, insert
        {
            db.execSQL("INSERT INTO code (codeName, codeValue, codeDataType) VALUES(" +
                    "'" + codeName + "'," +
                    "'" + cv + "'," +
                    "'" + codeDataType + "')" );
        }
    }

    public Object getCode(String codeName, Object defaultValue){

        //Check to see if it already exists
        String codeValue = "";
        String codeDataType = "";
        boolean found = false;
        Cursor codeRow  = db.rawQuery("SELECT * FROM code WHERE codeName = '"+  codeName + "'", null);
        if (codeRow.moveToFirst())
        {
            codeValue = codeRow.getString(codeRow.getColumnIndex("codeValue"));
            codeDataType = codeRow.getString(codeRow.getColumnIndex("codeDataType"));
            found = true;
        }

        if (found == false)
        {
            return defaultValue;
        }
        else if (codeDataType.toLowerCase().trim().equals("long") == true)
        {
            if (codeValue.equals("") == true)
            {
                return (long)0;
            }
            return Long.parseLong(codeValue);
        }
        else if (codeDataType.toLowerCase().trim().equals("int") == true)
        {
            if (codeValue.equals("") == true)
            {
                return (int)0;
            }
            return Integer.parseInt(codeValue);
        }
        else if (codeDataType.toLowerCase().trim().equals("date") == true)
        {
            if (codeValue.equals("") == true)
            {
                return null;
            }
            return new Date(Long.parseLong(codeValue));
        }
        else if (codeDataType.toLowerCase().trim().equals("boolean") == true)
        {
            if (codeValue.equals("") == true)
            {
                return false;
            }
            return Boolean.parseBoolean(codeValue);
        }
        else
        {
            return (String)codeValue;
        }
    }

    private static class OpenHelper extends SQLiteOpenHelper {

        OpenHelper(Context context) {
            super(context, DATABASE_NAME, null, DATABASE_VERSION);
        }

        @Override
        public void onCreate(SQLiteDatabase db) {
            db.execSQL("CREATE TABLE IF  NOT EXISTS code" +
            "(id INTEGER PRIMARY KEY, codeName TEXT, codeValue TEXT, codeDataType TEXT)");
        }

        @Override
        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        }
    }
}

Ein einfacher Anruf danach

dataHelper dh = new dataHelper(getBaseContext());
String status = (String) dh.getCode("appState", "safetyDisabled");
Date serviceStart = (Date) dh.getCode("serviceStartTime", null);
dh.close();
dh = null;

9 Stimmen

Weil es zu lange dauert, eine SQLite-Datenbank zu laden, wenn man bedenkt, dass dies auf dem kritischen Pfad ist, um dem Benutzer die Benutzeroberfläche der App zu zeigen. Ich habe keine Zeitmessung durchgeführt und lasse mich daher gerne korrigieren, aber das Laden und Öffnen einer Datenbankdatei ist sicher nicht schnell?

5 Stimmen

Vielen Dank für die Bereitstellung einer Lösung, die ein Neuling ausschneiden und in seine App einfügen und sofort verwenden kann! @Tom Was die Geschwindigkeit angeht, so dauert es etwa sieben Sekunden, um 1000 Paare zu speichern, aber man kann es in einer AsyncTask tun. Sie müssen jedoch ein finally { cursor.close() } hinzufügen, sonst kommt es zu einem Absturz aufgrund eines Speicherlecks.

3 Stimmen

Ich bin darauf gestoßen, und obwohl es ganz nett aussieht, zögere ich, es auf Google Glass zu verwenden, dem Gerät, mit dem ich in letzter Zeit arbeite.

66voto

roy mathew Punkte 7782

Ich glaube, ich habe die Antwort gefunden. Lassen Sie mich in einfachen Worten sagen, was ich getan habe:

Angenommen, ich habe zwei Aktivitäten, Aktivität1 und Aktivität2, und ich navigiere von Aktivität1 zu Aktivität2 (ich habe einige Arbeiten in Aktivität2 erledigt) und wieder zurück zu Aktivität1, indem ich auf eine Schaltfläche in Aktivität1 klicke. Jetzt möchte ich zu Aktivität2 zurückkehren und meine Aktivität2 im selben Zustand sehen, in dem ich sie zuletzt verlassen habe.

Für das obige Szenario, was ich getan habe, ist, dass in das Manifest ich einige Änderungen wie folgt gemacht:

<activity android:name=".activity2"
          android:alwaysRetainTaskState="true"      
          android:launchMode="singleInstance">
</activity>

Und in der Aktivität1 auf die Schaltfläche klicken Ereignis habe ich wie folgt getan:

Intent intent = new Intent();
intent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
intent.setClassName(this,"com.mainscreen.activity2");
startActivity(intent);

Und in activity2 auf Schaltfläche klicken Ereignis habe ich wie folgt getan:

Intent intent=new Intent();
intent.setClassName(this,"com.mainscreen.activity1");
startActivity(intent);

Die Änderungen, die wir in activity2 vorgenommen haben, gehen nicht verloren, und wir können activity2 in demselben Zustand betrachten, in dem wir es verlassen haben.

Ich glaube, das ist die Antwort, und sie funktioniert bei mir gut. Korrigieren Sie mich, wenn ich falsch liege.

2 Stimmen

@bagusflyer Könnten Sie etwas genauer sein??? Ihr Kommentar ist nicht hilfreich und niemand kann Ihnen auf dieser Grundlage helfen.

2 Stimmen

Dies ist eine Antwort auf eine andere Situation: zwei Aktivitäten innerhalb derselben Anwendung. Die OP handelt von verlassen. die App (z. B. die Home-Taste oder eine andere Möglichkeit, zu einer anderen App zu wechseln).

1 Stimmen

Das ist genau die Antwort, nach der ich gesucht habe!

50voto

User Punkte 30920

onSaveInstanceState() für transiente Daten (wiederhergestellt in onCreate() / onRestoreInstanceState() ), onPause() für persistente Daten (wiederhergestellt in onResume() ). Aus den technischen Ressourcen von Android:

onSaveInstanceState() wird von Android aufgerufen, wenn die Aktivität angehalten wird und kann beendet werden, bevor sie wieder aufgenommen wird! Das bedeutet, dass der Zustand gespeichert werden sollte, der notwendig ist, um beim Neustart der Activity den gleichen Zustand wiederherzustellen. Sie ist das Gegenstück zur onCreate()-Methode, und tatsächlich ist das an onCreate() übergebene savedInstanceState-Bundle dasselbe Bundle, das Sie als outState in der onSaveInstanceState()-Methode konstruieren.

onPause() y onResume() sind ebenfalls komplementäre Methoden. onPause() wird immer aufgerufen, wenn die Aktivität endet, auch wenn wir das veranlasst haben (z. B. mit einem finish()-Aufruf). Wir verwenden diese Methode, um die aktuelle Notiz in der Datenbank zu speichern. Es ist eine gute Praxis, alle Ressourcen, die während einer onPause() freigegeben werden können, ebenfalls freizugeben, um im passiven Zustand weniger Ressourcen zu verbrauchen.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X