画面の向きを変更した後でViewPager
から1ページを破棄(削除)する際に問題があります。私は次のような行で問題を説明しようとします。画面の向きを変更した後、ViewPagerのアダプタから項目を破棄します
私はのアダプターには、ViewPager
と、エンドレスビューページャーがどのように動作するかを記述する小さなインターフェースを使用しています。その背後にあるアイデアは、ViewPager
の終わりに達するまで右にスクロールすることができるということです。 API呼び出しからさらに結果をロードできる場合は、結果が来るまで進行状況ページが表示されます。
ここまでは問題ありませんが、今問題が発生します。このロード・プロセスの間に、私は画面を回転させた場合、(これは基本的にAsyncTask
あるAPIの呼び出しには影響しません)、コールから戻ると、私は、この例外を与えるアプリのクラッシュ:にビットを掘った後
E/AndroidRuntime(13471): java.lang.IllegalStateException: Fragment ProgressFragment{42b08548} is not currently in the FragmentManager
E/AndroidRuntime(13471): at android.support.v4.app.FragmentManagerImpl.saveFragmentInstanceState(FragmentManager.java:573)
E/AndroidRuntime(13471): at android.support.v4.app.FragmentStatePagerAdapter.destroyItem(FragmentStatePagerAdapter.java:136)
E/AndroidRuntime(13471): at mypackage.OutterFragment$PagedSingleDataAdapter.destroyItem(OutterFragment.java:609)
をライブラリのコードは、この場合、フラグメントのmIndex
データフィールドが0
未満であると思われ、この例外が発生します。
static class PagedSingleDataAdapter extends FragmentStatePagerAdapter implements
IEndlessPagerAdapter {
private WeakReference<OutterFragment> fragment;
private List<DataItem> data;
private SparseArray<WeakReference<Fragment>> currentFragments = new SparseArray<WeakReference<Fragment>>();
private ProgressFragment progressElement;
private boolean isLoadingData;
public PagedSingleDataAdapter(SherlockFragment fragment, List<DataItem> data) {
super(fragment.getChildFragmentManager());
this.fragment = new WeakReference<OutterFragment>(
(OutterFragment) fragment);
this.data = data;
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
Object item = super.instantiateItem(container, position);
currentFragments.append(position, new WeakReference<Fragment>(
(Fragment) item));
return item;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
currentFragments.put(position, null);
super.destroyItem(container, position, object);
}
@Override
public Fragment getItem(int position) {
if (isPositionOfProgressElement(position)) {
return getProgessElement();
}
WeakReference<Fragment> fragmentRef = currentFragments.get(position);
if (fragmentRef == null) {
return PageFragment.newInstance(args); // here I'm putting some info
// in the args, just deleted
// them now, not important
}
return fragmentRef.get();
}
@Override
public int getCount() {
int size = data.size();
return isLoadingData ? ++size : size;
}
@Override
public int getItemPosition(Object item) {
if (item.equals(progressElement) && !isLoadingData) {
return PagerAdapter.POSITION_NONE;
}
return PagerAdapter.POSITION_UNCHANGED;
}
public void setData(List<DataItem> data) {
this.data = data;
notifyDataSetChanged();
}
@Override
public boolean isPositionOfProgressElement(int position) {
return isLoadingData && position == data.size();
}
@Override
public void setLoadingData(boolean isLoadingData) {
this.isLoadingData = isLoadingData;
}
@Override
public boolean isLoadingData() {
return isLoadingData;
}
@Override
public Fragment getProgessElement() {
if (progressElement == null) {
progressElement = new ProgressFragment();
}
return progressElement;
}
public static class ProgressFragment extends SherlockFragment {
public ProgressFragment() {
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
TextView progressView = new TextView(container.getContext());
progressView.setGravity(Gravity.CENTER_HORIZONTAL
| Gravity.CENTER_VERTICAL);
progressView.setText(R.string.loading_more_data);
LayoutParams params = new LayoutParams(LayoutParams.FILL_PARENT,
LayoutParams.FILL_PARENT);
progressView.setLayoutParams(params);
return progressView;
}
}
}
必要であれば、基本的にはAPI呼び出しを開始し、以下のonPageSelected()
コールバック、::ここで
はページャアダプタのコードである
今@Override
public void onPageSelected(int currentPosition) {
updatePagerIndicator(currentPosition);
activity.invalidateOptionsMenu();
if (requestNextApiPage(currentPosition)) {
pagerAdapter.setLoadingData(true);
requestNextPageController.requestNextPageOfData(this);
}
、また、何を言って価値がありますAPIコールは結果を配信した後に行います。ここでは、コールバックがある:setData()
方法はnotifiyDataSetChanged()
を呼び出すため
@Override
public boolean onTaskSuccess(Context arg0, List<DataItem> result) {
data = result;
pagerAdapter.setLoadingData(false);
pagerAdapter.setData(result);
activity.invalidateOptionsMenu();
return true;
}
[OK]を、今、これはcurrentFragments
配列に現在あるフラグメントのためgetItemPosition()
を呼び出します。もちろん、進捗要素の場合は、このページを削除したいので、POSITION_NONE
を返します。このため、基本的にPagedSingleDataAdapter
からdestroyItem()
コールバックが呼び出されます。私は画面を回転させない場合、すべて正常に動作しますが、進捗要素が表示され、API呼び出しがまだ完了していないときに回転している場合は、アクティビティが再開された後にdestroyItem()
コールバックが呼び出されます。
ViewPager
を別のFragmentでホストしていて、アクティビティではないので、OutterFragment
がViewPager
をホストしているとも言わなければなりません。私はOutterFragment
のonActivityCreated()
コールバックでpagerAdapter
をインスタンス化し、画面(右、何も変更すべきではない?)pagerAdapter
は同じまま回転すると、ここでは、コードようsetRetainInstance(true)
を使用しています:
if (pagerAdapter == null) {
pagerAdapter = new PagedSingleDataAdapter(this, data);
}
pager.setAdapter(pagerAdapter);
if (savedInstanceState == null) {
pager.setOnPageChangeListener(this);
pager.setCurrentItem(currentPosition);
}
は今まとめます、PROBLEMは次のとおりです。
私は上記の例外を取得(画面の向きが変更された)、それがインスタンス化され、活動が破壊され、再作成された後ViewPager
から進捗要素を削除しようとした場合(pagerAdapter
は、同じままその中のすべてがまた、pagerAdapter
をホストするOutterFragment
が破壊されていないため、アクティビティから切り離されてから再接続されるため)。おそらくそれはフラグメントマネージャーで何か起こりますが、私は本当に何がわかりません。私はすでに試した何
:
を私はフラグメントマネージャからフラグメントを削除しようとしていた
onTaskSuccess()
コールバックに、すなわち、別の技術を使用して、私の進捗フラグメントを削除しようとすると、動作しませんでした。また、フラグメントマネージャから完全に削除するのではなく、進捗要素を隠そうとしました。これは50%働いていました。なぜなら、ビューはもう存在しないからですが、空のページがあるので、それは私が探しているものではありません。
また、画面の向きが変更された後に
progressFragment
をフラグメントマネージャに添付しようとしましたが、これも機能しませんでした。また、アクティビティが再作成された後、進行状況フラグメントをフラグメントマネージャに再度追加しようとしましたが、機能しませんでした。
onTaskSuccess()
コールバックから手動でdestroyItem()
をコールしようとしましたが(実際は実際には醜いですが動作しませんでした)
申し訳ありませんが、このような長い記事のためにみんなが、私はあなたたちはそれを理解できるように、として最高の私ができるように問題を説明しようとしていました。
どのような解決策でも、お勧めします。
ありがとうございます!
更新:解決済みの問題 OK、これはしばらく時間がかかりました。問題は、destroyItem()コールバックが進行方向のフラグメントで2回、画面の向きが変更されたときに1回、次にapi呼び出しの終了後にもう一度呼び出されたことです。それが例外の理由です。私が見つけた解決策は以下の通りです。 APIコールが終了したかどうかを追跡して、この場合は進行コードを破棄してください。
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
if (object.equals(progressElement) && apiCallFinished == true) {
apiCallFinished = false;
currentFragments.put(position, currentFragments.get(position + 1));
super.destroyItem(container, position, object);
} else if (!(object.equals(progressElement))) {
currentFragments.put(position, null);
super.destroyItem(container, position, object);
}
}
し、このapiCallFinishedはonTaskSuccess()
コールバックで、アダプタのコンストラクタでtrueにfalseに設定されています。 それは本当に機能します!
愚かな質問かもしれませんが、画面を回転させた後に実際にフラグメントをviewPagerに再追加しますか?オリエンテーションの変更であなたの活動が破壊されます。 –
ああ、いいですね。私はそれらを追加していますが、コードを追加するのを忘れていました:)。これを指摘してくれてありがとう、私は私のポストを少し編集します。乾杯! –
実際にonCreateで.addTab()を使用してタブを再度追加してみてください。問題はprogressFragmentだけですか? –