onSaveInstanceState () และ onRestoreInstanceState ()


138

ฉันพยายามที่จะบันทึกและเรียกคืนสถานะของนั้นActivityโดยใช้วิธีการและonSaveInstanceState()onRestoreInstanceState()

ปัญหาคือมันไม่เคยเข้าonRestoreInstanceState()วิธี มีใครอธิบายให้ฉันฟังได้ไหมว่าเพราะอะไร


1
@Nitin: ขอบคุณที่แบ่งปันลิงค์ ... สิ่งนี้ได้หักล้างบางสิ่งสำหรับฉัน +1
Taliadon

2
@NininBansal ลิงก์นั้นตาย
ashishdhiman2007

คำตอบ:


191

onCreate()โดยปกติแล้วคุณเรียกคืนสถานะของคุณ เป็นไปได้ที่จะกู้คืนในonRestoreInstanceState()เช่นกัน แต่ก็ไม่ธรรมดา ( onRestoreInstanceState()เรียกว่าหลังจากonStart()ในขณะที่เรียกว่าก่อนที่จะonCreate()onStart()

ใช้วิธีการวางเพื่อเก็บค่าในonSaveInstanceState():

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

และเรียกคืนค่าในonCreate():

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

2
ปัญหาคือว่าฉันใช้ startActivity เพื่อกลับไปที่กิจกรรม A. เมื่อกลับไปที่กิจกรรม B วัตถุที่เป็นน้ำแข็ง
BlaBRA

5
ถ้าฉันเข้าใจถูกต้องนี่คือสิ่งที่คุณกำลังทำ: จาก B คุณเรียก startActivity (A) จากนั้นคุณโทรไปที่ finish () เพื่อกลับไปที่ B. ใช่ไหม ในกรณีนั้นกิจกรรมแรกของคุณ B จะไม่ถูกทำลายและจะไม่มีการเรียก onCreate () หรือ onRestoreInstanceState () วิธีการเหล่านี้จะถูกเรียกเมื่อจำเป็นเท่านั้นนั่นคือเมื่อกิจกรรมถูกทำลายและจำเป็นต้องสร้างขึ้นใหม่โดยระบบ
Robert

4
ฉันควรเพิ่มว่ากิจกรรมแรกของคุณ B อาจถูกทำลายเนื่องจากเงื่อนไขหน่วยความจำเหลือน้อย สิ่งนี้จะทริกเกอร์ onCreate และ onRestoreInstanceState
Robert

1
ขั้นแรกใช่กิจกรรม B จะได้รับการดำเนินการต่อหรือในกรณีที่ระบบปฏิบัติการได้เรียกคืนมาสร้างใหม่และดำเนินการต่อแล้ว
Robert


149

onRestoreInstanceState()ถูกเรียกใช้เฉพาะเมื่อสร้างกิจกรรมใหม่หลังจากที่ระบบปฏิบัติการนั้นถูกฆ่า สถานการณ์ดังกล่าวเกิดขึ้นเมื่อ:

  • การวางแนวของการเปลี่ยนแปลงอุปกรณ์ (กิจกรรมของคุณถูกทำลายและสร้างใหม่)
  • มีกิจกรรมอื่นอยู่ข้างหน้าของคุณและในบางจุดระบบปฏิบัติการจะฆ่ากิจกรรมของคุณเพื่อเพิ่มหน่วยความจำ (ตัวอย่าง) ครั้งต่อไปเมื่อคุณเริ่มต้นกิจกรรมของคุณบนRestoreInstanceState () จะถูกเรียก

ในทางตรงกันข้าม: หากคุณอยู่ในกิจกรรมของคุณและคุณกดBackปุ่มบนอุปกรณ์กิจกรรมของคุณจะเสร็จสิ้น () ed (เช่นคิดว่ามันเป็นการออกจากแอปพลิเคชันเดสก์ท็อป) และในครั้งต่อไปที่คุณเริ่มแอป Backบันทึกรัฐเพราะคุณจงใจเดินออกมาจากมันเมื่อคุณกด

แหล่งที่มาของความสับสนอื่น ๆ คือเมื่อมีการเรียกแอพโฟกัสไปที่แอพอื่นonSaveInstanceState()แต่เมื่อคุณนำทางกลับไปที่แอพของคุณonRestoreInstanceState()อาจไม่ถูกเรียก นี่เป็นกรณีที่อธิบายไว้ในคำถามเดิมเช่นหากกิจกรรมของคุณไม่ถูกฆ่าในช่วงเวลาที่กิจกรรมอื่น ๆ อยู่ข้างหน้าonRestoreInstanceState()จะไม่ถูกเรียกเนื่องจากกิจกรรมของคุณค่อนข้าง "มีชีวิตชีวา"

ทั้งหมดตามที่ระบุไว้ในเอกสารประกอบสำหรับonRestoreInstanceState():

การใช้งานส่วนใหญ่จะใช้ onCreate (Bundle) เพื่อกู้คืนสถานะของพวกเขา แต่บางครั้งก็สะดวกที่จะทำที่นี่หลังจากการเริ่มต้นทั้งหมดเสร็จสิ้นหรืออนุญาตให้คลาสย่อยตัดสินใจว่าจะใช้การเริ่มต้นใช้งานของคุณหรือไม่ การใช้งานเริ่มต้นของวิธีนี้ทำการคืนค่าสถานะมุมมองใด ๆ ที่ก่อนหน้านี้ถูกตรึงโดย onSaveInstanceState (Bundle)

ตามที่ฉันได้อ่าน: ไม่มีเหตุผลใดที่จะลบล้างonRestoreInstanceState()ยกเว้นว่าคุณกำลังทำคลาสย่อยอยู่Activityและคาดว่าจะมีใครบางคนจะทำคลาสย่อยของคุณให้เป็นคลาสย่อย


3
ใช่นี่ดูเหมือนจะถูก แต่ก็แย่มาก imo มันควรจะทำงานเมื่อกลับไปที่กิจกรรมจากกิจกรรมอื่น มีสถานการณ์มากมายที่คุณต้องการสิ่งนี้
masi

4
@masi มีวิธีการอื่นที่เรียกใช้ในกิจกรรมเมื่อผู้ใช้กลับไปที่มัน (จากกิจกรรมอื่น) onSave / RestoreInstanceState () ใช้เพื่อจุดประสงค์อื่นโดยเฉพาะ
superjos

8

สถานะที่คุณบันทึกที่onSaveInstanceState()มีอยู่ในภายหลังที่onCreate()วิธีการภาวนา ดังนั้นใช้onCreate(และBundleพารามิเตอร์) เพื่อคืนสถานะกิจกรรมของคุณ


4

คุณสามารถจัดเก็บบันเดิลกับข้อมูลที่คุณต้องการเก็บไว้ใน Intent ที่คุณใช้เพื่อเริ่มกิจกรรม A

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

กิจกรรม A จะต้องผ่านสิ่งนี้กลับไปที่กิจกรรม B คุณจะต้องดึงความตั้งใจในวิธีการ onCreate ของกิจกรรม B

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

อีกแนวคิดหนึ่งคือการสร้างคลาสที่เก็บข้อมูลเพื่อเก็บสถานะกิจกรรมและให้แต่ละกิจกรรมอ้างอิงคลาสนั้น (เป็นไปได้โดยใช้โครงสร้างซิงเกิล) แม้ว่าการทำเช่นนั้นอาจเป็นปัญหามากกว่าที่ควรจะเป็น


3

สิ่งสำคัญคือถ้าคุณไม่เก็บไว้ในonSaveInstanceState()นั้นonRestoreInstanceState()จะไม่ถูกเรียก นี่คือความแตกต่างที่สำคัญระหว่างและrestoreInstanceState() onCreate()ตรวจสอบให้แน่ใจว่าคุณเก็บอะไรบางอย่างจริงๆ เป็นไปได้มากว่านี่เป็นปัญหาของคุณ


1
onRestoreInstanceState () จะถูกเรียกแม้ว่าคุณจะไม่เก็บอะไรไว้ใน OnSaveInstanceState ()
abh22ishek

3

ฉันพบว่า onSaveInstanceState จะถูกเรียกเสมอเมื่อมีกิจกรรมอื่นมาถึงเบื้องหน้า และดังนั้นจึงเป็นบนหยุด

อย่างไรก็ตาม onRestoreInstanceState ถูกเรียกเมื่อ onCreate และ onStart ถูกเรียกด้วย และ onCreate และ onStart ก็ไม่ได้ถูกเรียกเสมอ

ดังนั้นดูเหมือนว่า Android จะไม่ลบข้อมูลสถานะเสมอแม้ว่ากิจกรรมจะย้ายไปที่พื้นหลัง อย่างไรก็ตามมันเรียกวิธีการวงจรชีวิตเพื่อบันทึกสถานะเพียงเพื่อความปลอดภัย ดังนั้นหากสถานะไม่ถูกลบออก Android จะไม่เรียกวิธีการวงจรชีวิตเพื่อเรียกคืนสถานะเนื่องจากไม่จำเป็น

รูปที่ 2อธิบายสิ่งนี้


2

ฉันคิดว่ากระทู้นี้ค่อนข้างเก่า ฉันเพียงแค่พูดถึงอีกกรณีหนึ่งที่จะได้รับการเรียกว่าเป็นเมื่อคุณเรียกonSaveInstanceState()Activity.moveTaskToBack(boolean nonRootActivity)


1

หากคุณมีการจัดการกิจกรรมของการเปลี่ยนแปลงการวางแนวทางด้วยandroid:configChanges="orientation|screenSize"และonConfigurationChanged(Configuration newConfig), onRestoreInstanceState()จะไม่ถูกเรียก


1

ไม่จำเป็นว่า onRestoreInstanceState จะถูกเรียกหลังจาก onSaveInstanceState เสมอ

โปรดทราบว่า: onRestoreInstanceState จะถูกเรียกเสมอเมื่อมีการหมุนกิจกรรม (เมื่อไม่มีการจัดการการวางแนว) หรือเปิดกิจกรรมของคุณแล้วเปิดแอปอื่น ๆ เพื่อให้ระบบดำเนินการอินสแตนซ์กิจกรรมของคุณจากหน่วยความจำ


1

จากเอกสารการคืนค่าสถานะกิจกรรม UI โดยใช้สถานะอินสแตนซ์ที่บันทึกไว้จะมีการระบุเป็น:

แทนที่จะเรียกคืนสถานะระหว่าง onCreate () คุณสามารถเลือกใช้ onRestoreInstanceState () ซึ่งระบบจะเรียกใช้หลังจากเมธอด onStart () ระบบเรียกใช้ onRestoreInstanceState () เฉพาะเมื่อมีสถานะที่บันทึกไว้เพื่อกู้คืนดังนั้นคุณไม่จำเป็นต้องตรวจสอบว่า Bundle เป็นโมฆะหรือไม่ :

ป้อนคำอธิบายรูปภาพที่นี่

ป้อนคำอธิบายรูปภาพที่นี่

IMO นี่เป็นวิธีที่ชัดเจนกว่าการตรวจสอบที่ onCreate และเหมาะกับหลักการความรับผิดชอบเดียว


0

ในกรณีของฉันonRestoreInstanceStateถูกเรียกเมื่อกิจกรรมถูกสร้างขึ้นใหม่หลังจากเปลี่ยนการวางแนวอุปกรณ์ onCreate(Bundle)ก็เรียกว่าเป็นครั้งแรก แต่กำไม่ได้มีคีย์ / onSaveInstanceState(Bundle)ค่าที่ผมตั้งด้วย

หลังจากนั้นonRestoreInstanceState(Bundle)ถูกเรียกพร้อมกับบันเดิลที่มีคีย์ / ค่าที่ถูกต้อง


0

ฉันเพิ่งพบปัญหานี้และพบว่าเอกสารมีคำตอบของฉัน:

"ฟังก์ชั่นนี้จะไม่ถูกเรียกด้วยสถานะว่าง"

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

ในกรณีของฉันฉันสงสัยว่าทำไม onRestoreInstanceState จึงไม่ถูกเรียกใช้ในการเริ่มต้นเริ่มต้น นี่ก็หมายความว่าถ้าคุณไม่เก็บอะไรมันจะไม่ถูกเรียกเมื่อคุณไปสร้างมุมมองใหม่


0

ฉันสามารถทำเช่นนั้นได้ (ขออภัยที่ไม่ใช่ c # ไม่ใช่ java แต่ไม่ใช่ปัญหา ... ):

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

และในกิจกรรมของคุณเพื่อผลลัพธ์

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

ในที่สุด

protected override void OnActivityResult(int iRequestCode, Android.App.Result oResultCode, Intent oIntent)
{
    base.OnActivityResult (iRequestCode, oResultCode, oIntent);
    iValue = oIntent.Extras.GetInt("MYVALUE", -1); //=> 1234567890
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.