1. ホーム
  2. android

[解決済み] FragmentPagerAdapterが古いフラグメントへの参照を保持するサポート

2022-10-27 03:50:30

質問

私の問題は、FragmentManager が古いフラグメントのインスタンスを保持することと、ビューページャーが FragmentManager と同期していないことの問題であると絞り込まれました。この問題を参照してください。 http://code.google.com/p/android/issues/detail?id=19211#makechanges . 私はまだこれを解決する方法の手がかりを持っていません。何か提案はありますか?

私は長い間これをデバッグしようとしましたが、どんな助けでも非常に感謝されます。私は FragmentPagerAdapter を使用しており、このアダプタはこのようにフラグメントのリストを受け取ります。

List<Fragment> fragments = new Vector<Fragment>();
fragments.add(Fragment.instantiate(this, Fragment1.class.getName())); 
...
new PagerAdapter(getSupportFragmentManager(), fragments);

実装は標準的なものです。ActionBarSherlockとFragmentsのv4計算可能性ライブラリを使っています。

私の問題は、アプリを終了し、他のアプリケーションをいくつか開いて戻ってくると、フラグメントが FragmentActivity への参照を失うことです。 getActivity() == null ). なぜこのようなことが起こるのかがわかりません。私は、手動で setRetainInstance(true); を手動で設定しようとしましたが、これは役に立ちません。FragmentActivityが破壊されたときに発生すると考えましたが、ログメッセージが表示される前にアプリを開くと、まだこの現象が発生しています。何かアイデアはありますか?

@Override
protected void onDestroy(){
    Log.w(TAG, "DESTROYDESTROYDESTROYDESTROYDESTROYDESTROYDESTROY");
    super.onDestroy();
}

アダプタのことです。

public class PagerAdapter extends FragmentPagerAdapter {
    private List<Fragment> fragments;

    public PagerAdapter(FragmentManager fm, List<Fragment> fragments) {
        super(fm);

        this.fragments = fragments;

    }

    @Override
    public Fragment getItem(int position) {

        return this.fragments.get(position);

    }

    @Override
    public int getCount() {

        return this.fragments.size();

    }

}

フラグメントの1つが剥がれましたが、剥がれた部分を全てコメントアウトしても、まだ動きません。

public class MyFragment extends Fragment implements MyFragmentInterface, OnScrollListener {
...

@Override
public void onCreate(Bundle savedInstanceState){
    super.onCreate(savedInstanceState);
    handler = new Handler();    
    setHasOptionsMenu(true);
}

@Override
public void onAttach(Activity activity) {
    super.onAttach(activity);
    Log.w(TAG,"ATTACHATTACHATTACHATTACHATTACH");
    context = activity;
    if(context== null){
        Log.e("IS NULL", "NULLNULLNULLNULLNULLNULLNULLNULLNULLNULLNULL");
    }else{
        Log.d("IS NOT NULL", "NOTNOTNOTNOTNOTNOTNOTNOT");
    }

}

@Override
public void onActivityCreated(Bundle savedState) {
    super.onActivityCreated(savedState);
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    View v = inflater.inflate(R.layout.my_fragment,container, false);

    return v;
}


@Override
public void onResume(){
    super.onResume();
}

private void callService(){
    // do not call another service is already running
    if(startLoad || !canSet) return;
    // set flag
    startLoad = true;
    canSet = false;
    // show the bottom spinner
    addFooter();
    Intent intent = new Intent(context, MyService.class);
    intent.putExtra(MyService.STATUS_RECEIVER, resultReceiver);
    context.startService(intent);
}

private ResultReceiver resultReceiver = new ResultReceiver(null) {
    @Override
    protected void onReceiveResult(int resultCode, final Bundle resultData) {
        boolean isSet = false;
        if(resultData!=null)
        if(resultData.containsKey(MyService.STATUS_FINISHED_GET)){
            if(resultData.getBoolean(MyService.STATUS_FINISHED_GET)){
                removeFooter();
                startLoad = false;
                isSet = true;
            }
        }

        switch(resultCode){
        case MyService.STATUS_FINISHED: 
            stopSpinning();
            break;
        case SyncService.STATUS_RUNNING:
            break;
        case SyncService.STATUS_ERROR:
            break;
        }
    }
};

public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
    menu.clear();
    inflater.inflate(R.menu.activity, menu);
}

@Override
public void onPause(){
    super.onPause();
}

public void onScroll(AbsListView arg0, int firstVisible, int visibleCount, int totalCount) {
    boolean loadMore = /* maybe add a padding */
        firstVisible + visibleCount >= totalCount;
        
    boolean away = firstVisible+ visibleCount <= totalCount - visibleCount;
        
    if(away){
        // startLoad can now be set again
        canSet = true;
    }
        
    if(loadMore) 
        
}

public void onScrollStateChanged(AbsListView arg0, int state) {
    switch(state){
    case OnScrollListener.SCROLL_STATE_FLING: 
        adapter.setLoad(false); 
        lastState = OnScrollListener.SCROLL_STATE_FLING;
        break;
    case OnScrollListener.SCROLL_STATE_IDLE: 
        adapter.setLoad(true);
        if(lastState == SCROLL_STATE_FLING){
            // load the images on screen
        }
        
        lastState = OnScrollListener.SCROLL_STATE_IDLE;
        break;
    case OnScrollListener.SCROLL_STATE_TOUCH_SCROLL:
        adapter.setLoad(true);
        if(lastState == SCROLL_STATE_FLING){
            // load the images on screen
        }
        
        lastState = OnScrollListener.SCROLL_STATE_TOUCH_SCROLL;
        break;
    }
}

@Override
public void onDetach(){
    super.onDetach();
    if(this.adapter!=null)
        this.adapter.clearContext();
    
    Log.w(TAG, "DETACHEDDETACHEDDETACHEDDETACHEDDETACHEDDETACHED");
}

public void update(final int id, String name) {
    if(name!=null){
        getActivity().getSupportActionBar().setTitle(name);
    }
    
}

}

updateメソッドは、ユーザーが別のフラグメントと対話し、getActivityがnullを返しているときに呼び出されます。以下は、別のフラグメントが呼び出しているメソッドです。

((MyFragment) pagerAdapter.getItem(1)).update(id, name);

アプリを破棄して再度作成すると、デフォルトのフラグメントにアプリを起動するのではなく、アプリが起動し、viewpager が最後の既知のページにナビゲートするのだと思います。これは奇妙に思えますが、アプリはデフォルトのフラグメントにロードされるべきではないでしょうか?

どのように解決するのですか?

の外側でフラグメントをインスタンス化し、その参照を保持しているため、問題に遭遇しています。 PagerAdapter.getItem の外側でフラグメントへの参照をインスタンス化して保持し、それらの参照をViewPagerから独立して使用しようとしているためです。Seraphが言うように、あるフラグメントが特定の時間にViewPagerでインスタンス化/追加されたことを保証する必要があります。ViewPagerは、そのページの遅延ロードを行います。デフォルトでは、現在のページと、左右のページのみをロードします。

アプリをバックグラウンドにした場合、フラグメントマネージャーに追加されたフラグメントは、自動的に保存されます。アプリを終了しても、アプリを再起動すると、この情報は復元されます。

フラグメントマネージャに追加されたフラグメントA、B、Cのページを閲覧したとします。なぜなら、あなたは FragmentPagerAdapter ではなく FragmentStatePagerAdapter でない場合、これらのフラグメントは他のページにスクロールしたときに追加されます(ただし、切り離される可能性があります)。

その後、アプリケーションをバックグラウンドにし、それが強制終了された場合を考えてみましょう。戻ってきたとき、Android はフラグメント マネージャーにフラグメント A、B、および C があったことを覚えているので、それらを再作成し、追加します。 しかし、フラグメントマネージャーに追加されたフラグメントは、アクティビティーのフラグメントリストにあるものではありません。

FragmentPagerAdapter は、フラグメントマネージャを呼び出すために getPosition を呼び出そうとしません。実際、Android によって再作成されたフラグメントは決して削除されないので、それを getPosition . また、未知のタグで追加されているため、その参照を取得することもかなり困難です。これは意図的なもので、ビューページャーが管理しているフラグメントをいじらないようにするためです。フラグメント内ですべてのアクションを実行し、アクティビティと通信し、必要であれば、特定のページに切り替えるよう要求すべきです。

さて、行方不明のアクティビティに関する問題に戻ります。呼び出し pagerAdapter.getItem(1)).update(id, name) を実行した後、リストにあるフラグメントを返します。 を返しますが、これはまだフラグメントマネージャに追加されていません。 で、Activityの参照はありません。私は、あなたの更新メソッドは、いくつかの共有データ構造(おそらくアクティビティによって管理される)を変更する必要があり、その後、特定のページに移動すると、この更新されたデータに基づいて自分自身を描画することができます示唆していると思います。