วิธีใช้ตัวอย่าง onSavedInstanceState


110

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

public class Conversation extends Activity {
    private ProgressDialog progDialog;
    int typeBar;
    TextView text1;
    EditText edit;
    Button respond;
    private String name;
    private String textAtView;
    private String savedName;

    public void onCreate(Bundle savedInstanceState){
        super.onCreate(savedInstanceState);

        setContentView(R.layout.dorothydialog);
        text1 = (TextView)findViewById(R.id.dialog);
        edit = (EditText)findViewById(R.id.repsond);
        respond = (Button)findViewById(R.id.button01);

        if(savedInstanceState != null){
            savedInstanceState.get(savedName);
            text1.setText(savedName);
        }
        else{
            text1.setText("Hello! What is your name?");
            respond.setOnClickListener(new View.OnClickListener() {

                @Override
                public void onClick(View v) {
                    name = edit.getText().toString();
                    text1.setText("Nice to meet you "+ name);
                }   
            });
        }
    }

    @Override
    public void onSaveInstanceState(Bundle outState){
        super.onSaveInstanceState(outState);
        outState.putString(savedName, name);
    }
}

text1.setText (savedInstanceState.getString (บันทึกชื่อ));
Spidy

@Spidy แล้ว onBackpressed ล่ะ? ฉันจะตอบสนองต่อสิ่งนี้กับบันเดิลได้อย่างไร?
tj walker

คุณจะไม่ เมื่อผู้ใช้กดปุ่มย้อนกลับ กิจกรรมถูกฆ่า ใช้ฐานข้อมูลสำหรับจัดเก็บข้อมูลถาวร ใช้ Bundle เพื่อส่งคืนแอปพลิเคชันที่รีสตาร์ทกลับสู่สถานะก่อนหน้า
Spidy

คำตอบ:


198

Bundleเป็นภาชนะสำหรับทุกข้อมูลที่คุณต้องการที่จะบันทึก คุณใช้ฟังก์ชันใส่ * เพื่อแทรกข้อมูลลงในนั้น นี่คือรายการสั้น ๆ (มีอีกมากมาย) ของฟังก์ชันใส่ที่คุณสามารถใช้เพื่อจัดเก็บข้อมูลในไฟล์Bundle.

putString
putBoolean
putByte
putChar
putFloat
putLong
putShort
putParcelable (used for objects but they must implement Parcelable)

ในonCreateฟังก์ชันของคุณสิ่งนี้Bundleจะถูกส่งกลับไปยังโปรแกรม วิธีที่ดีที่สุดในการตรวจสอบว่ามีการโหลดแอปพลิเคชันใหม่หรือไม่หรือเริ่มเป็นครั้งแรกคือ:

if (savedInstanceState != null) {
    // Then the application is being reloaded
}

ในการดึงข้อมูลออกมาให้ใช้ฟังก์ชัน get * เหมือนกับฟังก์ชัน put * ข้อมูลจะถูกจัดเก็บเป็นคู่ชื่อ - ค่า นี่เป็นเหมือนแฮชแมป คุณระบุคีย์และค่าจากนั้นเมื่อคุณต้องการค่ากลับคุณให้คีย์และฟังก์ชันจะได้รับค่า นี่คือตัวอย่างสั้น ๆ

@Override
public void onSaveInstanceState(Bundle outState) {
   outState.putString("message", "This is my message to be reloaded");
   super.onSaveInstanceState(outState);
}

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    if (savedInstanceState != null) {
        String message = savedInstanceState.getString("message");
        Toast.makeText(this, message, Toast.LENGTH_LONG).show();
    }
}

ข้อความที่คุณบันทึกไว้จะถูกส่งไปที่หน้าจอ หวังว่านี่จะช่วยได้


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

@Spidy เจ๋ง! คุณทำให้ฉันเข้าใจทุกอย่างเกี่ยวกับมัด! ดังนั้นฉันเดาว่า outState ถูกส่งกลับไปยังบันเดิลที่บันทึกไว้ แก้ไข?
tj walker

ใช่. outState Bundle จะถูกส่งกลับเข้าไปในรูปแบบที่บันทึกไว้ InstanceState Bundle
Spidy

1
@tj walker - แหล่งข้อมูลที่ยอดเยี่ยมอีกอย่างคือหนังสืออ้างอิงทางเทคนิค Pro Android 3 เป็นทรัพยากรราคาถูก แต่กว้างขวางที่คุณหาได้จาก Amazon
Spidy

@Spidy ฉันโพสต์รหัสกิจกรรมของฉันไว้ด้านบนเพื่อให้คุณเห็น บางทีคุณอาจแจ้งให้เราทราบได้หากฉันประหยัดรัฐตามที่คุณแนะนำ
tj walker

34

ข้อสังเกตสำคัญประการหนึ่งที่นักพัฒนา Android ใหม่ทุกคนควรทราบคือข้อมูลใด ๆ ในวิดเจ็ต (TextView, ปุ่ม ฯลฯ ) จะยังคงอยู่โดยอัตโนมัติโดย Android ตราบเท่าที่คุณกำหนด ID ให้กับพวกเขา นั่นหมายความว่าสถานะ UI ส่วนใหญ่ได้รับการดูแลโดยไม่มีปัญหา เมื่อคุณต้องการจัดเก็บข้อมูลอื่นเท่านั้นที่จะกลายเป็นปัญหา

จากAndroid Docs :

สิ่งเดียวที่คุณต้องการคือการระบุ ID เฉพาะ (พร้อมด้วยแอตทริบิวต์ android: id) สำหรับแต่ละวิดเจ็ตที่คุณต้องการบันทึกสถานะ หากวิดเจ็ตไม่มี ID ก็จะไม่สามารถบันทึกสถานะได้


1
นั่นเป็นเรื่องจริงเหรอ? เนื่องจากฉันมีกิจกรรมที่มีปุ่มดูข้อความและแก้ไขข้อความ หากแอปพลิเคชันถูกทำลายหรือฆ่าทุกอย่างจะกลับสู่สถานะเดิม ในแอปพลิเคชันของฉันข้อความ textView จะเปลี่ยนทุกครั้งที่ผู้ใช้คลิกปุ่ม
tj walker

เอกสารประกอบไม่ถูกต้องหรือไม่? ฉันไม่เคยมี View บันทึกข้อมูลของตัวเอง ทางออกที่ดีที่สุดของคุณคือการบันทึกข้อมูลทั้งหมดของคุณด้วยตัวคุณเองในความคิดของฉัน
Spidy

2
หากเป้าหมายของคุณคือการบันทึกข้อมูลบน SaveInstanceState ไม่ใช่สถานที่ที่จะทำ นั่นเป็นเพราะไม่มีการรับประกันว่าจะถูกเรียก (ดูเอกสาร) คุณควรเขียนลงในฐานข้อมูล SharedPreferences และอื่น ๆ แทนใช่ข้อมูลนี้ถูกต้อง วิธีที่ดีที่สุดในการทดสอบว่า UI ของคุณยังคงอยู่ในลักษณะนี้หรือไม่คือการหมุนการแสดงผลของคุณเมื่อการเปลี่ยนแปลงการวางแนวเรียกใช้ onCreate ของคุณอีกครั้งและใช้บันเดิลเพื่อกู้คืนสถานะ
Keith Adler

@ นิสสันแฟนคุณสามารถยกตัวอย่างเช่น spidy ด้านบนได้หรือไม่? ด้วย sharedprefs และทั้งหมด? ขอบคุณ
tj walker

ตัวอย่างที่ดีที่สุดค่อนข้างตรงไปตรงมาจากเอกสารประกอบ developer.android.com/guide/topics/data/data-storage.html#pref
Keith Adler

6

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


5

เก็บข้อมูล:

static final String PLAYER_SCORE = "playerScore";
static final String PLAYER_LEVEL = "playerLevel";

@Override
public void onSaveInstanceState(Bundle savedInstanceState) {
    // Save the user's current game state
    savedInstanceState.putInt(PLAYER_SCORE, mCurrentScore);
    savedInstanceState.putInt(PLAYER_LEVEL, mCurrentLevel);

// Always call the superclass so it can save the view hierarchy state
super.onSaveInstanceState(savedInstanceState);
}

หากคุณไม่ต้องการกู้คืนข้อมูลใน onCreate-Method ของคุณ:

นี่คือตัวอย่าง: การสร้างกิจกรรมใหม่

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

public void onRestoreInstanceState(Bundle savedInstanceState) {
// Always call the superclass so it can restore the view hierarchy
super.onRestoreInstanceState(savedInstanceState);

// Restore state members from saved instance
mCurrentScore = savedInstanceState.getInt(PLAYER_SCORE);
mCurrentLevel = savedInstanceState.getInt(PLAYER_LEVEL);
}

0

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

สมมติว่าคุณมีกิจกรรมที่มี EditText ผู้ใช้เขียนข้อความข้างใน หลังจากนั้นระบบจะเรียกใช้ onSaveInstanceState () ของคุณ คุณอ่านข้อความจาก EditText และเขียนลงใน Bundle ผ่าน Bundle.putString ("edit_text_value", theValue)

ตอนนี้ onCreate เรียกว่า คุณตรวจสอบว่าบันเดิลที่ให้มาไม่เป็นโมฆะ หากเป็นเช่นนั้นคุณสามารถกู้คืนค่าของคุณผ่าน Bundle.getString ("edit_text_value") และใส่กลับเข้าไปใน EditText ของคุณ


0

สำหรับข้อมูลเพิ่มเติม

ลองนึกภาพสถานการณ์นี้

  1. กิจกรรมเปิดตัวกิจกรรม B.
  2. ActivityB เปิดตัว ActivityAPrime ใหม่โดย

    Intent intent = new Intent(getApplicationContext(), ActivityA.class);
    startActivity(intent);
  3. ActivityAPrime ไม่มีความสัมพันธ์กับ ActivityA
    ในกรณีนี้ Bundle ใน ActivityAPrime.onCreate () จะเป็นโมฆะ

หาก ActivityA และ ActivityAPrime ควรเป็นกิจกรรมเดียวกันแทนที่จะเป็นกิจกรรมที่ต่างกัน ActivityB ควรเรียกว่า finish () แทนที่จะใช้ startActivity ()


เพียงเพื่อชี้แจงในตัวอย่างของคุณคือ ActivityA == ActivityA instance 1 และ ActivityAPrime == ActivityA instance 2 หรือไม่ เช่นกันเมื่อคุณพูดว่า "ActivityB ควรเรียกว่า finish () มากกว่าการใช้ startActivity ()" คุณหมายถึง: (1) AcitivityB ควรเรียก finish () จากนั้นใช้ startActivity () หลังจากนั้น (2) หรือ ActivityB ควรเรียก finish () แทนที่จะใช้ startActivity () เลย? หากคุณหมายถึงตัวเลือกที่ 2 คุณจะแนะนำให้ใครบางคนเริ่มต้นกิจกรรมเดียวกันได้อย่างไรอินสแตนซ์ 1 เพื่อให้คุณสามารถโหลดข้อมูลกิจกรรมที่มีอยู่ก่อนที่จะถูกทำลาย / เสร็จสิ้น ขอบคุณ
cjayem13

ActivityA และ ActivityAPrime เป็นคลาสเดียวกัน แต่ต่างกันอินสแตนซ์ ในสถานการณ์สมมตินี้ ActivityA ยังไม่เสร็จสิ้นธุรกิจในระหว่างนั้น บริษัท ได้สร้างและเริ่ม ActivityB ดังนั้นเมื่อ ActivityB เสร็จสิ้น ActivityA ควรดำเนินธุรกิจที่เหลือต่อไป เรียก startActivity ผิดในกรณีนี้และคาดว่า ActivityA และ ActiviyAPrime จะเป็นอินสแตนซ์เดียวกัน ดังนั้นเราจึงไม่ควรรีสตาร์ท ActivityA เพียงแค่จบ ActivityB แล้วปล่อยให้ ActivityA กลับมาดำเนินการต่อ ...
ken

0

หากข้อมูลไม่ถูกโหลดจากการsavedInstanceStateใช้รหัสต่อไปนี้
ปัญหาคือการเรียก url ไม่เสร็จสมบูรณ์ดังนั้นตรวจสอบว่ามีการโหลดข้อมูลหรือไม่เพื่อแสดงค่า instanceState

//suppose data is not Loaded to savedInstanceState at 1st swipe
if (savedInstanceState == null && !mAlreadyLoaded){
    mAlreadyLoaded = true;
    GetStoryData();//Url Call
} else {
    if (listArray != null) {  //Data Array From JsonArray(ListArray)
        System.out.println("LocalData  " + listArray);
        view.findViewById(R.id.progressBar).setVisibility(View.GONE);
    }else{
        GetStoryData();//Url Call
    }
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.