Поиск…


замечания

Ссылка: https://guides.codepath.com/android/Handling-Configuration-Changes#references

Сохранение и восстановление состояния активности

По мере того как ваше действие начинает останавливаться, система вызывает onSaveInstanceState() поэтому ваша активность может сохранять информацию о состоянии с помощью набора пар ключ-значение. По умолчанию реализация этого метода автоматически сохраняет информацию о состоянии иерархии представлений активности, такую ​​как текст в EditText или позиции прокрутки ListView .

Чтобы сохранить дополнительную информацию о состоянии вашей деятельности, вы должны реализовать onSaveInstanceState() и добавить пары ключ-значение в объект Bundle. Например:

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 где мы можем восстановить состояние из пакета:

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

Состояние экземпляра также можно восстановить в стандартном методе Activity # onCreate, но это удобно делать в onRestoreInstanceState который гарантирует, что вся инициализация выполнена, и позволяет подклассам решать, использовать ли реализацию по умолчанию. Подробнее читайте в этой статье stackoverflow .

Обратите внимание, что onSaveInstanceState и onRestoreInstanceState не могут быть вызваны вместе. Android вызывает onSaveInstanceState() когда есть вероятность, что активность может быть уничтожена. Однако бывают случаи, когда onSaveInstanceState но действие не уничтожается и в результате onRestoreInstanceState не вызывается.

Сохранение и восстановление состояния фрагмента

Фрагменты также имеют метод 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;
   }
}

Чтобы состояние фрагмента сохранялось должным образом, мы должны быть уверены, что мы не будем излишне воссоздавать фрагмент при изменении конфигурации. Это означает быть осторожным, чтобы не повторно инициализировать существующие фрагменты, когда они уже существуют. Любые фрагменты, которые инициализируются в Activity, должны быть просмотрены тегом после изменения конфигурации:

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 официальные документы для получения дополнительной информации .

Теперь вы можете проверить, не существует ли фрагмент уже тегом перед его созданием, а фрагмент сохранит его состояние при изменении конфигурации. См Handling выполнения Changes руководство для получения более подробной информации .

Фиксирование ориентации экрана

Если вы хотите заблокировать изменение ориентации экрана на любом экране (активности) вашего приложения для Android, вам просто нужно установить свойство android:screenOrientation для <activity> в AndroidManifest.xml :

<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() :

// 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: configChanges и классе Configuration .

Обработка AsyncTask

Проблема:

  • Если после AsyncTask происходит поворот экрана, активность владельца уничтожается и воссоздается.
  • Когда AsyncTask завершает работу, он хочет обновить пользовательский интерфейс, который больше недействителен.

Решение:

Используя Loaders , можно легко преодолеть разрушение / отдых.

Пример:

Основная деятельность:

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) 


Modified text is an extract of the original Stack Overflow Documentation
Лицензировано согласно CC BY-SA 3.0
Не связан с Stack Overflow