Sự khác biệt giữa initLoader và restartLoader trong LoaderManager


129

Tôi hoàn toàn bị mất về sự khác biệt giữa initLoadervà các restartLoaderchức năng của LoaderManager:

  • Cả hai đều có cùng chữ ký.
  • restartLoader cũng tạo một trình tải, nếu nó không tồn tại ("Bắt đầu một trình tải mới hoặc khởi động lại Trình tải hiện có trong trình quản lý này").

Có một số mối quan hệ giữa hai phương pháp? Có phải gọi restartLoaderluôn luôn gọi initLoader? Tôi có thể gọi restartLoadermà không phải gọi initLoaderkhông? Có an toàn để gọi initLoaderhai lần để làm mới dữ liệu? Khi nào tôi nên sử dụng một trong hai và tại sao ?

Câu trả lời:


202

Để trả lời câu hỏi này, bạn cần đào sâu vào LoaderManagermã. Mặc dù tài liệu về LoaderManager không đủ rõ ràng (hoặc sẽ không có câu hỏi này), nhưng tài liệu về LoaderManagerImpl, một lớp con của LoaderManager trừu tượng, sẽ sáng tỏ hơn nhiều.

initLoader

Gọi để khởi tạo một ID cụ thể bằng Trình tải. Nếu ID này đã có Trình tải được liên kết với nó, nó sẽ không thay đổi và bất kỳ cuộc gọi lại nào trước đó được thay thế bằng các ID mới được cung cấp. Nếu hiện tại không có Trình tải cho ID, một trình tải mới sẽ được tạo và bắt đầu.

Hàm này thường được sử dụng khi một thành phần đang khởi tạo, để đảm bảo rằng Trình tải mà nó dựa vào được tạo ra. Điều này cho phép nó sử dụng lại dữ liệu của Trình tải hiện có nếu đã có dữ liệu, do đó, khi hoạt động được tạo lại sau khi thay đổi cấu hình, không cần tạo lại trình tải của nó.

khởi động lại

Gọi để tạo lại Trình tải được liên kết với một ID cụ thể. Nếu hiện tại có một Trình tải được liên kết với ID này, nó sẽ bị hủy / dừng / hủy nếu thích hợp. Trình tải mới với các đối số đã cho sẽ được tạo và dữ liệu của nó được gửi cho bạn một khi có sẵn.

[...] Sau khi gọi chức năng này, mọi Trình tải trước đó được liên kết với ID này sẽ được coi là không hợp lệ và bạn sẽ không nhận được cập nhật dữ liệu nào nữa từ chúng.

Về cơ bản có hai trường hợp:

  1. Trình tải với id không tồn tại: cả hai phương thức sẽ tạo một trình tải mới để không có sự khác biệt ở đó
  2. Trình tải với id đã tồn tại: initLoadersẽ chỉ thay thế các cuộc gọi lại được truyền dưới dạng tham số nhưng sẽ không hủy hoặc dừng trình tải. Đối với CursorLoaderđiều đó có nghĩa là con trỏ vẫn mở và hoạt động (nếu đó là trường hợp trước initLoadercuộc gọi). `restartLoader, mặt khác, sẽ hủy, dừng và hủy bộ tải (và đóng nguồn dữ liệu cơ bản như một con trỏ) và tạo một trình tải mới (cũng sẽ tạo một con trỏ mới và chạy lại truy vấn nếu trình tải một CoderLoader).

Đây là mã đơn giản hóa cho cả hai phương thức:

initLoader

LoaderInfo info = mLoaders.get(id);
if (info == null) {
    // Loader doesn't already exist -> create new one
    info = createAndInstallLoader(id, args, LoaderManager.LoaderCallbacks<Object>)callback);
} else {
   // Loader exists -> only replace callbacks   
   info.mCallbacks = (LoaderManager.LoaderCallbacks<Object>)callback;
}

khởi động lại

LoaderInfo info = mLoaders.get(id);
if (info != null) {
    LoaderInfo inactive = mInactiveLoaders.get(id);
    if (inactive != null) {
        // does a lot of stuff to deal with already inactive loaders
    } else {
        // Keep track of the previous instance of this loader so we can destroy
        // it when the new one completes.
        info.mLoader.abandon();
        mInactiveLoaders.put(id, info);
    }
}
info = createAndInstallLoader(id, args,  (LoaderManager.LoaderCallbacks<Object>)callback);

Như chúng ta có thể thấy trong trường hợp trình tải không tồn tại (thông tin == null) cả hai phương thức sẽ tạo một trình tải mới (thông tin = createdAndInstallLoader (...)). Trong trường hợp trình tải đã tồn tại initLoaderchỉ thay thế các cuộc gọi lại (info.mCallbacks = ...) trong khi restartLoadervô hiệu hóa trình tải cũ (nó sẽ bị hủy khi trình tải mới hoàn thành công việc của nó) và sau đó tạo một trình gọi mới.

Vì vậy, cho biết bây giờ rõ ràng khi nào nên sử dụng initLoadervà khi nào sử dụng restartLoadervà tại sao nó có ý nghĩa để có hai phương pháp. initLoaderđược sử dụng để đảm bảo có bộ nạp khởi tạo. Nếu không tồn tại một cái mới được tạo ra, nếu cái đó đã tồn tại thì nó được sử dụng lại. Chúng tôi luôn sử dụng phương thức này KHÔNG GIỚI HẠN, chúng tôi cần một trình tải mới vì truy vấn để chạy đã thay đổi (không phải dữ liệu cơ bản mà là truy vấn thực tế như trong câu lệnh SQL cho CoderLoader), trong trường hợp đó chúng tôi sẽ gọi restartLoader.

Vòng đời Hoạt động / Đoạn không liên quan gì đến quyết định sử dụng một hoặc phương thức khác (và không cần phải theo dõi các cuộc gọi bằng cờ một lần như Simon đề xuất)! Quyết định này được đưa ra chỉ dựa trên "nhu cầu" đối với bộ tải mới. Nếu chúng tôi muốn chạy cùng một truy vấn chúng tôi sử dụng initLoader, nếu chúng tôi muốn chạy một truy vấn khác, chúng tôi sử dụng restartLoader.

Chúng tôi luôn có thể sử dụng restartLoadernhưng điều đó sẽ không hiệu quả. Sau khi xoay màn hình hoặc nếu người dùng điều hướng khỏi ứng dụng và quay lại cùng một Hoạt động, chúng ta thường muốn hiển thị cùng một kết quả truy vấn và do đó restartLoadersẽ tạo lại trình tải một cách không cần thiết và loại bỏ kết quả truy vấn cơ bản (có khả năng tốn kém).

Điều rất quan trọng để hiểu sự khác biệt giữa dữ liệu được tải và "truy vấn" để tải dữ liệu đó. Giả sử chúng ta sử dụng một CoderLoader truy vấn một bảng cho các đơn đặt hàng. Nếu một đơn hàng mới được thêm vào bảng đó, CthonLoader sử dụng onContentChanged () để thông báo cho UI để cập nhật và hiển thị đơn hàng mới (không cần sử dụng restartLoadertrong trường hợp này). Nếu chúng tôi muốn chỉ hiển thị các đơn đặt hàng đang mở, chúng tôi cần một truy vấn mới và chúng tôi sẽ sử dụng restartLoaderđể trả về một CoderLoader mới phản ánh truy vấn mới.


Có một số mối quan hệ giữa hai phương pháp?

Họ chia sẻ mã để tạo Trình tải mới nhưng họ làm những việc khác nhau khi trình tải đã tồn tại.

Có phải gọi restartLoaderluôn luôn gọi initLoader?

Không, nó không bao giờ làm.

Tôi có thể gọi restartLoadermà không phải gọi initLoaderkhông?

Đúng.

Có an toàn để gọi initLoaderhai lần để làm mới dữ liệu?

Gọi initLoaderhai lần là an toàn nhưng không có dữ liệu nào được làm mới.

Khi nào tôi nên sử dụng một trong hai và tại sao ?


Điều đó (hy vọng) sẽ rõ ràng sau những giải thích của tôi ở trên.

Thay đổi cấu hình

LoaderManager duy trì trạng thái của nó qua các thay đổi cấu hình (bao gồm cả thay đổi hướng), do đó bạn sẽ nghĩ chúng tôi không còn gì để làm. Nghĩ lại...

Trước hết, LoaderManager không giữ lại các cuộc gọi lại, vì vậy nếu bạn không làm gì thì bạn sẽ không nhận được các cuộc gọi đến các phương thức gọi lại của mình như thế nào onLoadFinished()và tương tự và điều đó rất có thể sẽ phá vỡ ứng dụng của bạn.

Do đó, chúng ta PHẢI gọi ít nhất là initLoaderđể khôi phục các phương thức gọi lại ( restartLoaderdĩ nhiên là có thể). Các tài liệu nêu:

Nếu tại điểm gọi của người gọi đang ở trạng thái bắt đầu và trình tải được yêu cầu đã tồn tại và đã tạo dữ liệu của nó, thì cuộc gọi lại onLoadFinished(Loader, D)sẽ được gọi ngay lập tức (bên trong chức năng này) [...].

Điều đó có nghĩa là nếu chúng tôi gọi initLoadersau khi thay đổi định hướng, chúng tôi sẽ nhận được một onLoadFinishedcuộc gọi ngay lập tức vì dữ liệu đã được tải (giả sử đó là trường hợp trước khi thay đổi). Mặc dù điều đó nghe có vẻ khó khăn nhưng không phải tất cả chúng ta đều yêu thích Android ...).

Chúng ta phải phân biệt giữa hai trường hợp:

  1. Cấu hình của Handles tự thay đổi: đây là trường hợp của Fragment sử dụng setRetainInstance (true) hoặc cho một Activity với android:configChangesthẻ theo trong tệp kê khai. Các thành phần này sẽ không nhận được cuộc gọi onCreate sau khi quay màn hình, vì vậy hãy nhớ gọi initLoader/restartLoadertheo phương thức gọi lại khác (ví dụ: trong onActivityCreated(Bundle)). Để có thể khởi tạo (các) Trình tải, các id trình tải cần được lưu trữ (ví dụ: trong Danh sách). Vì thành phần được giữ lại qua các thay đổi cấu hình, chúng tôi chỉ có thể lặp qua các id và trình gọi của trình tải hiện có initLoader(loaderid, ...).
  2. Không tự xử lý các thay đổi cấu hình: Trong trường hợp này, Trình tải có thể được khởi tạo trong onCreate nhưng chúng tôi cần giữ lại các id trình tải theo cách thủ công hoặc chúng tôi sẽ không thể thực hiện các cuộc gọi initLoader / restartLoader cần thiết. Nếu các id được lưu trữ trong một ArrayList, chúng tôi sẽ thực hiện một thao tác
    outState.putIntegerArrayList(loaderIdsKey, loaderIdsArray)trong onSaveInstanceState và khôi phục các id trong onCreate: loaderIdsArray = savedInstanceState.getIntegerArrayList(loaderIdsKey)trước khi chúng tôi thực hiện cuộc gọi initLoader.

: +1: Một điểm cuối cùng. Nếu bạn sử dụng initLoader(và tất cả các cuộc gọi lại đã kết thúc, Trình tải không hoạt động) sau khi xoay bạn sẽ không nhận được onLoadFinishedcuộc gọi lại nhưng nếu bạn sử dụng thì restartLoaderbạn sẽ làm gì?
Blundell

Sai. Phương thức initLoader gọi phương thức onLoadFinished () trước khi nó trả về (nếu trình tải được khởi động và có dữ liệu). Tôi đã thêm một đoạn về thay đổi cấu hình để giải thích điều này chi tiết hơn.
Emanuel Moecklin

6
Tất nhiên, sự kết hợp giữa câu trả lời của bạn và @ alexlockwood đưa ra bức tranh đầy đủ. Tôi đoán câu trả lời cho người khác là, hãy sử dụng initLoader nếu Truy vấn của bạn là tĩnh và restartLoader nếu bạn muốn thay đổi truy vấn
Blundell

1
Điều đó triệu tập nó một cách độc đáo: "sử dụng initLoader nếu Truy vấn của bạn là tĩnh và restartLoader nếu bạn muốn thay đổi truy vấn"
Emanuel Moecklin

1
@Mhd. Tahawi bạn không thay đổi các cuộc gọi lại, bạn chỉ đặt chúng ở bất cứ nơi nào chúng nên đi. Sau khi xoay màn hình, chúng cần được thiết lập lại vì Android sẽ không giữ chúng xung quanh để tránh rò rỉ bộ nhớ. Bạn có thể đặt chúng thành bất cứ thứ gì bạn muốn miễn là chúng làm đúng.
Emanuel Moecklin

46

Gọi initLoaderkhi Trình tải đã được tạo (ví dụ: điều này thường xảy ra sau khi thay đổi cấu hình) báo cho Trình quản lý tải để gửi dữ liệu gần đây nhất của Trình tải đến onLoadFinishedngay lập tức. Nếu Trình tải chưa được tạo (ví dụ: khi hoạt động / đoạn đầu tiên khởi chạy, chẳng hạn), lệnh gọi để initLoaderTrình tải trình quản lý gọi onCreateLoaderđể tạo Trình tải mới.

Việc gọi restartLoadersẽ phá hủy Trình tải hiện có (cũng như mọi dữ liệu hiện có được liên kết với nó) và yêu cầu Trình tải quản lý gọi onCreateLoaderđể tạo Trình tải mới và bắt đầu tải mới.


Các tài liệu cũng khá rõ ràng về điều này:

  • initLoaderđảm bảo Trình tải được khởi tạo và kích hoạt. Nếu trình tải không tồn tại, một trình tạo được tạo và (nếu hoạt động / đoạn hiện đang bắt đầu) khởi động trình tải. Nếu không, trình tải được tạo cuối cùng được sử dụng lại.

  • restartLoaderbắt đầu một trình tải mới hoặc khởi động lại Trình tải hiện có trong trình quản lý này, đăng ký các cuộc gọi lại với nó và (nếu hoạt động / đoạn hiện đang bắt đầu) bắt đầu tải nó. Nếu một trình tải có cùng id đã được khởi động trước đó, nó sẽ tự động bị hủy khi trình tải mới hoàn thành công việc của nó. Cuộc gọi lại sẽ được gửi trước khi bộ tải cũ bị phá hủy.


@TomanMoney Tôi đã giải thích ý nghĩa của nó trong câu trả lời của tôi. Phần nào bạn bối rối về?
Alex Lockwood

bạn chỉ cần thử lại tài liệu. Nhưng tài liệu không đưa ra dấu hiệu nào về việc nên sử dụng từng phương pháp ở đâu và tại sao nó lại tệ khi làm hỏng nó. Theo kinh nghiệm của tôi, chỉ cần gọi restartLoader và không bao giờ gọi initLoader hoạt động tốt. Vì vậy, điều này vẫn còn khó hiểu.
Tom anMoney

3
@TomanMoney Thông thường bạn sử dụng initLoader()trong onCreate()/ onActivityCreated()khi hoạt động / đoạn đầu tiên bắt đầu. Bằng cách này, khi người dùng lần đầu mở một hoạt động, trình tải sẽ được tạo lần đầu tiên ... nhưng trên bất kỳ thay đổi cấu hình nào sau đó, toàn bộ hoạt động / đoạn phải bị hủy, lệnh gọi sau initLoader()sẽ chỉ trả về cũ Loaderthay vì tạo ra một cái mới Thông thường bạn sử dụng restartLoader()khi bạn cần thay đổi Loadertruy vấn của (nghĩa là bạn muốn nhận dữ liệu được lọc / sắp xếp, v.v.).
Alex Lockwood

4
Tôi vẫn bối rối về quyết định API có cả hai phương thức, vì chúng có cùng chữ ký. Tại sao API không thể là một phương thức startLoader () duy nhất thực hiện "đúng" mọi lúc? Tôi nghĩ rằng đây là phần khiến nhiều người bối rối.
Tom anMoney

1
@TomanMoney Tài liệu ở đây cho biết: developer.android.com/guide/components/loaders.html . "Chúng tự động kết nối lại với con trỏ của bộ tải cuối cùng khi được tạo lại sau khi thay đổi cấu hình. Do đó, chúng không cần phải truy vấn lại dữ liệu của chúng."
IgorGanapolsky

16

Gần đây tôi đã gặp sự cố với nhiều trình quản lý trình tải và thay đổi hướng màn hình và muốn nói rằng sau nhiều lần thử và lỗi, mẫu sau hoạt động với tôi trong cả Hoạt động và Đoạn:

onCreate: call initLoader(s)
          set a one-shot flag
onResume: call restartLoader (or later, as applicable) if the one-shot is not set.
          unset the one-shot in either case.

(nói cách khác, thiết lập một số cờ để initLoaderluôn luôn chạy một lần & rằng restartLoader được chạy trên 2 & sau đó đi qua onResume )

Ngoài ra, hãy nhớ chỉ định các id khác nhau cho mỗi trình tải của bạn trong một Hoạt động (có thể là một vấn đề với các đoạn trong hoạt động đó nếu bạn không cẩn thận với việc đánh số của mình)


Tôi đã thử chỉ sử dụng initLoader .... dường như không hoạt động hiệu quả.

Đã thử initLoader trên onCreate với null args (docs nói điều này là ổn) & restartLoader (với args hợp lệ) trong onResume .... docs sai & initLoader ném ngoại lệ nullpulum.

Đã thử restartLoader chỉ ... hoạt động được một lúc nhưng thổi vào định hướng lại màn hình thứ 5 hoặc thứ 6.

Đã thử initLoader trong onResume ; lại hoạt động được một lúc rồi thổi. (cụ thể là "Đã gọi doRetain khi chưa khởi động:" ... lỗi)

Đã thử các cách sau: (trích từ một lớp bìa có id trình tải được truyền vào hàm tạo)

/**
 * start or restart the loader (why bother with 2 separate functions ?) (now I know why)
 * 
 * @param manager
 * @param args
 * @deprecated use {@link #restart(LoaderManager, Bundle)} in onResume (as appropriate) and {@link #initialise(LoaderManager, Bundle)} in onCreate 
 */
@Deprecated 
public void start(LoaderManager manager, Bundle args) {
    if (manager.getLoader(this.id) == null) {
        manager.initLoader(this.id, args, this);
    } else {
        manager.restartLoader(this.id, args, this);
    }
}

(mà tôi tìm thấy ở đâu đó trong Stack-Overflow)

Một lần nữa, điều này làm việc trong một thời gian nhưng vẫn ném sự cố thỉnh thoảng.


Từ những gì tôi có thể tìm ra trong khi gỡ lỗi, tôi nghĩ rằng có một số việc phải làm với trạng thái lưu / khôi phục yêu cầu initLoader (/ s) được chạy trong phần onCreate của vòng đời nếu chúng tồn tại trong vòng quay của chu kỳ . ( Tôi có thể sai.)

trong trường hợp Người quản lý không thể khởi động cho đến khi kết quả quay lại từ người quản lý hoặc tác vụ khác (nghĩa là không thể khởi tạo trong onCreate ), tôi chỉ sử dụng initLoader . (Tôi có thể không đúng trong trường hợp này nhưng có vẻ như nó hoạt động. Các trình tải thứ cấp này không phải là một phần của trạng thái cá thể ngay lập tức nên sử dụng initLoader thực sự có thể đúng trong trường hợp này)

vòng đời


Nhìn vào sơ đồ và tài liệu, tôi có thể nghĩ rằng initLoader nên truy cập onCreate & restartLoader trong onRestart for Activity nhưng để lại Fragment sử dụng một số mẫu khác nhau và tôi không có thời gian để điều tra xem điều này có thực sự ổn định không. Bất cứ ai khác có thể nhận xét nếu họ có thành công với mô hình này cho các hoạt động?


/ @ Simon đúng 100% và đây phải là câu trả lời được chấp nhận. Tôi hoàn toàn không tin câu trả lời của anh ấy và đã dành vài giờ cố gắng tìm ra những cách khác nhau để thực hiện công việc này. Ngay khi tôi chuyển cuộc gọi initLoader sang onCreate, mọi thứ bắt đầu hoạt động. Sau đó, bạn cần cờ one-shot để tính toán số lần onStart được gọi nhưng không có onCreate
CjS

2
"Đã thử restartLoader chỉ ... hoạt động được một lúc nhưng thổi vào định hướng lại màn hình thứ 5 hoặc thứ 6." Nó không? Tôi chỉ thử nó và xoay màn hình hàng trăm lần và không bị nổ tung. Bạn đang nhận được loại ngoại lệ nào?
Tom anMoney

-1 Tôi đánh giá cao nỗ lực nghiên cứu đằng sau câu trả lời này nhưng hầu hết các kết quả đều không chính xác.
Emanuel Moecklin

1
@IgorGanapolsky gần như tất cả mọi thứ. Nếu bạn đọc và hiểu câu trả lời của tôi, bạn sẽ hiểu initLoader và restartLoader làm gì và khi nào nên sử dụng và bạn cũng sẽ hiểu tại sao hầu hết tất cả các kết luận của Simon đều sai. Không có kết nối giữa vòng đời của một phân đoạn / hoạt động và quyết định khi nào nên sử dụng initLoader / restartLoader (với một cảnh báo tôi giải thích theo các thay đổi cấu hình). Simon kết luận từ thử nghiệm & lỗi rằng vòng đời là đầu mối để hiểu hai phương pháp nhưng thực tế không phải vậy.
Emanuel Moecklin

@IgorGanapolsky Tôi không cố gắng quảng cáo câu trả lời của riêng tôi. Tôi chỉ đang cố gắng giúp các nhà phát triển khác và ngăn họ sử dụng kết quả của Simon cho các ứng dụng của riêng họ. Một khi bạn hiểu hai phương thức này có nghĩa là gì, toàn bộ điều này trở nên khá rõ ràng và dễ dàng thực hiện.
Emanuel Moecklin

0

initLoadersẽ sử dụng lại các tham số tương tự nếu bộ tải đã tồn tại. Nó trả về ngay lập tức nếu dữ liệu cũ đã được tải, ngay cả khi bạn gọi nó với các tham số mới. Trình tải nên lý tưởng tự động thông báo hoạt động của dữ liệu mới. Nếu màn hình xoay, initLoadersẽ được gọi lại và dữ liệu cũ sẽ được hiển thị ngay lập tức.

restartLoaderlà khi bạn muốn buộc tải lại và thay đổi các tham số. Nếu bạn tạo màn hình đăng nhập bằng bộ tải, bạn sẽ chỉ gọi restartLoadermỗi lần nhấp vào nút. (Nút có thể được bấm nhiều lần do thông tin không chính xác, v.v.). Bạn sẽ chỉ gọi initLoaderkhi khôi phục trạng thái thể hiện đã lưu của hoạt động trong trường hợp màn hình được xoay trong khi quá trình đăng nhập đang diễn ra.


-1

Nếu trình tải đã tồn tại, restartLoader sẽ dừng / hủy / hủy cái cũ, trong khi initLoader sẽ chỉ khởi tạo nó với cuộc gọi lại đã cho. Tôi không thể tìm ra những cuộc gọi lại cũ làm gì trong những trường hợp này, nhưng tôi đoán chúng sẽ bị bỏ rơi.

Tôi đã quét qua http://grepcode.com/file/reposective.grepcode.com/java/ext/com.google.android/android/4.0.1_r1/android/app/LoaderManager.java nhưng tôi không thể tìm ra chính xác sự khác biệt là, ngoài các phương pháp làm những việc khác nhau. Vì vậy, tôi sẽ nói, hãy sử dụng initLoader lần đầu tiên và khởi động lại cho những lần sau, mặc dù tôi không thể nói chắc chắn rằng mỗi người trong số họ sẽ làm gì chính xác.


Và những gì sẽ initLoaderlàm trong trường hợp này?
theomega

-1

Trình tải ban đầu khi bắt đầu lần đầu sử dụng phương thức loadInBackground (), ở lần khởi động thứ hai, nó sẽ bị bỏ qua. Vì vậy, ý kiến ​​của tôi, giải pháp tốt hơn là:

Loader<?> loa; 
try {
    loa = getLoaderManager().getLoader(0);
} catch (Exception e) {
    loa = null;
}
if (loa == null) {
    getLoaderManager().initLoader(0, null, this);
} else {
    loa.forceLoad();
}

///////////////////////////////////////////////////// /////////////////////////////

protected SimpleCursorAdapter mAdapter;

private abstract class SimpleCursorAdapterLoader 
    extends AsyncTaskLoader <Cursor> {

    public SimpleCursorAdapterLoader(Context context) {
        super(context);
    }

    @Override
    protected void onStartLoading() {
        if (takeContentChanged() || mAdapter.isEmpty()) {
            forceLoad();
        }
    }

    @Override
    protected void onStopLoading() {
        cancelLoad();
    }

    @Override
    protected void onReset() {
        super.onReset();
        onStopLoading();
    }
}

Tôi đã dành nhiều thời gian để tìm giải pháp này - restartLoader (...) không hoạt động đúng trong trường hợp của tôi. ForceLoad () duy nhất cho phép hoàn thành luồng tải trước mà không cần gọi lại (vì vậy bạn sẽ hoàn thành tất cả các giao dịch db đúng cách) và bắt đầu lại luồng mới. Vâng, nó đòi hỏi một chút thời gian, nhưng ổn định hơn. Chỉ chủ đề bắt đầu cuối cùng sẽ có cuộc gọi lại. Do đó, nếu bạn muốn thực hiện các thử nghiệm làm gián đoạn các giao dịch db của mình - chào mừng bạn, hãy thử khởi động lạiLoader (...), nếu không thì bắt buộcLoad (). Sự tiện lợi duy nhất của restartLoader (...) là cung cấp dữ liệu ban đầu mới, ý tôi là các tham số. Và đừng quên phá hủy bộ nạp trong phương thức onDetach () của Fragment phù hợp trong trường hợp này. Ngoài ra, hãy nhớ rằng, đôi khi, khi bạn có một hoạt động và, hãy để họ nói, 2 mảnh với Trình tải mỗi hoạt động bao gồm - bạn sẽ chỉ tiếp cận 2 Trình quản lý trình tải, do đó Activity chia sẻ Trình tải của nó với (các) Đoạn, được hiển thị trên màn hình trước khi tải. Hãy thử LoaderManager.enableDebugLogging (đúng); để xem chi tiết trong từng trường hợp nhất định.


2
-1 để gói cuộc gọi đến getLoader(0)trong a try { ... } catch (Exception e) { ... }.
Alex Lockwood
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.