Đầu tiên là vấn đề:Android - Chiến lược nhóm chủ đề và Trình tải có thể được sử dụng để triển khai nó?
- tôi đang làm việc trên các ứng dụng sử dụng nhiều
FragmentLists
trong một tùy chỉnhFragmentStatePagerAdapter
. Có thể có, số lượng đáng kể các đoạn như vậy có thể từ 20 đến 40. - Mỗi đoạn là một danh sách trong đó mỗi mục có thể chứa văn bản hoặc hình ảnh.
- Các hình ảnh cần phải được tải lên không đồng bộ từ các trang web và được lưu trữ để bộ nhớ cache tạm thời và cũng để SD nếu có
- Khi Fragment đi ra khỏi màn hình bất kỳ cập nhật và hoạt động hiện tại nên bị hủy bỏ (không bị tạm dừng)
Triển khai đầu tiên của tôi theo sau nổi tiếng image loader code từ Google. Vấn đề của tôi với mã đó là về cơ bản nó tạo ra một thể hiện của AsyncTask
cho mỗi hình ảnh. Mà trong trường hợp của tôi giết chết ứng dụng thật nhanh.
Vì tôi đang sử dụng gói tương thích v4, tôi đã nghĩ rằng việc sử dụng Trình tải tùy chỉnh mở rộng AsyncTaskLoader
sẽ giúp tôi kể từ khi triển khai bên trong một nhóm luồng. Tuy nhiên để ngạc nhiên khó chịu của tôi nếu tôi thực thi mã này nhiều lần mỗi lời gọi sau đây sẽ làm gián đoạn trước đó. Nói rằng tôi có điều này trong phương pháp ListView#getView
tôi:
getSupportLoaderManager().restartLoader(0, args, listener);
Phương pháp này được thực hiện trong vòng lặp cho mỗi mục trong danh sách đó đi vào xem. Và như tôi đã nói - mỗi lời kêu gọi sau sẽ chấm dứt cuộc gọi trước đó. Hoặc ít nhất đó là những gì xảy ra dựa trên LogCat
11-03 13:33:34.910: V/LoaderManager(14313): restartLoader in LoaderManager: args=Bundle[{URL=http://blah-blah/pm.png}]
11-03 13:33:34.920: V/LoaderManager(14313): Removing pending loader: LoaderInfo{405d44c0 #2147483647 : ImageLoader{405118a8}}
11-03 13:33:34.920: V/LoaderManager(14313): Destroying: LoaderInfo{405d44c0 #2147483647 : ImageLoader{405118a8}}
11-03 13:33:34.920: V/LoaderManager(14313): Enqueuing as new pending loader
Sau đó tôi nghĩ rằng có thể cung cấp id duy nhất cho mỗi trình tải sẽ giúp ích cho vấn đề nhưng dường như không có sự khác biệt nào. Kết quả là tôi kết thúc với hình ảnh dường như ngẫu nhiên và các ứng dụng không bao giờ tải ngay cả 1/4 những gì tôi cần.
Các Câu hỏi
- Điều gì sẽ là cách để sửa chữa Loader để làm những gì tôi muốn (và có cách nào?)
- Nếu một cách tốt để tạo
AsyncTask
hồ bơi không phải là những gì và là có lẽ làm việc thực hiện nó?
Để cung cấp cho bạn ý tưởng về mã, đây là phiên bản rút gọn của Trình tải nơi tải xuống/lưu logic thực tế nằm trong lớp ImageManager riêng biệt.
public class ImageLoader extends AsyncTaskLoader<TaggedDrawable> {
private static final String TAG = ImageLoader.class.getName();
/** Wrapper around BitmapDrawable that adds String field to id the drawable */
TaggedDrawable img;
private final String url;
private final File cacheDir;
private final HttpClient client;
/**
* @param context
*/
public ImageLoader(final Context context, final String url, final File cacheDir, final HttpClient client) {
super(context);
this.url = url;
this.cacheDir = cacheDir;
this.client = client;
}
@Override
public TaggedDrawable loadInBackground() {
Bitmap b = null;
// first attempt to load file from SD
final File f = new File(this.cacheDir, ImageManager.getNameFromUrl(url));
if (f.exists()) {
b = BitmapFactory.decodeFile(f.getPath());
} else {
b = ImageManager.downloadBitmap(url, client);
if (b != null) {
ImageManager.saveToSD(url, cacheDir, b);
}
}
return new TaggedDrawable(url, b);
}
@Override
protected void onStartLoading() {
if (this.img != null) {
// If we currently have a result available, deliver it immediately.
deliverResult(this.img);
} else {
forceLoad();
}
}
@Override
public void deliverResult(final TaggedDrawable img) {
this.img = img;
if (isStarted()) {
// If the Loader is currently started, we can immediately deliver its results.
super.deliverResult(img);
}
}
@Override
protected void onStopLoading() {
// Attempt to cancel the current load task if possible.
cancelLoad();
}
@Override
protected void onReset() {
super.onReset();
// Ensure the loader is stopped
onStopLoading();
// At this point we can release the resources associated with 'apps'
// if needed.
if (this.img != null) {
this.img = null;
}
}
}
'AsyncTask' đã sử dụng một nhóm. Các hồ bơi đi lên đến 128 chủ đề IIRC, có thể là nguồn gốc của khó khăn của bạn. Bạn luôn có thể triển khai nhóm luồng của riêng mình bằng cách sử dụng các lớp 'java.util.concurrent'. – CommonsWare
Nếu sự phát triển của bạn nhắm mục tiêu đến Android 3.0 (API Cấp 11), bạn có thể sử dụng API mới được thêm [AsyncTask.executeOnExecutor()] (http://developer.android.com/reference/android/os/AsyncTask.html#executeOnExecutor% 28java.util.concurrent.Executor,% 20Params ...% 29) kiểm soát tốt hồ bơi thread của bạn với vòng đời tạo ra AsyncTask của bạn. – yorkw
Tuy nhiên, AsynkTask chỉ có thể được thực hiện một lần vì vậy tôi cần tạo một cá thể cho mỗi hình ảnh tôi đang tải. làm cho nó 60 và đó là rất nhiều đối tượng – Bostone