5

phiên bản ngắn:onResume() không được gọi vào ViewPager đoạn khi sử dụng Loader tùy chỉnh

Tôi có một mảnh duy trì một ViewPager để hiển thị hai mảnh khác, chúng ta hãy gọi chúng FragmentOneFragmentTwo. Khi bắt đầu ứng dụng FragmentOne hiển thị và FragmentTwo tắt màn hình, chỉ hiển thị khi một lần vuốt chế độ xem sang trái.

Thông thường onStart()onResume() được gọi ngay lập tức cho cả hai phân đoạn ngay khi ứng dụng được bắt đầu.

Vấn đề tôi gặp phải là khi FragmentOne bắt đầu tùy chỉnh Loader thì onResume() không được gọi trên FragmentTwo cho đến khi hiển thị hoàn toàn.

Screenshot showing the problem

Câu hỏi:

Đây có phải là một vấn đề với mã của tôi hoặc một lỗi trong các thư viện hỗ trợ Android? (Vấn đề không xảy ra với bản sửa đổi 12 của thư viện, nó bắt đầu với bản sửa đổi 13.)

Nếu đó là lỗi trong các lần xem lại 13 và 18, có cách giải quyết khác không?

Có điều gì sai với tùy chỉnh Loader của tôi không?

phiên bản Long:

tôi đã xây dựng một ứng dụng mẫu đó chứng tỏ vấn đề. Tôi đã cố gắng để giảm mã số đến mức tối thiểu nhưng nó vẫn còn rất nhiều vì vậy xin vui lòng chịu với tôi.

Tôi có một MainActivity tải MainFragment tạo ViewPager. Điều quan trọng đối với ứng dụng của tôi là ViewPager được duy trì bởi một Fragment thay vì Activity.

MainFragment tạo một FragmentPagerAdapter do đó tạo ra các đoạn FragmentOneFragmentTwo.

Hãy bắt đầu với các bit thú vị, hai mảnh:

FragmentOne là một ListFragment có sử dụng một tùy chỉnh Loader để tải nội dung:

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"); 
     } 
    } 
} 

Nó là Loader điều đó dường như gây ra các vấn đề . Nhận xét ra dòng initLoader làm cho chu kỳ sống của vòng quay hoạt động như mong đợi một lần nữa.

FragmentTwo thay đổi nội dung của nó dựa trên việc onResume() đã được gọi hay không:

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"); 
    } 
} 

Và đây là phần còn lại nhàm chán của mã này.

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(); 
    } 
} 

Layout 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(); 
     } 
    } 
} 

Layout 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" /> 

Trả lời

11

Dường như đây là lỗi trong thư viện hỗ trợ. Thay đổi bên dưới giải quyết vấn đề.

// 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

Tôi đang gặp chính xác cùng một vấn đề như bạn đang có, bạn tác phẩm giải pháp nhưng với hiệu suất - giá chậm trễ. Làm thế nào bạn tìm thấy giải pháp? –

+0

tại sao bạn đăng nó vào trình xử lý? – Xenione

+2

@Xenione Đây chỉ là giải pháp thay thế, nhưng nó an toàn để sử dụng. Đây là suy nghĩ của tôi. Chúng ta thấy rằng việc gọi initLoader() trong Fragment đầu tiên ngăn cản việc gọi onResume() trên các đoạn khác (có thể là do lỗi trong thư viện). Trong không có cuộc gọi như vậy, tất cả các phương thức onResume() được gọi trong một khung thực thi duy nhất. Về mặt logic, nếu chúng ta muốn khung công tác gọi phương thức onResume() trong tất cả các Fragments, chúng ta phải tránh gọi initLoader(). Về mặt logic, để khởi tạo bộ nạp ngay sau khi onResume() chúng ta cần thực hiện nó trong khung thực hiện tiếp theo. Đây là nơi handler.post() giúp rất nhiều. –

3

Một workaround mà làm việc cho tôi là sử dụng người quản lý của MainFragment loader:

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

Tôi đang tìm kiếm giải pháp cho câu hỏi của mình http://stackoverflow.com/q/34503845/2277631 khi tôi tìm thấy một http://stackoverflow.com/q/17885053/2277631 tương tự đã dẫn tôi đến đây. Điều này dường như chỉ hoạt động. Bạn có thấy bất kỳ nhược điểm nào khi sử dụng phân đoạn gốc để bắt đầu trình tải không? –

Các vấn đề liên quan