Why do I need a Looper in my AsyncTask? - java

I want to use AsyncTask for update my db4o with a server. In the doInBackground method , I connect to the server, update the db4o, and schedule a pendingintents. Not modify UI or show any toast.
Initially, I had the following error:
Can't create handler inside thread that has not called Looper.prepare()
After adding the Looper.prepare(), works fine, but only for five updates (AsyncTask). I've read this topic: AsyncTask threads never die (Android) , and I don't now that fails. When I throw the sixth update, the app crashes:
FATAL EXCEPTION: AsyncTask #1
java.lang.RuntimeException: An error occured while executing doInBackground()
at android.os.AsyncTask$3.done(AsyncTask.java:200)
at java.util.concurrent.FutureTask$Sync.innerSetException(FutureTask.java:274)
at java.util.concurrent.FutureTask.setException(FutureTask.java:125)
at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:308)
at java.util.concurrent.FutureTask.run(FutureTask.java:138)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1088)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:581)
at java.lang.Thread.run(Thread.java:1019)
Caused by: java.lang.RuntimeException: Only one Looper may be created per thread
at android.os.Looper.prepare(Looper.java:74)
(...)
I've read in the documentation that I need the Looper.loop(), but whith this, the app crashes..
Example:
protected Integer doInBackground(Void... params) {
Looper.prepare();
update = new Update();
update.checknewObjects();
update.deleteOldObjects();
update.updateObjects();
Looper.loop();
}
Why do I need Looper?
Why the app crashes after five updates?
Where can I schedule Looper.loop()?
Thanks in advance!

If you want to use AsyncTask so use it, you shouldn't mix it with Lopper...
protected Integer doInBackground(Void... params) {}
already working on background thread and there is no reason to call Lopper, for what?
If your application need to do some kind of long computation so AsyncTask is very good tool for it because offers methods which working on UI Thread and allow to update UI with some progress of work because every User that will use your application should know that application "doing something" (when it takes more than 2-5 seconds).
Also it's generic and that provide some benefits.
If you do not need to update UI just use for example Handler.

If you want to schedule tasks you should use Timer & TimerTask, from what I understand I think they should fit better to your needs.
http://developer.android.com/reference/java/util/Timer.html

in asynck Task you can't use looping in background function .it giving error

Related

Why android room inserts an object at the end of the asynctask generating it (the object)?

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...

Handling the closing of App By Android

I have created an App which requires to run a operation in background for quite some time suppose 10 - 15 mins.
I am running this operation in An AsyncTask. So during this time the user is minimizing the Screen and using his other apps in his phone as usual.
When this operation is started I am creating a Progress Dialog box and then keep updating it regularly.
But this is the error which I am receiving sometimes very rarely once the operation is over
Fatal Exception: java.lang.IllegalArgumentException
View=DecorView#1234567[ABC:] not attached to window manager PackageName
And this is the detailed stack log
Fatal Exception: java.lang.IllegalArgumentException
View=DecorView#1234567[ABC:] not attached to window manager PackageName
at android.view.WindowManagerGlobal.findViewLocked(WindowManagerGlobal.java:508)
at android.view.WindowManagerGlobal.removeView(WindowManagerGlobal.java:417)
at android.view.WindowManagerImpl.removeViewImmediate(WindowManagerImpl.java:136)
at android.app.Dialog.dismissDialog(Dialog.java:446)
at android.app.Dialog.dismiss(Dialog.java:429)
at android.app.Dialog.cancel(Dialog.java:1353)
at PACKAGENAME
at android.app.Activity.runOnUiThread(Activity.java:6078)
at PACKAGENAME
at PACKAGENAME
at android.os.AsyncTask.finish(AsyncTask.java:667)
at android.os.AsyncTask.-wrap1(AsyncTask.java)
at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:684)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6823)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1557)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1445)
To my knowledge this error is because the Android OS wanted to release some memory hence my App was closed since this was not visible to the user. But is there any way to tackle this thing?
Any help would be really appreciated.
EDIT: This is the code which I am using
public class load extends AsyncTask<Void, Void, Void> {
#Override
public Void doInBackground(Void... voids) {
for(int i=0;i<number;i++){
PerformSomeOperation();
UpdateTheProgress();
}
return null;
}
#Override
protected void onPostExecute(Void n) {
runOnUiThread(new Runnable() {
#Override
public void run() {
mProgressDialog.cancel();
CreateAnotherDialog();//This dialog is created to show the user completion of the progress.
}
});
}
You're having this crash because you're trying to update the UI when it's in the background so your Activity could be destroyed at that point. By the way, onPostExecute runs your code on the main thread already but as you're sending a separate message to the main looper you're postponing your logic a bit which can also cause a problem. Moreover, But the main question - why to update the UI if it's not visible to the user anyways?
Also, because you're using the AsyncTask as an inner class you may leak (though temporarily) your Activity object as it's referenced implicitly by the task.
From Android Documentation:
AsyncTasks should ideally be used for short operations (a few seconds
at the most.) If you need to keep threads running for long periods of
time, it is highly recommended you use the various APIs provided by
the java.util.concurrent package such as Executor, ThreadPoolExecutor
and FutureTask.
So, don't use AsyncTasks for long-running operations. A better approach would be to use:
IntentService together with BroadcastReceiver to communicate with your Activity / Fragment (in API >= 26 you should use JobIntentService as IntentService may misbehave due to new restrictions on background services).
RxAndroid (or just ExecutorService/Thread) together with Architecture-Components (more specifically with LiveData) - this way a result of your task can be cached or it can survive the config change.
My personal favourite is option 2.
There are few things to say: (1) the "onPostExecuted()" method is already executed on the UiThread/MainThread, so "runOnUiThread()" is not required. (2) if the Activity is minimized/destroyed when the Asynctask reach the final pass you get an Exception. So you have to check if the View is attached using "View. IsAttachedToWindow()" before execute some GUI methods like "mProgressDialog.cancel()". (3) you have to create a Thread or a Service to do a task that should run/work more than few seconds, or the System could kill it at anytime.

how to terminate AsyncTask in Android?

I'm currently have an Android application with 3 activities.
Main activity:
Constantly polling a Xml file using AsyncTask and update UI using onPostExecute.
The AsyncTask is loop by:
Handler.postDelayed(runnableCode, Poll_internval);
Second Activity:
Does the same thing, pulling Xml using another AsyncTask and update UI using onPostExecute.
loop by :
Handler.postDelayed(runnableCode, Poll_internval);
How should i kill the AsyncTask as it is constantly looping?
Would like to kill it when ending this activity with finish();
There is no way to cancel the AsyncTask, even with cancel method.
You need to implement your logic for canceling the task manually, see this link :
How to completly kill/remove/delete/stop an AsyncTask in Android
You can use like:
Asyn mAsyn = new Asyn();
mAsyn.execute();
if(mAsyn.isCancelled()){
mAsyn.cancel(true);
}
There is provision,
you can remove async task in call back in handler, there is method
handler.removeCallbacks(runnable);
In Asynctask there is status, you have to develop logic and check status code.
AsyncTask statuc
In my project, i have same condition and i developed this kind of logic, it work in my code.
please check it.
Have a look at the androidannotations framework, that has support for running async tasks and also cancelling them. You can checkout the details here:
https://github.com/excilys/androidannotations/wiki/WorkingWithThreads#background]
Basically, all you need to do is annotate the method that needs to run in another thread with
#Background(id="cancellable_task")
void someCancellableBackground(String aParam, long anotherParam) {
[...]
}
where "id" is the id of the new thread. Then, to cancel it you just call
BackgroundExecutor.cancelAll("id");

Android Main Thread Looper concern

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

Is there any way to stop background thread without process kill in Android?

My application has one service which runs until user pressed exit button. I know giving exit button in android is not good design but in my application it is desired.
In my application I also have a thread to send Http request, download a file and then parse it in background so that UI will not block. In my thread's run method there are sequential steps (like download a file, then parse it), there is no while or for loop in it.
When user presses exit button, is there any way to stop the background thread if it is running without kill process (using Process.kiil(pid) or System.exit(0)) ?
I have tried AsyncTask also. Whatever in run method of thread, i put it in doInBackground method. When user presses exit button i have canceled asynctask. Cancelling task not stop the background thread completely because after file download it will go in parser to parse the file (i.e. parsing is done in background thread but it at the time of parsing it is not in doInBackground or run method. It will in parsing method of parser class or in Default handler class for parsing.)
From googling I read many blogs and other stackoverflow questions about thread but still I cannot find any solution for it.
Please help....thanks in advance..
before each step you could add a line like
if(stillRunning){
//next step
}
and when you want it to stop, you just set stillRunning to false.
(1) use this to stop application instead of exit
finish();
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
intent.addCategory(Intent.CATEGORY_HOME);
startActivity(intent);
(2) use new Thread instead of asynk task which you can stop by calling stop method
Thread myThread = new Thread ()
{
public void run()
{
Looper.prepare();
doMyWork();
}
}.start();
and call stop on myThread
Probably, your connection and parser use same InputStream. If you quit, try to close the stream and a connection. In that case, some kind of Exception will be thrown and background thread will finish job with error but very fast. If you are in the middle of file saving, you must check every write(buffer) if you are canceled or try to close FileOutputStream.
Stop thread at instance (when exit event occurred from UI) is not possible without using
Process.killProcess(Process.myPid());

Categories