In andorid, the switch between threads is very frequent. Any time-consuming operation will lead to the emergence of rxjava, which is simple in structure, simple in switching and ready to use. If rxjava is not available, it seems that there is handler notification method, or runonhruitead. What about notifications between threads. In this case, the use of a class of Future in java will occur. = - = Old. In other words, you can't use a third party, you can only use native. And you can't jump out of threads.
Take a chestnut: This chestnut is copied.
If you suddenly want to cook, but there is no kitchen utensils, no food. It's more convenient to buy Kitchenware online, and it's more reassuring to buy food in supermarket.
Realization analysis: During the delivery of kitchen utensils by couriers, we will definitely not be idle, we can go to the supermarket to buy food materials. So, in the main thread there is another sub-thread to buy Kitchenware online.
However, the result of subthread execution is to return to the kitchen utensils, and the run method has no return value. So, that's the difficulty. We need to think about it carefully.
Here I encapsulate Future to make it better to use. And I use it in combination with threads.
XFuture<T> mFutureResult = new XFuture<>();
This time I'm using a request to download a file. It's already in a sub-thread. Set the request to data in Result. Through the setResult method
File file = new File(mContext.getCacheDir(), MD5.md5(downUrl) + ".png"); if (file.exists()) { // Prevent multiple downloads mFutureResult.setResult(file); return; }
GetTask is the sub-thread of the request, and the data is still requested in it, but the external access to Result has begun. At this time, the getLoad method is still in the sub-thread. Because I have blocked the operation internally.
GetTask getTask = new GetTask(mContext, IconUrl); getNativeTask.execute(ThreadManager.getNetExecutor()); File imageFile = GetTask.getLoad();
So you can get the data.
Paste up part of download code
public GetTask(Context context, String url) { super("getImage"); this.mContext = context; this.downUrl = url; } public File getLoad() throws CodeException { // Setting timeout events File file = this.mFutureResult.get(30000L, TimeUnit.MILLISECONDS); if (null != file) { return file; } throw new IOException(-4, "load timeout"); } @Override protected void doFire() { File file = new File(mContext.getCacheDir(), MD5.md5(downUrl) + ".png"); if (file.exists()) { // Prevent multiple downloads mFutureResult.setResult(file); return; } byte[] bytes = WebUtils.doGet(downUrl); try { FileOutputStream fileOutputStream = new FileOutputStream(file); fileOutputStream.write(bytes, 0, bytes.length); fileOutputStream.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } mFutureResult.setResult(file); }
This is the best way to do it. Without any third party, you can complete your own multi-threaded operation. Pro-test is available.
Paste encapsulation code.
public class XFuture<R> implements Future<R> { private static final String TAG = "XFuture"; private boolean done = false; private boolean cancelled = false; private String message = null; private R result = null; public boolean isDone() { return this.done; } public boolean isCancelled() { return this.cancelled; } public R get() { if (!this.done) { ensureNotOnMainThread(); } synchronized (this) { if (!this.done) { try { wait(); } catch (InterruptedException e) { LOG.e("XFuture", "wait result failed(InterruptedException)", e); setMessage(e.getMessage()); } } } return (R) this.result; } public R get(long timeout, TimeUnit unit) { if (!this.done) { ensureNotOnMainThread(); } synchronized (this) { if (!this.done) { try { long millis = unit.toMillis(timeout); long start = System.currentTimeMillis(); wait(millis); long interval = System.currentTimeMillis() - start; if ((interval >= millis) && (!this.done)) { LOG.e("XFuture", "[" + timeout + " " + unit + "] wait result timeout(" + interval + "MS)"); setMessage("timeout"); } } catch (InterruptedException e) { LOG.e("XFuture", "[" + timeout + " " + unit + "] wait result failed(InterruptedException)", e); setMessage(e.getMessage()); } } } return (R) this.result; } public boolean cancel(boolean interrupt) { this.cancelled = true; this.message = "cancelled"; this.result = null; synchronized (this) { notifyAll(); this.done = true; } return true; } public void setResult(R result) { this.cancelled = false; this.result = result; synchronized (this) { notifyAll(); this.done = true; } } public String toString() { return "QFuture{d=" + this.done + " c=" + this.cancelled + " m=" + this.message + " r=" + this.result + "}"; } protected void setMessage(String message) { this.message = message; } private void ensureNotOnMainThread() { Looper myLooper = Looper.myLooper(); Looper mainLooper = Looper.getMainLooper(); if ((null != myLooper) && (myLooper == mainLooper)) { IllegalStateException e = new IllegalStateException("calling on main thread may lead to deadlock and/or ANRs"); throw e; } } }