Handler.postDelayed 和 Orientaton 更改问题

zoz*_*lfo 1 android handler

我面临着一个我无法解决的奇怪问题。问题是,我有一个活动,按下按钮后我更改了某些布局的可见性。之后,我使用 aHandler来在 4 秒后恢复该情况,并将所有内容恢复为之前的状态。

一切都按预期工作,除了当我更改设备方向时,如果我在此过程中更改设备方向,我的视图将不会恢复,我不确定问题出在哪里:S。

这是相关代码

private View mLoginFormView;
private View mLoginStatusView;
private boolean mLogginIn = false;


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

    super.onCreate(savedInstanceState);

    setContentView(R.layout.activity_login_layout);

    mLoginFormView = findViewById(R.id.login_form);
    mLoginStatusView = findViewById(R.id.login_status);

    if (savedInstanceState == null) {
        mLogginIn = false;


    } else {

        mLogginIn = savedInstanceState.getBoolean(getString(R.string.user_login_in),false);
        Log.d(TAG,"RESTORING MLOGIN IN = " + mLogginIn);
    }

    findViewById(R.id.sign_in_button).setOnClickListener(
            new View.OnClickListener() {
                @Override
                public void onClick(View view) {

                    attemptLogin();
                }
            });

    if(mLogginIn)
        showProgress(true);
}
Run Code Online (Sandbox Code Playgroud)

现在我介绍一下相关的功能

//.......

public void attemptLogin() {

    showProgress(true);
    mMenu.findItem(R.id.started).setVisible(false);

    Handler handler = new Handler();

    handler.postDelayed(new Runnable() {
        @Override
        public void run() {
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    showProgress(false);
                    Log.d(TAG,"MLOGGIN VALUE PROGRESS = " + mLogginIn);
                    mLogginIn = false;
                }
            });

        }
    },4000);
}
Run Code Online (Sandbox Code Playgroud)

ShowProgress()

private void showProgress(final boolean show) {
    mLogginIn = show;
    Log.d(TAG, "showProgress " + mLogginIn);

    int shortAnimTime = getResources().getInteger(
            android.R.integer.config_shortAnimTime);

    mLoginStatusView.setVisibility(View.VISIBLE);
    mLoginStatusView.animate().setDuration(shortAnimTime)
    .alpha(show ? 1 : 0).setListener(new AnimatorListenerAdapter() {
        @Override
        public void onAnimationEnd(Animator animation) {
            mLoginStatusView.setVisibility(show ? View.VISIBLE
                    : View.GONE);
        }
    });

    mLoginFormView.setVisibility(View.VISIBLE);
    mLoginFormView.animate().setDuration(shortAnimTime).alpha(show ? 0 : 1)
    .setListener(new AnimatorListenerAdapter() {
        @Override
        public void onAnimationEnd(Animator animation) {
            mLoginFormView.setVisibility(show ? View.GONE
                    : View.VISIBLE);
        }
    });
}
Run Code Online (Sandbox Code Playgroud)

最奇怪的是,当代码执行onRestoreInstanceState后调用时,显示了之前的值(true),就好像它根本没有效果一样。postDelayedmLogginIn

提前致谢

Gil*_*ach 5

当您Activity因配置更改而重新创建时,它是一个完全不同的对象实例,具有另一个嵌入的视图层次结构。您Handler与旧对象实例紧密相关,因此它也修改了旧视图层次结构。因此你什么也看不到。

不要这样做:它会泄漏内存并可能导致崩溃。

解决方案

  1. 当您发布 时Runnable,将Runnable实例和当前时间戳保存在两个引用中。如果Runnable运行正常,请将时间戳设置为-1(在Runnable代码内)。

  2. 如果onSaveInstanceState(Bundle)时间戳不同于 -1,则在配置更改中保留它,并使用 . 从处理程序中删除可运行的回调Handler.removeCallbacks(Runnable)

  3. 当您重新创建活动时,恢复时间戳并计算与当前时间的差异。发布一个Runnable具有相同逻辑的新延迟(如果它是 0 或负数,您可能希望立即运行可运行程序而不是发布它)。现在这Runnable与 的新实例紧密相关Activity