Просмотр видимости потери состояния при возобновлении активности с ранее запущенным Переход активности

Объяснение:

  • Я начинаю операцию В с переходом активности из действия А.

  • После запуска нового действия B я изменяю состояния видимости некоторых видов (View.GONE) в B.

Проблема заключается в следующем:

При запуске нового действия C и возвращении к активности B (или принудительной onPause в B), представления с измененными состояниями видимости появляются снова, без каких-либо прикосновений к представлениям по коду или другим.

Следующее видео объясняет проблему на снимках: https://youtu.be/oqCZo5CSkQk

При отсутствии перехода все работает так, как ожидалось. У кого-нибудь есть идея, как предотвратить потерю зрения представления при возобновлении Activity? Я неправильно использую ActivityOptionsCompat?

Я использую библиотеки поддержки:

'com.android.support:support-v4:27.1.1' и 'com.android.support:appcompat-v7:27.1.1'

Но проблема также возникает для более старых версий и для разных производителей телефонов (Pixel, Samsung и т.д.).

Вот код для воспроизведения проблем:

Макеты

Деятельность A:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center_horizontal"
    android:orientation="vertical">

  <TextView
      style="@style/TextAppearance.AppCompat.Title"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:layout_margin="24dp"
      android:gravity="center"
      android:text="Activity A | this starts the transition to another activity"/>

  <android.support.v7.widget.AppCompatImageView
      android:id="@+id/imageToAnimate"
      android:layout_width="20dp"
      android:layout_height="20dp"
      app:srcCompat="@android:drawable/star_big_on"/>

  <Button
      android:id="@+id/start_next_activity"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:layout_marginTop="30dp"
      android:text="start Another Activity"/>

</LinearLayout>

Активность B:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center_horizontal"
    android:orientation="vertical"
    app:layout_behavior="@string/appbar_scrolling_view_behavior">

  <TextView
      style="@style/TextAppearance.AppCompat.Title"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:layout_margin="24dp"
      android:gravity="center"
      android:text="Activity B | with progressbar"/>

  <android.support.v7.widget.AppCompatImageView
      android:id="@+id/imageToAnimate"
      android:layout_width="100dp"
      android:layout_height="100dp"
      android:transitionName="toAnimate"
      app:srcCompat="@android:drawable/star_big_on"/>

  <ProgressBar
      android:id="@+id/progress"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:layout_marginTop="24dp"
      android:visibility="gone"/>

  <TextView
      android:id="@+id/dismiss_text"
      style="@style/TextAppearance.AppCompat.Subhead"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:layout_marginBottom="24dp"
      android:text="Also a text to dismiss"/>

  <Button
      android:id="@+id/show"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:text="SHOW"/>

  <Button
      android:id="@+id/hide_gone"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:text="SET GONE"/>

  <Button
      android:id="@+id/hide_invisible"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:text="SET INVISIBLE"/>

  <Button
      android:id="@+id/start_activity_c"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:text="START activity"/>


</LinearLayout>

Деятельность C:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    android:orientation="vertical">

  <TextView
      style="@style/TextAppearance.AppCompat.Title"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:text="Activity C"
      android:textSize="40sp"/>

</LinearLayout>

Исходный код операции

Деятельность A:

public class DebugActivityA extends AppCompatActivity {

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_a);
        findViewById(R.id.start_next_activity).setOnClickListener(v -> startWithTransition());
    }

    private void startWithTransition() {
        ActivityOptionsCompat options = ActivityOptionsCompat
                .makeSceneTransitionAnimation(DebugActivityA.this,
                                              findViewById(R.id.imageToAnimate),
                                              "toAnimate");
        startActivity(new Intent(DebugActivityA.this, DebugActivityB.class), options.toBundle());
    }

}

Активность B:

public class DebugActivityB extends AppCompatActivity {

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_b);

        View progressbar = findViewById(R.id.progress);
        View dismissText = findViewById(R.id.dismiss_text);
        progressbar.setVisibility(View.VISIBLE);
        findViewById(R.id.show).setOnClickListener(v -> {
            progressbar.setVisibility(View.VISIBLE);
            dismissText.setVisibility(View.VISIBLE);
        });
        findViewById(R.id.hide_gone).setOnClickListener(v -> {
            progressbar.setVisibility(View.GONE);
            dismissText.setVisibility(View.GONE);
        });
        findViewById(R.id.hide_invisible).setOnClickListener(v -> {
            progressbar.setVisibility(View.INVISIBLE);
            dismissText.setVisibility(View.INVISIBLE);
        });
        findViewById(R.id.start_activity_c).setOnClickListener(this::startOtherActivity);
    }

    private void startOtherActivity(View view) {
        startActivity(new Intent(this, DebugActivityC.class));
    }

}

Деятельность C:

public class DebugActivityC extends AppCompatActivity {

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_c);
    }

}

Ответы

Ответ 1

Вы можете использовать метод onSaveInstanceState для сохранения состояния пользовательского интерфейса при выходе из него, а затем использовать onRestoreInstanceState чтобы восстановить его обратно в это состояние. Добавьте onSaveInstanceState в действие B:

@Override
public void onSaveInstanceState(Bundle savedInstanceState) {
  super.onSaveInstanceState(savedInstanceState);
  // Save UI state changes to the savedInstanceState.
  // This bundle will be passed to onCreate if the process is
  // killed and restarted.
  savedInstanceState.putInt("progressbarVisibility", progressbar.getVisibility());
  savedInstanceState.putInt("dismissTextVisibility", dismissText.getVisibility());
}

Затем добавьте модификацию метода onCreate B:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_multi_play);

    View progressbar = findViewById(R.id.progress);
    View dismissText = findViewById(R.id.dismiss_text);
    if (savedInstanceState != null){
        dismissText.setVisibility(savedInstanceState.getInt("dismissTextVisibility", View.VISIBLE));
        progressbar.setVisibility(savedInstanceState.getInt("progressbarVisibility", View.VISIBLE)); 
    }
    // The rest of your code.
}

Ответ 2

Для этого может быть создана работа.

Вместо того, чтобы изменять видимость просмотров в onCreate, который вызывается только при создании Activity, попробуйте манипулировать видимостью представлений в onResume на основе флагов в самой Activity B

Используйте SharedPreference или даже на основе простых логических флагов

Теперь, когда Activity B вернется к видимости, одно и то же состояние будет повторно применено на основе самих этих флагов из onResume.

Если вы используете SharedPreference, обновите новое значение, нажав новую Activity C

В onResume проверьте значение и измените целевые представления. Очистить флаг, как только операция Activity B будет удалена из backstack ie (onDestroy of Activity B)

Ответ 3

Это может быть или не быть проблемой с общей передачей, я придумал подход ниже, чтобы исправить проблему видимости. Почти провел день!

Позвольте мне поделиться своим наблюдением здесь.

Такая проблема не будет существовать, если вы измените состояние видимости общих просмотров перехода.

Если у вас есть такое требование, когда вы хотите изменить видимость некоторых представлений при использовании совместного перехода, сделайте их как общий вид.

ViewCompat.setTransitionName(<view>, <uniqueString>);

Применяя измененные файлы, я проверял и решает нашу проблему.

ActivityA

public class ActivityA extends AppCompatActivity {

    private View startNextActivity;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_a);
        startNextActivity = findViewById(R.id.start_next_activity);
        startNextActivity.setOnClickListener(v -> startWithTransition());
    }

    private void startWithTransition() {
        ActivityOptionsCompat options = ActivityOptionsCompat
                .makeSceneTransitionAnimation(this,
                        new Pair<View, String>(startNextActivity, ActivityB.VIEW_NAME_IMAGEVIEW)
                        new Pair<View, String>(startNextActivity, ActivityB.VIEW_NAME_PROGRESSBAR),
                        new Pair<View, String>(startNextActivity, ActivityB.VIEW_NAME_DETAIL_TEXTVIEW));
        startActivity(new Intent(ActivityA.this, ActivityB.class), options.toBundle());
    }

}

ActivityB

public class ActivityB extends AppCompatActivity {

    public static final String VIEW_NAME_PROGRESSBAR = "progressbar";
    public static final String VIEW_NAME_IMAGEVIEW = "toAnimate";
    public static final String VIEW_NAME_DETAIL_TEXTVIEW = "detailTextView";

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_b);

        View progressbar = findViewById(R.id.progress);
        View dismissText = findViewById(R.id.dismiss_text);
        View animateView = findViewById(R.id.imageToAnimate);

        // Key lines to fix our issue
        ViewCompat.setTransitionName(animateView, VIEW_NAME_IMAGEVIEW);
        ViewCompat.setTransitionName(progressbar, VIEW_NAME_PROGRESSBAR);
        ViewCompat.setTransitionName(dismissText, VIEW_NAME_DETAIL_TEXTVIEW);

        progressbar.setVisibility(View.VISIBLE);
        findViewById(R.id.show).setOnClickListener(v -> {
            progressbar.setVisibility(View.VISIBLE);
            dismissText.setVisibility(View.VISIBLE);
        });
        findViewById(R.id.hide_gone).setOnClickListener(v -> {
            progressbar.setVisibility(View.GONE);
            dismissText.setVisibility(View.GONE);
        });
        findViewById(R.id.hide_invisible).setOnClickListener(v -> {
            progressbar.setVisibility(View.INVISIBLE);
            dismissText.setVisibility(View.INVISIBLE);
        });
        findViewById(R.id.start_activity_c).setOnClickListener(this::startOtherActivity);
    }

    private void startOtherActivity(View view) {
        startActivity(new Intent(this, ActivityC.class));
    }

}

Надеюсь, это может помочь вам как-то.

Хорошего дня !!

Ответ 4

Да. Теперь вы можете использовать onSaveInstanceState и onRestoreInstanceState.

Вы можете сохранить состояние visblity в состоянии onSaveInstanceState и восстановить onRestoreInstanceState. Активность всегда вызывает onSaveInstanceState & onRestoreInstanceState, которые работают отлично.

Счастливое кодирование !!!

Ответ 5

Когда вы запускаете операцию C и возвращаете, XML активности B перерисовывается, поэтому используются значения по умолчанию VIEW.Visible. Затем просмотры снова появляются (появляются).

Вам нужно как-то сохранить состояние представления. Пытаться:

  • savedInstanceState или
  • SharedPreferences