当在 setRetainInstance 设置为 true 的片段上调用 findFragmentByTag 时,不会返回相同的实例
When findFragmentByTag is called on a fragment with setRetainInstance set to true, the same instance is not returned
我有一个包含两个片段的 activity 应用程序:
- 包含所有UI的片段;
- 没有视图的片段,其成员为
AsyncTask
,并且 setRetainInstance
设置为 true。
目标是即使在 activity 被销毁后仍保留 AsyncTask 运行,并在应用程序恢复焦点时重用它。
我没有使用 setTargetFragment
,片段之间的所有通信都是通过 MainActivity
完成的。
我认为 setRetainInstance
所做的是防止片段被重新创建并保留完全相同的实例供我使用,因此当我调用 findFragmentByTag
重新创建已销毁的 activity 时,它应该 return 与创建时相同的保留实例,但情况似乎并非如此。
结果是我得到了一个在后台不断计数的 noUi 片段(我可以在调试器中看到这个混蛋),以及另一个没有引用我的 运行 异步任务...
我做错了什么?
这是一些代码:
public class MainActivity extends Activity
implements FragmentCounter.Callback, FragmentMainScreen.Callback {
private static final String TAG_MAINFRAGMENT = "TAG_MAINFRAGMENT";
private static final String TAG_COUNTERFRAGMENT = "TAG_COUNTERFRAGMENT";
private FragmentMainScreen mFragmentMain;
private FragmentCounter mFragmentCounter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (savedInstanceState == null) {
mFragmentMain = FragmentMainScreen.getInstance();
mFragmentCounter = FragmentCounter.getInstance();
getFragmentManager().beginTransaction()
.add(R.id.container, mFragmentMain, TAG_MAINFRAGMENT)
.add(mFragmentCounter, TAG_COUNTERFRAGMENT)
.commit();
} else {
mFragmentMain = (FragmentMainScreen) getFragmentManager()
.findFragmentByTag(TAG_MAINFRAGMENT);
//The fragment that gets returned here is not the same instance as the one
//I returned with getInstance() above.
mFragmentCounter = (FragmentCounter) getFragmentManager()
.findFragmentByTag(TAG_COUNTERFRAGMENT);
}
}
}
noGui 片段:
public class FragmentCounter extends Fragment
implements CounterAsyncTask.Callback, FragmentMainScreen.Callback {
private Callback mListener;
private CounterAsyncTask mCounterTask;
public static FragmentCounter getInstance(){
return new FragmentCounter();
}
public interface Callback {
public void onData(int aValue);
}
@Override
public void onAttach(Activity activity){
super.onAttach(activity);
if (activity instanceof Callback)
mListener = (Callback) activity;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return null;
}
@Override
public void onValueChanged(int value) {
//In the debugger, I can see this callback beeing called,
//even after my activity gets destroyed.
//The mListener is null since I set it that way in the onDetach to
//prevent memory leaks.
//The new activity has a different instance of this Fragment.
if (mListener != null)
mListener.onData(value);
}
@Override
public void startCounting(int from) {
mCounterTask = new CounterAsyncTask(this);
mCounterTask.execute(from);
}
@Override
public void onDetach() {
super.onDetach();
mListener = null;
}
}
异步任务:
public class CounterAsyncTask extends AsyncTask<Integer, Integer, Void>{
private int counter;
private Callback mListener;
private static final int SKIP = 5000;
public CounterAsyncTask(Callback listener) {
mListener = listener;
}
@Override
protected Void doInBackground(Integer...values) {
if (values != null)
counter = values[0];
while(!this.isCancelled()){
publishProgress(counter+=SKIP);
try{
Thread.sleep(SKIP);
}
catch(InterruptedException e){
e.printStackTrace();
}
}
return null;
}
@Override
protected void onProgressUpdate(Integer... values) {
mListener.onValueChanged(values[0]);
}
public interface Callback{
public void onValueChanged(int value);
}
}
提前致谢!
我的错误。使用 setRetainInstance 时,仅 在 配置 更改时保留片段。因此,片段状态将在屏幕旋转时保持,或者如果 activity 在后台但 而不是 如果 activity 被破坏。
为了达到我想要的结果,我可能应该使用服务。
我有一个包含两个片段的 activity 应用程序:
- 包含所有UI的片段;
- 没有视图的片段,其成员为
AsyncTask
,并且setRetainInstance
设置为 true。
目标是即使在 activity 被销毁后仍保留 AsyncTask 运行,并在应用程序恢复焦点时重用它。
我没有使用 setTargetFragment
,片段之间的所有通信都是通过 MainActivity
完成的。
我认为 setRetainInstance
所做的是防止片段被重新创建并保留完全相同的实例供我使用,因此当我调用 findFragmentByTag
重新创建已销毁的 activity 时,它应该 return 与创建时相同的保留实例,但情况似乎并非如此。
结果是我得到了一个在后台不断计数的 noUi 片段(我可以在调试器中看到这个混蛋),以及另一个没有引用我的 运行 异步任务...
我做错了什么?
这是一些代码:
public class MainActivity extends Activity
implements FragmentCounter.Callback, FragmentMainScreen.Callback {
private static final String TAG_MAINFRAGMENT = "TAG_MAINFRAGMENT";
private static final String TAG_COUNTERFRAGMENT = "TAG_COUNTERFRAGMENT";
private FragmentMainScreen mFragmentMain;
private FragmentCounter mFragmentCounter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (savedInstanceState == null) {
mFragmentMain = FragmentMainScreen.getInstance();
mFragmentCounter = FragmentCounter.getInstance();
getFragmentManager().beginTransaction()
.add(R.id.container, mFragmentMain, TAG_MAINFRAGMENT)
.add(mFragmentCounter, TAG_COUNTERFRAGMENT)
.commit();
} else {
mFragmentMain = (FragmentMainScreen) getFragmentManager()
.findFragmentByTag(TAG_MAINFRAGMENT);
//The fragment that gets returned here is not the same instance as the one
//I returned with getInstance() above.
mFragmentCounter = (FragmentCounter) getFragmentManager()
.findFragmentByTag(TAG_COUNTERFRAGMENT);
}
}
}
noGui 片段:
public class FragmentCounter extends Fragment
implements CounterAsyncTask.Callback, FragmentMainScreen.Callback {
private Callback mListener;
private CounterAsyncTask mCounterTask;
public static FragmentCounter getInstance(){
return new FragmentCounter();
}
public interface Callback {
public void onData(int aValue);
}
@Override
public void onAttach(Activity activity){
super.onAttach(activity);
if (activity instanceof Callback)
mListener = (Callback) activity;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return null;
}
@Override
public void onValueChanged(int value) {
//In the debugger, I can see this callback beeing called,
//even after my activity gets destroyed.
//The mListener is null since I set it that way in the onDetach to
//prevent memory leaks.
//The new activity has a different instance of this Fragment.
if (mListener != null)
mListener.onData(value);
}
@Override
public void startCounting(int from) {
mCounterTask = new CounterAsyncTask(this);
mCounterTask.execute(from);
}
@Override
public void onDetach() {
super.onDetach();
mListener = null;
}
}
异步任务:
public class CounterAsyncTask extends AsyncTask<Integer, Integer, Void>{
private int counter;
private Callback mListener;
private static final int SKIP = 5000;
public CounterAsyncTask(Callback listener) {
mListener = listener;
}
@Override
protected Void doInBackground(Integer...values) {
if (values != null)
counter = values[0];
while(!this.isCancelled()){
publishProgress(counter+=SKIP);
try{
Thread.sleep(SKIP);
}
catch(InterruptedException e){
e.printStackTrace();
}
}
return null;
}
@Override
protected void onProgressUpdate(Integer... values) {
mListener.onValueChanged(values[0]);
}
public interface Callback{
public void onValueChanged(int value);
}
}
提前致谢!
我的错误。使用 setRetainInstance 时,仅 在 配置 更改时保留片段。因此,片段状态将在屏幕旋转时保持,或者如果 activity 在后台但 而不是 如果 activity 被破坏。
为了达到我想要的结果,我可能应该使用服务。