5

ショートバージョン:onResume()

私は2つの他のフラグメントを表示するためのViewPagerを維持フラグメントを持っている、のは彼らFragmentOneFragmentTwoを呼びましょう。アプリを起動すると、はオフスクリーンになり、ビューを左にスワイプすると表示されるようになります。FragmentOneが表示されます。

通常、アプリケーションが開始されるとすぐに、両方のフラグメントに対してすぐにonStart()onResume()が呼び出されます。

私が持っている問題はFragmentOneは、カスタムLoaderを開始したとき、それは完全に見えるようになるまで、onResume()FragmentTwoに呼び出されませんです。

Screenshot showing the problem

質問:

これは私のコードやAndroidサポートライブラリのバグに問題ですか? (問題はライブラリのリビジョン12では発生しませんでした。リビジョン13から始まりました)

リビジョン13とリビジョン18のバグなら、回避策がありますか?

私のカスタムLoaderに何か問題がありますか?

ロングバージョン:私は、問題を示すサンプルアプリケーションを構築している

。私はコードを最小限に抑えようとしましたが、それでもまだたくさんありますので、私と一緒にご負担ください。

MainActivityにはMainFragmentがロードされ、ViewPagerが作成されています。私のアプリケーションでは、ViewPagerはアクティビティではなくフラグメントによって維持されることが重要です。

MainFragmentは、順番に断片FragmentOneFragmentTwoを作成FragmentPagerAdapterを作成します。

のは面白いビットから始めましょうは、二つの断片:

FragmentOneは、コンテンツをロードするためのカスタムLoaderを使用していますListFragmentです:

public class FragmentOne extends ListFragment implements LoaderCallbacks<List<String>> { 
    private ArrayAdapter<String> adapter; 

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

     adapter = new ArrayAdapter<String>(getActivity(), android.R.layout.simple_list_item_1); 
     setListAdapter(adapter); 

     setEmptyText("Empty"); 
    } 

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

     // initializing the loader seems to cause the problem! 
     getLoaderManager().initLoader(0, null, this); 
    } 

    @Override 
    public Loader<List<String>> onCreateLoader(int id, Bundle args) { 
     return new MyLoader(getActivity()); 
    } 

    @Override 
    public void onLoadFinished(Loader<List<String>> loader, List<String> data) { 
     adapter.clear(); 
     adapter.addAll(data); 
    } 

    @Override 
    public void onLoaderReset(Loader<List<String>> loader) { 
     adapter.clear(); 
    } 

    public static class MyLoader extends AsyncTaskLoader<List<String>> { 
     public MyLoader(Context context) { 
      super(context); 
     } 

     @Override 
     protected void onStartLoading() { 
      forceLoad(); 
     } 

     @Override 
     public List<String> loadInBackground() { 
      return Arrays.asList("- - - - - - - - - - - - - - - - - - - foo", 
        "- - - - - - - - - - - - - - - - - - - bar", 
        "- - - - - - - - - - - - - - - - - - - baz"); 
     } 
    } 
} 

それは問題を引き起こすように見えることLoaderということです。 initLoader行をコメントアウトすると、フラグメントのライフサイクルが再び期待通りに動作します。

FragmentTwoonResume()が呼び出されているか否かに基づいて、その内容に変更:

public class FragmentTwo extends Fragment { 
    private TextView text; 

    @Override 
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 
     text = new TextView(container.getContext()); 
     text.setText("onCreateView() called"); 
     return text; 
    } 

    @Override 
    public void onResume() { 
     super.onResume(); 
     Log.i("Fragment2", "onResume() called"); 
     text.setText("onResume() called"); 
    } 
} 

をそしてここでのコードの退屈残りです。

MainActivity

public class MainActivity extends FragmentActivity { 
    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 

     setContentView(R.layout.activity_main); 

     Fragment fragment = new MainFragment(); 
     getSupportFragmentManager().beginTransaction().add(R.id.container, fragment).commit(); 
    } 
} 

レイアウトactivity_main

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:id="@+id/container" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" /> 
MainFragment

public class MainFragment extends Fragment { 
    private ViewPager viewPager; 

    @Override 
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 
     View layout = inflater.inflate(R.layout.frag_master, container, false); 
     viewPager = (ViewPager) layout.findViewById(R.id.view_pager); 
     return layout; 
    } 

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

     viewPager.setAdapter(new MyPagerAdapter(getChildFragmentManager())); 
    } 

    private static final class MyPagerAdapter extends FragmentPagerAdapter { 
     public MyPagerAdapter(FragmentManager fragmentManager) { 
      super(fragmentManager); 
     } 

     @Override 
     public int getCount() { 
      return 2; 
     } 

     @Override 
     public Fragment getItem(int position) { 
      if (position == 0) 
       return new FragmentOne(); 
      else 
       return new FragmentTwo(); 
     } 
    } 
} 

レイアウトfrag_master

<android.support.v4.view.ViewPager xmlns:android="http://schemas.android.com/apk/res/android" 
    android:id="@+id/view_pager" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" /> 

答えて

11

サポートライブラリにバグがあるようです。以下の変更が問題を解決します。 - 遅延価格

getParentFragment().getLoaderManager().initLoader(0, null, this); 
+0

あなたがそうであるように、私はまったく同じ問題を抱えている、あなたのソリューションは動作しますが、パフォーマンスで:

// FragmentOne.java @Override public void onResume() { super.onResume(); Handler handler = getActivity().getWindow().getDecorView().getHandler(); handler.post(new Runnable() { @Override public void run() { // initialize the loader here! getLoaderManager().initLoader(0, null, FragmentOne.this); } }); } 

+0

なぜそれをハンドラに投稿しますか? – Xenione

+2

@ Xenioneこれは単なる回避策ですが、安全に使用できます。ここに私の考えがあります。最初のフラグメントでinitLoader()を呼び出すと、他のフラグメントでonResume()を呼び出すことができなくなります(ほとんどの場合、ライブラリのバグが原因です)。そのような呼び出しがない場合、すべてのonResume()メソッドが単一の実行フレームで呼び出されます。論理的には、フレームワークがすべてのフラグメントでonResume()メソッドを呼び出すようにするには、initLoader()を呼び出さないでください。論理的には、onResume()の直後にローダーを初期化するために、次の実行フレームでそれを行う必要があります。これは、handler.post()が多く役立つところです。 –

3

私のために働いた別の回避策

はMainFragmentのローダマネージャを使用することでした。どのように解決策を見つけましたか?
+0

私は私の質問http://stackoverflow.com/q/34503845/2277631の解決策を探していたとき、私はここに私を導いた同様のものhttp://stackoverflow.com/q/17885053/2277631を見つけました。これはちょうどうまくいくようです。ローダーを初期化するために親フラグメントを使用することの欠点を見つけましたか? –

関連する問題