কীভাবে কোনও ক্রিয়াকলাপ সংরক্ষণ করুন সেভ ইনস্ট্যান্স স্টেট ব্যবহার করে?


2619

আমি অ্যান্ড্রয়েড এসডিকে প্ল্যাটফর্মে কাজ করছি এবং কোনও অ্যাপ্লিকেশনের অবস্থা কীভাবে সংরক্ষণ করা যায় এটি কিছুটা অস্পষ্ট। সুতরাং 'হ্যালো, অ্যান্ড্রয়েড' উদাহরণটির এই ছোটখাটো পুনরায় সরঞ্জামটি দেওয়া হয়েছে:

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

আমি ভেবেছিলাম এটি সহজতম ক্ষেত্রে যথেষ্ট হবে, তবে আমি অ্যাপ থেকে কীভাবে নেভিগেট করি না কেন, এটি সর্বদা প্রথম বার্তার সাথে সাড়া দেয়।

আমি নিশ্চিত যে সমাধানটি ওভাররাইডিং onPauseবা এর মতো আরও কিছু সহজ , তবে আমি 30 মিনিট বা তার বেশি সময় ধরে ডকুমেন্টেশনে ঝাঁকিয়ে পড়েছি এবং সুস্পষ্ট কিছু খুঁজে পাইনি।


9
যখন SaveInstanceState == নাল হয় এবং কখন তা শূন্য হয় না?
Trojan.ZBOT

90
আপনি স্পষ্টভাবে আপনার ক্রিয়াকলাপটি ধ্বংস করে দিচ্ছেন - যেমন আপনি বলেছিলেন, এ থেকে দূরে নেভিগেট করা, যেমন পিছনে টিপে। প্রকৃতপক্ষে, যখন এই 'সেভডআইনস্ট্যান্সস্টেট' ব্যবহার করা হয়, তখন অ্যান্ড্রয়েড বিনোদনের জন্য আপনার ক্রিয়াকলাপটি ধ্বংস করে দেয়। তাত্পর্য জন্য: আপনি যদি ক্রিয়াকলাপ চলাকালীন আপনার ফোনের ভাষা পরিবর্তন করেন (এবং আপনার প্রকল্পের বিভিন্ন সংস্থানগুলি লোড করা দরকার)। আর একটি খুব সাধারণ পরিস্থিতি হ'ল যখন আপনি আপনার ফোনটি পাশের দিকে ঘোরান যাতে ক্রিয়াকলাপটি পুনরায় তৈরি করা হয় এবং ল্যান্ডস্কেপে প্রদর্শিত হয়।
ভিলোরেন

16
দ্বিতীয় বার্তাটি পেতে, ডি অপশনগুলিতে "ক্রিয়াকলাপগুলি রাখবেন না" সক্ষম করুন। একটি হোম বোতাম টিপুন এবং রিসেন্টগুলি থেকে ফিরে আসুন।
ইয়ারোস্লাভ মেটকালিক


6
আপনি এটি দিয়ে এটি করতে পারেন: onSaveInstanceState (বান্ডেল
সেভড ইনস্ট্যান্সস্টেট

উত্তর:


2568

আপনি এই onSaveInstanceState(Bundle savedInstanceState)জাতীয় Bundleপ্যারামিটারে পরিবর্তন করতে চান এমন অ্যাপ্লিকেশন রাষ্ট্রের মানগুলি ওভাররাইড করে লিখতে হবে :

@Override
public void onSaveInstanceState(Bundle savedInstanceState) {
  super.onSaveInstanceState(savedInstanceState);
  // Save UI state changes to the savedInstanceState.
  // This bundle will be passed to onCreate if the process is
  // killed and restarted.
  savedInstanceState.putBoolean("MyBoolean", true);
  savedInstanceState.putDouble("myDouble", 1.9);
  savedInstanceState.putInt("MyInt", 1);
  savedInstanceState.putString("MyString", "Welcome back to Android");
  // etc.
}

বান্ডিলটি মূলত একটি এনভিপি ("নাম-মান জুটি") মানচিত্র সংরক্ষণের একটি উপায় এবং এটি এর onCreate()পরেও onRestoreInstanceState()চলে যাবে এবং যেখানে আপনি এর পরে ক্রিয়াকলাপ থেকে মানগুলি বের করতে পারবেন:

@Override
public void onRestoreInstanceState(Bundle savedInstanceState) {
  super.onRestoreInstanceState(savedInstanceState);
  // Restore UI state from the savedInstanceState.
  // This bundle has also been passed to onCreate.
  boolean myBoolean = savedInstanceState.getBoolean("MyBoolean");
  double myDouble = savedInstanceState.getDouble("myDouble");
  int myInt = savedInstanceState.getInt("MyInt");
  String myString = savedInstanceState.getString("MyString");
}

বা একটি টুকরা থেকে।

@Override
public void onViewStateRestored(@Nullable Bundle savedInstanceState) {
    super.onViewStateRestored(savedInstanceState);
    // Restore UI state from the savedInstanceState.
    // This bundle has also been passed to onCreate.
    boolean myBoolean = savedInstanceState.getBoolean("MyBoolean");
    double myDouble = savedInstanceState.getDouble("myDouble");
    int myInt = savedInstanceState.getInt("MyInt");
    String myString = savedInstanceState.getString("MyString");
}

আপনি সাধারণত আপনার অ্যাপ্লিকেশনটির জন্য উদাহরণ মান সংরক্ষণ করতে এই কৌশলটি ব্যবহার করবেন (নির্বাচন, সংরক্ষণ না করা পাঠ্য ইত্যাদি)।


24
কোনও সুযোগ এই ফোনে কাজ করে, তবে এমুলেটরটিতে নয়? আমি একটি নন-নাল সেভডইনস্ট্যান্স স্টেট পেয়ে যাব বলে মনে হচ্ছে না।
অ্যাডাম জ্যাক

491
যত্নবান: আপনার মানগুলি বান্ডলে যুক্ত করার আগে আপনাকে সুপার.অনসেভআইনস্ট্যান্সস্টেট (সেভড ইনস্ট্যান্সস্টেট) কল করতে হবে, বা তারা সেই কলটি মুছে ফেলবে (ড্রয়েড এক্স অ্যান্ড্রয়েড ২.২)।
jkschneider

121
সতর্কতা: অফিসিয়াল ডকুমেন্টেশনে বলা হয়েছে, অনপস-মেথডের মধ্যে আপনার গুরুত্বপূর্ণ তথ্য সংরক্ষণ করা উচিত কারণ অনস্যাভেইনস্ট্যান্স-পদ্ধতি অ্যান্ড্রয়েড লাইফেসাইকেলের অংশ নয় of বিকাশকারী.অ্যান্ড্রয়েড
রেফারেন্স

32
এই ঘটনাটি কার্যকরভাবে onSaveInstanceStateকেবলমাত্র পর্দার ওরিয়েন্টেশন পরিবর্তনের ক্ষেত্রে বাদ দিয়ে প্রায় অকেজো করে তোলে । প্রায় সব ক্ষেত্রেই আপনি কখনই এটির উপর নির্ভর করতে পারবেন না এবং আপনার ইউআই রাষ্ট্রটি অন্য কোথাও ম্যানুয়ালি সংরক্ষণ করতে হবে। অথবা পিএইচসি বোতামের আচরণকে ওভাররাইড করে আপনার অ্যাপ্লিকেশনটিকে হত্যা হতে বাধা দিচ্ছে। আমি বুঝতে পারি না কেন তারা এমনকি এটি প্রথম স্থানে প্রয়োগ করেছিল। পুরোপুরি অনিশ্চিত। এবং আপনার যে বান্ডিল সিস্টেমটি আপনাকে এই খুব বিশেষ পদ্ধতি ব্যতীত জিনিসগুলি সংরক্ষণ করতে দেয় তা থাকতে পারে না।
চক্রত

12
নোট করুন যে বান্ডেল থেকে / থেকে UI রাজ্যের সংরক্ষণ / পুনরুদ্ধার করা আইডি বরাদ্দ করা হয়েছে তাদের জন্য স্বয়ংক্রিয়ভাবে যত্ন নেওয়া হয় । দস্তাবেজগুলি থেকে : "ডিফল্ট রূপায়ণটি আইডি রয়েছে এমন হায়ারার্কির প্রতিটি দৃশ্যে কল করে এবং বর্তমানে ফোকাস করা ভিউয়ের আইডি সংরক্ষণ করে (সমস্ত কিছুই পুনরুদ্ধার করা হয়েছে) আপনার জন্য প্রতি-নজির রাজ্যের বেশিরভাগ ইউআইয়ের যত্ন নেয় এর ডিফল্ট বাস্তবায়ন দ্বারা ) "ViewonSaveInstanceStateonSaveInstanceState()onRestoreInstanceState(Bundle)
ভিকি চিজওয়ানি

433

দ্য savedInstanceStateশুধুমাত্র একটি ভ্রমণ বর্তমান উদাহরণস্বরূপ সঙ্গে যুক্ত রাষ্ট্র সংরক্ষণ, উদাহরণস্বরূপ বর্তমান গৌণ বা নির্বাচন তথ্যের জন্য জন্য, তাই যে যদি অ্যান্ড্রয়েড ধ্বংস এবং কোনো recreates, এটা ফিরে আসতে পারে যেমন আগে থেকেই আছেন। onCreateএবং এর জন্য ডকুমেন্টেশন দেখুনonSaveInstanceState

আরও দীর্ঘকালীন অবস্থায় থাকার জন্য, এসকিউএল ডাটাবেস, একটি ফাইল বা পছন্দগুলি ব্যবহার করার বিষয়টি বিবেচনা করুন। দেখুন জেদি রাজ্য সংরক্ষণ করা হচ্ছে


3
যখন SaveInstanceState == নাল হয় এবং কখন তা শূন্য হয় না?
Trojan.ZBOT

6
যখন সিস্টেমটি আপনার ক্রিয়াকলাপের একটি নতুন উদাহরণ তৈরি করে এবং পুনরুদ্ধার করা হয় তখন শূন্য হয় না সেভড ইনস্ট্যান্সস্টেটটি বাতিল হয়।
গ্যাব্রিয়েল কামারা

6
... যা সিস্টেমে কখন ক্রিয়াকলাপের একটি নতুন উদাহরণ তৈরি করতে হবে তা নিয়ে প্রশ্ন উত্থাপন করে । অ্যাপ্লিকেশন থেকে বেরিয়ে আসার কয়েকটি উপায় একটি বান্ডিল তৈরি করে না, তাই একটি নতুন উদাহরণ তৈরি করতে হবে। এটিই মূল সমস্যা; এর অর্থ এটি যে কোনও বান্ডিলের অস্তিত্বের উপর নির্ভর করতে পারে না এবং অবিরাম সঞ্চয় করার কিছু বিকল্প উপায় করতে হবে। অন ​​সেভ / অনরেস্টোরইনস্ট্যান্সস্টেটের সুবিধা হ'ল এটি এমন একটি প্রক্রিয়া যা সিস্টেম হঠাৎ করে করতে পারে , খুব বেশি সিস্টেমের সংস্থান ব্যয় না করে । সুতরাং এটি সমর্থন করা ভাল, পাশাপাশি অ্যাপ্লিকেশন থেকে আরও করুণাময় প্রস্থান করার জন্য অবিরাম সঞ্চয়স্থান রয়েছে।
টুলমেকারস্টেভ

415

নোট করুন যে এটি ব্যবহার করা এবং ধ্রুবক ডেটার জন্য নিরাপদ নয় , ক্রিয়াকলাপের ডকুমেন্টেশন অনুসারে http://developer.android.com/references/android/app/Activity.html তে ক্রিয়াকলাপে লেখা আছে ।onSaveInstanceStateonRestoreInstanceState

দস্তাবেজটিতে বলা হয়েছে ('ক্রিয়াকলাপ জীবনচক্র' বিভাগে):

মনে রাখবেন onPause()পরিবর্তে অবিরাম ডেটা সংরক্ষণ করা জরুরী onSaveInstanceState(Bundle) কারণ পরবর্তীকালে লাইফসাইকাল কলব্যাকের অংশ নয়, সুতরাং এটির ডকুমেন্টেশনে বর্ণিত প্রতিটি অবস্থাতেই ডাকা হবে না।

অন্য কথায়, অবিচ্ছিন্ন ডেটার জন্য আপনার সেভ / পুনরুদ্ধার কোডটি রাখুন onPause()এবং onResume()!

সম্পাদনা : আরও স্পষ্টতার জন্য, এখানে onSaveInstanceState()ডকুমেন্টেশন রয়েছে:

কোনও ক্রিয়াকলাপ হত্যার আগে এই পদ্ধতিটি বলা হয় যাতে ভবিষ্যতে যখন কিছু সময় ফিরে আসে তখন এটি তার অবস্থা পুনরুদ্ধার করতে পারে। উদাহরণস্বরূপ, যদি ক্রিয়াকলাপ বি এর আগে ক্রিয়াকলাপ বি চালু করা হয় এবং সংস্থানগুলি পুনরায় দাবি করার জন্য কোনও পর্যায়ে ক্রিয়াকলাপী মারা যায়, ক্রিয়াকলাপ A এর এই পদ্ধতির মাধ্যমে তার ব্যবহারকারী ইন্টারফেসের বর্তমান অবস্থা সংরক্ষণ করার সুযোগ থাকবে যাতে ব্যবহারকারী যখন ফিরে আসবে ক্রিয়াকলাপ এ এ, ব্যবহারকারীর ইন্টারফেসের অবস্থা onCreate(Bundle)বা মাধ্যমে পুনরুদ্ধার করা যেতে পারে onRestoreInstanceState(Bundle)


55
শুধু নিটপিক করার জন্য: এটিও নিরাপদ নয়। এটি কেবল আপনি কী সংরক্ষণ করতে চান এবং কতক্ষণের জন্য, যা বার্নার্ড তার মূল প্রশ্নে সম্পূর্ণ পরিষ্কার নয় depends ইনস্ট্যান্সস্টেট বর্তমান ইউআই রাষ্ট্র সংরক্ষণের জন্য উপযুক্ত (ডেটা নিয়ন্ত্রণে প্রবেশ করা হয়েছে, তালিকাগুলিতে বর্তমান অবস্থানগুলি এবং এর আগে), যেখানে দীর্ঘকালীন অবিরাম স্টোরেজ করার জন্য বিরতি / পুনঃসূচনা একমাত্র সম্ভাবনা।
পন্টাস গ্যাজে

30
এটি ডাউনভোট করা উচিত। লাইফসাইकल পদ্ধতিগুলির মতো (সংরক্ষণ করুন | পুনরুদ্ধার করুন) ইনস্ট্যান্সস্টেটে এটি ব্যবহার করা নিরাপদ নয় (অর্থাত্ রাজ্য সংরক্ষণ / পুনরুদ্ধার ব্যতীত এগুলিতে অন্য কিছু করুন)। রাষ্ট্র সংরক্ষণ / পুনরুদ্ধার করার জন্য তারা পুরোপুরি ভাল। এছাড়াও, আপনি কীভাবে অনপেজ এবং অনরেউসুমে রাষ্ট্র সংরক্ষণ / পুনরুদ্ধার করতে চান? আপনি যে পদ্ধতিগুলি ব্যবহার করতে পারেন সেগুলিতে আপনি বান্ডিল পান না, তাই আপনাকে ডেটাবেস, ফাইল ইত্যাদিতে কিছু অন্যান্য রাষ্ট্র-সঞ্চয় নিয়োগ করতে হবে যা বোকা।
ফেলিক্স

141
আমরা কমপক্ষে এই ব্যক্তিকে ভোট দেওয়া উচিত নয়, তিনি ডকুমেন্টেশনের মধ্য দিয়ে যাওয়ার চেষ্টা করেছিলেন এবং আমি মনে করি আমরা জনগণ বাস্তবে জ্ঞানীয় সম্প্রদায় গড়ে তোলার জন্য এবং একে অপরকে ভোট ডাউন না করতে সহায়তা করার জন্য রয়েছি। সুতরাং 1 জন চেষ্টা করে ভোট দিন এবং আমি আপনাকে জনগণকে অনুরোধ করব যে ভোটটি নামাবেন না বরং ভোট দিন বা ভোট না দিন .... এই ব্যক্তি নথিভুক্তির সময় যে বিভ্রান্তি থাকতে হবে তা পরিষ্কার করুন। 1 টি ভোট আপ :)
এজেড

21
আমি মনে করি না যে এই উত্তরটি একটি ডাউনটাউটের যোগ্য। কমপক্ষে তিনি উত্তর দেওয়ার চেষ্টা করেছিলেন এবং ডকো থেকে একটি অংশ উদ্ধৃত করেছিলেন।
জিএস্রি

34
এই উত্তরটি একেবারে সঠিক এবং ইউপি ভোটের দাবিদার, নিচে নয়! যারা ছেলেমেয়েরা এটি দেখেন না তাদের জন্য রাষ্ট্রগুলির মধ্যে পার্থক্য স্পষ্ট করে বলি। একটি জিইউআই রাষ্ট্র, যেমন নির্বাচিত রেডিও-বোতাম এবং ইনপুট ক্ষেত্রে কিছু পাঠ্য, ডেটা স্টেটের চেয়ে অনেক কম গুরুত্বপূর্ণ, যেমন তালিকাভিউতে প্রদর্শিত তালিকায় যুক্ত রেকর্ড। পরেরটি অবশ্যই অনপস-এ ডাটাবেসে সংরক্ষণ করতে হবে কারণ এটিই কেবলমাত্র গ্যারান্টিযুক্ত কল। পরিবর্তে আপনি যদি সেভআইনস্ট্যান্সস্টেটে এটি রাখেন, যদি এটি না বলা হয় তবে আপনি ডেটা হারাতে ঝুঁকিপূর্ণ করবেন। তবে যদি একই কারণে রেডিও-বাটন নির্বাচন সংরক্ষণ না করা হয় - এটি কোনও বড় বিষয় নয়।
জেবিএম

206

আমার সহকর্মীরা একটি নিবন্ধ কার্যকলাপ জীবনচক্র এবং রাষ্ট্র তথ্যের উপর ব্যাখ্যা, কিভাবে রাষ্ট্র তথ্য সংরক্ষণ সহ Android ডিভাইসে আবেদন রাষ্ট্র ব্যাখ্যা লিখেছিলেন, এবং রাষ্ট্র সংরক্ষণ Bundleএবং SharedPreferencesএবং এখানে কটাক্ষপাত করা

নিবন্ধটিতে তিনটি পন্থা রয়েছে:

উদাহরণস্বরূপ স্ট্যান্ড বান্ডেল ব্যবহার করে অ্যাপ্লিকেশন আজীবনের জন্য স্থানীয় ভেরিয়েবল / ইউআই কন্ট্রোল ডেটা সঞ্চয় করুন ie

[Code sample  Store state in state bundle]
@Override
public void onSaveInstanceState(Bundle savedInstanceState)
{
  // Store UI state to the savedInstanceState.
  // This bundle will be passed to onCreate on next call.  EditText txtName = (EditText)findViewById(R.id.txtName);
  String strName = txtName.getText().toString();

  EditText txtEmail = (EditText)findViewById(R.id.txtEmail);
  String strEmail = txtEmail.getText().toString();

  CheckBox chkTandC = (CheckBox)findViewById(R.id.chkTandC);
  boolean blnTandC = chkTandC.isChecked();

  savedInstanceState.putString(“Name”, strName);
  savedInstanceState.putString(“Email”, strEmail);
  savedInstanceState.putBoolean(“TandC”, blnTandC);

  super.onSaveInstanceState(savedInstanceState);
}

অংশীদারি পছন্দগুলি ব্যবহার করে অ্যাপ্লিকেশন উদাহরণগুলির মধ্যে (যেমন স্থায়ীভাবে) স্থানীয় ভেরিয়েবল / ইউআই নিয়ন্ত্রণ ডেটা সঞ্চয় করুন

[Code sample  store state in SharedPreferences]
@Override
protected void onPause()
{
  super.onPause();

  // Store values between instances here
  SharedPreferences preferences = getPreferences(MODE_PRIVATE);
  SharedPreferences.Editor editor = preferences.edit();  // Put the values from the UI
  EditText txtName = (EditText)findViewById(R.id.txtName);
  String strName = txtName.getText().toString();

  EditText txtEmail = (EditText)findViewById(R.id.txtEmail);
  String strEmail = txtEmail.getText().toString();

  CheckBox chkTandC = (CheckBox)findViewById(R.id.chkTandC);
  boolean blnTandC = chkTandC.isChecked();

  editor.putString(“Name”, strName); // value to store
  editor.putString(“Email”, strEmail); // value to store
  editor.putBoolean(“TandC”, blnTandC); // value to store
  // Commit to storage
  editor.commit();
}

রক্ষণাবেক্ষণহীন অ-কনফিগারেশন উদাহরণটি ব্যবহার করে অ্যাপ্লিকেশনকালীন ক্রিয়াকলাপগুলির মধ্যে স্মৃতিতে অবজেক্টের উদাহরণগুলি জীবিত রাখা

[Code sample  store object instance]
private cMyClassType moInstanceOfAClass; // Store the instance of an object
@Override
public Object onRetainNonConfigurationInstance()
{
  if (moInstanceOfAClass != null) // Check that the object exists
      return(moInstanceOfAClass);
  return super.onRetainNonConfigurationInstance();
}

3
@ মার্টিনবেচার-ইগো নিবন্ধটি শেরেডপ্রেফারেন্সে থাকা ডেটা সম্পর্কে বলে যে "এই ডেটাটি ডিভাইসে থাকা ডাটাবেজে লেখা আছে .." আমি বিশ্বাস করি যে ফাইল সিস্টেমের অ্যাপ্লিকেশন ডিরেক্টরিতে কোনও ফাইলে ডেটা সংরক্ষণ করা আছে।
টম

2
@ টম শেয়ারফ্রেফস ডেটা এক্সএমএল ফাইলে লেখা হয়। এক্সএমএল কি এক ধরণের ডাটাবেস? আমি বলব এটি হ'ল;)
ম্যাকিয়েজগার্সকি

148

এটি অ্যান্ড্রয়েড বিকাশের একটি ক্লাসিক 'গেটচা'। এখানে দুটি বিষয় আছে:

  • একটি সূক্ষ্ম অ্যান্ড্রয়েড ফ্রেমওয়ার্ক বাগ রয়েছে যা বিকাশের সময় অ্যাপ্লিকেশন স্ট্যাক পরিচালনার ক্ষেত্রে কমপক্ষে লিগ্যাসির সংস্করণগুলিতে (কখন / কখন / কীভাবে এটি স্থির করা হয়েছিল তা পুরোপুরি নিশ্চিত নয়) ব্যাপকভাবে জটিল করে তোলে। আমি নীচে এই বাগ আলোচনা করব।
  • এই সমস্যাটি পরিচালনা করার 'স্বাভাবিক' বা উদ্দেশ্যযুক্ত উপায় হ'ল অনপেজ / অনরেউসুম এবং onSaveInstanceState / onRestoreInstanceState এর দ্বৈততার সাথে বরং জটিল is

এই সমস্ত থ্রেড জুড়ে ব্রাউজ করে আমার সন্দেহ হয় যে বেশিরভাগ সময় বিকাশকারী একই সাথে এই দুটি ভিন্ন বিষয় নিয়ে কথা বলছেন ... সুতরাং "এটি আমার পক্ষে কাজ করে না" এর সমস্ত বিভ্রান্তি এবং রিপোর্টগুলি।

প্রথমে 'উদ্দেশ্যে' আচরণটি স্পষ্ট করতে: onSaveInstance এবং onRestoreInstance নাজুক এবং কেবলমাত্র ক্ষণস্থায়ী অবস্থার জন্য। উদ্দেশ্যযুক্ত ব্যবহার (আফকাটিক) হ'ল ফোনটি যখন ঘোরানো হয় তখন (ক্রিয়াকলাপ পরিবর্তন) কার্যকলাপ ক্রিয়াকলাপ পরিচালনা করে। অন্য কথায়, উদ্দিষ্ট ব্যবহারটি যখন আপনার ক্রিয়াকলাপটি এখনও যৌক্তিকভাবে 'শীর্ষে' থাকে তবে তবুও সিস্টেমটিকে অবশ্যই এটি পুনর্বহাল করতে হবে। সংরক্ষিত বান্ডিলটি প্রক্রিয়া / মেমরি / গিসির বাইরে স্থির থাকে না, তাই যদি আপনার ক্রিয়াকলাপ ব্যাকগ্রাউন্ডে চলে যায় তবে আপনি সত্যিই এটির উপর নির্ভর করতে পারবেন না। হ্যাঁ, সম্ভবত আপনার ক্রিয়াকলাপের স্মৃতি পটভূমিতে যাত্রা থেকে বেঁচে থাকবে এবং জিসিকে পালিয়ে যাবে, তবে এটি নির্ভরযোগ্য নয় (এটি পূর্বাভাসযোগ্যও নয়)।

সুতরাং আপনার যদি এমন কোনও দৃশ্যের উপস্থিতি থাকে যেখানে অর্থবোধক 'ব্যবহারকারীর অগ্রগতি' বা আপনার অ্যাপ্লিকেশনটির 'আরম্ভের' মধ্যে স্থির থাকা উচিত এমন অবস্থা রয়েছে, তবে গাইডসটি অনপস এবং অন-রিসুম ব্যবহার করা। আপনাকে অবশ্যই নিজের একটি ধ্রুবক স্টোরটি বেছে নিতে হবে এবং প্রস্তুত করতে হবে।

কিন্তু - একটি খুব বিভ্রান্তিকর বাগ রয়েছে যা এই সমস্তকে জটিল করে তোলে। বিশদ এখানে:

http://code.google.com/p/android/issues/detail?id=2373

http://code.google.com/p/android/issues/detail?id=5277

মূলত, যদি আপনার অ্যাপ্লিকেশনটি সিঙ্গেল টাস্ক পতাকা দিয়ে চালু করা হয় এবং তারপরে আপনি এটি হোম স্ক্রিন বা লঞ্চার মেনু থেকে চালু করেন, তবে পরবর্তী অনুরোধটি একটি নতুন টাস্ক তৈরি করবে ... আপনার কার্যত আপনার অ্যাপ্লিকেশনের দুটি পৃথক উদাহরণ থাকবে একই স্ট্যাকের বসবাস ... খুব দ্রুত খুব অদ্ভুত হয়ে ওঠে। আপনি বিকাশের সময় আপনার অ্যাপ্লিকেশন চালু করার সময় এটি ঘটবে বলে মনে হয় (যেমন: গ্রহন বা ইন্টেলিজ থেকে), তাই বিকাশকারীরা এটির প্রচুর পরিমাণে চলে। তবে অ্যাপ স্টোর আপডেটের কয়েকটি পদ্ধতির মাধ্যমে (সুতরাং এটি আপনার ব্যবহারকারীদের উপরও প্রভাব ফেলে)।

আমি এই থ্রেডগুলির মধ্যে কয়েক ঘন্টা লড়াইয়ের আগে বুঝতে পেরেছিলাম যে আমার মূল সমস্যাটি এই বাগ, উদ্দেশ্যযুক্ত কাঠামোর আচরণ নয়। একটি দুর্দান্ত লেখার এবংকার্যসংক্রান্ত (আপডেট: নীচে দেখুন) এই উত্তরটিতে ব্যবহারকারী @ কাকিউলার কাছ থেকে মনে হয়েছে:

হোম কী প্রেস আচরণ

জুন 2013 আপডেট করুন : মাস পরে, আমি অবশেষে 'সঠিক' সমাধানটি পেয়েছি। আপনার নিজের কোনও স্ট্যাটাল স্টার্টড অ্যাপ্লিকেশন ফ্ল্যাগ পরিচালনা করার দরকার নেই, আপনি এটি ফ্রেমওয়ার্ক থেকে সনাক্ত করতে পারেন এবং যথাযথভাবে জামিন করতে পারেন। আমি এটি আমার লঞ্চারঅ্যাক্টিভিটি.অনক্রিয়েটের শুরুতে ব্যবহার করি:

if (!isTaskRoot()) {
    Intent intent = getIntent();
    String action = intent.getAction();
    if (intent.hasCategory(Intent.CATEGORY_LAUNCHER) && action != null && action.equals(Intent.ACTION_MAIN)) {
        finish();
        return;
    }
}

87

onSaveInstanceStateযখন সিস্টেমটিকে মেমরির প্রয়োজন হয় এবং একটি অ্যাপ্লিকেশন মেরে ফেলা হয়। যখন ব্যবহারকারী কেবল অ্যাপ্লিকেশনটি বন্ধ করে তখন এটি বলা হয় না। তাই আমি মনে করি আবেদন রাষ্ট্র এছাড়াও সংরক্ষণ করা উচিত onPauseএটা মত কিছু বার-বার সঞ্চয় সংরক্ষণ করা উচিত PreferencesবাSqlite


36
দুঃখিত, এটি পুরোপুরি সঠিক নয়। ক্রিয়াকলাপটি পুনরায় তৈরি করার আগে onSaveInstanceState কল হয়ে যায়। অর্থাৎ প্রতিবার ব্যবহারকারী ডিভাইসটি ঘোরান। এটি ক্ষণস্থায়ী দর্শন রাষ্ট্রগুলি সঞ্চয় করার জন্য oring অ্যান্ড্রয়েড যখন অ্যাপ্লিকেশনটি বন্ধ করতে বাধ্য করে, অনসাইভ ইনস্ট্যান্সস্টেটকে আসলে বলা হয় না (যার কারণে এটি গুরুত্বপূর্ণ অ্যাপ্লিকেশন ডেটা সংরক্ষণের জন্য নিরাপদ নয়)। অনপস, তবুও কার্যকলাপটি মারা যাওয়ার আগে কল করার নিশ্চয়তা দেওয়া হয়েছে, তাই এটি পছন্দ বা স্কুলাইটে স্থায়ী তথ্য সঞ্চয় করতে ব্যবহার করা উচিত। সঠিক উত্তর, ভুল কারণ।
মুভআওয়ে

74

দুটি পদ্ধতিই কার্যকর এবং বৈধ এবং উভয়ই বিভিন্ন পরিস্থিতিতে উপযুক্ত ari

  1. ব্যবহারকারী অ্যাপ্লিকেশনটি বন্ধ করে দেয় এবং পরবর্তী তারিখে এটি পুনরায় খোলে, তবে অ্যাপ্লিকেশনটির শেষ সেশন থেকে ডেটা পুনরায় লোড করা দরকার - এটির জন্য অবিরাম স্টোরেজ পদ্ধতির প্রয়োজন যেমন এসকিউএলাইট ব্যবহার করা।
  2. ব্যবহারকারী অ্যাপ্লিকেশনটি স্যুইচ করে এবং তারপরে আসলটিতে ফিরে আসে এবং তারা যেখানে ফেলে রেখেছিল সেখানে নিতে চায় - বান্ডিল ডেটা সংরক্ষণ এবং পুনরুদ্ধার করে (যেমন অ্যাপ্লিকেশন স্টেট ডেটা) onSaveInstanceState()এবং onRestoreInstanceState()সাধারণত পর্যাপ্ত is

আপনি যদি অবিচ্ছিন্নভাবে রাষ্ট্রের ডেটা সংরক্ষণ করেন তবে এটি একটি onResume()বা onCreate()(বা আসলে কোনও লাইফাইসাইক্ল কল এ) পুনরায় লোড করা যেতে পারে । এটি পছন্দসই আচরণ বা নাও হতে পারে। আপনি যদি এটি একটি বান্ডেলে সংরক্ষণ করেন InstanceState, তবে এটি ক্ষণস্থায়ী এবং কেবল একই ব্যবহারকারীর 'সেশনে' ব্যবহারের জন্য ডেটা সংরক্ষণের জন্য উপযুক্ত (আমি সেশন শব্দটি আলগাভাবে ব্যবহার করি) তবে 'সেশনগুলির' মধ্যে নয়।

এটি নয় যে একটি পদ্ধতির অন্যের চেয়ে ভাল, যেমন প্রতিটি কিছুর জন্য আপনার কী আচরণ প্রয়োজন তা বোঝা এবং সবচেয়ে উপযুক্ত পদ্ধতির নির্বাচন করা কেবল গুরুত্বপূর্ণ।


70

যতটা আমি উদ্বিগ্ন সেভিং স্টেট একটি ক্লডজ best আপনার যদি অবিরাম ডেটা সংরক্ষণ করতে হয় তবে কেবল একটি এসকিউএল ডাটাবেস ব্যবহার করুন । অ্যান্ড্রয়েড এটা তোলে sooo সহজ।

এটার মতো কিছু:

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

তার পরে একটি সহজ কল

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

9
কারণ কোনও এসকিউএলাইট ডাটাবেস লোড করতে এটি খুব বেশি সময় নেয়, এটি বিবেচনা করে যে এটি ব্যবহারকারীর অ্যাপ্লিকেশনটির ইউআই দেখানোর জন্য গুরুত্বপূর্ণ পথে রয়েছে। আমি আসলে এটির সময় নিই নি, তাই আমি সংশোধন করে খুশি, তবে অবশ্যই একটি ডেটাবেস ফাইল লোড করা এবং খোলানো দ্রুত হবে না?
টম

5
কোনও নবাগত তাদের অ্যাপ্লিকেশনটিতে কাটা এবং আটকানো যেতে পারে এমন সমাধান সরবরাহ করার জন্য আপনাকে অনেক ধন্যবাদ! @ টম যত দ্রুত গতিতে যায় 1000 জুড়ি সঞ্চয় করতে প্রায় সাত সেকেন্ড সময় লাগে তবে আপনি এটি অ্যাসিঙ্কটাস্কে করতে পারেন। তবে আপনাকে একটি শেষ অবধি। কার্সার.ক্লোজ () add যুক্ত করতে হবে বা এটি করার সময় এটি মেমরি ফুটো থেকে ক্রাশ হবে।
নুমেনন

3
আমি এটি পেরিয়ে এসেছি এবং এটি পরিষ্কার পরিচ্ছন্ন বলে মনে হচ্ছে আমি গুগল গ্লাসে এটি ব্যবহার করার চেষ্টা করতে দ্বিধা বোধ করছি, এটি আমি যে ডিভাইসটিতে কাজ করছি / ইদানীং নিয়ে কাজ করছি।
স্টিফেন টেট্রোল্ট

61

আমি মনে করি আমি উত্তরটি খুঁজে পেয়েছি। সহজ কথায় আমি কী করেছি তা আমাকে বলি:

ধরুন আমার দুটি ক্রিয়াকলাপ, ক্রিয়াকলাপ 1 এবং ক্রিয়াকলাপ 2 আছে এবং আমি ক্রিয়াকলাপ 1 থেকে ক্রিয়াকলাপ 2 এ চলেছি (আমি ক্রিয়াকলাপ 2 তে কিছু কাজ করেছি) এবং আবার ক্রিয়াকলাপ 1 এর বোতামে ক্লিক করে আবার কার্যকলাপ 1 এ ফিরে আসছি। এখন এই পর্যায়ে আমি ক্রিয়াকলাপ 2 এ ফিরে যেতে চেয়েছিলাম এবং আমি আমার ক্রিয়াকলাপ 2 একই অবস্থায় দেখতে চাই যখন আমি শেষ 2 কার্যকলাপ বামে রেখে যাই।

উপরের দৃশ্যের জন্য আমি যা করেছি তা হ'ল ম্যানিফেস্টে আমি এরকম কিছু পরিবর্তন করেছি:

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

এবং ক্রিয়াকলাপ 1 এ বোতামটি ক্লিক ইভেন্টে আমি এটি করেছি:

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

এবং ক্রিয়াকলাপ 2 এ বোতাম ক্লিক ইভেন্টে আমি এটি করেছি:

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

এখন যা ঘটবে তা হ'ল আমরা ক্রিয়াকলাপ 2 এ যা কিছু পরিবর্তন করেছি তা হারাবে না, এবং আমরা পূর্বে যেমন রেখেছি ঠিক তেমন একইভাবে কার্যকলাপ 2 দেখতে পারি।

আমি বিশ্বাস করি এটিই উত্তর এবং এটি আমার পক্ষে ভাল কাজ করে। আমি ভুল হলে আমাকে সংশোধন করুন।


2
@ ব্যাগসফ্লাইয়ার কেয়ার আরও সুনির্দিষ্ট হতে ??? আপনার মন্তব্য সহায়ক নয় এবং এর ভিত্তিতে কেউ আপনাকে সহায়তা করতে পারে না।
স্টিফেন টেট্রোল্ট

2
এটি একটি পৃথক পরিস্থিতির উত্তর: একই অ্যাপের মধ্যে দুটি ক্রিয়াকলাপ। ওপি অ্যাপ্লিকেশনটি ছাড়ার বিষয়ে রয়েছে (যেমন হোম বোতাম বা অন্য কোনও অ্যাপ্লিকেশনে স্যুইচ করার অন্যান্য উপায়)।
টুলমেকারস্টেভ

44

onSaveInstanceState()অস্থায়ী ডেটার জন্য (পুনরুদ্ধার ইন onCreate()/ onRestoreInstanceState()), onPause()ধ্রুবক ডেটার জন্য (পুনরুদ্ধার করা onResume())। অ্যান্ড্রয়েড প্রযুক্তিগত সম্পদ থেকে:

onSaveInstanceState ()ক্রিয়াকলাপ বন্ধ করা হচ্ছে এবং এটি আবার চালু করার আগে হত্যা করা যেতে পারে অ্যান্ড্রয়েড দ্বারা কে ডাকা হয়! এর অর্থ ক্রিয়াকলাপটি পুনরায় শুরু করা হলে একই অবস্থায় পুনরায় আরম্ভ করার জন্য প্রয়োজনীয় যে কোনও রাজ্য সংরক্ষণ করা উচিত। এটি অনক্রিয়েট () পদ্ধতির প্রতিচ্ছবি এবং প্রকৃতপক্ষে সেভডআইনস্ট্যান্সস্টেট বান্ডেলটি অনক্রিট () এ পাস করেছে এটি একই বান্ডিল যা আপনি অন সেভআইনস্ট্যান্সস্টেট () পদ্ধতিতে আউটস্টেট হিসাবে নির্মাণ করেন।

onPause () এবং onResume () এছাড়াও প্রশংসামূলক পদ্ধতি। ক্রিয়াকলাপ শেষ হয়ে গেলে অনপস () সর্বদা ডাকা হয়, এমনকি যদি আমরা সেই প্ররোচনা দিয়েছিলাম (উদাহরণস্বরূপ একটি ফিনিস () কল দিয়ে)। এটি ব্যবহার করে আমরা বর্তমান নোটটি ডেটাবেসে সংরক্ষণ করতে পারি। ভাল অনুশীলন হ'ল অনপেজ () চলাকালীন প্রকাশিত হতে পারে এমন কোনও সংস্থানকে মুক্তি দেওয়া, প্যাসিভ অবস্থায় থাকাকালীন কম সংস্থান গ্রহণ করা।


40

onSaveInstanceState()ক্রিয়াকলাপ ব্যাকগ্রাউন্ডে গেলে সত্যিই ডাকা হয়।

দস্তাবেজগুলির উদ্ধৃতি: "কোনও ক্রিয়াকলাপ হত্যার আগে এই পদ্ধতিটি বলা হয়েছিল যাতে ভবিষ্যতে কিছু সময় ফিরে এলে এটি তার অবস্থা পুনরুদ্ধার করতে পারে।" সূত্র


37

বয়লারপ্লেট হ্রাস করতে সহায়তা করার জন্য আমি নিম্নলিখিতটি ব্যবহার করি interfaceএবং সংরক্ষণের অবস্থা হিসাবে সংরক্ষণের জন্য একটিতে classপড়তে / লিখতে Bundle


প্রথমে এমন একটি ইন্টারফেস তৈরি করুন যা আপনার উদাহরণের ভেরিয়েবলগুলি বর্নিত করতে ব্যবহৃত হবে:

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({
        ElementType.FIELD
})
public @interface SaveInstance {

}

তারপরে, এমন একটি শ্রেণী তৈরি করুন যেখানে বান্ডলে মানগুলি সংরক্ষণ করতে প্রতিবিম্বটি ব্যবহৃত হবে:

import android.app.Activity;
import android.app.Fragment;
import android.os.Bundle;
import android.os.Parcelable;
import android.util.Log;

import java.io.Serializable;
import java.lang.reflect.Field;

/**
 * Save and load fields to/from a {@link Bundle}. All fields should be annotated with {@link
 * SaveInstance}.</p>
 */
public class Icicle {

    private static final String TAG = "Icicle";

    /**
     * Find all fields with the {@link SaveInstance} annotation and add them to the {@link Bundle}.
     *
     * @param outState
     *         The bundle from {@link Activity#onSaveInstanceState(Bundle)} or {@link
     *         Fragment#onSaveInstanceState(Bundle)}
     * @param classInstance
     *         The object to access the fields which have the {@link SaveInstance} annotation.
     * @see #load(Bundle, Object)
     */
    public static void save(Bundle outState, Object classInstance) {
        save(outState, classInstance, classInstance.getClass());
    }

    /**
     * Find all fields with the {@link SaveInstance} annotation and add them to the {@link Bundle}.
     *
     * @param outState
     *         The bundle from {@link Activity#onSaveInstanceState(Bundle)} or {@link
     *         Fragment#onSaveInstanceState(Bundle)}
     * @param classInstance
     *         The object to access the fields which have the {@link SaveInstance} annotation.
     * @param baseClass
     *         Base class, used to get all superclasses of the instance.
     * @see #load(Bundle, Object, Class)
     */
    public static void save(Bundle outState, Object classInstance, Class<?> baseClass) {
        if (outState == null) {
            return;
        }
        Class<?> clazz = classInstance.getClass();
        while (baseClass.isAssignableFrom(clazz)) {
            String className = clazz.getName();
            for (Field field : clazz.getDeclaredFields()) {
                if (field.isAnnotationPresent(SaveInstance.class)) {
                    field.setAccessible(true);
                    String key = className + "#" + field.getName();
                    try {
                        Object value = field.get(classInstance);
                        if (value instanceof Parcelable) {
                            outState.putParcelable(key, (Parcelable) value);
                        } else if (value instanceof Serializable) {
                            outState.putSerializable(key, (Serializable) value);
                        }
                    } catch (Throwable t) {
                        Log.d(TAG, "The field '" + key + "' was not added to the bundle");
                    }
                }
            }
            clazz = clazz.getSuperclass();
        }
    }

    /**
     * Load all saved fields that have the {@link SaveInstance} annotation.
     *
     * @param savedInstanceState
     *         The saved-instance {@link Bundle} from an {@link Activity} or {@link Fragment}.
     * @param classInstance
     *         The object to access the fields which have the {@link SaveInstance} annotation.
     * @see #save(Bundle, Object)
     */
    public static void load(Bundle savedInstanceState, Object classInstance) {
        load(savedInstanceState, classInstance, classInstance.getClass());
    }

    /**
     * Load all saved fields that have the {@link SaveInstance} annotation.
     *
     * @param savedInstanceState
     *         The saved-instance {@link Bundle} from an {@link Activity} or {@link Fragment}.
     * @param classInstance
     *         The object to access the fields which have the {@link SaveInstance} annotation.
     * @param baseClass
     *         Base class, used to get all superclasses of the instance.
     * @see #save(Bundle, Object, Class)
     */
    public static void load(Bundle savedInstanceState, Object classInstance, Class<?> baseClass) {
        if (savedInstanceState == null) {
            return;
        }
        Class<?> clazz = classInstance.getClass();
        while (baseClass.isAssignableFrom(clazz)) {
            String className = clazz.getName();
            for (Field field : clazz.getDeclaredFields()) {
                if (field.isAnnotationPresent(SaveInstance.class)) {
                    String key = className + "#" + field.getName();
                    field.setAccessible(true);
                    try {
                        Object fieldVal = savedInstanceState.get(key);
                        if (fieldVal != null) {
                            field.set(classInstance, fieldVal);
                        }
                    } catch (Throwable t) {
                        Log.d(TAG, "The field '" + key + "' was not retrieved from the bundle");
                    }
                }
            }
            clazz = clazz.getSuperclass();
        }
    }

}

ব্যবহারের উদাহরণ:

public class MainActivity extends Activity {

    @SaveInstance
    private String foo;

    @SaveInstance
    private int bar;

    @SaveInstance
    private Intent baz;

    @SaveInstance
    private boolean qux;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Icicle.load(savedInstanceState, this);
    }

    @Override
    public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        Icicle.save(outState, this);
    }

}

দ্রষ্টব্য: এই কোডটি অ্যান্ড্রয়েড আউটওয়ায়ার নামে একটি লাইব্রেরি প্রকল্প থেকে অভিযোজিত হয়েছিল যা এমআইটি লাইসেন্সের আওতায় লাইসেন্সযুক্ত


34

এদিকে আমি সাধারণভাবে আর ব্যবহার করি না

Bundle savedInstanceState & Co

জীবনচক্রটি বেশিরভাগ ক্রিয়াকলাপগুলির জন্য খুব জটিল এবং প্রয়োজনীয় নয়।

এবং গুগল নিজেই বলেছে, এটি এমনকি নির্ভরযোগ্য নয়।

আমার উপায় হ'ল পছন্দগুলি তত্ক্ষণাত যে কোনও পরিবর্তনগুলি সংরক্ষণ করুন:

 SharedPreferences p;
 p.edit().put(..).commit()

কোনও উপায়ে ভাগ করা পছন্দগুলি বান্ডিলের মতো কাজ করে। এবং স্বাভাবিকভাবে এবং প্রথমে এ জাতীয় মানগুলি পছন্দগুলি থেকে পড়তে হয়।

জটিল ডেটার ক্ষেত্রে আপনি পছন্দগুলি ব্যবহার না করে SQLite ব্যবহার করতে পারেন।

এই ধারণাটি প্রয়োগ করার সময়, ক্রিয়াকলাপটি কেবলমাত্র সর্বশেষ সংরক্ষিত রাজ্যটি ব্যবহার করে চালিয়ে যায়, নির্বিশেষে এটি পিছনের স্ট্যাকের কারণে পুনরায় বুট করা বা পুনরায় খোলা ছিল কিনা তা প্রাথমিকভাবে নয়।


31

মূল প্রশ্নের সরাসরি উত্তর দিতে। SaveInstancestate নাল কারণ আপনার ক্রিয়াকলাপটি আর কখনও তৈরি হচ্ছে না।

আপনার ক্রিয়াকলাপ কেবলমাত্র একটি রাজ্য বান্ডিল দিয়ে পুনরায় তৈরি করা হবে যখন:

  • কনফিগারেশন পরিবর্তন যেমন ওরিয়েন্টেশন বা ফোনের ভাষা পরিবর্তনের জন্য একটি নতুন ক্রিয়াকলাপ তৈরির প্রয়োজন হতে পারে।
  • ওএস ক্রিয়াকলাপটি ধ্বংস করার পরে আপনি ব্যাকগ্রাউন্ড থেকে অ্যাপটিতে ফিরে যান।

অ্যান্ড্রয়েড যখন মেমরির চাপের মধ্যে থাকে বা তারা দীর্ঘ সময় ধরে ব্যাকগ্রাউন্ডে থাকে তার পরে ব্যাকগ্রাউন্ড ক্রিয়াকলাপ ধ্বংস করে দেয়।

আপনার হ্যালো ওয়ার্ল্ড উদাহরণটি পরীক্ষা করার সময় ক্রিয়াকলাপে ফিরে যাওয়ার এবং ফিরে আসার কয়েকটি উপায় রয়েছে।

  • আপনি যখন পিছনের বোতামটি টিপেন তখন ক্রিয়াকলাপ শেষ হয়। অ্যাপটি পুনরায় চালু করা একেবারে নতুন উদাহরণ। আপনি পটভূমি থেকে মোটেও শুরু করছেন না।
  • আপনি যখন হোম বোতাম টিপেন বা টাস্ক স্যুইচারটি ব্যবহার করেন তখন কার্যকলাপটি পটভূমিতে চলে যাবে। অনক্রিটে অ্যাপ্লিকেশনটিতে ফিরে নেভিগেট করার সময় যদি কার্যকলাপটি ধ্বংস করতে হয় তবেই কল করা হবে।

বেশিরভাগ ক্ষেত্রে যদি আপনি কেবল বাড়িতে চাপছেন এবং তারপরে আবার অ্যাপ্লিকেশন চালু করছেন তবে ক্রিয়াকলাপটি পুনরায় তৈরি করার প্রয়োজন হবে না। এটি ইতিমধ্যে মেমরিতে বিদ্যমান তাই অনক্রিট () কল করা হবে না।

সেটিংস -> বিকাশকারী বিকল্পগুলিতে "ক্রিয়াকলাপগুলি রাখবেন না" নামে একটি বিকল্প রয়েছে called যখন এটি সক্ষম করা থাকে অ্যান্ড্রয়েড সর্বদা ক্রিয়াকলাপগুলি ধ্বংস করে দেয় এবং যখন তারা ব্যাকগ্রাউন্ড হয় তখন তাদের পুনরায় তৈরি করে। এটি বিকাশের সময় সক্ষম থাকা ছেড়ে যাওয়ার এক দুর্দান্ত বিকল্প কারণ এটি সবচেয়ে খারাপ ক্ষেত্রেটির পরিস্থিতি অনুকরণ করে। (একটি স্বল্প স্মৃতিযুক্ত ডিভাইস আপনার ক্রিয়াকলাপ সর্বদা পুনর্ব্যবহার করে)।

অন্যান্য উত্তরগুলি মূল্যবান যে এগুলি আপনাকে স্টেট সংরক্ষণের সঠিক উপায়গুলি শিখায় তবে আমি অনুভব করি না যে তারা সত্যই উত্তর দিয়েছে কেন আপনার কোডটি আপনার প্রত্যাশায় কাজ করছে না।


28

onSaveInstanceState(bundle)এবং onRestoreInstanceState(bundle)পদ্ধতি ডাটা অধ্যবসায় স্ক্রিন (স্থিতিবিন্যাস পরিবর্তন) আবর্তিত নিছক কিছুদিনের জন্য দরকারী।
তারা অ্যাপ্লিকেশন একটি থেকে অন্যটিতে পরিবর্তন (যেহেতু সময় এমনকি ভাল হয় না onSaveInstanceState()পদ্ধতি বলা হয় কিন্তু onCreate(bundle)onRestoreInstanceState(bundle)আবার প্রার্থনা করা হয় না।
আরো অধ্যবসায় ব্যবহার ভাগ পছন্দগুলি জন্য। এই নিবন্ধটি পড়তে


2
আপনার ক্ষেত্রে onCreateএবং onRestoreInstanceStateডাকা হচ্ছে না কারণ Activityআপনি অ্যাপ্লিকেশনগুলিতে স্যুইচ করার সময় এটি বিনষ্ট হয় না, তাই কোনও কিছুর পুনরুদ্ধার করার দরকার নেই। onSaveInstanceStateক্রিয়াকলাপটি পরে ধ্বংস হয়ে যাওয়ার ক্ষেত্রে অ্যান্ড্রয়েড কল দেয় (যা স্ক্রিনটি ঘোরানোর সময় 100% নিশ্চিততার সাথে ঘটে কারণ পুরো ডিভাইস কনফিগারেশনটি পরিবর্তিত হয়েছে এবং ক্রিয়াকলাপটি স্ক্র্যাচ থেকে পুনরায় তৈরি করতে হবে)।
ভিকি চিজওয়ানি

20

আমার সমস্যাটি হ'ল কেবলমাত্র আবেদনের সময়কালে আমার অধ্যবসায়ের প্রয়োজন (যেমন একই অ্যাপ্লিকেশনের মধ্যে অন্যান্য উপ-ক্রিয়াকলাপ শুরু করা এবং ডিভাইসটি ঘোরানো সহ একক কার্যকরকরণ)। আমি উপরের উত্তরগুলির বিভিন্ন সংমিশ্রণ চেষ্টা করেছি কিন্তু সমস্ত পরিস্থিতিতে যা চেয়েছিলাম তা পেলাম না। শেষ পর্যন্ত আমার জন্য যা কাজ করেছিল তা হ'ল অনক্রিট চলাকালীন সেভড ইনস্ট্যান্সস্টেটের একটি রেফারেন্স পাওয়া:

mySavedInstanceState=savedInstanceState;

এবং যখন আমার প্রয়োজন হয় তখন আমার ভেরিয়েবলের সামগ্রীগুলি পেতে এটি ব্যবহার করুন:

if (mySavedInstanceState !=null) {
   boolean myVariable = mySavedInstanceState.getBoolean("MyVariable");
}

আমি ব্যবহার করেছি onSaveInstanceStateএবং onRestoreInstanceStateউপরে প্রস্তাবিত হিসাবে কিন্তু আমার ধারণা আমি পরিবর্তন করতে চাইলে পরিবর্তনটি সংরক্ষণ করার জন্য আমি বা বিকল্পভাবে আমার পদ্ধতিটি ব্যবহার করতে পারি (যেমন ব্যবহার করে putBoolean)


19

যদিও গৃহীত উত্তরটি সঠিক, তবে আইসপিক নামে একটি লাইব্রেরি ব্যবহার করে অ্যান্ড্রয়েডে ক্রিয়াকলাপের অবস্থা সংরক্ষণের জন্য একটি দ্রুত এবং সহজ পদ্ধতি রয়েছে । আইসপিক হ'ল একটি এনোটেশন প্রসেসর যা আপনার জন্য রাষ্ট্র সংরক্ষণ এবং পুনরুদ্ধার করতে ব্যবহৃত সমস্ত বয়লারপ্লেট কোডের যত্ন করে।

আইসেপিকের সাথে এরকম কিছু করা:

class MainActivity extends Activity {
  @State String username; // These will be automatically saved and restored
  @State String password;
  @State int age;

  @Override public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    Icepick.restoreInstanceState(this, savedInstanceState);
  }

  @Override public void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    Icepick.saveInstanceState(this, outState);
  }
}

এটি করার মতোই:

class MainActivity extends Activity {
  String username;
  String password;
  int age;

  @Override
  public void onSaveInstanceState(Bundle savedInstanceState) {
    super.onSaveInstanceState(savedInstanceState);
    savedInstanceState.putString("MyString", username);
    savedInstanceState.putString("MyPassword", password);
    savedInstanceState.putInt("MyAge", age); 
    /* remember you would need to actually initialize these variables before putting it in the
    Bundle */
  }

  @Override
  public void onRestoreInstanceState(Bundle savedInstanceState) {
    super.onRestoreInstanceState(savedInstanceState);
    username = savedInstanceState.getString("MyString");
    password = savedInstanceState.getString("MyPassword");
    age = savedInstanceState.getInt("MyAge");
  }
}

আইসপিক যে কোনও অবজেক্টের সাথে কাজ করবে যা তার রাজ্যের সাথে একটি সংরক্ষণ করে Bundle


16

যখন কোনও ক্রিয়াকলাপ তৈরি করা হয় তখন এটিকে অনক্রিট () পদ্ধতি বলা হয়।

   @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }

সেভড ইনস্ট্যান্সস্টেটটি বান্ডিল শ্রেণীর একটি অবজেক্ট যা প্রথমবারের জন্য নাল, তবে এটি পুনরায় তৈরি করার সময় এর মান রয়েছে। ক্রিয়াকলাপের রাজ্যটি সংরক্ষণ করতে আপনাকে onSaveInstanceState () ওভাররাইড করতে হবে।

   @Override
    protected void onSaveInstanceState(Bundle outState) {
      outState.putString("key","Welcome Back")
        super.onSaveInstanceState(outState);       //save state
    }

আপনার মানগুলিকে "আউটস্টেট" বান্ডিল অবজেক্টের মতো আউটস্টেট.পুটস্ট্রিং ("কী", "ওয়েলকাম ব্যাক") রাখুন এবং সুপারকে কল করে সংরক্ষণ করুন। যখন ক্রিয়াকলাপটি ধ্বংস হয়ে যাবে তখন এটি বান্ডিল অবজেক্টে রাজ্যটি রক্ষিত হবে এবং অনক্রিট () বা অনরেস্টোরইনস্ট্যান্সস্টেট () এ বিনোদনের পরে পুনরুদ্ধার করা যাবে। OnCreate () এবং onRestoreInstanceState () এ প্রাপ্ত বান্ডেলটি একই।

   @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

          //restore activity's state
         if(savedInstanceState!=null){
          String reStoredString=savedInstanceState.getString("key");
            }
    }

অথবা

  //restores activity's saved state
 @Override
    protected void onRestoreInstanceState(Bundle savedInstanceState) {
      String restoredMessage=savedInstanceState.getString("key");
    }

15

এই পরিবর্তনটি বাস্তবায়নের জন্য দুটি উপায় রয়েছে।

  1. ব্যবহার onSaveInstanceState()এবং onRestoreInstanceState()
  2. প্রকাশে android:configChanges="orientation|screenSize"

আমি সত্যিই দ্বিতীয় পদ্ধতি ব্যবহার করার পরামর্শ দিই না। যেহেতু আমার একটি অভিজ্ঞতায় এটি প্রতিকৃতি থেকে ল্যান্ডস্কেপ এ ঘোরাতে গিয়ে ডিভাইসের স্ক্রিনের অর্ধেকটি কালো হয়ে গেছে।

উপরে উল্লিখিত প্রথম পদ্ধতিটি ব্যবহার করে, যখন ওরিয়েন্টেশন পরিবর্তন করা হয় বা কোনও কনফিগারেশনের পরিবর্তন ঘটে থাকে তখন আমরা ডেটা ধরে রাখতে পারি। আমি এমন একটি উপায় জানি যার মাধ্যমে আপনি সেভেনস্ট্যান্স স্টেট অবজেক্টের মধ্যে যে কোনও ধরণের ডেটা সঞ্চয় করতে পারেন।

উদাহরণ: আপনি যদি জেসন অবজেক্ট অবিরত রাখতে চান তবে একটি কেস বিবেচনা করুন। গিটারস এবং সেটটারগুলির সাথে একটি মডেল ক্লাস তৈরি করুন।

class MyModel extends Serializable{
JSONObject obj;

setJsonObject(JsonObject obj)
{
this.obj=obj;
}

JSONObject getJsonObject()
return this.obj;
} 
}

এখন onCreate এবং onSaveInstanceState পদ্ধতিতে আপনার ক্রিয়াকলাপে নিম্নলিখিতটি করুন। এটি দেখতে এরকম কিছু দেখাবে:

@override
onCreate(Bundle savedInstaceState){
MyModel data= (MyModel)savedInstaceState.getSerializable("yourkey")
JSONObject obj=data.getJsonObject();
//Here you have retained JSONObject and can use.
}


@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
//Obj is some json object 
MyModel dataToSave= new MyModel();
dataToSave.setJsonObject(obj);
oustate.putSerializable("yourkey",dataToSave); 

}

11

এখানে একটি মন্তব্য থেকে স্টিভ Moseley এর উত্তর (দ্বারা ToolmakerSteve ) যে দৃষ্টিকোণ রাখে জিনিষ (পুরো onSaveInstanceState বনাম onPause সালে পূর্ব খরচ বনাম পশ্চিমে খরচ কাহিনী)

@ ভিভিকে - আমি আংশিকভাবে একমত নই। অ্যাপ্লিকেশন থেকে বেরিয়ে আসার কিছু উপায় onSaveInstanceState (oSIS) এ ট্রিগার করে না। এটি ওএসআইএসের কার্যকারিতা সীমাবদ্ধ করে। ন্যূনতম ওএস সংস্থানগুলির জন্য এটি সমর্থনযোগ্য, তবে কোনও অ্যাপ্লিকেশন যদি ব্যবহারকারীকে যে অবস্থায় ছিল সে অবস্থায় ফিরিয়ে দিতে চায় তবে অ্যাপটি কীভাবে বেরিয়ে এসেছিল তা বিবেচনা না করে পরিবর্তে অবিরাম স্টোরেজ পদ্ধতির ব্যবহার করা প্রয়োজন। আমি বান্ডিলটি যাচাই করতে অনক্রিট ব্যবহার করি এবং এটি যদি অনুপস্থিত থাকে তবে অবিরাম সঞ্চয়স্থান পরীক্ষা করে দেখুন এটি সিদ্ধান্ত গ্রহণকে কেন্দ্রিক করে তোলে। আমি ক্রাশ থেকে পুনরুদ্ধার করতে পারি, বা পিছনে বোতামের প্রস্থান বা কাস্টম মেনু আইটেমটি প্রস্থান করতে পারি, বা অনেক দিন পরে পর্দার ব্যবহারকারীর কাছে ফিরে যেতে পারি। - টুলমেকারস্টেভ সেপ্টেম্বর 19 '15 এ 10:38 এ


10

কোটলিন কোড:

সংরক্ষণ:

override fun onSaveInstanceState(outState: Bundle) {
    super.onSaveInstanceState(outState.apply {
        putInt("intKey", 1)
        putString("stringKey", "String Value")
        putParcelable("parcelableKey", parcelableObject)
    })
}

এবং তারপরে onCreate()বাonRestoreInstanceState()

    val restoredInt = savedInstanceState?.getInt("intKey") ?: 1 //default int
    val restoredString = savedInstanceState?.getString("stringKey") ?: "default string"
    val restoredParcelable = savedInstanceState?.getParcelable<ParcelableClass>("parcelableKey") ?: ParcelableClass() //default parcelable

আপনার বিকল্পগুলি না চাইলে ডিফল্ট মান যুক্ত করুন


9

সঞ্চিত ক্রিয়াকলাপের স্টেটের ডেটা সঞ্চয় করতে onCreate(), প্রথমে আপনাকে ওভাররাইড SaveInstanceState(Bundle savedInstanceState)পদ্ধতিতে সেভড ইনস্ট্যান্সস্টেটে ডেটা সংরক্ষণ করতে হবে ।

যখন ক্রিয়াকলাপ ধ্বংসের SaveInstanceState(Bundle savedInstanceState)পদ্ধতিটি কল করা হয় এবং সেখানে আপনি সংরক্ষণ করতে চান এমন ডেটা সংরক্ষণ করেন। এবং onCreate()ক্রিয়াকলাপটি পুনরায় চালু হওয়ার সময় আপনি একই রকম হন ((সেভড ইনস্ট্যান্সস্টেটটি নষ্ট হবে না কারণ আপনি ক্রিয়াকলাপটি ধ্বংস হওয়ার আগে এতে কিছু তথ্য সংরক্ষণ করেছেন)


6

এই সমস্যার সমাধানের জন্য সহজ দ্রুত হ'ল আইসপিক ব্যবহার করা

প্রথমে লাইব্রেরিটি সেটআপ করুন app/build.gradle

repositories {
  maven {url "https://clojars.org/repo/"}
}
dependencies {
  compile 'frankiesardo:icepick:3.2.0'
  provided 'frankiesardo:icepick-processor:3.2.0'
}

এখন, ক্রিয়াকলাপে রাষ্ট্র কীভাবে সংরক্ষণ করবেন নীচে এই উদাহরণটি দেখুন check

public class ExampleActivity extends Activity {
  @State String username; // This will be automatically saved and restored

  @Override public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    Icepick.restoreInstanceState(this, savedInstanceState);
  }

  @Override public void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    Icepick.saveInstanceState(this, outState);
  }
}

এটি ক্রিয়াকলাপ, টুকরোগুলি বা যে কোনও অবজেক্টের জন্য কাজ করে যা কোনও বান্ডলে তার রাজ্যটিকে সিরিয়ালাইজ করা প্রয়োজন (যেমন মর্টারের ভিউপ্রিসেন্টার)

আইসপিক কাস্টম দর্শনগুলির জন্য দৃষ্টান্তের রাজ্য কোডও তৈরি করতে পারে:

class CustomView extends View {
  @State int selectedPosition; // This will be automatically saved and restored

  @Override public Parcelable onSaveInstanceState() {
    return Icepick.saveInstanceState(this, super.onSaveInstanceState());
  }

  @Override public void onRestoreInstanceState(Parcelable state) {
    super.onRestoreInstanceState(Icepick.restoreInstanceState(this, state));
  }

  // You can put the calls to Icepick into a BaseCustomView and inherit from it
  // All Views extending this CustomView automatically have state saved/restored
}

1
@ র‌্যালস্প্পস হ্যাঁ, এটি খণ্ড এবং কাস্টম ভিউয়ের জন্য কাজ করে। উদাহরণ কোড চেক করুন। আমি আমার উত্তর সম্পাদনা করেছি। আমি আপনাকে আরও কোড নমুনা খুঁজে পেতে github.com/frankiesardo/icepick এখানে অফিসিয়াল ডক্সে যেতে পরামর্শ দিই
THN Phearum

@ চেতানমেরা আপনার পছন্দমত কাস্টম ভিউ ক্লাস, তাই না? এটি যদি কাস্টম ভিউ হয় তবে আমরা কাস্টম ভিউর উদাহরণের মতো onSaveInstanceState এবং onRestoreInstanceState কে ওভাররাইড করতে পারি।
THN Phearum

উদাহরণস্বরূপ দেখুন শ্রেণীর ভিতরে শ্রেণীর অবজেক্টের অর্থ: শ্রেণি কাস্টমভিউ দেখুন View @ স্টেট ক্লাসএ এ; class বা শ্রেণি কাস্টমভিউ দেখুন প্রসারিত করে {@ রাজ্য অভ্যন্তরীণ শ্রেণি {}}
চেতন মেহরা

@ THANNPhearum আমি কি এটি অন্য প্রশ্ন হিসাবে জিজ্ঞাসা করব?
চেতন মেহরা

আমি দেখি. যদি তা হয় তবে আপনার ক্লাসএ পার্সলেবল হওয়া উচিত। যেমন এটি উল্লেখ করেছে যে এটি ক্রিয়াকলাপ, টুকরোগুলি বা কোনও বস্তুর জন্য কাজ করে যা একটি
বান্ডিলের

6

আমার সমাধানটির উপর ভিত্তি করে কিনা তা নিশ্চিত নই, তবে আমি ভিউমোডেল স্থিতি বজায় রাখতে একটি সীমাবদ্ধ পরিষেবা ব্যবহার করি। আপনি পরিষেবাটিতে এটিকে মেমরিতে সঞ্চয় করে রাখুন বা SQLite ডাটাবেস থেকে অবিচল থাকা এবং পুনরুদ্ধার করা আপনার প্রয়োজনীয়তার উপর নির্ভর করে। এটি কোনও গন্ধের পরিষেবাগুলিই করে, এগুলি অ্যাপ্লিকেশনের অবস্থা বজায় রাখা এবং বিমূর্ত সাধারণ ব্যবসার যুক্তি হিসাবে পরিষেবা সরবরাহ করে।

মোবাইল ডিভাইসে অন্তর্নিহিত মেমরি এবং প্রক্রিয়াজাতকরণের সীমাবদ্ধতার কারণে, আমি অ্যান্ড্রয়েড ভিউগুলিকে একটি ওয়েব পৃষ্ঠার মতোই ব্যবহার করি। পৃষ্ঠাটি স্থিতি বজায় রাখে না, এটি নিখুঁতভাবে একটি উপস্থাপনা স্তর উপাদান যাঁর একমাত্র উদ্দেশ্য অ্যাপ্লিকেশনের অবস্থা উপস্থাপন করা এবং ব্যবহারকারীর ইনপুট গ্রহণ করা। ওয়েব অ্যাপ্লিকেশন আর্কিটেকচারের সাম্প্রতিক প্রবণতাগুলি পুরানো মডেল, ভিউ, কন্ট্রোলার (এমভিসি) প্যাটার্নটি ব্যবহার করে যেখানে পৃষ্ঠাটি ভিউ, ডোমেন ডেটা মডেল এবং নিয়ন্ত্রক একটি ওয়েব পরিষেবার পিছনে বসে। অ্যান্ড্রয়েডে একই প্যাটার্নটি নিয়োগের সাথে দেখা যায়, ভিউ, ভাল ... দেখুন, মডেলটি আপনার ডোমেন ডেটা এবং কন্ট্রোলার অ্যান্ড্রয়েড বাউন্ড পরিষেবা হিসাবে প্রয়োগ করা হয়েছে। আপনি যখনই নিয়ামকের সাথে ইন্টারেক্ট করার জন্য একটি ভিউ চান, এটিকে শুরু / পুনরায় শুরুতে আবদ্ধ করুন এবং স্টপ / বিরাম বন্ধ করুন।

এই পদ্ধতিটি আপনাকে কনসার্ন ডিজাইনের নীতিটি পৃথককরণের যুক্ত বোনাস দেয় যাতে আপনারা সমস্ত অ্যাপ্লিকেশন ব্যবসার যুক্তি আপনার পরিষেবাতে স্থানান্তরিত হতে পারে যা একাধিক মতামত জুড়ে সদৃশ যুক্তি হ্রাস করে এবং দৃষ্টিভঙ্গিকে আরেকটি গুরুত্বপূর্ণ নকশার নীতিটি সিঙ্গেল দায়বদ্ধতার প্রয়োগ করতে দেয়।


5

Kotlin

আপনি ওভাররাইড আবশ্যক onSaveInstanceStateএবং onRestoreInstanceStateসংরক্ষণ এবং আপনি ক্রমাগত হতে চান আপনার ভেরিয়েবল পুনরুদ্ধার করতে

জীবনচক্র গ্রাফ

ভেরিয়েবল স্টোর করুন

public override fun onSaveInstanceState(savedInstanceState: Bundle) {
    super.onSaveInstanceState(savedInstanceState)

    // prepare variables here
    savedInstanceState.putInt("kInt", 10)
    savedInstanceState.putBoolean("kBool", true)
    savedInstanceState.putDouble("kDouble", 4.5)
    savedInstanceState.putString("kString", "Hello Kotlin")
}

ভেরিয়েবলগুলি পুনরুদ্ধার করুন

public override fun onRestoreInstanceState(savedInstanceState: Bundle) {
    super.onRestoreInstanceState(savedInstanceState)

    val myInt = savedInstanceState.getInt("kInt")
    val myBoolean = savedInstanceState.getBoolean("kBool")
    val myDouble = savedInstanceState.getDouble("kDouble")
    val myString = savedInstanceState.getString("kString")
    // use variables here
}

2

এখন অ্যান্ড্রয়েড রাষ্ট্র সংরক্ষণের জন্য ভিউমোডেলগুলি সরবরাহ করে , আপনার সেভআইন্সট্যান্সস্টেটের পরিবর্তে এটি ব্যবহার করার চেষ্টা করা উচিত।


3
এটি সত্য নয়। ডকুমেন্টেশন থেকে: "সংরক্ষিত উদাহরণের রাজ্যের বিপরীতে, ভিউমোডেলগুলি সিস্টেম-সূচিত প্রক্রিয়া মৃত্যুর সময় নষ্ট হয়ে যায় on এজন্য আপনাকে onSaveInstanceState () (বা কিছু অন্যান্য ডিস্কের অধ্যবসায়) এর সাথে মিলিয়ে ভিউমোডেল অবজেক্টগুলি ব্যবহার করা উচিত, দেখার জন্য সাহায্যের জন্য সেভিয়েস্ট্যান্সস্টেটে সনাক্তকারীদের স্ট্যাশিং করা উচিত মডেলগুলি সিস্টেমের মৃত্যুর পরে ডেটা পুনরায় লোড করে। "
ভাইচাস্লাভ মার্টিনেঙ্কো

ব্যাকগ্রাউন্ডে অনুমতি পরিবর্তনের সাথে এটির মধ্যে দৌড়ে গেল।
ব্রিল প্যাপিন 21

আমি সম্মত হয়েছি, ডকটি থেকে "যদি আপনাকে সিস্টেম-প্রবর্তিত প্রক্রিয়া মৃত্যুর পরিচালনা করতে হয় তবে আপনি onSaveInstanceState () কে ব্যাকআপ হিসাবে ব্যবহার করতে চাইতে পারেন।"
জার

2

কোনও পদ্ধতি প্রয়োগ না করে অ্যান্ড্রয়েডকে রাজ্যগুলি সংরক্ষণের উপায় রয়েছে। ক্রিয়াকলাপ ঘোষণায় আপনার ম্যানিফেস্টে এই লাইনটি কেবল যুক্ত করুন:

android:configChanges="orientation|screenSize"

এটিকে ঐটির মত দেখতে হবে:

<activity
    android:name=".activities.MyActivity"
    android:configChanges="orientation|screenSize">
</activity>

এখানে আপনি এই সম্পত্তি সম্পর্কে আরও তথ্য পেতে পারেন।

ম্যানুয়ালি হ্যান্ডলিংয়ের চেয়ে অ্যান্ড্রয়েডকে আপনার জন্য এটি হ্যান্ডেল করার পরামর্শ দেওয়া হচ্ছে।


2
রাষ্ট্রকে রক্ষা করার সাথে এর কোনও যোগসূত্র নেই, আপনি কেবল ওরিয়েন্টেশন পরিবর্তনগুলি ছেড়ে দিচ্ছেন, মনে রাখবেন আপনার অ্যাপটি পুনরায় শুরু এবং বিরাম দেওয়া এবং বিভিন্ন ইভেন্টের জন্য যে কোনও সময়ে পুনরায় শুরু করা যেতে পারে
লর্ড-রাল্ফ-অ্যাডল্ফ

1
এই উত্তরটি তাদের পক্ষে যারা রাজ্যটি বাঁচাতে চায় যখন অভিমুখ পরিবর্তন হয় এবং বোঝা যায় এবং জটিল পথে বাস্তবায়ন এড়াতে চায়
IgniteCoders

যথেষ্ট পরিমাণে আমি আপনার বক্তব্যটি দেখতে পাচ্ছি, আমি মনে করি বেশিরভাগ লোকেরা যারা রাষ্ট্র বাঁচাতে লড়াই করে তারা টুকরোগুলি ব্যবহার করে কারণ ক্রিয়াকলাপগুলি আসলে কোনও আইডি থাকাকালীন ইউআই উপাদানগুলির স্ট্যাট সংরক্ষণ করে তবে খণ্ডগুলি আরও বিশেষ, আমি একবার খণ্ড ব্যবহার করেছি তবে আমি কখনও ব্যবহার করব না তাদের আবার সেভ ইনস্ট্যান্স স্ট্যাটটি মোকাবেলা করার জন্য একটি বেদনা ছিল
লর্ড-রাল্ফ-অ্যাডল্ফ

এটি কার্যকর ... ধন্যবাদ
ফানাাদেজ

1

কী বাঁচাবেন আর কী করবেন না?

কখনও ভেবে দেখেছেন কেন EditTextঅভিমুখী পরিবর্তন চলাকালীন পাঠ্যগুলি স্বয়ংক্রিয়ভাবে সংরক্ষণ হয়? ঠিক আছে, এই উত্তরটি আপনার জন্য।

যখন কোনও ক্রিয়াকলাপের উদাহরণ নষ্ট হয়ে যায় এবং সিস্টেম একটি নতুন উদাহরণ পুনরায় তৈরি করে (উদাহরণস্বরূপ, কনফিগারেশন পরিবর্তন)। এটি পুরানো ক্রিয়াকলাপ রাজ্যের ( উদাহরণস্বরূপ রাজ্য ) এর সংরক্ষিত ডেটার সেট ব্যবহার করে এটি পুনরায় তৈরি করার চেষ্টা করে ।

ইনস্ট্যান্স রাজ্য হ'ল একটি বস্তুতে সঞ্চিত কী-মান জোড়ার সংকলন Bundle

ডিফল্টরূপে সিস্টেম উদাহরণস্বরূপ বান্ডলে ভিউ অবজেক্টগুলিকে সংরক্ষণ করে।

  • পাঠ্য EditText
  • ListViewইত্যাদিতে স্ক্রোল অবস্থান

উদাহরণস্বরূপ অংশ হিসাবে সংরক্ষণের জন্য আপনার যদি অন্য ভেরিয়েবলের প্রয়োজন হয় তবে আপনার পদ্ধতিটি ওভাররিড করা উচিত onSavedInstanceState(Bundle savedinstaneState)

উদাহরণস্বরূপ, int currentScoreএকটি গেমঅ্যাক্টিভিটিতে

ডেটা সংরক্ষণ করার সময় onSaaveInstanceState (বান্ডেল সেভডইনস্টেন স্টেট) সম্পর্কে আরও বিশদ

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

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

সুতরাং ভুল করে আপনি কল করতে ভুলে super.onSaveInstanceState(savedInstanceState);গেলে ডিফল্ট আচরণটি কার্যকর হবে না অর্থাৎ সম্পাদনা পাঠ্য পাঠ্য সংরক্ষণ করবে না।

কার্যকলাপের অবস্থা পুনরুদ্ধারের জন্য কোনটি বেছে নেবেন?

 onCreate(Bundle savedInstanceState)

অথবা

onRestoreInstanceState(Bundle savedInstanceState)

উভয় পদ্ধতিই একই বান্ডিল বস্তু পায়, তাই আপনি যেখানে আপনার পুনরুদ্ধার যুক্তিটি লিখেন তাতে আসলেই কিছু আসে যায় না। পার্থক্যটি হ'ল onCreate(Bundle savedInstanceState)পদ্ধতিতে আপনাকে নাল চেক দিতে হবে যখন এটি পরবর্তী ক্ষেত্রে প্রয়োজন হয় না। অন্যান্য উত্তরে ইতিমধ্যে কোড স্নিপেট রয়েছে। আপনি তাদের উল্লেখ করতে পারেন।

OnRestoreInstanceState (বান্ডিল সেভডইনস্টেন স্টেট) সম্পর্কে আরও বিশদ

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

    // Restore state members from the saved instance
    mCurrentScore = savedInstanceState.getInt(STATE_SCORE);
}

সর্বদা কল করুন super.onRestoreInstanceState(savedInstanceState);যাতে সিস্টেমটি ডিফল্টরূপে ভিউ হায়ারার্কিকে পুনরুদ্ধার করে

বোনাস

onSaveInstanceState(Bundle savedInstanceState)সিস্টেম দ্বারা প্রার্থনা শুধুমাত্র যখন ব্যবহারকারী কার্যকলাপ ফিরে আসা করতে ইচ্ছুক হয়। উদাহরণস্বরূপ, আপনি অ্যাপ এক্স ব্যবহার করছেন এবং হঠাৎ আপনি একটি কল পান। আপনি কলার অ্যাপে চলে যান এবং এক্স অ্যাপে ফিরে আসেন this এক্ষেত্রেonSaveInstanceState(Bundle savedInstanceState) পদ্ধতিটি শুরু করা হবে।

কোনও ব্যবহারকারী যদি পিছনের বোতামটি টিপেন তবে এটি বিবেচনা করুন। ধারণা করা হয় যে ব্যবহারকারীর ক্রিয়াকলাপে ফিরে আসার ইচ্ছা নেই, সুতরাং onSaveInstanceState(Bundle savedInstanceState)এক্ষেত্রে সিস্টেম দ্বারা প্রার্থনা করা হবে না। পয়েন্ট হ'ল ডেটা সংরক্ষণের সময় আপনার সমস্ত পরিস্থিতি বিবেচনা করা উচিত।

প্রাসঙ্গিক লিঙ্ক:

ডিফল্ট আচরণের ডেমো
অ্যান্ড্রয়েড অফিসিয়াল ডকুমেন্টেশন


1

এখন ভিউ মডেলে 2 টি উপায় করা বুদ্ধিমান। যদি আপনি প্রথমটিকে একটি সংরক্ষিত উদাহরণ হিসাবে সংরক্ষণ করতে চান: আপনি এই মডেলটিতে https://developer.android.com/topic/libraries/architecture/viewmodel-savedstate#java এর মত মডেলটিতে স্টেট প্যারামিটার যুক্ত করতে পারেন

বা আপনি ভিউ মডেলে ভেরিয়েবল বা অবজেক্ট সংরক্ষণ করতে পারেন, এক্ষেত্রে ভিউ মডেলটি কার্যকলাপ নষ্ট না হওয়া পর্যন্ত জীবনচক্রকে ধরে রাখবে।

public class HelloAndroidViewModel extends ViewModel {
   public Booelan firstInit = false;

    public HelloAndroidViewModel() {
        firstInit = false;
    }
    ...
}

public class HelloAndroid extends Activity {

  private TextView mTextView = null;
  HelloAndroidViewModel viewModel = ViewModelProviders.of(this).get(HelloAndroidViewModel.class);
  /** Called when the activity is first created. */
  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    mTextView = new TextView(this);

    //Because even if the state is deleted, the data in the viewmodel will be kept because the activity does not destroy
    if(!viewModel.firstInit){
        viewModel.firstInit = true
        mTextView.setText("Welcome to HelloAndroid!");
    }else{
       mTextView.setText("Welcome back.");
    }

    setContentView(mTextView);
  }
}

আপনি ঠিক বলেছেন, তবে এই গ্রন্থাগারটি এখনও
অবমুক্ত রয়েছে

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.