Reputation: 1137
bellow is the default PicassoExecutorService.java , it just do request bitmap from net (and from http cache,if loaded before ) . say , if have 100 task , and 95 is loaded in cache and 5 is from net , if the 5 in the first 5 of the queue , the 95 image will never show when the 5 picture be loaded . so , i want to change PicassoExecutorService.java , i want to know is it possible to create a new thread in ExecutorService to just do disk cache fetch job ? should i create a new queue? i have not so much exprience with java thread coding , so i need your help , thaks .
class PicassoExecutorService extends ThreadPoolExecutor {
private static final int DEFAULT_THREAD_COUNT = 3;
PicassoExecutorService() {
super(DEFAULT_THREAD_COUNT, DEFAULT_THREAD_COUNT, 0, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(), new Utils.PicassoThreadFactory());
}
void adjustThreadCount(NetworkInfo info) {
if (info == null || !info.isConnectedOrConnecting()) {
setThreadCount(DEFAULT_THREAD_COUNT);
return;
}
switch (info.getType()) {
case ConnectivityManager.TYPE_WIFI:
case ConnectivityManager.TYPE_WIMAX:
case ConnectivityManager.TYPE_ETHERNET:
setThreadCount(4);
break;
case ConnectivityManager.TYPE_MOBILE:
switch (info.getSubtype()) {
case TelephonyManager.NETWORK_TYPE_LTE: // 4G
case TelephonyManager.NETWORK_TYPE_HSPAP:
case TelephonyManager.NETWORK_TYPE_EHRPD:
setThreadCount(3);
break;
case TelephonyManager.NETWORK_TYPE_UMTS: // 3G
case TelephonyManager.NETWORK_TYPE_CDMA:
case TelephonyManager.NETWORK_TYPE_EVDO_0:
case TelephonyManager.NETWORK_TYPE_EVDO_A:
case TelephonyManager.NETWORK_TYPE_EVDO_B:
setThreadCount(2);
break;
case TelephonyManager.NETWORK_TYPE_GPRS: // 2G
case TelephonyManager.NETWORK_TYPE_EDGE:
setThreadCount(1);
break;
default:
setThreadCount(DEFAULT_THREAD_COUNT);
}
break;
default:
setThreadCount(DEFAULT_THREAD_COUNT);
}
}
private void setThreadCount(int threadCount) {
setCorePoolSize(threadCount);
setMaximumPoolSize(threadCount);
}
}
static class PicassoThreadFactory implements ThreadFactory {
@SuppressWarnings("NullableProblems")
public Thread newThread(Runnable r) {
return new PicassoThread(r);
}
}
private static class PicassoThread extends Thread {
public PicassoThread(Runnable r) {
super(r);
}
@Override public void run() {
Process.setThreadPriority(THREAD_PRIORITY_BACKGROUND);
super.run();
}
}
Upvotes: 1
Views: 564
Reputation: 16476
The class PicassoExecutorService
is an implementation of an executor service which adjusts thread count for a connection type. I.e. for 2G it chooses 1 thread because 2G is slow and setting 4 simultaneous threads would exhaust your connection.
The problem you're facing is because some of the not cached jobs get ahead of the cached requests.
Now, if you're able to determine if the job is cached, you just create a separate service or thread for the disk jobs. The thread pool you showed us is a connection thread which limits the resources based on the connection type. It's better not to mix up the concerns and create a separate thread pool for the disk jobs.
If you can't say if the job is cached before trying to fetch it from the internet, I'll update the answer with a strategy, which is quite sophisticated.
UPDATE
The strategy.
First you need to get an idea of a disk read timeout on all of your devices. You need 95th percentile timeout value, e.g. the value less than a maximum. So if you have 1ms, 2ms, 1ms, 50ms, 20ms, 3ms, you don't choose 20ms or 50ms. Let it be 3ms for a disk read. Your average (or better median) connection timeout should be much greater - like 100-500ms.
So the idea is to first submit your jobs to a thread pool of like 10-20 threads with this small timeout. Thus it will filter out all the slow jobs.
Next step is to terminate the slow jobs. This depends on whether your connections are interruptible or not. And if not, it's a different question.
After this you just re-submit the slow jobs to the connection thread pool. And that's it.
Upvotes: 2