Android
अभिविन्यास परिवर्तन
खोज…
टिप्पणियों
सेविंग एंड रिस्टोरिंग एक्टिविटी स्टेट
जैसे ही आपकी गतिविधि बंद onSaveInstanceState()
शुरू होती है, सिस्टम onSaveInstanceState()
कॉल करता है, इसलिए आपकी गतिविधि कुंजी-मूल्य जोड़े के संग्रह के साथ राज्य की जानकारी को बचा सकती है। इस पद्धति का डिफ़ॉल्ट कार्यान्वयन स्वचालित रूप से गतिविधि के दृश्य पदानुक्रम की स्थिति के बारे में जानकारी को सहेजता है, जैसे कि एक EditText
विजेट में पाठ या ListView
की स्क्रॉल स्थिति।
अपनी गतिविधि के लिए अतिरिक्त राज्य जानकारी को बचाने के लिए, आपको onSaveInstanceState()
को लागू करना होगा और बंडल ऑब्जेक्ट में कुंजी-मूल्य जोड़े जोड़ना होगा। उदाहरण के लिए:
public class MainActivity extends Activity {
static final String SOME_VALUE = "int_value";
static final String SOME_OTHER_VALUE = "string_value";
@Override
protected void onSaveInstanceState(Bundle savedInstanceState) {
// Save custom values into the bundle
savedInstanceState.putInt(SOME_VALUE, someIntValue);
savedInstanceState.putString(SOME_OTHER_VALUE, someStringValue);
// Always call the superclass so it can save the view hierarchy state
super.onSaveInstanceState(savedInstanceState);
}
}
किसी गतिविधि के नष्ट होने से पहले सिस्टम उस विधि को कॉल करेगा। फिर बाद में सिस्टम onRestoreInstanceState
कॉल onRestoreInstanceState
जहां हम बंडल से राज्य को पुनर्स्थापित कर सकते हैं:
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
// Always call the superclass so it can restore the view hierarchy
super.onRestoreInstanceState(savedInstanceState);
// Restore state members from saved instance
someIntValue = savedInstanceState.getInt(SOME_VALUE);
someStringValue = savedInstanceState.getString(SOME_OTHER_VALUE);
}
इंस्टेंट राज्य को मानक गतिविधि # ऑनक्रिएट विधि में भी बहाल किया जा सकता है, लेकिन इसे onRestoreInstanceState
में करना सुविधाजनक है, जो सुनिश्चित करता है कि सभी आरंभीकरण हो चुका है और उपवर्गों को यह तय करने की अनुमति देता है कि क्या डिफ़ॉल्ट कार्यान्वयन का उपयोग करना है। विवरण के लिए इस स्टैकओवरफ़्लो पोस्ट को पढ़ें।
ध्यान दें कि onSaveInstanceState
और onRestoreInstanceState
को एक साथ बुलाए जाने की गारंटी नहीं है। जब कोई गतिविधि नष्ट हो सकती है, तो Android onSaveInstanceState()
करता है। हालांकि, ऐसे मामले हैं जहां onSaveInstanceState
कहा जाता है, लेकिन गतिविधि नष्ट नहीं होती है और परिणामस्वरूप onRestoreInstanceState
को लागू नहीं किया जाता है।
सेविंग एंड रिस्टोरिंग फ्रैगमेंट स्टेट
Fragments में एक onSaveInstanceState()
विधि भी होती है जिसे तब कहा जाता है जब उनके राज्य को सहेजने की आवश्यकता होती है:
public class MySimpleFragment extends Fragment {
private int someStateValue;
private final String SOME_VALUE_KEY = "someValueToSave";
// Fires when a configuration change occurs and fragment needs to save state
@Override
protected void onSaveInstanceState(Bundle outState) {
outState.putInt(SOME_VALUE_KEY, someStateValue);
super.onSaveInstanceState(outState);
}
}
फिर हम onCreateView
में इस सहेजी गई स्थिति से डेटा खींच सकते हैं:
public class MySimpleFragment extends Fragment {
// ...
// Inflate the view for the fragment based on layout XML
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.my_simple_fragment, container, false);
if (savedInstanceState != null) {
someStateValue = savedInstanceState.getInt(SOME_VALUE_KEY);
// Do something with value if needed
}
return view;
}
}
खंड स्थिति को ठीक से सहेजे जाने के लिए, हमें यह सुनिश्चित करने की आवश्यकता है कि हम कॉन्फ़िगरेशन परिवर्तनों पर अनावश्यक रूप से टुकड़े को फिर से नहीं बना रहे हैं। इसका मतलब है कि पहले से मौजूद होने पर मौजूदा टुकड़ों पर लगाम नहीं लगाना सावधान रहना चाहिए। किसी गतिविधि में आरंभ होने वाले किसी भी टुकड़े को कॉन्फ़िगरेशन परिवर्तन के बाद टैग द्वारा देखा जाना चाहिए:
public class ParentActivity extends AppCompatActivity {
private MySimpleFragment fragmentSimple;
private final String SIMPLE_FRAGMENT_TAG = "myfragmenttag";
@Override
protected void onCreate(Bundle savedInstanceState) {
if (savedInstanceState != null) { // saved instance state, fragment may exist
// look up the instance that already exists by tag
fragmentSimple = (MySimpleFragment)
getSupportFragmentManager().findFragmentByTag(SIMPLE_FRAGMENT_TAG);
} else if (fragmentSimple == null) {
// only create fragment if they haven't been instantiated already
fragmentSimple = new MySimpleFragment();
}
}
}
लेन-देन के दौरान गतिविधि में एक टुकड़ा डालते समय हमें देखने के लिए एक टैग शामिल करने के लिए सावधान रहने की आवश्यकता है:
public class ParentActivity extends AppCompatActivity {
private MySimpleFragment fragmentSimple;
private final String SIMPLE_FRAGMENT_TAG = "myfragmenttag";
@Override
protected void onCreate(Bundle savedInstanceState) {
// ... fragment lookup or instantation from above...
// Always add a tag to a fragment being inserted into container
if (!fragmentSimple.isInLayout()) {
getSupportFragmentManager()
.beginTransaction()
.replace(R.id.container, fragmentSimple, SIMPLE_FRAGMENT_TAG)
.commit();
}
}
}
इस सरल पैटर्न के साथ, हम ठीक से टुकड़ों का फिर से उपयोग कर सकते हैं और कॉन्फ़िगरेशन परिवर्तनों के दौरान उनकी स्थिति को पुनर्स्थापित कर सकते हैं।
फ्रेगमेंट्स को रिटेन करना
कई मामलों में, हम समस्याओं से बच सकते हैं जब किसी गतिविधि को केवल टुकड़ों का उपयोग करके बनाया जाता है। यदि आपके विचार और स्थिति एक टुकड़े के भीतर हैं, तो गतिविधि को फिर से बनाए जाने पर हम आसानी से उस खंड को बनाए रख सकते हैं:
public class RetainedFragment extends Fragment {
// data object we want to retain
private MyDataObject data;
// this method is only called once for this fragment
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// retain this fragment when activity is re-initialized
setRetainInstance(true);
}
public void setData(MyDataObject data) {
this.data = data;
}
public MyDataObject getData() {
return data;
}
}
यह दृष्टिकोण गतिविधि जीवनचक्र के दौरान नष्ट होने से बचाए रखता है। इसके बजाय उन्हें फ्रैगमेंट मैनेजर के अंदर रखा जाता है। अधिक जानकारी के लिए Android आधिकारिक डॉक्स देखें ।
अब आप यह देख सकते हैं कि एक बनाने से पहले ही टुकड़ा पहले से मौजूद है या नहीं, यह खंड विन्यास परिवर्तनों के दौरान स्थिति बनाए रखेगा। अधिक जानकारी के लिए हैंडलिंग रनटाइम परिवर्तन गाइड देखें ।
लॉकिंग स्क्रीन ओरिएंटेशन
यदि आप अपने एंड्रॉइड एप्लिकेशन के किसी भी स्क्रीन (गतिविधि) के स्क्रीन ओरिएंटेशन परिवर्तन को लॉक करना चाहते हैं, तो आपको एंड्रॉइड को स्क्रीन करने की आवश्यकता है android:screenOrientation
AndroidManifest.xml के भीतर <activity>
की android:screenOrientation
संपत्ति:
<activity
android:name="com.techblogon.screenorientationexample.MainActivity"
android:screenOrientation="portrait"
android:label="@string/app_name" >
<!-- ... -->
</activity>
अब वह गतिविधि हमेशा " पोर्ट्रेट " मोड में प्रदर्शित होने के लिए मजबूर होती है।
मैन्युअल रूप से कॉन्फ़िगरेशन परिवर्तन का प्रबंधन
यदि आपके एप्लिकेशन को किसी विशिष्ट कॉन्फ़िगरेशन परिवर्तन के दौरान संसाधनों को अपडेट करने की आवश्यकता नहीं है और आपके पास एक प्रदर्शन सीमा है, जिसके लिए आपको गतिविधि पुनरारंभ से बचने की आवश्यकता है, तो आप घोषणा कर सकते हैं कि आपकी गतिविधि कॉन्फ़िगरेशन परिवर्तन को स्वयं संभालती है, जो सिस्टम को आपके पुनरारंभ करने से रोकती है गतिविधि।
हालाँकि, इस तकनीक को एक अंतिम उपाय माना जाना चाहिए जब आपको कॉन्फ़िगरेशन परिवर्तन के कारण पुनरारंभ से बचना चाहिए और अधिकांश अनुप्रयोगों के लिए अनुशंसित नहीं है। इस दृष्टिकोण को लेने के लिए, हमें android:configChanges
नोड को AndroidManifest.xml के भीतर गतिविधि में जोड़ना होगा:
<activity android:name=".MyActivity"
android:configChanges="orientation|screenSize|keyboardHidden"
android:label="@string/app_name">
अब, जब इनमें से एक कॉन्फ़िगरेशन बदलता है, तो गतिविधि फिर से शुरू नहीं होती है, बल्कि इसके बजाय onConfigurationChanged()
कॉल प्राप्त करता है onConfigurationChanged()
:
// Within the activity which receives these changes
// Checks the current device orientation, and toasts accordingly
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
// Checks the orientation of the screen
if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
Toast.makeText(this, "landscape", Toast.LENGTH_SHORT).show();
} else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT){
Toast.makeText(this, "portrait", Toast.LENGTH_SHORT).show();
}
}
हैंडलिंग डॉक्स बदलें देखें। अधिक जानकारी के लिए कि आप अपनी गतिविधि में कौन सा कॉन्फ़िगरेशन परिवर्तन कर सकते हैं, Android देखें : कॉन्फ़िगरेशन दस्तावेज़ और कॉन्फ़िगरेशन वर्ग।
AsyncTask को हैंडल करना
मुसीबत:
- यदि
AsyncTask
शुरू होने के बाद एक स्क्रीन रोटेशन होता है तो मालिक की गतिविधि नष्ट हो जाती है और उसे फिर से बनाया जाता है। - जब
AsyncTask
खत्म हो जाता है तो यह UI को अपडेट करना चाहता है जो अब मान्य नहीं हो सकता है।
समाधान:
लोडर का उपयोग करके, कोई भी आसानी से गतिविधि विनाश / मनोरंजन पर काबू पा सकता है।
उदाहरण:
मुख्य गतिविधि:
public class MainActivity extends AppCompatActivity
implements LoaderManager.LoaderCallbacks<Bitmap> {
//Unique id for the loader
private static final int MY_LOADER = 0;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
LoaderManager loaderManager = getSupportLoaderManager();
if(loaderManager.getLoader(MY_LOADER) == null) {
loaderManager.initLoader(MY_LOADER, null, this).forceLoad();
}
}
@Override
public Loader<Bitmap> onCreateLoader(int id, Bundle args) {
//Create a new instance of your Loader<Bitmap>
MyLoader loader = new MyLoader(MainActivity.this);
return loader;
}
@Override
public void onLoadFinished(Loader<Bitmap> loader, Bitmap data) {
// do something in the parent activity/service
// i.e. display the downloaded image
Log.d("MyAsyncTask", "Received result: ");
}
@Override
public void onLoaderReset(Loader<Bitmap> loader) {
}
}
AsyncTaskLoader:
public class MyLoader extends AsyncTaskLoader<Bitmap> {
private WeakReference<Activity> motherActivity;
public MyLoader(Activity activity) {
super(activity);
//We don't use this, but if you want you can use it, but remember, WeakReference
motherActivity = new WeakReference<>(activity);
}
@Override
public Bitmap loadInBackground() {
// Do work. I.e download an image from internet to be displayed in gui.
// i.e. return the downloaded gui
return result;
}
}
ध्यान दें:
V4 संगतता पुस्तकालय या नहीं का उपयोग करना महत्वपूर्ण है, लेकिन एक के हिस्से और दूसरे के हिस्से का उपयोग न करें, क्योंकि यह संकलन त्रुटियों को जन्म देगा। जाँचने के लिए आप android.support.v4.content
और android.content
के आयात को देख सकते हैं (आपके पास दोनों नहीं होने चाहिए)।
लॉक स्क्रीन के रोटेशन को प्रोग्रामेटिक रूप से लॉक करें
यह बहुत आम है कि विकास के दौरान, किसी को कोड के विशिष्ट भागों के दौरान डिवाइस स्क्रीन को लॉक / अनलॉक करने के लिए बहुत उपयोगी मिल सकता है।
उदाहरण के लिए, जानकारी के साथ डायलॉग दिखाते समय, डेवलपर स्क्रीन के घुमाव को लॉक करना चाह सकता है ताकि संवाद को खारिज न किया जा सके और वर्तमान गतिविधि को फिर से अनलॉक करने के लिए फिर से बनाया जा सके जब संवाद खारिज हो जाए।
भले ही हम प्रकट से रोटेशन लॉकिंग प्राप्त कर सकते हैं:
<activity
android:name=".TheActivity"
android:screenOrientation="portrait"
android:label="@string/app_name" >
</activity>
निम्नांकित करके कोई भी इसे प्रोग्रामेटिक रूप से कर सकता है:
public void lockDeviceRotation(boolean value) {
if (value) {
int currentOrientation = getResources().getConfiguration().orientation;
if (currentOrientation == Configuration.ORIENTATION_LANDSCAPE) {
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE);
} else {
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT);
}
} else {
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_FULL_USER);
} else {
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR);
}
}
}
और फिर निम्नलिखित को कॉल करके क्रमशः डिवाइस रोटेशन को लॉक और अनलॉक करें
lockDeviceRotation(true)
तथा
lockDeviceRotation(false)