I'm writing a library, which does some intensive network work. So, I'm using a HandlerThread to carry out this operation like this:
Looper.prepare();
libraryThread = new LibraryHandlerThread(context);
libraryThread.start();
libraryThread.getLooper();
LibraryHandlerThread does the network operations and other time consuming operations.
When I call this code from a worker thread (any thread other than Main thread), it works fine. But complains about "can't initialize another looper when one is already active". I believe that a Looper runs on Main thread by default, and complains about Looper.prepare(). I can do something like following to make it working from Main thread:
Looper.getMainLooper().quit();
Looper.prepare();
libraryThread = new LibraryHandlerThread(context);
libraryThread.start();
libraryThread.getLooper();
My question is: what would be the impact on Main thread. In my ideal world, I want to run my library's operations on a separate thread without impacting the main thread. How can I achieve this without much destruction?
Try the below code:
private static final HandlerThread sWorkerThread = new HandlerThread("network-operations");
static {
sWorkerThread.start();
}
private static final Handler sWorker = new Handler(sWorkerThread.getLooper());
What you will want to look into is using a Asynctask to run this in the background which will allow your main thread to keep working http://developer.android.com/reference/android/os/AsyncTask.html
Or you can create a service if this is something that you will need constantly running. http://developer.android.com/reference/android/app/Service.html
Related
My goal is to run multiple objects concurrently without creating new Thread due to scalability issues. One of the usage would be running a keep-alive Socket connection.
while (true) {
final Socket socket = serverSocket.accept();
final Thread thread = new Thread(new SessionHandler(socket)).start();
// this will become a problem when there are 1000 threads.
// I am looking for alternative to mimic the `start()` of Thread without creating new Thread for each SessionHandler object.
}
For brevity, I will use Printer anology.
What I've tried:
Use CompletableFuture, after checking, it use ForkJoinPool which is a thread pool.
What I think would work:
Actor model. Honestly, the concept is new to me today and I am still figuring out how to run an Object method without blocking the main thread.
main/java/SlowPrinter.java
public class SlowPrinter {
private static final Logger logger = LoggerFactory.getLogger(SlowPrinter.class);
void print(String message) {
try {
Thread.sleep(100);
} catch (InterruptedException ignored) {
}
logger.debug(message);
}
}
main/java/NeverEndingPrinter.java
public class NeverEndingPrinter implements Runnable {
private final SlowPrinter printer;
public NeverEndingPrinter(SlowPrinter printer) {
this.printer = printer;
}
#Override
public void run() {
while (true) {
printer.print(Thread.currentThread().getName());
}
}
}
test/java/NeverEndingPrinterTest.java
#Test
void withThread() {
SlowPrinter slowPrinter = new SlowPrinter();
NeverEndingPrinter neverEndingPrinter = new NeverEndingPrinter(slowPrinter);
Thread thread1 = new Thread(neverEndingPrinter);
Thread thread2 = new Thread(neverEndingPrinter);
thread1.start();
thread2.start();
try {
Thread.sleep(1000);
} catch (InterruptedException ignored) {
}
}
Currently, creating a new Thread is the only solution I know of. However, this became issue when there are 1000 of threads.
The solution that many developers in the past have come up with is the ThreadPool. It avoids the overhead of creating many threads by reusing the same limited set of threads.
It however requires that you split up your work in small parts and you have to link the small parts step by step to execute a flow of work that you would otherwise do in a single method on a separate thread. So that's what has resulted in the CompletableFuture.
The Actor model is a more fancy modelling technique to assign the separate steps in a flow, but they will again be executed on a limited number of threads, usually just 1 or 2 per actor.
For a very nice theoretical explanation of what problems are solved this way, see https://en.wikipedia.org/wiki/Staged_event-driven_architecture
If I look back at your original question, your problem is that you want to receive keep-alive messages from multiple sources, and don't want to use a separate thread for each source.
If you use blocking IO like while (socket.getInputStream().read() != -1) {}, you will always need a thread per connection, because that implementation will sleep the thread while waiting for data, so the thread cannot do anything else in the mean time.
Instead, you really should look into NIO. You would only need 1 selector and 1 thread where you continuously check the selector for incoming messages from any source (without blocking the thread), and use something like a HashMap to keep track of which source is still sending messages.
See also Java socket server without using threads
The NIO API is very low-level, BTW, so using a framework like Netty might be easier to get started.
You're looking for a ScheduledExecutorService.
Create an initial ScheduledExecutorService with a fixed appropriate number of threads, e.g. Executors.newScheduledThreadPool(5) for 5 threads, and then you can schedule a recurring task with e.g. service.scheduleAtFixedRate(task, initialDelay, delayPeriod, timeUnit).
Of course, this will use threads internally, but it doesn't have the problem of thousands of threads that you're concerned about.
Summary
Room immediately inserts entities generated through UI, but delays those sent by an asynctask until the (far) end of the generating asynctask : the entity objects received are usable and displayed on UI, but without any id from database, hampering any other operation relying on id.
The insert operation happens only when the generating asynctask is properly stopped: Why? And how to solve this?
More context
The generating asynctask
We use an asynctask to monitor a socket and send back some events (as Room entity) to the application repository (as intended by android architecture components). This asynctask basically runs continuously in background (with some sleep regularly set) and is only stopped a while before the end of use of the application (if done right). So far it hasn't caused any issue for us to deviate so much from the original concept of short-lived asynctask.
I am pretty much aware we could improve the design, but this is another subject/question/time-hole ;-).
Room insert operation
Insertion happens through a dedicated asynctask, where the returned id of the entry in database is affected back to the entity just inserted (see code below). This is logged and entities from UI are persisted "immediately", they get back their ID and all is well. The asynctask-generated entities, well they wait for their "parent" task to stop and are then all inserted.
Entity composition
At first, the entity was generated inside the asynctask and sent through progress message. Then the construction of the object was moved outside of the asynctask and at the same level of the UI event construction, yet same behavior.
These events are some longs (timestamps) and several strings.
From the generating asynctask all starts from here:
#Override
protected void onProgressUpdate(OnProgressObject... values) {
OnProgressObject onProgressObject = values[0];
if (onProgressObject instanceof OnProgressEvent) {
eventRecipient.sendAutoEvent(((OnProgressEvent) onProgressObject).autoEvent);
}
}
The eventRecipient is the EventsRepository:
public void sendAutoEvent(AutoEvent autoEvent) {
Log.d(LOG_TAG, "got an autoevent to treat...");
EventModel newEvent = EventModel.fromCub(
autoEvent.cubTimeStamp,
autoEvent.description,
autoEvent.eventType
);
addEvent(newEvent);
}
public void addEvent(EventModel event) {
new insertEventAsyncTask(event).execute(event);
// other operations using flawlessly the "event"...
}
private class insertEventAsyncTask extends AsyncTask<EventModel, Void, Long> {
private EventModel eventModel;
public insertEventAsyncTask(EventModel eventModel) {
this.eventModel = eventModel;
}
#Override
protected Long doInBackground(EventModel... eventModels) {
// inserting the event "only"
return eventDao.insert(eventModels[0]);
}
#Override
protected void onPostExecute(Long eventId) {
super.onPostExecute(eventId);
// inserting all the medias associated to this event
// only one media is expected this way though.
eventModel.id = eventId;
Log.d(LOG_TAG, "event inserted in DB, got id : " + eventId);
}
}
I am pretty much aware we could improve the design, but this is another subject/question/time-hole
Since I suspect that it is the cause of your current problem, perhaps you should not dismiss this.
My interpretation of your problem is: you have an outer AsyncTask (the one with the onPublishProgress() method shown in the first code listing). You are executing that with execute(). Inside of that outer AsyncTask you have an inner AsyncTask (the one from your repository). You are executing that with execute(). And, your complaint is that the inner AsyncTask does not run until the outer AsyncTask completes.
If so, your problem is that execute() is single-threaded, and you are tying up that thread by having an AsyncTask run indefinitely. Until your outer AsyncTask completes its background work and returns from doInBackground(), the inner AsyncTask is blocked.
The "can we keep using hacks?" solution is to continue using AsyncTask but switch to executeOnExecutor() instead of execute(), supplying a thread pool to use. AsyncTask.THREAD_POOL_EXECUTOR would be a candidate.
The "OK, can we clean this up a little bit?" solution is to replace both AsyncTask instances with either simple Thread objects or the direct use of some multi-thread thread pool (see Executors). AsyncTask is obsolete, but to the extent that it is useful, only use it when you need to do work on the main application thread (onPostExecute()) after completing the background work (doInBackground()). Neither of your AsyncTask implementations need to be doing work on the main application thread after the background work is complete, so you do not need an AsyncTask for either of them. So, for example, your run-forever thread could be a Thread, while you use a thread pool inside of your repository for your DAO calls.
(the "hey, can we get modern on our threading, to go along with our use of Architecture Components?" solution is to switch to RxJava or Kotlin coroutines, in conjunction with LiveData — this is much more work, but they each have their own merits over manual thread management)
Why ?
Basically, it was written in the AsyncTask documentation : all asynctasks are executed serially on a unique background thread.
My code, even without nested asynctask, was blocking this thread with an almost never-ending task, delaying all database operations until its completion (or app crash, hence some data loss).
A quick solution : moving an AsyncTask to a Thread
Other alternatives were nicely listed by (CommonsWare)[https://stackoverflow.com/a/56925864/9138818], here are the steps I followed that solved this issue.
The main difficulty was to redirect code that was executed on UI thread (onPreExecute, onProgressUpdate, onPostExecute) through a Handler associated to the main thread.
First step was get a reference to a handler :
// Inside Runnable task's constructor :
// get the handler of the main thread (UI), needed for sending back data.
this.uiHandler = new Handler(Looper.getMainLooper());
Then, the "doInBackground" is refactored to fit a Runnable main method signature :
// previously "public String doInBackground()"
// returned value handled through publishProgress.
#Override
public void run() {
// recommended by Android Thread documentation
android.os.Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
// code previously in doInBackground
Now, code in the onProgressUpdate (that was called by publishProgress inside doInBackground method) was moved into a Runnable posted on the UI thread handler :
// asynctask method onProgressUpdate was renamed publishProgress =>
// doInBackground's body is almost untouched.
private void publishProgress(final OnProgressObject... values) {
uiHandler.post(new Runnable() {
#Override
public void run() {
// move here code previously in the AsyncTask's publishProgress()
}
});
}
At last, I had to change the way the task was created, runned and stopped by using Thread.interrupted instead of isCancelled and by creating the Runnable task before the thread :
public void startCUBMonitoring() {
if (autoEventThread == null) {
Log.d(LOG_TAG, "startCUBMonitoring");
addUIEvent("CUB MONITORING STARTED", "CUB_connexion");
SessionRepository sessionRepository =
ElabsheetApplication.getInstance().getSessionRepository();
// Creation of the task
AutoEventTask autoEventTask = new AutoEventTask(
this,
sessionRepository,
sessionRepository.getCUBConfig()
);
autoEventThread = new Thread(autoEventTask);
autoEventThread.start();
}
}
public void stopCUBMonitoring() {
if (autoEventThread != null) {
Log.d(LOG_TAG, "stopCUBMonitoring");
addUIEvent("CUB MONITORING STOPPED", "CUB_connexion");
autoEventThread.interrupt();
autoEventThread = null;
}
}
Hoped it could help...
My Situation :
I'm communicating with a sensor using BLE, sending 'Session' objects, as strings, from the sensor to the android device.
When all the sessions are on the android device, I call a session on the UI thread that uploads them to a server using Volley. (call 'uploadSessions()')
When all the sessions are on the server, (After I receive a Response from the server confirming they have been received), I need to erase the sensor's memory. (onResponse calls 'sessionsSuccessfullyUploaded()')
PROBLEM : I can't access functions in the GattCallback from the UI thread (cannot call 'eraseDevice()' from 'sessionsSuccessfullyUploaded()')
What I've tried: I've tried looping,
I do this in the callback :
public void waitForServerResponse() {
int WAIT_INTERVAL = 500;
new Handler().postDelayed(new Runnable() {
#Override
public void run () {
if(sessionCountUploadedToServer == IBSessionCount) {
eraseDevice();
} else waitForServerResponse();
}
},WAIT_INTERVAL);
}`
I get this error :
java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
Look into Broadcast Intents and Receivers. This document can help:
http://www.techotopia.com/index.php/Android_Broadcast_Intents_and_Broadcast_Receivers
It would also help to put the callback in a special Bluetooth Service Class that extends Service
mHandler is created from non-UI thread. If you want to do any UI operations then make sure you create it on the main thread.
If you do not intend to do UI Operations then call Looper.Prepare() as the error suggests to you - in the thread which is constructing the handler.
Create the mHandler as below :
HandlerThread mHandlerThread = new HandlerThread("tHandlerThread");
mHandlerThread.start();
mHandler = new Handler(mHandlerThread.getLooper());
Alternatively you can also consider using AsyncTask or IntentService - these might be more suited for what you are trying to do - background operations.
I have an activity running, of course, on UI thread and there is another thread running in background and communicating with activity using Handler post method(through looper).
When screen is turned of or application is hidden it continues to work.
So I need to stop this thread in onPause method and wake it up in onResume mehtod.
In my thread I have condition to pause it or to stop.
How to can I put thread to sleep in onPause method. And wake it up after activity is again in foreground.
I can do it with one object using monitor calling wait method and than notify on this object.
But is it good approach ? Or there is another way to do this elegantly.
Sounds like a good place to use a turnstile. Initialize a Semaphore with one permit:
Semaphore turnstile = new Semaphore(1);
Make your background activity periodically pass through the turnstile like so:
turnstile.acquire();
turnstile.release();
When the foreground thread wants the background thread to pause at the turnstile, it can lock the turnstile:
turnstile.acquire();
And when the foreground thread wants that background thread to start working again, it can unlock the turnstile():
turnstile.release();
Good software engineering practice would be to wrap the whole thing up in a Turnstile class with appropriately named methods for the foreground and background threads to call. I'll leave that as an exercise for the reader.
Android suggests using services for long term background tasks, but if you're just opening a new thread that is tied to your Android lifecycle, I don't think it would be bad to use a monitor and call wait/notify. Can you be more specific with what you are doing?
This is an overview of how I would stop and resume a stopped thread. (You may want to implement runnable in yours)
class ThreadDemo extends Thread {
private Object monitor; //This is the monitor
private boolean keepRunning = true;
private Thread t;
ThreadDemo(){
System.out.println("Creating thread");
}
public void callinOnResume(){
synchronized(monitor){
monitor.notify();
}
}
public void callinOnPause(){
try {
synchronized(monitor){
System.out.println(threadName + "Waiting");
monitor.wait();
}
} catch (InterruptedException e) {
System.out.println("Thread interrupted " + e.toString());
}
}
public void run() {
System.out.println("Starting to loop.");
while (keepRunning) {
//stuff
}
System.out.println("Done looping.");
}
public void start ()
{
System.out.println("Starting " + threadName );
if (t == null)
{
t = new Thread (this, threadName);
t.start ();
}
}
}
It is a bad practice to stop/resume a thread outside that thread. The thread must decide itself when to run and when to stop. As a result, the background thread should check periodically if its work is still needed, and the client (foreground) thread should issue some signals about that.
One way to issue signals is to form that signals as jobs of type Runnable and then execute them on a thread pool. So when the activity sleeps, it just does not issue signals.
The main problem when a background thread wants to update the UI is that the target Activity can be closed (or in the process of recreation) and the updating task fails. The AcyncTask class does not solve this problem. A correct solution is published at my Github workspace. But before to use this or another solution, think twice if you really need a background thread. The best way is not to use background thread at all, making all UI updates directly on the UI thread. Of course, if updates are taken from the network, then a background thread must be used.
My application is to use nanoHTTPD as an alternative to pressing buttons and keying in text on an Android UI for automation and regression test I currently have a main UI thread and a customized nanoHTTPD running in a different thread. Consider each HTTP request will be serviced very quickly in the UI thread. I think my model could be simplified if I could force nanoHTTPD to NOT start a new thread for each incoming request. I would not mind the blocking I/O model at all for my use cases. I see there is a pluggable strategy for threading. Can the below be modified such that only one web request is active at a time (blocking model)?
public static class DefaultAsyncRunner implements AsyncRunner {
private long requestCount;
#Override
public void exec(Runnable code) {
++requestCount;
Thread t = new Thread(code);
t.setDaemon(true);
t.setName("NanoHttpd Request Processor (#" + requestCount + ")");
t.start();
}
}
I could probably also do more elaborate message queues but "dumbing-down" to nanoHTTPD in one thread seems simplest.