Sök…


Anmärkningar

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

Spara och återställa aktivitetstillstånd

När din aktivitet börjar stoppa, anropar onSaveInstanceState() så att din aktivitet kan spara tillståndsinformation med en samling nyckelvärdespar. Standardimplementeringen av den här metoden sparar automatiskt information om tillståndet i aktivitetens visningshierarki, till exempel texten i en EditText widget eller rullningspositionen för en ListView .

För att spara ytterligare tillståndsinformation för din aktivitet måste du implementera onSaveInstanceState() och lägga till nyckelvärdenspar till Bundle-objektet. Till exempel:

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

Systemet kommer att kalla den metoden innan en aktivitet förstörs. Senare kommer systemet att ringa på onRestoreInstanceState där vi kan återställa tillstånd från paketet:

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

Instansläget kan också återställas i standardaktivitet # onCreate-metoden, men det är bekvämt att göra det i onRestoreInstanceState som säkerställer att alla initialiseringar har gjorts och gör att underklasser kan välja om standardimplementeringen ska användas. Läs detta stackoverflow-inlägg för mer information.

Observera att onSaveInstanceState och onRestoreInstanceState inte garanteras att de ska kallas samman. Android åberopar onSaveInstanceState() när det finns en chans att aktiviteten kan förstöras. Men det finns fall där onSaveInstanceState kallas men aktiviteten förstörs inte och som ett resultat onRestoreInstanceState inte åberopas.

Spara och återställa fragmentstillstånd

Fragment har också en onSaveInstanceState() -metod som kallas när deras tillstånd behöver sparas:

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

Då kan vi dra ut data från det sparade tillståndet i 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;
   }
}

För att fragmentstillståndet ska sparas ordentligt måste vi vara säkra på att vi inte onödigt återskapar fragmentet vid konfigurationsändringar. Detta innebär att man är försiktig så att man inte initialiserar befintliga fragment när de redan finns. Alla fragment som initialiseras i en aktivitet måste letas upp efter tagg efter en konfigurationsändring:

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

Detta kräver att vi är noga med att inkludera en tagg för uppslagning när vi lägger ett fragment i aktiviteten inom en transaktion:

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

Med detta enkla mönster kan vi korrekt använda fragment och återställa deras tillstånd genom konfigurationsändringar.

Bevara fragment

I många fall kan vi undvika problem när en aktivitet skapas igen genom att helt enkelt använda fragment. Om dina åsikter och tillstånd ligger inom ett fragment kan vi enkelt låta fragmentet behållas när aktiviteten skapas om:

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

Denna strategi hindrar fragmentet från att förstöras under aktivitetslivscykeln. De hålls istället kvar i Fragment Manager. Se de officiella Android-dokumenten för mer information .

Nu kan du kontrollera om fragmentet redan finns med taggen innan du skapar ett och fragmentet behåller dess tillstånd över konfigurationsändringar. Se Hantering Runtime Förändringar guide för mer information .

Låsning av skärmorientering

Om du vill låsa skärmorienteringsändringen för någon skärm (aktivitet) i din Android-applikation behöver du bara ställa in android:screenOrientation egenskapen för en <activity> i AndroidManifest.xml :

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

Nu tvingas den aktiviteten att alltid visas i " stående " -läge.

Hantera konfigurationsändringar manuellt

Om din applikation inte behöver uppdatera resurser under en specifik konfigurationsändring och du har en prestandabegränsning som kräver att du undviker aktivitetsstart, kan du förklara att din aktivitet hanterar själva konfigurationsändringen, vilket hindrar systemet från att starta om din aktivitet.

Denna teknik bör dock betraktas som en sista utväg när du måste undvika omstart på grund av en konfigurationsändring och inte rekommenderas för de flesta applikationer. För att ta detta tillvägagångssätt måste vi lägga till android:configChanges noden till aktiviteten i AndroidManifest.xml :

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

När en av dessa konfigurationer ändras startas inte aktiviteten utan får istället ett samtal till 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();
    }
}

Se Hantera ändringsdokumenten . Mer information om vilka konfigurationsändringar du kan hantera i din aktivitet, se android: configChanges- dokumentationen och klassen Configuration .

Hantering av AsyncTask

Problem:

  • Om efter att AsyncTask startar finns en AsyncTask förstörs och återskapas ägaraktiviteten.
  • När AsyncTask vill den uppdatera användargränssnittet som kanske inte gäller längre.

Lösning:

Med hjälp av lastare kan man enkelt övervinna aktivitetens förstörelse / rekreation.

Exempel:

Huvudaktivitet:

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

Notera:

Det är viktigt att använda antingen v4-kompatibilitetsbiblioteket eller inte, men inte använda en del av det ena och det andra, eftersom det kommer att leda till kompilationsfel. För att kontrollera kan du titta på importen för android.support.v4.content och android.content (du borde inte ha båda).

Lås skärmens rotation programmatiskt

Det är mycket vanligt att man under utvecklingen kan hitta mycket användbart för att låsa / låsa upp skärmen under specifika delar av koden .

Till exempel, medan en dialog med information visar utvecklaren kanske vill låsa skärmens rotation för att förhindra att dialogrutan tas bort och den aktuella aktiviteten från att byggas om för att låsa upp den igen när dialogen avslutas.

Även om vi kan uppnå rotationslåsning från manifestet genom att göra:

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

Man kan göra det programmatiskt också genom att göra följande:

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

Och sedan ringa följande för att låsa respektive låsa upp enhetens rotation

lockDeviceRotation(true)

och

lockDeviceRotation(false) 


Modified text is an extract of the original Stack Overflow Documentation
Licensierat under CC BY-SA 3.0
Inte anslutet till Stack Overflow