标签: android-lifecycle

使用FragmentTransaction.replace()时Android片段视图状态丢失

我有一个很大的问题,我不太了解发生了什么.我正在开发一个使用Fragments(来自支持库)的应用程序,并且正在使用FragmentTransaction.replace()将新片段放到后端堆栈上并替换旧堆栈.代码如下:

FragmentManager fm = getSupportFragmentManager();
FragmentTransaction ft = ft.beginTransaction();
// Animations in my res/anim folder
ft.setCustomAnimations(R.anim.slide_in_right, R.anim.slide_out_left, R.anim.slide_in_left, R.anim.slide_out_right);
ft.replace(R.id.fragment_container, newFragment, tag);
ft.addToBackStack(null);
ft.commit();
Run Code Online (Sandbox Code Playgroud)

这成功地取代了我的片段.我的问题如下.在一个片段中,我有一个根据用户输入构建的项目列表.现在,当用户单击下一步然后单击后退按钮(返回列表)时,列表为空,因为视图已被销毁.现在,我注意到以下内容:

  1. 不调用onSaveInstanceState.我相信这是因为只有当父Activity告诉它时才会调用它.基于以下文档:"在很多情况下,片段可能会被大部分拆除(例如放置在没有显示UI的后台堆栈上),但是在其拥有的活动实际需要保存其状态之前不会保存其状态".显然,在FragmentTransaction上执行替换不是其中之一.有没有人对此有确认或更好的解释?
  2. setOnRetainInstanceState(true)在这种情况下没有帮助.同样,我认为这与文档中的信息有关:"控制是否在活动重新创建(例如从配置更改)中保留片段实例".我没有在重新创建活动时执行任何操作,所以这没用.

所以,我想我的主要问题是:有没有办法在使用时保留View状态(只是保留Fragment)replace?有FragmentTransaction.add(),但也存在一些问题.一个是没有执行退出动画,因此动画不正确.另一个是旧片段(即处于不可见状态的片段)仍然是可点击的新片段.例如,如果我有一个ListFragment,并且我使用add将内容片段放在其上,我仍然可以单击ListFragment中的列表项.

android android-lifecycle android-fragments android-fragmentactivity

10
推荐指数
1
解决办法
3015
查看次数

锁定屏幕后调用Android onCreate

当我的应用程序在"顶部"运行时锁定屏幕时,系统几乎立即调用onCreate(屏幕仍为黑色).这种破坏性行为可能是什么原因?

lifecycle android locking oncreate android-lifecycle

10
推荐指数
2
解决办法
2693
查看次数

使用"向上"按钮在Android中恢复状态

onSaveInstanceState()用来存储ArrayList成员变量并onCreate()在主要活动的方法中恢复它.这适用于大多数情况,例如旋转屏幕等但如果我打开一个新活动并使用"向上"按钮(而不是后退按钮)导航回主屏幕,它似乎创建一个新的主要活动而不通过国家捆绑onCreate().

我已经确认当按下向上按钮时,onDestroy()为主活动的原始实例调用该方法,这对我来说没有意义,因为我希望它恢复现有活动,就像我按下后退按钮而不是创建一个新一.

有没有办法可以强制新活动恢复旧活动或只恢复现有活动?

android android-lifecycle android-activity

10
推荐指数
1
解决办法
1558
查看次数

是否总是调用onActivityCreated?

查看https://github.com/xxv/android-lifecycle上的优秀图表,它表示在片段重启时不会调用onActivityCreated().

我对此表示怀疑:

  • 真的吗?有人可以提供一些链接来做解释生命周期行为的文档吗?
  • 究竟什么是Fragment restart()?
  • Android可以决定删除不可见的片段,但是保留那些包含它们的活动吗?

注1:我已经测试过,由于活动重新创建而添加了Fragment时调用了onActivityCreated,并且在活动完全启动和激活后手动添加片段时也是如此.

注2:我正在使用23.3.0支持版本进行测试.某些行为是否有可能从以前的版本发生变化?

android android-lifecycle android-fragments

10
推荐指数
1
解决办法
3229
查看次数

活动开始时的动画跳跃

我正在为我的Android应用设置动画自定义视图.我已经通过Property Animations完成了这项工作,并根据https://developer.android.com/guide/topics/graphics/prop-animation.html调用invalidate()onAnimationUpdate()回调中的View :

根据您动画的属性或对象,您可能需要在视图上调用invalidate()方法以强制屏幕使用更新的动画值重绘自身.您可以在onAnimationUpdate()回调中执行此操作.

我的问题是,当这些动画在新启动的 Activity 的开头运行时,它们会在开头跳过帧,导致它们非常明显地跳跃.我试过了两个:

  1. 立即从Activity的onCreate()方法开始动画
  2. OnGlobalLayout()使用Activity的根视图的ViewTreeObserver在回调时启动动画.

我做了后者因为我认为可能在布局完成之前调用了动画,但结果是一样的.

使用日志,我确定在onAnimationUpdate()整个动画中一致地调用回调(即,从开始到结束每隔10-20毫秒左右).onAnimationUpdate()简单地调用invalidate(),这应该强制View重绘自己,理想情况下立即(但文档只声称这种情况发生在"未来的某个时刻").这似乎正是问题所在:onDraw()在一开始只调用一次或两次,而不是被调用大约250 ms.在此之后,它每10-20毫秒恢复一次,因为它应该有整个时间.但是这段时间会导致动画中出现非常明显的延迟.

要清楚,此问题仅发生在活动的开头.如果我在开始动画之前只设置了300毫秒的延迟,它就会一直平稳运行.但我不喜欢这个解决方案,因为它很笨拙.似乎问题是在活动开始附近onDraw()没有立即调用invalidate().但是,我无法弄清楚为什么会这样,阻塞什么onDraw(),或者如何解决它.

我发现只有这个StackOverFlow线程:活动开始时的动画会跳过海报有相同问题的.基本代码就在那里,视频可以清楚地解决问题.我也可以发布我的代码,但我认为问题出现在最基本的测试应用程序中的事实表明还有其他事情正在发生.

animation android android-animation android-layout android-lifecycle

10
推荐指数
1
解决办法
777
查看次数

Android视图 - onAttachedToWindow和onDetachedFromWindow - 它们何时在活动生命周期中调用?

我相信onAttachedToWindow在调用onCreate时onAttachedToWindow()被调用.那么我可以假设在活动生命周期中,当活动被销毁时调用onDetachedFromWindow?我的问题是如何将这两个回调钩子绑定到活动生命周期?

我可以说onAttachedToWindow绑定到onCreate而onDetachedFromWindow绑定到onDestroy吗?

android android-lifecycle

10
推荐指数
2
解决办法
9910
查看次数

Android:ViewModel.无法调用观察者方法

我正在使用新的拱门.来自谷歌的组件.

我有活动登录/注册管理片段,感谢 FragmentTransaction

Activity->RegisterFragment (with ViewPager) -> RegistrationSteps (adapter)

在RegisterFragment里面我有ViewPager.我希望里面的所有页面ViewPager都使用相同的ViewModel.

这些都是注册步骤(RegistrationStepFragment),其采用母公司RegistrationFragment LifecycleOwner该范围的视图模型到它-我只是想视图模型先限定这个父片段.

RegistrationFragment.class来自

public interface FragmentViewPagerListener<T extends LifecycleFragment> {
    void nextPage();
    T getLifecycleFragment();
}
Run Code Online (Sandbox Code Playgroud)

RegistartionSteps(页面)来自

public abstract class RegisterStepFragment extends LifecycleFragment {
    protected FragmentViewPagerListener mListener;
    protected RegisterViewModel mViewModel;

    public void setListener(FragmentViewPagerListener fragmentViewPagerListener) {
        this.mListener = fragmentViewPagerListener;
    }

    protected abstract void observeViewModel();

    @Override
    public void onCreated(@Nullable Bundle savedInstanceState) {
        super.onCreated(savedInstanceState);
        mViewModel = ViewModelProviders.of(mListener.getLifecycleFragment()).get(RegisterViewModel.class);
        observeViewModel();
    }

    protected abstract boolean validateData();
}
Run Code Online (Sandbox Code Playgroud)

一切顺利,直到我达到3页,我想向后移动(到第二页)然后抛出异常mViewPager.setCurrentItem(1) …

android android-lifecycle android-fragments android-viewmodel

10
推荐指数
0
解决办法
5107
查看次数

Android实时数据 - 观察配置更改后始终触发

我目前正在重构我的代码,将ViewModel包含在android.arch库提供的LiveData中.我有一个简单的活动,可以将密码更改请求发送到服务器,并根据HTTP响应代码执行操作.

为此,我创建了一个类,它扩展了ViewModel的数据和一个存储库类来调用服务器.我的ViewModel类有一个MutableLiveData字段,我使用.observe(...)方法从我的活动订阅.问题是.observe(...)中的代码在配置更改(即屏幕旋转)后一直触发,我不明白为什么.

以下是ViewModel,Repository和Activity类的代码:

ChangePasswordViewModel

public class ChangePasswordViewModel extends ViewModel{

    private MutableLiveData<Integer> responseCode;
    private PasswordChangeRepository passwordChangeRepository;

    public ChangePasswordViewModel() {
        responseCode = new MutableLiveData<>();
        passwordChangeRepository = new PasswordChangeRepositoryImpl();
    }

    public MutableLiveData<Integer> responseCodeLiveData() {
        return responseCode;
    }

    public void sendChangePasswordRequest(String newPassword){
        passwordChangeRepository.changePassword(newPassword,     passChangeCallback());
    }

    // Callback that fires after server sends a response
    private Callback passChangeCallback(){
        ...
        responseCode.postValue(serverResponse)
        ...
}
Run Code Online (Sandbox Code Playgroud)

PasswordChangeRepository

public class PasswordChangeRepositoryImpl {

    public void changePassword(String newPassword, Callback<Void> callback){
        //Sending new password to server and processing response in callback
        ServerCalls.changePassword(newPassword, callback); …
Run Code Online (Sandbox Code Playgroud)

android android-lifecycle android-livedata

10
推荐指数
1
解决办法
3563
查看次数

如何在片段打开的自定义对话框中保留监听器?

我遇到了一些障碍.我有一个非常类似于下面描述的场景:DialogFragment - 在屏幕旋转后保留监听器

建议的解决方案适用于作者,因为他的对话框是从活动中调用的.我的情况完全相同,但我的自定义对话框是从片段而不是活动调用的.(IE Activity-> Fragment-> Dialog)

我实现了相同的解决方案(在调用Fragment中设置onResume中的监听器)但在这种情况下它不起作用.

似乎正在发生的事情是,当屏幕旋转时,Android会杀死Dialog和Fragment.然后按顺序重新创建它们.因此,当我的自定义对话框上调用onCreateDialog时,包含的片段尚未重新创建,因此它为侦听器设置为正和负按钮时为null.

有没有人知道这方面的方法?

如果有人认为有必要,我可以发布代码,但它与链接线程上的代码几乎相同.

更新代码:

public class RecipeDetailEditFragment extends SherlockFragment implements DialogInterface.OnClickListener {
    private EditStepFragmentDialog stepDialog;
    private Recipe newRecipe; //main data object implements parcelable
    ...
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ...
        stepDialog = EditStepFragmentDialog.newInstance(newRecipe);
        //I've also tried passing 'this' into the newInstance constructor and 
        //setting the listener there, but that doesn't work either
    }

    public void onResume() {
        stepDialog.setListener(this);
        super.onResume();
    }
    ...
}


public class EditStepFragmentDialog extends DialogFragment {
    private DialogInterface.OnClickListener …
Run Code Online (Sandbox Code Playgroud)

android android-lifecycle android-fragments android-dialogfragment

9
推荐指数
1
解决办法
2792
查看次数

savedInstanceState vs getIntent().getExtras()

我遇到了两种不同的类型,可以根据一些参数来运行我的活动.第一个是savedInstanceState,另一个是getIntent.getExtras()

Q1)所以我不明白的是,一旦我将bundle传递给我的活动然后启动它,它应该有捆绑.但是,如果由于某种原因再次重新创建活动,它应该重新拥有相同的包.(我对吗?)

Q2)基于Q1是真的事实,以及我不能只在活动已经开始时覆盖捆绑的事实,我想如果由于某种原因在我已经开始的Activity中,我想要改变一些params捆绑,我应该创建一些活动字段,并在我的活动生活中使用这些字段.如果由于某种原因重新创建我的活动,则覆盖saveInstanseState以保存新字段.这是真的吗?

Q3)基于以上事实都是正确的事实,在onCreate()中,Android世界中的每个活动都需要像这样开始:

if (savedInstanceState != null) {
    mType = savedInstanceState.getInt("some_val1");
    mCardId = savedInstanceState.getLong("some_val2");
    mQuery =  savedInstanceState.getString("some_val3");
    mCategory = savedInstanceState.getLong("some_val4");;
} else {
    mType = getIntent().getExtras().getInt("some_val1");
    mCardId  = getIntent().getExtras().getLong("some_val2");
    mQuery = getIntent().getExtras().getString("some_val3");
    mCategory = getIntent().getExtras().getString("some_val4");
}
Run Code Online (Sandbox Code Playgroud)

Q4)假设onSaveInstanceState被调用并且保存的值与启动活动的原始包(getIntent.getExtras)不同,如果再次重新创建活动,这是否意味着saveInstanceState与getIntent.getExtras()或它们不同现在一样吗?(如果它们是相同的,那么上面代码中的if/else没有真正含义,因为它是相同的!).

Q5)如果我没有覆盖onSaveInstanceState但是当我创建活动时我将它传递给Bundle,这是否意味着如果再次重新创建活动,我可以获得原始包?(我想这个问题会根据其他答案回答)

android android-lifecycle android-activity

9
推荐指数
1
解决办法
3929
查看次数