2014-10-04 115 views
1

我正面临一个我无法解决的奇怪问题。事情是,我有一个活动,按下按钮后,我改变了一些布局的可见性。之后,我正在使用Handler以便在4秒后恢复这种情况,并将所有内容都放回原处。Handler.postDelayed and orientaton change issues

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

下面是相关代码

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

现在我提出的相关功能

//....... 

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

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

最奇怪的事情是,当onRestoreInstanceState被称为后代码为postDelayed已执行,mLogginIn显示以前的值(真),就好像它根本没有效果一样。

在此先感谢

回答

4

当您的Activity由于配置更改而重新创建时,它是一个完全不同的对象实例,具有另一个嵌入式视图层次结构。您的Handler对于旧的对象实例很严格,因此它也会修改旧的视图层次结构。因此你什么都看不到。

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

解决方案

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

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

  3. 当您重新创建活动时,请恢复时间戳并计算与当前时间的差异。使用与此延迟相同的逻辑发布新的Runnable(如果它是0或负数,您可能想立即运行可运行代替而不是发布它)。此Runnable现在对Activity的新实例很紧。

+0

谢谢!我明白这个问题。只是一个问题。通过保存可运行实例,你的意思是什么?正在释放onsaveInstanceState?或者只是在课堂上提供参考? – zozelfelfo 2014-10-04 13:43:45

+0

将其保存在参考中。您需要引用来在'onSaveInstanceState()'后面删除回调。 – 2014-10-04 14:27:21

+0

这个想法是时间戳引用充当一个标志:非负= Runnable发布,负=不发布Runnable。当Runnable运行时,它会清除标志(负数)。您可以使用此标志来安全地保存和恢复状态。 – 2014-10-04 14:33:01

1

当设备方向改变你的活动被破坏,新的创建,并通过savedInstanceState束恢复状态。但是,您使用postDelayed发布的runnable是与原始活动绑定的匿名内部类。这个活动对象仍然在,你的runnable会修改它,但它不再可见。

您当前的体系结构不起作用,您必须选择另一个来实现您想要的结果。