Zoeken…


Opmerkingen

Referentie: https://guides.codepath.com/android/Handling-Configuration-Changes#references

Activiteitstatus opslaan en herstellen

Wanneer uw activiteit begint te stoppen, roept het systeem onSaveInstanceState() zodat uw activiteit onSaveInstanceState() kan opslaan met een verzameling sleutel / waarde-paren. De standaardimplementatie van deze methode slaat automatisch informatie op over de status van de weergavehiërarchie van de activiteit, zoals de tekst in een EditText widget of de schuifpositie van een ListView .

Als u aanvullende onSaveInstanceState() voor uw activiteit wilt opslaan, moet u onSaveInstanceState() implementeren en sleutel / waarde-paren toevoegen aan het Bundle-object. Bijvoorbeeld:

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

Het systeem roept die methode aan voordat een activiteit wordt vernietigd. Dan zal het systeem later onRestoreInstanceState waar we de status van de bundel kunnen herstellen:

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

De instantiestatus kan ook worden hersteld in de standaard Activity # onCreate-methode, maar het is handig om dit te doen in onRestoreInstanceState waardoor alle initialisatie is uitgevoerd en subklassen kunnen beslissen of de standaardimplementatie wordt gebruikt. Lees dit stapeloverloopbericht voor meer informatie.

Merk op dat onSaveInstanceState en onRestoreInstanceState niet gegarandeerd samen worden gebeld. Android roept onSaveInstanceState() wanneer de kans bestaat dat de activiteit wordt vernietigd. Er zijn echter gevallen waarin onSaveInstanceState wordt aangeroepen maar de activiteit niet wordt vernietigd en als gevolg hiervan op onRestoreInstanceState niet wordt aangeroepen.

Fragmentstatus opslaan en herstellen

Fragmenten hebben ook een methode onSaveInstanceState() die wordt aangeroepen wanneer hun status moet worden opgeslagen:

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

Vervolgens kunnen we gegevens uit deze opgeslagen status halen in 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;
   }
}

Om de fragmentstatus goed te kunnen opslaan, moeten we er zeker van zijn dat we het fragment niet onnodig opnieuw maken bij configuratiewijzigingen. Dit betekent dat je ervoor moet zorgen dat je bestaande fragmenten niet opnieuw initialiseert wanneer ze al bestaan. Fragmenten die in een activiteit worden geïnitialiseerd, moeten na een configuratiewijziging per tag worden opgezocht:

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

Dit vereist dat we ervoor zorgen dat we een tag opnemen om op te zoeken wanneer we een fragment in de activiteit in een transactie plaatsen:

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

Met dit eenvoudige patroon kunnen we fragmenten correct hergebruiken en hun status herstellen via configuratiewijzigingen.

Fragmenten behouden

In veel gevallen kunnen we problemen voorkomen wanneer een activiteit opnieuw wordt gemaakt door eenvoudigweg fragmenten te gebruiken. Als uw weergaven en status zich binnen een fragment bevinden, kunnen we het fragment gemakkelijk behouden wanneer de activiteit opnieuw wordt gemaakt:

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

Deze aanpak voorkomt dat het fragment wordt vernietigd tijdens de activiteitenlevenscyclus. Ze worden in plaats daarvan bewaard in de Fragment Manager. Raadpleeg de officiële Android-documenten voor meer informatie .

Nu kunt u controleren of het fragment al bestaat per tag voordat u er een maakt en het fragment behoudt zijn status bij configuratiewijzigingen. Raadpleeg de handleiding Veranderingen in runtime-wijzigingen voor meer informatie .

Vergrendelschermstand

Als u de schermoriëntatie van elk scherm (activiteit) van uw Android-applicatie wilt vergrendelen, moet u gewoon de eigenschap android:screenOrientation van een <activity> in AndroidManifest.xml :

<activity
    android:name="com.techblogon.screenorientationexample.MainActivity"
    android:screenOrientation="portrait"
    android:label="@string/app_name" >
    <!-- ... -->
</activity>

Nu moet die activiteit altijd in de portretmodus worden weergegeven.

Configuratiewijzigingen handmatig beheren

Als uw toepassing geen bronnen hoeft bij te werken tijdens een specifieke configuratiewijziging en u een prestatiebeperking heeft die vereist dat u het opnieuw opstarten van de activiteit voorkomt, dan kunt u verklaren dat uw activiteit de configuratiewijziging zelf afhandelt, wat voorkomt dat het systeem uw werkzaamheid.

Deze techniek moet echter worden beschouwd als een laatste redmiddel wanneer u opnieuw opstarten moet voorkomen vanwege een configuratiewijziging en wordt niet aanbevolen voor de meeste toepassingen. Om deze aanpak te volgen, moeten we het knooppunt android:configChanges aan de activiteit in AndroidManifest.xml :

<activity android:name=".MyActivity"
          android:configChanges="orientation|screenSize|keyboardHidden"
          android:label="@string/app_name">

Wanneer een van deze configuraties verandert, wordt de activiteit niet opnieuw onConfigurationChanged() maar wordt in plaats daarvan een oproep ontvangen naar 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();
    }
}

Zie de Documenten afhandelen . Zie de documentatie van android: configChanges en de klasse Configuration voor meer informatie over welke configuratiewijzigingen u kunt verwerken in uw activiteit.

AsyncTask gebruiken

Probleem:

  • Als nadat de AsyncTask gestart, er een schermrotatie is, wordt de eigendomsactiviteit vernietigd en opnieuw gemaakt.
  • Wanneer de AsyncTask voltooid, wil deze de gebruikersinterface bijwerken die mogelijk niet meer geldig is.

Oplossing:

Met behulp van laders kan men gemakkelijk de vernietiging / recreatie van activiteiten overwinnen.

Voorbeeld:

Hoofdactiviteit:

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

Notitie:

Het is belangrijk om de v4-compatibiliteitsbibliotheek te gebruiken of niet, maar gebruik geen deel van het ene en een deel van het andere, omdat dit tot compilatiefouten leidt. Om dit te controleren, kunt u kijken naar de invoer voor android.support.v4.content en android.content (u zou niet beide moeten hebben).

Vergrendel de rotatie van het scherm programmatisch

Het is heel gebruikelijk dat het tijdens de ontwikkeling erg handig kan zijn om het apparaatscherm tijdens specifieke delen van de code te vergrendelen / ontgrendelen .

Terwijl een dialoogvenster met informatie wordt weergegeven, wil de ontwikkelaar bijvoorbeeld de rotatie van het scherm vergrendelen om te voorkomen dat het dialoogvenster wordt gesloten en de huidige activiteit opnieuw wordt opgebouwd om het opnieuw te ontgrendelen wanneer het dialoogvenster wordt gesloten.

Hoewel we rotatie-vergrendeling van het manifest kunnen bereiken door te doen:

<activity
    android:name=".TheActivity"
    android:screenOrientation="portrait"
    android:label="@string/app_name" >
</activity>

Je kunt het ook programmatisch doen door het volgende te doen:

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

En dan het volgende aanroepen om respectievelijk de apparaatrotatie te vergrendelen en ontgrendelen

lockDeviceRotation(true)

en

lockDeviceRotation(false) 


Modified text is an extract of the original Stack Overflow Documentation
Licentie onder CC BY-SA 3.0
Niet aangesloten bij Stack Overflow