2011-04-24 111 views
0

我正在使用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堆棧。

回答

2

以下是我想先試用一下:

第1步:有IntentService不放PriorityBlockingQueue

步驟#2:讓onHandleIntent()迭代PriorityBlockingQueue,隨着從隊列中彈出下載每個文件,輪流下載每個文件。

步驟3:有onStartCommand()看看命令是否是「啓動所有下載」命令(在這種情況下,鏈接到超類)。相反,如果是「優先下載此命令」命令,請重新設置PriorityBlockingQueue中的條目優先順序,以便在當前下載完成時接下來選擇onHandleIntent()

+0

謝謝Mark,我按照你的建議完成了! :)我是StackOverflow的新手,所以我不確定如何在評論中添加代碼,因爲存在字符限制,所以我編輯了原始帖子並放入了代碼,以及另一個問題。 – albnok 2011-04-25 05:31:22

+0

@albonk:用戶不太可能要求20億張圖片,所以你的'int'不是問題。一個'PriorityBlockingQueue'只是一個可能的實現 - 只要你使你的集合線程安全,歡迎你做任何漂浮你的船。 – CommonsWare 2011-04-25 12:32:02

+0

謝謝馬克! 再多一點Google搜索一下,看起來'BlockingDeque'就是我正在尋找的東西,它讓我可以向隊列頭部提供物品,但是這在API級別9中超出了我的目標構建。 同時加入了一個檢查,以防萬一應用程序運行到猴子......但是一旦我們達到這個極限的LIFO行爲失敗: 'code' 如果(currentWeight + 1 albnok 2011-04-27 02:28:29