IntentService通过一个列表运行,可以通过onHandleIntent并发重新排序

发布于 2024-11-03 03:16:25 字数 5146 浏览 0 评论 0原文

我正在使用 IntentService 从列表中下载 200 个大型 JPG。加载时,用户可以跳过未加载的 JPG 并加载 JPG #156,但加载后,应继续加载其余部分。所以它就像一个惰性加载器......但它在空闲时继续。

我之前使用过 onHandleIntent 并放置了一个从 #1 到 #200 的循环...当我尝试发送另一个 JPG #156 的 IntentService 调用时,这显然不起作用。因此,对 #156 的调用仅在 onHandleIntent 使用 #200 完成后才会发生。

然后我更改了它,以便 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) - 有没有一种方法可以以编程方式添加到队列并自动成为队列的头部?我尝试用 String 替换 WeightedAsset,但它没有像我想要的那样 poll(),作为 FIFO 而不是 LIFO 堆栈。

I am using IntentService to download 200 large JPGs from a list. While this is loading, the user can skip through the not-loaded JPGs and load JPG #156 for example, but after it is loaded, it should continue loading the rest. So it's like a Lazy Loader... but it continues when it's idle.

I previously used onHandleIntent and put a loop from #1 to #200... which obviously doesn't work when I try to send another IntentService call for JPG #156. So the call to #156 only happens after onHandleIntent is done with #200.

I then changed it so onHandleIntent reorders request #156 to be at the top of the list, then requests the top of the list (and downloads the JPG), then removes it from the list. It then calls the IntentService again, which sounds rather risky from a recursive/stack overflow kinda way. It works sometimes and I can see file #156 being put first... sometimes.

Is there a better way to do this? A way I could think of would be to run it all through a database.

EDIT: This is what I have come up with:

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

Then I have this Activity:

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

Now the messy bit is that I have to keep an ever-increasing counter that runs the risk of going out of int bounds (WeightedAsset.weight) - is there a way to programmatically add to the queue and have it automatically be the head of the queue? I tried to replace WeightedAsset with a String, but it didn't poll() as I wanted, as a FIFO instead of a LIFO stack.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

南…巷孤猫 2024-11-10 03:16:25

下面是我首先尝试的方法:

步骤 #1:让 IntentService 保留 PriorityBlockingQueue

步骤#2:让 onHandleIntent() 迭代 PriorityBlockingQueue,在每个文件从队列中弹出时依次下载该文件。

步骤#3:让 onStartCommand() 查看该命令是否是“启动所有下载”命令(在这种情况下,链接到超类)。相反,如果是“优先考虑此下载”命令,请重新确定 PriorityBlockingQueue 中该条目的优先级,以便接下来当 onHandleIntent()当前下载已完成。

Here's how I'd try it first:

Step #1: Have the IntentService hold onto a PriorityBlockingQueue.

Step #2: Have onHandleIntent() iterate over the PriorityBlockingQueue, downloading each file in turn as it gets popped off the queue.

Step #3: Have onStartCommand() see if the command is the "kick off all downloads" command (in which case, chain to the superclass). If, instead, it's the "prioritize this download" command, re-prioritize that entry in the PriorityBlockingQueue, so it'll be picked up next by onHandleIntent() when the current download is finishing.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文