在允许用户通过社交网络登录的android应用程序中,我使用以下代码显示并隐藏aFAB
:
public abstract class LoginFragment extends Fragment {
private FloatingActionButton mFab;
private Animation mShowFab;
private Animation mHideFab;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mShowFab = AnimationUtils.makeInAnimation(getContext(), false);
mShowFab.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
mFab.setVisibility(View.VISIBLE);
}
@Override
public void onAnimationEnd(Animation animation) {
}
@Override
public void onAnimationRepeat(Animation animation) {
}
});
mHideFab = AnimationUtils.makeOutAnimation(getContext(), true);
mHideFab.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
}
@Override
public void onAnimationEnd(Animation animation) {
mFab.setVisibility(View.INVISIBLE);
}
@Override
public void onAnimationRepeat(Animation animation) {
}
});
}
private void showFab(boolean show) {
boolean visible = mFab.isShown();
if (show && !visible) {
mFab.startAnimation(mShowFab);
} else if (!show && visible) {
mFab.startAnimation(mHideFab);
}
}
当我调用上面的
showFab
方法足够慢时,这很好。在开始任何动画之前,我检查当前
FloatingActionButton
可见性,以便动画只播放一次-即使我连续多次调用showFab(true)
。我的问题:
当我的应用程序中显示a
LoginFragment
时,我首先向aServiceIntent
发送请求以从sqlite获取用户数据,并调用以下方法将我的ui设置为“等待”状态:private void setBusy(boolean busy) {
mProgressBar.setVisibility(busy ? View.VISIBLE : View.INVISIBLE);
showFab(!busy);
}
几乎立即,sqlite的响应返回-通过
LocalBroadcastManager
并再次调用上面的方法:setBusy(false)
。然后发生错误,
FAB
不可见。如果我用无动画代码替换
FAB
方法,一切正常:private void showFab(boolean show) {
mFab.setVisibility(show ? View.VISIBLE : View.INVISIBLE);
}
但有了动画-赛车的情况似乎发生了。
作为解决方法,我尝试取消两个动画-但这无助于:
private void showFab(boolean show) {
mShowFab.cancel();
mShowFab.reset();
mHideFab.cancel();
mHideFab.reset();
boolean visible = mFab.isShown();
if (show && !visible) {
mFab.startAnimation(mShowFab);
} else if (!show && visible) {
mFab.startAnimation(mHideFab);
}
}
请建议在这里可以做些什么。
我已经在调试器中多次使用我的应用程序。当显示片段时,
setBusy
(和showFab
)只调用两次,但两次调用都发生得非常快,FAB
没有显示-第一次运行:
第二轮:
更新:
不幸的是,使方法
synchronized
也没有帮助-FAB
保持隐藏:private synchronized void showFab(boolean show) {
mShowFab.cancel();
mShowFab.reset();
mHideFab.cancel();
mHideFab.reset();
boolean visible = mFab.isShown();
if (show && !visible) {
mFab.startAnimation(mShowFab);
} else if (!show && visible) {
mFab.startAnimation(mHideFab);
}
}
最佳答案
每个动画都在不同的线程中运行。正如你所说,这会导致一种种族状况。
下面是发生的事情:
showfab是用true,然后用false触发的。
mshowfab onanimationstart方法执行并将fab设置为可见。
mhidefab onanimationstart方法执行而不执行任何操作。
mshowfab onanimationend方法执行而不执行任何操作。
mhidefab onanimationend方法执行并将fab设置为不可见。
最后你会发现一个不可见的晶圆厂应该是可见的。
第二次运行中的变量显示mshowfab动画永远不会运行。
您应该能够通过监听隐藏动画的结尾来解决竞赛条件。像这样的:
private void showFab(boolean show) {
if (show) {
// if you have an animation currently running and you want to show the fab
if (mFab.getAnimation() != null && !mFab.getAnimation().hasEnded()) {
// then wait for it to complete and begin the next one
mFab.getAnimation().setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
}
@Override
public void onAnimationEnd(Animation animation) {
mFab.setVisibility(View.INVISIBLE);
mFab.startAnimation(mShowFab);
}
@Override
public void onAnimationRepeat(Animation animation) {
}
});
} else {
mFab.startAnimation(mShowFab);
}
} else {
mFab.startAnimation(mHideFab);
}
}