android - रोटेशन एंड्रॉइड पर गतिविधि पुनरारंभ करें




rotation android-activity (20)

मेरे एंड्रॉइड एप्लिकेशन में, जब मैं डिवाइस को घुमाता हूं (कीबोर्ड को स्लाइड करता हूं) तो मेरी Activity पुनरारंभ होती है ( onCreate को कॉल किया जाता है)। अब, शायद यह होना चाहिए कि यह कैसे होना चाहिए, लेकिन मैं onCreate विधि में बहुत प्रारंभिक सेटिंग करता हूं, इसलिए मुझे या तो चाहिए:

  1. सभी प्रारंभिक सेटिंग को किसी अन्य फ़ंक्शन में रखें ताकि डिवाइस डिवाइस रोटेशन पर यह सब खो न जाए
  2. इसे इतना बनाओ onCreate को फिर से नहीं कहा जाता है और लेआउट बस समायोजित करता है या
  3. ऐप को केवल पोर्ट्रेट तक सीमित करें ताकि onCreate को कॉल न किया जा सके।

 onConfigurationChanged is called when the screen rotates. 
 (onCreate is no longer called when screen rotates due to manifest, see:  
 android:configChanges)

मेनिफेस्ट का कौन सा हिस्सा यह बताता है " onCreate() " पर कॉल न करें?

साथ ही, Google के दस्तावेज़ android:configChanges का उपयोग करने से बचने के लिए कहते हैं android:configChanges (अंतिम उपाय के रूप में छोड़कर) .... लेकिन फिर वैकल्पिक तरीकों से वे सभी का उपयोग करते हैं android:configChanges

यह मेरा अनुभव रहा है कि एमुलेटर हमेशा घूर्णन पर onCreate() पर कॉल करता है।
लेकिन 1-2 डिवाइस जो मैं एक ही कोड चलाता हूं ... नहीं। (यकीन नहीं है कि कोई अंतर क्यों होगा।)


आप एंड्रॉइड प्लेटफॉर्म के अभिविन्यास परिवर्तनों में लगातार डेटा के तरीके का उपयोग करने पर भी विचार कर सकते हैं: onRetainNonConfigurationInstance() और getLastNonConfigurationInstance()

यह आपको कॉन्फ़िगरेशन परिवर्तनों में डेटा को जारी रखने की अनुमति देता है, जैसे कि सर्वर से प्राप्त जानकारी या किसी अन्य चीज जिसे आपने गणना की onCreate या बाद में गणना की गई है, जबकि एंड्रॉइड को अब भी उन्मुखता के लिए xml फ़ाइल का उपयोग करके अपनी Activity को फिर से लेआउट करने की इजाजत देता है उपयोग में।

here या यहां देखें।

यह ध्यान दिया जाना चाहिए कि इन तरीकों को अब बहिष्कृत किया गया है (हालांकि उपरोक्त समाधानों में से अधिकांश के रूप में अभिविन्यास को बदलने से अधिक लचीला है) सिफारिश के साथ कि हर कोई Fragments स्विच करता है और इसके बजाय प्रत्येक Fragment पर setRetainInstance(true) उपयोग करता है setRetainInstance(true) आप बनाए रखना चाहते हैं ।


आपको सभी पैरामीटर को अपने पैरामीटर में स्टोर करने के लिए ऑनवेडइनस्टेंसस्टेट विधि का उपयोग करने की आवश्यकता है, यह बंडल है

@Override
    public void onSaveInstanceState(Bundle outState, PersistableBundle outPersistentState) {
        super.onSaveInstanceState(outState, outPersistentState);
        outPersistentState.putBoolean("key",value);
    }

और उपयोग करें

@Override
    protected void onRestoreInstanceState(Bundle savedInstanceState) {
        super.onRestoreInstanceState(savedInstanceState);
        savedInstanceState.getBoolean("key");
    } 

वस्तुओं को देखने के लिए मूल्य को पुनः प्राप्त करने और सेट करने के लिए यह स्क्रीन रोटेशन को संभालेगा


इस पंक्ति को अपने मैनिफेस्ट में जोड़ें: -

android:configChanges="orientation|keyboard|keyboardHidden|screenSize|screenLayout|uiMode"

और गतिविधि के लिए यह स्निपेट: -

@Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
                WindowManager.LayoutParams.FLAG_FULLSCREEN);
    }

इसे करने बहुत सारे तरीके हैं:

गतिविधि राज्य सहेजें

आप गतिविधि स्थिति को onSaveInstanceState में onSaveInstanceState

@Override
public void onSaveInstanceState(Bundle outState) {
    /*Save your data to be restored here
    Example : outState.putLong("time_state", time); , time is a long variable*/
    super.onSaveInstanceState(outState);
}

और फिर राज्य को पुनर्स्थापित करने के लिए bundle का उपयोग करें।

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

    if(savedInstanceState!= null){
       /*When rotation occurs
        Example : time = savedInstanceState.getLong("time_state", 0); */
    } else {
      //When onCreate is called for the first time
    }
}

अपने आप को अभिविन्यास परिवर्तन संभाल लें

एक और विकल्प अपने आप को अभिविन्यास परिवर्तनों को संभालना है। लेकिन यह एक अच्छा अभ्यास नहीं माना जाता है।

इसे अपनी मेनिफेस्ट फ़ाइल में जोड़ें।

android:configChanges="keyboardHidden|orientation"

एंड्रॉइड 3.2 और बाद में:

android:configChanges="keyboardHidden|orientation|screenSize"

@Override
public void onConfigurationChanged(Configuration config) {
    super.onConfigurationChanged(config);

if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) {
        //Handle rotation from landscape to portarit mode here
    } else if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE){
        //Handle rotation from portrait to landscape mode here
    }
}

रोटेशन प्रतिबंधित करें

घूर्णन से बचने के लिए आप अपनी गतिविधि को पोर्ट्रेट या लैंडस्केप मोड में भी सीमित कर सकते हैं।

इसे अपनी मेनिफेस्ट फ़ाइल में गतिविधि टैग में जोड़ें:

        android:screenOrientation="portrait"

या अपनी गतिविधि में प्रोग्रामेटिक रूप से कार्यान्वित करें:

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

एंड्रॉइड 3.2 और उच्चतर के लिए अपडेट करें:

सावधानी : एंड्रॉइड 3.2 (एपीआई लेवल 13) के साथ शुरुआत, डिवाइस "पोर्ट साइज" भी बदलता है जब डिवाइस पोर्ट्रेट और लैंडस्केप ओरिएंटेशन के बीच स्विच करता है। इस प्रकार, यदि आप एपीआई स्तर 13 या उच्चतर (जैसा कि minSdkVersion और targetSdkVersion विशेषताओं द्वारा घोषित किया गया है) के लिए विकास करते समय अभिविन्यास परिवर्तन के कारण रनटाइम पुनरारंभ करना रोकना चाहते हैं, तो आपको "screenSize" मान के अतिरिक्त "screenSize" मान शामिल करना होगा। यही है, आपको android:configChanges="orientation|screenSize" घोषित करना होगा android:configChanges="orientation|screenSize" । हालांकि, यदि आपका एप्लिकेशन एपीआई स्तर 12 या उससे कम लक्षित करता है, तो आपकी गतिविधि हमेशा इस कॉन्फ़िगरेशन को स्वयं ही बदलती है (यह कॉन्फ़िगरेशन परिवर्तन आपकी गतिविधि को पुनरारंभ नहीं करता है, यहां तक ​​कि एंड्रॉइड 3.2 या उच्चतर डिवाइस पर चलते समय भी)।


जब आप एंड्रॉइड के orientation को बदलते हैं तो onCreate विधि अभी भी कॉल की जाती है। तो इस विधि के लिए सभी भारी कार्यक्षमता को स्थानांतरित करने में आपकी सहायता नहीं होगी


जिस तरह से मुझे ऐसा करने के लिए मिला है, वह onRestoreInstanceState और onSaveInstanceState इवेंट्स का उपयोग Bundle में कुछ सहेजने के लिए किया जाता है (भले ही आपको सहेजे गए किसी भी चर की आवश्यकता न हो, बस वहां कुछ डालें ताकि Bundle खाली न हो)। फिर, onCreate विधि पर, यह देखने के लिए जांचें कि Bundle खाली है या नहीं, और यदि यह है, तो प्रारंभ करें, यदि नहीं, तो ऐसा करें।


परीक्षण और त्रुटि के कुछ समय बाद, मुझे एक समाधान मिला जो ज्यादातर स्थितियों में मेरी आवश्यकताओं को फिट करता है। कोड यहां है:

प्रकटीकरण विन्यास:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
          package="com.pepperonas.myapplication">

    <application
        android:name=".App"
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity
            android:name=".MainActivity"
            android:configChanges="orientation|keyboardHidden|screenSize">
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>

                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>
    </application>

</manifest>

मुख्य गतिविधि:

import android.content.res.Configuration;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.Button;

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    private static final String TAG = "MainActivity";

    private Fragment mFragment;

    private int mSelected = -1;


    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.d(TAG, "onCreate  " + "");

        // null check not realy needed - but just in case...
        if (savedInstanceState == null) {

            initUi();

            // get an instance of FragmentTransaction from your Activity
            FragmentManager fragmentManager = getSupportFragmentManager();
            FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();

            /*IMPORTANT: Do the INITIAL(!) transaction only once!
            * If we call this everytime the layout changes orientation,
            * we will end with a messy, half-working UI.
            * */
            mFragment = FragmentOne.newInstance(mSelected = 0);
            fragmentTransaction.add(R.id.frame, mFragment);
            fragmentTransaction.commit();
        }
    }


    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        Log.d(TAG, "onConfigurationChanged  " +
                   (newConfig.orientation
                    == Configuration.ORIENTATION_LANDSCAPE
                    ? "landscape" : "portrait"));

        initUi();

        Log.i(TAG, "onConfigurationChanged - last selected: " + mSelected);
        makeFragmentTransaction(mSelected);
    }


    /**
     * Called from {@link #onCreate} and {@link #onConfigurationChanged}
     */
    private void initUi() {
        setContentView(R.layout.activity_main);
        Log.d(TAG, "onCreate  instanceState == null / reinitializing..." + "");
        Button btnFragmentOne = (Button) findViewById(R.id.btn_fragment_one);
        Button btnFragmentTwo = (Button) findViewById(R.id.btn_fragment_two);
        btnFragmentOne.setOnClickListener(this);
        btnFragmentTwo.setOnClickListener(this);
    }


    /**
     * Not invoked (just for testing)...
     */
    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        Log.d(TAG, "onSaveInstanceState  " + "YOU WON'T SEE ME!!!");
    }


    /**
     * Not invoked (just for testing)...
     */
    @Override
    protected void onRestoreInstanceState(Bundle savedInstanceState) {
        super.onRestoreInstanceState(savedInstanceState);
        Log.d(TAG, "onSaveInstanceState  " + "YOU WON'T SEE ME, AS WELL!!!");
    }


    @Override
    protected void onResume() {
        super.onResume();
        Log.d(TAG, "onResume  " + "");
    }


    @Override
    protected void onPause() {
        super.onPause();
        Log.d(TAG, "onPause  " + "");
    }


    @Override
    protected void onDestroy() {
        super.onDestroy();
        Log.d(TAG, "onDestroy  " + "");
    }


    @Override
    public void onClick(View v) {

        switch (v.getId()) {
            case R.id.btn_fragment_one:
                Log.d(TAG, "onClick btn_fragment_one " + "");
                makeFragmentTransaction(0);
                break;

            case R.id.btn_fragment_two:
                Log.d(TAG, "onClick btn_fragment_two " + "");
                makeFragmentTransaction(1);
                break;

            default:
                Log.d(TAG, "onClick  null - wtf?!" + "");
        }
    }


    /**
     * We replace the current Fragment with the selected one.
     * Note: It's called from {@link #onConfigurationChanged} as well.
     */
    private void makeFragmentTransaction(int selection) {

        switch (selection) {
            case 0:
                mFragment = FragmentOne.newInstance(mSelected = 0);
                break;
            case 1:
                mFragment = FragmentTwo.newInstance(mSelected = 1);
                break;
        }

        // Create new transaction
        FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();

        // Replace whatever is in the fragment_container view with this fragment,
        // and add the transaction to the back stack
        transaction.replace(R.id.frame, mFragment);

        /*This would add the Fragment to the backstack...
        * But right now we comment it out.*/
        //        transaction.addToBackStack(null);

        // Commit the transaction
        transaction.commit();
    }

}

और नमूना टुकड़ा:

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

/**
 * @author Martin Pfeffer (pepperonas)
 */
public class FragmentOne extends Fragment {

    private static final String TAG = "FragmentOne";


    public static Fragment newInstance(int i) {
        Fragment fragment = new FragmentOne();
        Bundle args = new Bundle();
        args.putInt("the_id", i);
        fragment.setArguments(args);
        return fragment;
    }


    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        Log.d(TAG, "onCreateView  " + "");
        return inflater.inflate(R.layout.fragment_one, container, false);
    }

}

github पर पाया जा सकता है।


भले ही यह "एंड्रॉइड तरीका" नहीं है, फिर भी मुझे अभिविन्यास परिवर्तनों को संभालने और आसानी से विजेट को पुनर्स्थापित करने के लिए बहुत अच्छे परिणाम प्राप्त हुए हैं ताकि परिवर्तित अभिविन्यास को ध्यान में रखा जा सके। यह किसी भी अन्य दृष्टिकोण से तेज़ है, क्योंकि आपके विचारों को सहेजने और पुनर्स्थापित करने की आवश्यकता नहीं है। यह उपयोगकर्ता को अधिक सहज अनुभव प्रदान करता है, क्योंकि बस्तियां विजेट बिल्कुल वही विजेट होते हैं, बस स्थानांतरित होते हैं और / या आकार बदलते हैं। न केवल मॉडल राज्य, बल्कि राज्य को भी देखते हैं, इस तरह से संरक्षित किया जा सकता है।

RelativeLayout कभी-कभी उस दृश्य के लिए एक अच्छा विकल्प हो सकता है जिसे समय-समय पर खुद को पुन: पेश करना पड़ता है। आप प्रत्येक बच्चे विजेट के लिए प्रत्येक पर अलग-अलग रिश्तेदार पोजीशनिंग नियमों के साथ पोर्ट्रेट लेआउट पैराम्स और लैंडस्केप लेआउट पैराम्स का एक सेट प्रदान करते हैं। फिर, आपके onConfigurationChanged() विधि में, आप उपयुक्त बच्चे को प्रत्येक बच्चे पर onConfigurationChanged() setLayoutParams() कॉल पर पास करते हैं। अगर किसी भी बच्चे के नियंत्रण को आंतरिक रूप से पुनर्निर्मित करने की आवश्यकता होती है, तो आप उस बच्चे को पुनर्विचार करने के लिए बस एक विधि कहते हैं। वह बच्चा इसी तरह के किसी भी बाल नियंत्रण पर विधियों को कॉल करता है जिसके लिए आंतरिक पुनर्विचार की आवश्यकता होती है, और इसी तरह।


मैंने क्या किया...

मैनिफेस्ट में, गतिविधि खंड में, जोड़ा गया:

android:configChanges="keyboardHidden|orientation"

गतिविधि के लिए कोड में, कार्यान्वित:

//used in onCreate() and onConfigurationChanged() to set up the UI elements
public void InitializeUI()
{
    //get views from ID's
    this.textViewHeaderMainMessage = (TextView) this.findViewById(R.id.TextViewHeaderMainMessage);

    //etc... hook up click listeners, whatever you need from the Views
}

//Called when the activity is first created.
@Override
public void onCreate(Bundle savedInstanceState)
{
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    InitializeUI();
}

//this is called when the screen rotates.
// (onCreate is no longer called when screen rotates due to manifest, see: android:configChanges)
@Override
public void onConfigurationChanged(Configuration newConfig)
{
    super.onConfigurationChanged(newConfig);
    setContentView(R.layout.main);

    InitializeUI();
}


लोग कह रहे हैं कि आपको उपयोग करना चाहिए

android:configChanges="keyboardHidden|orientation"

लेकिन एंड्रॉइड में रोटेशन को संभालने का सबसे अच्छा और सबसे पेशेवर तरीका लोडर क्लास का उपयोग करना है। यह एक प्रसिद्ध वर्ग नहीं है (मुझे नहीं पता क्यों), लेकिन यह AsyncTask से बेहतर तरीका है। मैंने एंड्रॉइड नैनो डिग्री कोर्स से लोकप्रिय-मूवीज़-भाग -1 असाइनमेंट को पूरा करने के लिए इसका इस्तेमाल किया।

लोकप्रिय फिल्में भाग 1

बेशक आप मूल्यों या विचारों को ऑनवेस्टेंसस्टेट के साथ स्टोर कर सकते हैं और उन्हें रीस्टोर इंस्टेंसस्टेट के साथ पढ़ सकते हैं। यह वास्तव में आप पर निर्भर है।


विभिन्न अभिविन्यास पर विभिन्न कार्यों को करने के लिए orientation श्रोता का उपयोग करें।

@Override
public void onConfigurationChanged(Configuration myConfig) 
{
    super.onConfigurationChanged(myConfig);
    int orient = getResources().getConfiguration().orientation; 
    switch(orient) 
    {
       case Configuration.ORIENTATION_LANDSCAPE:
          setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
                    break;
       case Configuration.ORIENTATION_PORTRAIT:
          setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
                    break;
       default:
          setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
    }
}

Android Manifest में अपनी Activity में कोड को नीचे रखें।

android:configChanges="orientation"

जब आप अभिविन्यास बदलेंगे तो यह आपकी गतिविधि को पुनरारंभ नहीं करेगा।


AndroidManifest.xml में स्क्रीन अभिविन्यास (परिदृश्य या चित्र) को ठीक करें

android:screenOrientation="portrait" या android:screenOrientation="landscape"

इसके लिए आपके onResume() विधि को नहीं कहा जाता है।


manifest के गतिविधि खंड में, जोड़ें:

android:configChanges="keyboardHidden|orientation"

onCreate() को पूरी तरह से निकालने से रोकने की कोशिश करने के बजाय, शायद Bundle savedInstanceState किए गए जांच की जांच करें, यह देखने के लिए घटना में पारित किया जा रहा है कि यह शून्य है या नहीं।

उदाहरण के लिए, यदि मेरे पास कुछ तर्क है जो Activity को वास्तव में बनाया गया है, प्रत्येक अभिविन्यास परिवर्तन पर नहीं, तो केवल उस तर्क को onCreate() में ही चलाया जाए यदि savedInstanceState गए savedInstanceState शून्य है।

अन्यथा, मैं अभी भी लेआउट को अभिविन्यास के लिए ठीक से फिर से निकालना चाहता हूं।

public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_game_list);

        if(savedInstanceState == null){
            setupCloudMessaging();
        }
}

सुनिश्चित नहीं है कि यह अंतिम जवाब है, लेकिन यह मेरे लिए काम करता है।


नोट: अगर मैं भविष्य में किसी को भी उसी समस्या का सामना करता हूं तो मैं यह जवाब पोस्ट करता हूं। मेरे लिए निम्नलिखित पंक्ति नहीं मांगी गई थी:

android:configChanges="orientation"

जब मैंने स्क्रीन को घुमाया, तो विधि 'कॉन्फ़िगरेशन चेंज (कॉन्फ़िगरेशन न्यू कॉन्फिग) को कॉल नहीं किया गया था।

समाधान: मुझे "स्क्रीनसाइज" भी जोड़ना पड़ा, भले ही समस्या को उन्मुखीकरण के साथ किया जाए। तो AndroidManifest.xml - फ़ाइल में, इसे जोड़ें:

android:configChanges="keyboardHidden|orientation|screenSize"

फिर onConfigurationChanged(Configuration newConfig)


आप इस कोड का उपयोग कर स्क्रीन के वर्तमान अभिविन्यास को लॉक कर सकते हैं ...

int currentOrientation =context.getResources().getConfiguration().orientation;
        if (currentOrientation == Configuration.ORIENTATION_PORTRAIT) {
            ((Activity) context).setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
        } else {
            ((Activity) context). setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
        }




android-activity