onSaveInstanceState () dan onRestoreInstanceState ()

138

Saya mencoba untuk menyimpan dan memulihkan keadaan Activitymenggunakan metode onSaveInstanceState()dan onRestoreInstanceState().

Masalahnya adalah itu tidak pernah memasuki onRestoreInstanceState()metode. Adakah yang bisa menjelaskan kepada saya mengapa ini terjadi?

BlaBRA
sumber
1
@Nitin: terima kasih telah berbagi tautan ... ini telah menyelesaikan beberapa hal untuk saya +1
Taliadon
2
@NitinBansal tautannya sudah mati.
ashishdhiman2007

Jawaban:

191

Biasanya Anda mengembalikan negara Anda di onCreate(). Dimungkinkan untuk mengembalikannya onRestoreInstanceState()juga, tetapi tidak terlalu umum. ( onRestoreInstanceState()Disebut setelah onStart(), sedangkan onCreate()disebut sebelumnya onStart().

Gunakan metode put untuk menyimpan nilai di onSaveInstanceState():

protected void onSaveInstanceState(Bundle icicle) {
  super.onSaveInstanceState(icicle);
  icicle.putLong("param", value);
}

Dan kembalikan nilai dalam onCreate():

public void onCreate(Bundle icicle) {
  if (icicle != null){
    value = icicle.getLong("param");
  }
}
Robert
sumber
2
masalahnya adalah bahwa saya menggunakan startActivity untuk kembali ke aktivitas A. Ketika kembali ke aktivitas B, objeknya adalah null icicle.
BlaBRA
5
Jika saya mengerti dengan benar, inilah yang Anda lakukan: Dari B Anda menelepon startActivity (A). Kemudian dari A Anda panggil finish () untuk kembali ke B. Benar? Dalam hal ini aktivitas pertama Anda, B tidak akan dihancurkan, dan onCreate () atau onRestoreInstanceState () tidak akan dipanggil. Metode-metode ini hanya dipanggil ketika dibutuhkan, yaitu ketika suatu kegiatan telah dihancurkan dan perlu diciptakan kembali oleh sistem.
Robert
4
Saya harus menambahkan bahwa aktivitas pertama Anda, B, mungkin hancur karena kondisi memori yang rendah. Ini akan memicu onCreate dan onRestoreInstanceState.
Robert
1
erikb, ya, aktivitas B akan dilanjutkan, atau seandainya OS telah mengklaimnya kembali, diciptakan kembali dan kemudian dilanjutkan.
Robert
1
Oh, inilah sebabnya
Al Lelopath
149

onRestoreInstanceState()dipanggil hanya ketika membuat ulang aktivitas setelah dibunuh oleh OS. Situasi seperti itu terjadi ketika:

  • orientasi perangkat berubah (aktivitas Anda dihancurkan dan diciptakan kembali).
  • ada aktivitas lain di depan Anda dan di beberapa titik OS membunuh aktivitas Anda untuk membebaskan memori (misalnya). Lain kali ketika Anda memulai aktivitas Anda diRestoreInstanceState () akan dipanggil.

Sebaliknya: jika Anda berada dalam aktivitas Anda dan menekan Backtombol pada perangkat, aktivitas Anda selesai () ed (yaitu menganggapnya sebagai keluar dari aplikasi desktop) dan lain kali Anda memulai aplikasi Anda itu dimulai "segar", yaitu tanpa disimpan negara karena Anda sengaja keluar ketika Anda menekan Back.

Sumber kebingungan lainnya adalah ketika sebuah aplikasi kehilangan fokus ke aplikasi lain onSaveInstanceState()dipanggil tetapi ketika Anda menavigasi kembali ke aplikasi Anda onRestoreInstanceState()mungkin tidak dipanggil. Ini adalah kasus yang dijelaskan dalam pertanyaan awal, yaitu jika aktivitas Anda TIDAK terbunuh selama periode ketika aktivitas lain di depan onRestoreInstanceState()TIDAK akan dipanggil karena aktivitas Anda cukup banyak "hidup".

Secara keseluruhan, sebagaimana dinyatakan dalam dokumentasi untuk onRestoreInstanceState():

Sebagian besar implementasi hanya akan menggunakan onCreate (Bundle) untuk memulihkan keadaan mereka, tetapi kadang-kadang nyaman untuk melakukannya di sini setelah semua inisialisasi telah dilakukan atau untuk memungkinkan subkelas untuk memutuskan apakah akan menggunakan implementasi default Anda. Implementasi default metode ini melakukan pengembalian kondisi tampilan apa pun yang sebelumnya telah dibekukan oleh onSaveInstanceState (Bundle).

Seperti yang saya baca: Tidak ada alasan untuk mengesampingkan onRestoreInstanceState()kecuali Anda mensubclassing Activitydan diharapkan seseorang akan membuat subclass subclass Anda.

Ognyan
sumber
3
kamu sepertinya ini benar, tapi itu menyebalkan. imo itu juga harus dijalankan ketika kembali ke aktivitas dari aktivitas lain. ada banyak situasi di mana Anda membutuhkan ini.
masi
4
@masi sudah ada metode lain yang dipanggil pada Activity ketika pengguna kembali ke sana (dari aktivitas lain). OnSave / RestoreInstanceState () digunakan untuk tujuan spesifik lain, hanya itu.
superjos
8

Keadaan tempat Anda menyimpan onSaveInstanceState()nanti tersedia di onCreate()pemanggilan metode. Jadi gunakan onCreate(dan Bundleparameternya) untuk memulihkan keadaan aktivitas Anda.

Konstantin Burov
sumber
4

Sebagai solusinya, Anda bisa menyimpan bundel dengan data yang ingin Anda pertahankan di Intent yang Anda gunakan untuk memulai aktivitas A.

Intent intent = new Intent(this, ActivityA.class);
intent.putExtra("bundle", theBundledData);
startActivity(intent);

Kegiatan A harus meneruskan ini kembali ke Kegiatan B. Anda akan mengambil maksud dalam metode onCreate Kegiatan B.

Intent intent = getIntent();
Bundle intentBundle;
if (intent != null)
    intentBundle = intent.getBundleExtra("bundle");
// Do something with the data.

Gagasan lain adalah membuat kelas repositori untuk menyimpan status aktivitas dan meminta setiap aktivitas Anda mereferensikan kelas tersebut (mungkin menggunakan struktur tunggal). Meskipun demikian, melakukannya mungkin lebih banyak masalah daripada nilainya.

sotrh
sumber
3

Hal utama adalah bahwa jika Anda tidak menyimpannya onSaveInstanceState()maka onRestoreInstanceState()tidak akan dipanggil. Ini adalah perbedaan utama antara restoreInstanceState()dan onCreate(). Pastikan Anda benar-benar menyimpan sesuatu. Kemungkinan besar ini adalah masalah Anda.

pengguna1771286
sumber
1
onRestoreInstanceState () akan dipanggil, bahkan jika Anda tidak menyimpan apa pun di OnSaveInstanceState ()
abh22ishek
3

Saya menemukan bahwa onSaveInstanceState selalu dipanggil ketika Kegiatan lain datang ke latar depan. Dan begitu juga OnStop.

Namun, onRestoreInstanceState dipanggil hanya ketika onCreate dan onStart juga dipanggil. Dan, onCreate dan onStart TIDAK selalu dipanggil.

Jadi sepertinya Android tidak selalu menghapus informasi status bahkan jika Aktivitas bergerak ke latar belakang. Namun, ia memanggil metode siklus hidup untuk menyelamatkan keadaan hanya agar aman. Jadi, jika status tidak dihapus, maka Android tidak memanggil metode siklus hidup untuk memulihkan status karena tidak diperlukan.

Gambar 2 menjelaskan hal ini.

berdengung
sumber
2

Saya pikir utas ini sudah cukup tua. Saya hanya menyebutkan kasus lain, yang onSaveInstanceState()juga akan dipanggil, adalah ketika Anda menelepon Activity.moveTaskToBack(boolean nonRootActivity).

macio.Jun
sumber
1

Jika Anda menangani perubahan orientasi aktivitas dengan android:configChanges="orientation|screenSize"dan onConfigurationChanged(Configuration newConfig), onRestoreInstanceState()tidak akan dipanggil.

Rajkiran
sumber
1

Tidak perlu bahwa onRestoreInstanceState akan selalu dipanggil setelah onSaveInstanceState.

Perhatikan bahwa: onRestoreInstanceState akan selalu dipanggil, ketika aktivitas diputar (ketika orientasi tidak ditangani) atau buka aktivitas Anda dan kemudian buka aplikasi lain sehingga instance aktivitas Anda dihapus dari memori oleh OS.

Ashutosh Srivastava
sumber
1

Dari dokumentasi Restore state UI aktivitas menggunakan status instance tersimpan dinyatakan sebagai:

Alih-alih mengembalikan keadaan selama onCreate () Anda dapat memilih untuk mengimplementasikan onRestoreInstanceState (), yang dipanggil sistem setelah metode onStart (). Sistem memanggil onRestoreInstanceState () hanya jika ada negara yang disimpan untuk memulihkan, sehingga Anda tidak perlu memeriksa apakah Bundel itu nol :

masukkan deskripsi gambar di sini

masukkan deskripsi gambar di sini

IMO, ini lebih jelas daripada memeriksa ini di onCreate, dan lebih cocok dengan prinsip tanggung jawab tunggal.

Teoman shipahi
sumber
0

Dalam kasus saya, onRestoreInstanceStatedipanggil ketika aktivitas direkonstruksi setelah mengubah orientasi perangkat. onCreate(Bundle)dipanggil terlebih dahulu, tetapi bundel tidak memiliki kunci / nilai yang saya atur onSaveInstanceState(Bundle).

Tepat setelah onRestoreInstanceState(Bundle)itu , dipanggil dengan bundel yang memiliki kunci / nilai yang benar.

elvitucho
sumber
0

Saya baru saja menemukan ini dan memperhatikan bahwa dokumentasi tersebut memiliki jawaban saya:

"Fungsi ini tidak akan pernah dipanggil dengan keadaan nol."

https://developer.android.com/reference/android/view/View.html#onRestoreInstanceState(android.os.Parcelable)

Dalam kasus saya, saya bertanya-tanya mengapa onRestoreInstanceState tidak dipanggil pada instantiasi awal. Ini juga berarti bahwa jika Anda tidak menyimpan apa pun, itu tidak akan dipanggil ketika Anda akan merekonstruksi pandangan Anda.

Ben Scannell
sumber
0

Saya bisa melakukan itu (maaf itu c # bukan java tapi itu tidak masalah ...):

private int iValue = 1234567890;

function void MyTest()
{
    Intent oIntent = new Intent (this, typeof(Camera2Activity));
    Bundle oBundle = new Bundle();
    oBundle.PutInt("MYVALUE", iValue); //=> 1234567890
    oIntent.PutExtras (oBundle);
    iRequestCode = 1111;
    StartActivityForResult (oIntent, 1111);
}

DAN DALAM AKTIVITAS ANDA UNTUK HASIL

private int iValue = 0;

protected override void OnCreate(Bundle bundle)
{
    Bundle oBundle =  Intent.Extras;
    if (oBundle != null)
    {
        iValue = oBundle.GetInt("MYVALUE", 0);
        //=>1234567890
    }
}

private void FinishActivity(bool bResult)
{
    Intent oIntent = new Intent();
    Bundle oBundle = new Bundle();
    oBundle.PutInt("MYVALUE", iValue);//=>1234567890
    oIntent.PutExtras(oBundle);
    if (bResult)
        {
            SetResult (Result.Ok, oIntent);
        }
    else
        SetResult(Result.Canceled, oIntent);
    GC.Collect();
    Finish();
}

AKHIRNYA

protected override void OnActivityResult(int iRequestCode, Android.App.Result oResultCode, Intent oIntent)
{
    base.OnActivityResult (iRequestCode, oResultCode, oIntent);
    iValue = oIntent.Extras.GetInt("MYVALUE", -1); //=> 1234567890
}
EDynamic90
sumber