我正在使用IntentService從列表中下載200個大型JPG。在加載時,用戶可以跳過未加載的JPG並加載JPG#156,但在加載之後,它應該繼續加載其餘部分。所以它就像一個懶惰的加載程序...但它在閒置時會繼續。IntentService通過列表運行,可以通過onHandleIntent同時重新排列列表
我以前使用onHandleIntent,並放置從#1到#200的循環...當我嘗試發送另一個IntentService調用JPG#156時,這顯然不起作用。所以對#156的調用只發生在用#200完成onHandleIntent之後。
然後我改變它,所以onHandleIntent重新排列請求#156在列表頂部,然後請求列表頂部(並下載JPG),然後從列表中刪除它。然後它再次調用IntentService,這聽起來有點像遞歸/堆棧溢出那樣有風險。它有時可以工作,我可以看到文件#156被放在第一位...有時。
有沒有更好的方式來做到這一點?我能想到的一種方式是通過數據庫來運行它。
編輯:這是我想出了:
code
public class PBQDownloader extends IntentService {
int currentWeight = 0;
PriorityBlockingQueue<WeightedAsset> pbQueue = new PriorityBlockingQueue<WeightedAsset>(100, new CompareWeightedAsset());
public PBQDownloader() {
super("PBQDownloader");
}
public PBQDownloader(String name) {
super(name);
}
@Override
protected void onHandleIntent(Intent intent) {
String downloadUrl = "-NULL-";
Bundle extras = intent.getExtras();
if (extras!=null) {
downloadUrl = extras.getString("url");
Log.d("onHandleIntent 1.1", "asked to download: " + downloadUrl);
} else {
Log.d("onHandleIntent 1.2", "no URL sent so let's start queueing everything");
int MAX = 10;
for (int i = 1; i <= MAX; i++) {
// should read URLs from list
WeightedAsset waToAdd = new WeightedAsset("url: " + i, MAX - i);
if (pbQueue.contains(waToAdd)) {
Log.d("onStartCommand 1", downloadUrl + " already exists, so we are removing it and adding it back with a new priority");
pbQueue.remove(waToAdd);
}
pbQueue.put(waToAdd);
}
currentWeight = MAX + 1;
}
while (!pbQueue.isEmpty()) {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
}
WeightedAsset waToProcess = pbQueue.poll();
Log.d("onHandleIntent 2 DOWNLOADED", waToProcess.url);
}
Log.d("onHandleIntent 99", "finished all IntentService calls");
}
@Override
public int onStartCommand(Intent intent, int a, int b) {
super.onStartCommand(intent, a, b);
currentWeight++;
String downloadUrl = "-NULL-";
Bundle extras = intent.getExtras();
if (extras!=null) downloadUrl = extras.getString("url");
Log.d("onStartCommand 0", "download: " + downloadUrl + " with current weight: " + currentWeight);
WeightedAsset waToAdd = new WeightedAsset(downloadUrl, currentWeight);
if (pbQueue.contains(waToAdd)) {
Log.d("onStartCommand 1", downloadUrl + " already exists, so we are removing it and adding it back with a new priority");
pbQueue.remove(waToAdd);
}
pbQueue.put(waToAdd);
return 0;
}
private class CompareWeightedAsset implements Comparator<WeightedAsset> {
@Override
public int compare(WeightedAsset a, WeightedAsset b) {
if (a.weight < b.weight) return 1;
if (a.weight > b.weight) return -1;
return 0;
}
}
private class WeightedAsset {
String url;
int weight;
public WeightedAsset(String u, int w) {
url = u;
weight = w;
}
}
}
code
然後,我有這樣的活動:
code
public class HelloPBQ extends Activity {
int sCount = 10;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Button tv01 = (Button) findViewById(R.id.tv01);
Button tv02 = (Button) findViewById(R.id.tv02);
Button tv03 = (Button) findViewById(R.id.tv03);
tv01.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
doPBQ();
}
});
tv02.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
doInitPBQ();
}
});
tv03.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
sCount = 0;
}
});
}
private void doInitPBQ() {
Intent intent = new Intent(getApplicationContext(), PBQDownloader.class);
//intent.putExtra("url", "url: " + sCount);
startService(intent);
}
private void doPBQ() {
sCount++;
Intent intent = new Intent(getApplicationContext(), PBQDownloader.class);
intent.putExtra("url", "url: " + sCount);
startService(intent);
}
}
code
現在凌亂的一點是,我必須保持運行的外出INT界(WeightedAsset.weight)的風險不斷增加的反 - 有沒有辦法以編程方式添加到隊列和讓它自動成爲隊列的頭部?我試圖用字符串替換WeightedAsset,但它並沒有像我想要的那樣輪詢(),而是使用FIFO而不是LIFO堆棧。
謝謝Mark,我按照你的建議完成了! :)我是StackOverflow的新手,所以我不確定如何在評論中添加代碼,因爲存在字符限制,所以我編輯了原始帖子並放入了代碼,以及另一個問題。 – albnok 2011-04-25 05:31:22
@albonk:用戶不太可能要求20億張圖片,所以你的'int'不是問題。一個'PriorityBlockingQueue'只是一個可能的實現 - 只要你使你的集合線程安全,歡迎你做任何漂浮你的船。 – CommonsWare 2011-04-25 12:32:02
謝謝馬克! 再多一點Google搜索一下,看起來'BlockingDeque'就是我正在尋找的東西,它讓我可以向隊列頭部提供物品,但是這在API級別9中超出了我的目標構建。 同時加入了一個檢查,以防萬一應用程序運行到猴子......但是一旦我們達到這個極限的LIFO行爲失敗: 'code' 如果(currentWeight + 1
albnok
2011-04-27 02:28:29