2011-10-12 43 views
16

Tôi đang cố gắng sử dụng FragmentActivity với ViewPager để hiển thị danh sách động Fragments. Có rất nhiều ví dụ về cách làm một phiên bản tĩnh của nó. Vấn đề của tôi là danh sách mà tôi hiển thị cần được nạp động và cũng có thể thay đổi dựa trên đầu vào của người dùng (thêm/xóa). Tôi đang cố gắng sử dụng tùy chỉnh android.support.v4.content.Loader để tải tập dữ liệu mà tôi có thể sử dụng để tạo danh sách của mình.Android - sự cố khi sử dụng FragmentActivity + Trình tải lên để cập nhật FragmentStatePagerAdapter

Tất cả mọi thứ đi tốt trong thiết lập của tôi cho đến khi tôi nhận được điểm khi tôi muốn để cập nhật các bộ chuyển đổi và ban hành FragmentStatePagerAdapter#notifyDataSetChanged() cuộc gọi tại thời điểm đó mã này được thực hiện (từ FragmentStatePagerAdapter)

public void finishUpdate(View container) 
{ 
    if(mCurTransaction != null) 
    { 
     mCurTransaction.commit(); // BANG!!! The exception is thrown 
     mCurTransaction = null; 
     mFragmentManager.executePendingTransactions(); 
    } 
} 

Giao dịch cam kết không thành công với tin nhắn này:

java.lang.IllegalStateException: Can not perform this action inside of onLoadFinished

vì bên trong FragmentManagerImpl mã này được thực hiện:

private void checkStateLoss() { 
    if (mStateSaved) { 
     throw new IllegalStateException(
       "Can not perform this action after onSaveInstanceState"); 
    } 
    if (mNoTransactionsBecause != null) { 
     throw new IllegalStateException(
       "Can not perform this action inside of " + mNoTransactionsBecause); 
    } 
} 

Nó chỉ ra rằng mNoTransactionsBecause giá trị không phải là null và nó được thiết lập trong LoaderManagerImpl.LoaderInfo khi kết quả được trả về lại onLoadFinished

Tôi đã nhìn vào các biến khác nhau cố gắng bằng cách nào đó thay đổi tramsaction.commit()-transaction.commitAllowingStateLoss() nhưng tất cả mọi thứ liên quan giao dịch có vẻ là riêng tư hoặc ít nhất được bảo vệ theo gói.

Ai đó có thể cho tôi một ý tưởng chung nếu tôi có thể làm những gì tôi cần làm (và làm thế nào)?

Chỉ cần lưu ý rằng mã của tôi hoạt động tốt nếu thay vì sử dụng Loader Tôi chạy ops tải trong AsyncTask

+0

Bạn có thể tìm ra cách thích hợp để thực hiện việc này với Trình tải không? Tôi đang đối mặt với cùng một vấn đề. Tôi đã có thể làm cho nó hoạt động bằng cách sử dụng 'transaction.commitAllowingStateLoss()', nhưng nó vẫn sẽ được tốt đẹp để biết những gì Google dự định chúng tôi làm ... nó có vẻ như cần phải có một cách để thực hiện một giao dịch mảnh sau khi tải dữ liệu bằng cách sử dụng bộ nạp ... – ashughes

+0

Tôi thường từ bỏ việc này và đang sử dụng ModernTaskLoader với giới hạn tổng hợp – Bostone

+0

ModernTaskLoader là gì? Không thể tìm thấy bất kỳ thông tin nào về nó ở bất kỳ đâu ... – ashughes

Trả lời

35

Tôi đã có một vấn đề rất giống với vấn đề này và giải quyết nó bằng cách sử dụng trình xử lý trên Phân đoạn.

tôi muốn hiển thị một hộp thoại cảnh báo trên onLoadFinished(), tương tự như sau

public class MyFragment extends Fragment 
    implements LoaderManager.LoaderCallbacks<T> { 

    public void onLoadFinished(Loader<T> loader, T data) { 
     showDialog(); 
    } 

    public void showDialog() { 
     MyAlertDialogFragment fragment = new MyAlertDialogFragment(); 
     fragment.show(getActivity().getSupportFragmentManager(), "dialog"); 

    } 
} 

Nhưng điều này đã đưa ra một lỗi

không thể thực hiện hành động này bên trong onLoadFinished

Giải pháp là thêm người xử lý vào đoạn để xử lý hộp thoại

private Handler handler = new Handler() { 
    @Override 
    public void handleMessage(Message msg) { 
     if(msg.what == MSG_SHOW_DIALOG) { 
      showDialog(); 
     } 
    } 
}; 

Và sau đó sửa đổi onLoadFinished (...) để gửi một thông điệp tới xử lý thay vì

public void onLoadFinished(Loader<T> loader, T data) { 
     handler.sendEmptyMessage(MSG_SHOW_DIALOG); 
    } 
+11

Hoặc bạn gửi một runnable lên xử lý. 'Trình xử lý h = Trình xử lý mới (Looper.getMainLooper()); h.post (Runnable mới() {....}); 'etc –

+1

@ Chris.Jenkins Việc triển khai của Ian hiệu quả hơn vì nó chỉ yêu cầu phân bổ đối tượng đơn. :) –

+0

@AlexLockwood Không thực sự là vấn đề trừ khi bạn đang tạo 1000 đối tượng trong một lần truy cập trong một kịch bản hiệu suất cao. –

0

Bạn có thể sao chép FragmentStatePagerAdapter và thay đổi nó tuy nhiên bạn thích, hoặc tạo của riêng PagerAdapter bạn từ đầu. Hoặc đơn giản là không sử dụng Loader.

+0

Đây không phải là vấn đề với bộ điều hợp, tất cả nó đang làm - cam kết giao dịch. Nhưng ai đó đã đi đến nỗ lực đáng kể để ngăn chặn các giao dịch cam kết trong onLoadFinished. Tôi muốn biết tại sao? Tôi cũng không thích viết lại các lớp học vì lợi ích của một dòng duy nhất Và tôi làm như khái niệm Loader và muốn sử dụng nó. Như tôi đã nói - Tôi có thực hiện làm việc trực tiếp bằng cách sử dụng AsyncTask – Bostone

+4

Rõ ràng vì có một số khả năng mất trạng thái khi gọi trong 'onLoadFinished()'. Từ JavaDoc: 'Lưu ý rằng thông thường một ứng dụng không được phép thực hiện các giao dịch phân đoạn trong khi thực hiện cuộc gọi này, vì nó có thể xảy ra sau khi trạng thái của hoạt động được lưu. Xem FragmentManager.openTransaction() để thảo luận thêm về điều này. 'Bạn phải thay đổi thành bộ điều hợp để sử dụng 'commitAllowingStateLoss()' hoặc loại bỏ bộ nạp. Tôi đã có cùng một vấn đề, và đây là câu trả lời tôi nhận được: https://groups.google.com/forum/#!topic/android-developers/dXZZjhRjkMk/discussion –

0

Nó hoạt động bằng rootView.post(). Chỉ cần xác định biến rootView trong phạm vi lớp và sau đó tăng nó trênCreateView(). Cuối cùng onLoadFinished() chỉ cần sử dụng nó như sau:

  rootView.post(new Runnable() { 
       public void run() { 
        General.showFragment(); 
       } 

      }); 
Các vấn đề liên quan