onSaveInstanceState () và onRestoreInstanceState ()


138

Tôi đang cố gắng lưu và khôi phục trạng thái của một Activityphương thức onSaveInstanceState()onRestoreInstanceState().

Vấn đề là nó không bao giờ đi vào onRestoreInstanceState()phương thức. Bất cứ ai có thể giải thích cho tôi tại sao điều này là?


1
@Nitin: cảm ơn vì đã chia sẻ liên kết ... điều này đã làm sáng tỏ một số điều cho tôi +1
Taliadon

2
@NitinBansal liên kết đã chết.
ashishdhiman2007

Câu trả lời:


190

Thông thường bạn khôi phục lại trạng thái của bạn trong onCreate(). Có thể khôi phục nó onRestoreInstanceState()là tốt, nhưng không phổ biến lắm. ( onRestoreInstanceState()được gọi sau onStart(), trong khi onCreate()được gọi trước onStart().

Sử dụng các phương thức put để lưu trữ giá trị trong onSaveInstanceState():

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

Và khôi phục các giá trị trong onCreate():

public void onCreate(Bundle icicle) {
  if (icicle != null){
    value = icicle.getLong("param");
  }
}

2
vấn đề là tôi sử dụng startActivity để quay lại hoạt động A. Khi quay lại hoạt động B, đối tượng là ic ic null.
BlaBRA

5
Nếu tôi hiểu chính xác, đây là những gì bạn đang làm: Từ B bạn gọi startActivity (A). Sau đó, từ A bạn gọi kết thúc () để quay lại B. Phải không? Trong trường hợp đó, hoạt động đầu tiên của bạn, B sẽ không bị hủy và cả onCreate () cũng như onRestoreInstanceState () sẽ không được gọi. Các phương thức này chỉ được gọi khi cần thiết, đó là khi một hoạt động đã bị hủy và cần được hệ thống tạo lại.
Robert

4
Tôi nên thêm rằng hoạt động đầu tiên của bạn, B, có thể bị phá hủy do điều kiện bộ nhớ thấp. Điều này sẽ kích hoạt onCreate và onRestoreInstanceState.
Robert

1
erikb, vâng, hoạt động B sẽ được nối lại hoặc trong trường hợp HĐH đã lấy lại nó, tái tạo và sau đó tiếp tục lại.
Robert


149

onRestoreInstanceState()chỉ được gọi khi tái tạo hoạt động sau khi nó bị hệ điều hành giết chết . Tình huống như vậy xảy ra khi:

  • hướng của thiết bị thay đổi (hoạt động của bạn bị phá hủy và được tạo lại).
  • có một hoạt động khác ở phía trước của bạn và tại một số điểm, HĐH sẽ giết chết hoạt động của bạn để giải phóng bộ nhớ (ví dụ). Lần tới khi bạn bắt đầu hoạt động, onRestoreInstanceState () sẽ được gọi.

Ngược lại: nếu bạn đang hoạt động và nhấn Backnút trên thiết bị, hoạt động của bạn sẽ kết thúc () ed (nghĩa là nghĩ đó là thoát ứng dụng máy tính để bàn) và lần sau khi bạn khởi động ứng dụng, nó sẽ bắt đầu "mới", tức là không có lưu trạng thái vì bạn cố tình thoát nó khi bạn nhấn Back.

Một nguồn gây nhầm lẫn khác là khi một ứng dụng mất tập trung vào một ứng dụng khác onSaveInstanceState()được gọi nhưng khi bạn điều hướng trở lại ứng dụng của bạn onRestoreInstanceState()có thể không được gọi. Đây là trường hợp được mô tả trong câu hỏi ban đầu, tức là nếu hoạt động của bạn KHÔNG bị giết trong khoảng thời gian khi hoạt động khác ở phía trước onRestoreInstanceState()sẽ KHÔNG được gọi vì hoạt động của bạn khá "sống".

Tất cả trong tất cả, như đã nêu trong tài liệu cho onRestoreInstanceState():

Hầu hết các triển khai sẽ chỉ đơn giản là sử dụng onCreate (Gói) để khôi phục trạng thái của chúng, nhưng đôi khi thuận tiện để thực hiện ở đây sau khi tất cả việc khởi tạo đã được thực hiện hoặc cho phép các lớp con quyết định có sử dụng triển khai mặc định của bạn hay không. Việc triển khai mặc định của phương thức này thực hiện khôi phục bất kỳ trạng thái xem nào trước đây đã bị đóng băng bởi onSaveInstanceState (Gói).

Như tôi đã đọc: Không có lý do gì để ghi đè onRestoreInstanceState()trừ khi bạn đang phân lớp Activityvà dự kiến ​​sẽ có người phân lớp phụ của bạn.


3
yeh điều này có vẻ đúng, nhưng nó hút. Tôi cũng nên chạy khi quay lại hoạt động từ hoạt động khác. có rất nhiều tình huống mà bạn cần điều này.
Masi

4
@masi đã có các phương thức khác được gọi trên Activity khi người dùng quay lại nó (từ một hoạt động khác). OnSave / RestoreInstanceState () được sử dụng cho mục đích cụ thể khác, đó là nó.
superjos

8

Trạng thái bạn lưu tại onSaveInstanceState()sau này có sẵn tại onCreate()lời gọi phương thức. Vì vậy, sử dụng onCreate(và Bundletham số của nó ) để khôi phục trạng thái hoạt động của bạn.


4

Như một giải pháp thay thế, bạn có thể lưu trữ một gói với dữ liệu bạn muốn duy trì trong Mục đích bạn sử dụng để bắt đầu hoạt động A.

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

Hoạt động A sẽ phải chuyển lại hoạt động này cho Hoạt động B. Bạn sẽ truy xuất ý định trong phương thức onCreate của Hoạt động B.

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

Một ý tưởng khác là tạo một lớp kho lưu trữ để lưu trữ trạng thái hoạt động và để mỗi hoạt động của bạn tham chiếu lớp đó (có thể sử dụng cấu trúc đơn lẻ.) Mặc dù vậy, làm như vậy có lẽ rắc rối hơn giá trị của nó.


3

Điều chính là nếu bạn không lưu trữ onSaveInstanceState()thì onRestoreInstanceState()sẽ không được gọi. Đây là sự khác biệt chính giữa restoreInstanceState()onCreate(). Hãy chắc chắn rằng bạn thực sự lưu trữ một cái gì đó. Nhiều khả năng đây là vấn đề của bạn.


1
onRestoreInstanceState () sẽ được gọi, ngay cả khi bạn không lưu trữ bất cứ thứ gì trong OnSaveInstanceState ()
abh22ishek 17/215

3

Tôi thấy rằng onSaveInstanceState luôn được gọi khi một Hoạt động khác xuất hiện ở phía trước. Và trênStop cũng vậy.

Tuy nhiên, onRestoreInstanceState chỉ được gọi khi onCreate và onStart cũng được gọi. Và, onCreate và onStart KHÔNG phải lúc nào cũng được gọi.

Vì vậy, có vẻ như Android không phải lúc nào cũng xóa thông tin trạng thái ngay cả khi Hoạt động chuyển sang nền. Tuy nhiên, nó gọi các phương thức vòng đời để lưu trạng thái chỉ để an toàn. Do đó, nếu trạng thái không bị xóa, thì Android sẽ không gọi các phương thức vòng đời để khôi phục trạng thái vì chúng không cần thiết.

Hình 2 mô tả điều này.


2

Tôi nghĩ chủ đề này đã khá cũ. Tôi chỉ đề cập đến một trường hợp khác, đó onSaveInstanceState()cũng sẽ được gọi, là khi bạn gọi Activity.moveTaskToBack(boolean nonRootActivity).


1

Nếu bạn đang xử lý các thay đổi hướng của hoạt động với android:configChanges="orientation|screenSize"onConfigurationChanged(Configuration newConfig), onRestoreInstanceState()sẽ không được gọi.


1

Không cần thiết rằng onRestoreInstanceState sẽ luôn được gọi sau onSaveInstanceState.

Lưu ý rằng: onRestoreInstanceState sẽ luôn được gọi, khi hoạt động được xoay (khi không xử lý định hướng) hoặc mở hoạt động của bạn và sau đó mở các ứng dụng khác để hệ điều hành hoạt động của bạn bị xóa khỏi bộ nhớ.


1

Từ tài liệu Khôi phục trạng thái UI hoạt động bằng trạng thái đã lưu, nó được ghi là:

Thay vì khôi phục trạng thái trong khi onCreate (), bạn có thể chọn triển khai onRestoreInstanceState () mà hệ thống gọi sau phương thức onStart (). Hệ thống chỉ gọi onRestoreInstanceState () nếu có trạng thái đã lưu để khôi phục, do đó bạn không cần kiểm tra xem Bundle có null hay không :

nhập mô tả hình ảnh ở đây

nhập mô tả hình ảnh ở đây

IMO, đây là cách rõ ràng hơn so với việc kiểm tra điều này tại onCreate và phù hợp hơn với nguyên tắc phản hồi đơn.


0

Trong trường hợp của tôi, onRestoreInstanceStateđược gọi khi hoạt động được xây dựng lại sau khi thay đổi hướng thiết bị. onCreate(Bundle)được gọi đầu tiên, nhưng gói không có khóa / giá trị tôi đặt onSaveInstanceState(Bundle).

Ngay sau đó, onRestoreInstanceState(Bundle)được gọi với một gói có khóa / giá trị chính xác.


0

Tôi vừa chạy vào đây và nhận thấy rằng tài liệu có câu trả lời của tôi:

"Hàm này sẽ không bao giờ được gọi với trạng thái null."

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

Trong trường hợp của tôi, tôi đã tự hỏi tại sao onRestoreInstanceState không được gọi vào khởi tạo ban đầu. Điều này cũng có nghĩa là nếu bạn không lưu trữ bất cứ thứ gì, nó sẽ không được gọi khi bạn xây dựng lại chế độ xem của mình.


0

Tôi có thể làm như vậy (xin lỗi, nó không phải là java nhưng nó không phải là vấn đề ...):

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

VÀ TRONG HOẠT ĐỘNG CỦA BẠN ĐỂ KẾT QUẢ

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

Cuối cùng

protected override void OnActivityResult(int iRequestCode, Android.App.Result oResultCode, Intent oIntent)
{
    base.OnActivityResult (iRequestCode, oResultCode, oIntent);
    iValue = oIntent.Extras.GetInt("MYVALUE", -1); //=> 1234567890
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.