Multithreading library for Android.
Needle makes multithreading simple on Android.
Are you struggling with Thread
, Handler
, Looper
, AsyncTask
, ThreadPoolExecutor
, FutureTask
, View.post()
or Activity.runOnUiThread()
?
Needle.onMainThread().execute(new Runnable() {
@Override
public void run() {
// e.g. change one of the views
}
});
You might be better off using Needle
.
Needle supports Android 1.5 (API Level 3) and above; and it behaves the same on all platform versions.
Needle.onMainThread().execute(new Runnable() {
@Override
public void run() {
// e.g. change one of the views
}
});
Needle.onBackgroundThread().execute(new Runnable() {
@Override
public void run() {
// something cpu-intensive and/or not UI-related
}
});
The executor returned by onBackgroundThread()
has a thread pool with 3 (Needle.DEFAULT_POOL_SIZE
) threads. If all threads in the pool are busy executing code then Runnable
instances are enqueued and executed as soon as possible.
This way you can make sure you never bog down the CPU with a lot of concurrent threads; number of concurrent threads is bounded.
Needle.onBackgroundThread().withThreadPoolSize(6).execute(new Runnable() {
@Override
public void run() {
// something that blocks often thus can have a larger thread pool,
// for instance, downloading a file (with blocking IO)
}
});
Subsequent executors obtained with
Needle.onBackgroundThread()
.withThreadPoolSize(poolSize)
with the same poolSize
parameter will use the same thread pool.
Needle.onBackgroundThread()
is equivalent to
Needle.onBackgroundThread()
.withThreadPoolSize(Needle.DEFAULT_POOL_SIZE)
Needle.onBackgroundThread().serially().execute(new Runnable() {
@Override
public void run() {
// something that we want to do serially but not on the main thread
}
});
Needle.onBackgroundThread().serially()
is equivalent to
Needle.onBackgroundThread()
.withThreadPoolSize(1)
Needle
.onBackgroundThread()
.withTaskType("file-downloading")
.execute(new Runnable() {
@Override
public void run() {
// downloading a file in a thread pool
// different from thread pool of "image-processing"
}
});
Needle
.onBackgroundThread()
.withTaskType("image-processing")
.execute(new Runnable() {
@Override
public void run() {
// processing an image in a thread pool
// different from thread pool of "file-downloading"
}
});
Needle
.onBackgroundThread()
.withTaskType("cpu-inensive-but-has-to-be-serial")
.withThreadPoolSize(1)
.execute(new Runnable() {
@Override
public void run() {
// something that we want to do serially but not on the main thread
}
});
Needle
.onBackgroundThread()
.withTaskType("something-else-that-has-to-be-serial")
.serially()
.execute(new Runnable() {
@Override
public void run() {
// something else that we want to do serially
// and also not on the main thread
// and should not interfere with
// "cpu-inensive-but-has-to-be-serial" tasks
}
});
Tasks with different types will be executed independently from each other, i.e. each task type will have its own, separated thread pool.
To be more precise, in case of these two calls
Needle.onBackgroundThread()
.withThreadPoolSize(poolSizeA)
.withTaskType(taskTypeA)
.execute(runnableA)
and
Needle.onBackgroundThread()
.withThreadPoolSize(poolSizeB)
.withTaskType(taskTypeB)
.execute(runnableB)
tasks runnableA
and runnableB
will be executed in the same thread pool if, and only if, poolSizeA
equals poolSizeB
and taskTypeA
equals taskTypeB
.
Needle.onBackgroundThread().withTaskType(taskType)
is equivalent to
Needle.onBackgroundThread()
.withTaskType(taskType)
.withThreadPoolSize(Needle.DEFAULT_POOL_SIZE)
Needle.onBackgroundThread().withThreadPoolSize(poolSize)
is equivalent to
Needle.onBackgroundThread()
.withTaskType(Needle.DEFAULT_TASK_TYPE)
.withThreadPoolSize(poolSize)
Needle.onBackgroundThread().execute(new UiRelatedTask<Integer>() {
@Override
protected Integer doWork() {
int result = 1+2;
return result;
}
@Override
protected void thenDoUiRelatedWork(Integer result) {
mSomeTextView.setText("result: " + result);
}
});
Callback thenDoUiRelatedWork(Result result)
is executed on the UI/main thread.
Needle.onBackgroundThread().execute(new UiRelatedProgressTask<String, Integer>() {
@Override
protected String doWork() {
int result = 0;
for (int i = 0; i < 10; i++) {
result += 1;
publishProgress(result);
}
return "The result is: " + result;
}
@Override
protected void thenDoUiRelatedWork(String result) {
mSomeTextView.setText(result);
}
@Override
protected void onProgressUpdate(Integer progress) {
mSomeTextView.setText("progress: " + progress);
}
});
Both thenDoUiRelatedWork(Result result)
and onProgressUpdate(Progress progress)
are executed on the UI/main thread.
CancelableTask task = new CancelableTask() {
@Override
protected void doWork() {
// will be never executed
}
};
task.cancel();
Needle.onBackgroundThread().execute(task);
Passing a task to .execute()
that is not canceled doesn't necessarily mean that it will be executed. If the task gets canceled while it is waiting it the thread pool queue (because all threads are busy to process it) then it won't be executed either (ever).
CancelableTask task = new CancelableTask() {
@Override
protected void doWork() {
int lotOfIterations = ...;
for (int i=0; i < lotOfIterations; i++) {
if (isCanceled()) {
break;
} else {
// work on current iteration
}
}
}
};
Needle.onBackgroundThread().execute(task);
// a little time goes by
task.cancel();
In case your task takes a very long time to execute you may want to check inside doWork()
whether the task has been canceled - to stop execution.
Classes CancelableTask
, UiRelatedTask
and UiRelatedProgressTask
are all cancelable.
The source code of Needle is available on GitHub.
<dependency>
<groupId>com.zsoltsafrany</groupId>
<artifactId>needle</artifactId>
<version>1.0.0</version>
</dependency>
compile 'com.zsoltsafrany:needle:1.0.0'
The MIT License (MIT)
Copyright (c) 2014 Zsolt Safrany
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.