I am using async task with latest OS Oreo, my issue is onPostExecute() called every time but once in a while it is not getting called. I am wondering which use case is not allowing to get it called.
More details on the task I am doing:-
I am trying to open Bluetooth socket inside doInBackground then return 0 from this method.
mBTConnectTask = new AsyncTask<Void, Void, Byte>() {
#Override
protected void onPreExecute() {
super.onPreExecute();
LogConfig.logd(TAG,"BTConnectTask : onPreExecute show progressBar");
}
#Override
protected Byte doInBackground(Void... params) {
LogConfig.logd(TAG, "Inside startBluetoothProcess");
byte val = BTinit(context);
if (val == 0) {
if (BTconnect()) {
return ErrorStatus.DEVICE_NOT_CONNECTED;
}
} else {
return val;
}
return 0;
}
#Override
protected void onPostExecute(Byte val) {
LogConfig.logd(TAG, "onPostExecute()");
}
};
mBTConnectTask.execute();
Any help will appreciated.
Related
This is my class that i have extended from Asynctask:
public class HttpAsyncTaskSendData extends AsyncTask<String, Void, String> {
public interface SendDataCallback {
void onComplete(AsyncTask task,String nidSave, String guid);
void onError(String msg);
}
...
#Override
protected String doInBackground(String... urls) {
Thread.currentThread().setPriority(Thread.MAX_PRIORITY);
return PostJson.POST(urls[0], urls[1]);
}
#Override
protected void onPostExecute(String result) {
if (result != null) {
...
dataCallback.onComplete(this,res.getString("NidSave"), guid);
} else {
dataCallback.onError("No response from server");
}
}
....
}
I am using this class in my activity like this:
sendDataQueue.add(httpAsyncTaskSendData = new HttpAsyncTaskSendData(cur.getString(cur.getColumnIndex("Guid")),
cur.getString(cur.getColumnIndex("SendStateGps")), datasource, database1
, Housing, new HttpAsyncTaskSendData.SendDataCallback() {
#Override
public void onComplete(AsyncTask task ,String nidSave, String guid) {
if (task.getStatus().equals(AsyncTask.Status.FINISHED) &&
!nidSave.equals("00000000-0000-0000-0000-000000000000")) {
sendDataQueue.remove(task);
} else {
queueHasError = true;
}
if (!queueHasError) {
if (sendDataQueue.size() == 0) {
SendGps(nidSave, guid);
}
}
}
#Override
public void onError(String msg) {
queueHasError = true;
toastError(DetailsActivity.this, msg);
}
}).executeOnExecutor((AsyncTask.THREAD_POOL_EXECUTOR),
AppUtil.getConfig(DetailsActivity.this,
MainActivity.SETTING_GEO_SERVICE) + "SaveVisit/",
json.toString()));
My question is why on onComplete callback when i check Asyncktask status , this is in Running mode? and it is not in Finnish.
My onComplete callback called on onPostExecute and in this section my task should be finished its job!!! but still is running? What's is happen and what's my problem?
onPostExecute is not yet finished, thus the state of the AsyncTask is not FINISH
AsyncTask.Status
FINISHED
Indicates that AsyncTask.onPostExecute(Result) has finished.
I'm working on an Android app by adding a new functionality that fetch and save data with API calls.
These calls are made in a Fragment. There is a call made in an AsyncTask, and I don't want to create an AsyncTask for every call, so I just try send parameters to my controlles in some function, but when I debug every time I try to make a call without using an AsyncTask, I got an IOException "Cancelled". Is there a way to do this without using AsyncTasks in the same Fragment?
This is the AsyncTask:
private void validateUnit(#NonNull String unitCode, final int routeId, final boolean goodCondition) {
mUnitDetails = new UnitDetails();
if (mFindUnitAysncTask != null) {
mFindUnitAysncTask.cancel(true);
}
mFindUnitAysncTask = new AsyncTask<String, Void, FindUnitResponse>() {
#Override
protected void onPreExecute() {
super.onPreExecute();
showProgressDialog();
}
#Override
protected FindUnitResponse doInBackground(String... params) {
FindUnitResponse unitResponse = mUnitController.findUnit(params[0], routeId);
FindUnitDetailsResponse unitDetailsResponse = mUnitController.getUnitDetails(
unitResponse.getUnits().get(0), mUser);
if(unitDetailsResponse.isSuccess()) {
mUnitDetails.setBranchCode(unitDetailsResponse.getBranchCode());
mUnitDetails.setBranchName(unitDetailsResponse.getBranchName());
mUnitDetails.setCompanyId(unitDetailsResponse.getCompanyId());
mUnitDetails.setEconomicNumber(unitDetailsResponse.getEconomicNumber());
mUnitDetails.setFuelType(unitDetailsResponse.getFuelType());
mUnitDetails.setFuelTypeId(unitDetailsResponse.getFuelTypeId());
mUnitDetails.setFuelPrice(unitDetailsResponse.getFuelPrice());
mUnitDetails.setModel(unitDetailsResponse.getModel());
mUnitDetails.setBrand(unitDetailsResponse.getBrand());
mUnitDetails.setUnitType(unitDetailsResponse.getUnitType());
mUnitDetails.setRouteCode(unitDetailsResponse.getRouteCode());
mUnitDetails.setRealTrips(unitDetailsResponse.getRealTrips());
mUnitDetails.setMaximumMileageRange(unitDetailsResponse.getMaximumMileageRange());
}
else {
showMessage(unitDetailsResponse.getMessage());
}
return unitResponse;
}
#Override
protected void onPostExecute(FindUnitResponse response) {
super.onPostExecute(response);
dismissProgressDialog();
if (response != null && response.isSuccess()) {
//Unit unit = response.getUnits().get(0);
unit = response.getUnits().get(0);
finishChecklist(unit, goodCondition);
} else {
showMessage(response.getMessage());
saveChecklist();
}
}
#Override
protected void onCancelled() {
super.onCancelled();
dismissProgressDialog();
}
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, unitCode);
}
With that I fetch the details of a vehicle. Then I have a method called validateMileage.
private void validateMileage(#NonNull Unit unit, #NonNull User user, #NonNull int mileage, int travels,
final boolean dayFinished) {
List<Incident> incidents = mIncidentController.getIncidentList();
Incident suspiciousMileageIncident = mIncidents.get(2);
List<Manager> managers = mManagersController.findByIncidentId(suspiciousMileageIncident.getId());
.....
}
If I just try to make calls like .getIncidentsList or .findByIncidentId I got an IOException when I wait for the response. But if I make the call in an AsyncTask, there is not errors.
In my application, there are multiple asynctasks. Please let me know why doInBackground of an asynctask sometimes does not getting called. Its onPreExecute method gets called. Is there any issue because of multiple asynctasks or something else?
/* ASync class for test table */
public class TestAsynch extends AsyncTask<String, Void, String>{
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected String doInBackground(String... params) {
String status = null;
String result1=API_Manager.getInstance().sendTestData(userName);
try {
if(result1 != null) {
// save in db
}
}
}
catch( Exception e) {
e.printStackTrace();
}
return status;
}
#Override
protected void onPostExecute(String status) {
}
}
If your project has multiple asynctasks you must check that there is a limit of asynctasks that can be executed. When you create a new AsyncTask it will be added on a Pool and will be execute only when is possible.
Check this answer:
Multitasking on android
And the docs: ThreadPoolExecutor
Here is an example on how properly handle multiple AsyncTasks AsyncTaskManager
OnPreExecute() gets called on the UI thread and doInBackground() is called on the background thread.
There is one dedicated background thread for the async task. This behaviour can be changed if you want to.
http://android-er.blogspot.in/2014/04/run-multi-asynctask-as-same-time.html
Now, say you have multiple instances of async task and I'm assuming you are calling execute() to run the async tasks. This will trigger all the preExecute immediately since UI thread is free but for the doInBackground it will triggered one by one. Hence it may take some time for the next async task to start.
doInBackground should run on a loop using a Boolean to check before execution. Before your Task is being executed, set a global boolean (may be true/false) depends on which you prefer and values add on thread should call runOnUiThread.
startExect = true;
new TestAsynch().execute();
then change this
public class TestAsynch extends AsyncTask<String, Void, String>{
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected String doInBackground(String... params) {
String status = null;
String result1=API_Manager.getInstance().sendTestData(userName);
try {
if(result1 != null) {
// save in db
}
}
}
catch( Exception e) {
e.printStackTrace();
}
return status;
}
#Override
protected void onPostExecute(String status) {
}
}
to this
public class TestAsynch extends AsyncTask<String, Void, String> {
String result1 = null;
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected String doInBackground(String... params) {
String status = null;
result1=API_Manager.getInstance().sendTestData(userName);
while (startExecute) {
Thread exe = new Thread(new Runnable() {
#Override
public void run() {
try {
Thread.sleep(5);
}
catch( Exception e) {
e.printStackTrace();
}
runOnUiThread(new Runnable() {
#Override
public void run() {
if(result1 != null) {
// save in db
}
}
});
}
}); exe.start();
}
return status;
}
#Override
protected void onPostExecute(String status) {
}
}
I know that the first you gonna this is... why the heck on the world you then use AsyncTask.
So here is my problem i am working on some Android app (API 7 for android 2.1 or higher) , and i am testing on emulator and everything was fine, so then i tested on HTC Sensation and it says NetworkOnMainThreadExeption!
I was downloading some pictures and then draw on the map.
So to solve this problem every (internet connection) in this case downloading the pictures i must put on AsyncTask to work.
So i need a method how to know when all pictures are done so i can start drawing..
I was trying so much and no result i have no idea. I got one solution with handler but if run on slower net i get nullpointer(because the pictures are not downloaded).
So please help me.
EDIT:
here is the idea:
Bitmap bubbleIcon ;
onCreate(){
...
// i am making call for Async
new ImgDown().execute(url);
//and then i calling functions and classes to draw with that picture bubbleIcon !
DrawOnMap(bubbleIcon);
}
//THIS IS ASYNC AND FOR EX. SUPPOSE I NEED TO DOWNLOAD THE PIC FIRST
class ImgDown extends AsyncTask<String, Void, Bitmap> {
private String url;
public ImgDown() {
}
#Override
protected Bitmap doInBackground(String... params) {
url = params[0];
try {
return getBitmapFromURL(url);
} catch (Exception err) {
}
return null;
}
#Override
protected void onPostExecute(Bitmap result) {
bubbleIcon = result;
bubbleIcon = Bitmap
.createScaledBitmap(bubbleIcon, 70, 70, true);
}
public Bitmap getBitmapFromURL(String src) {
try {
Log.e("src", src);
URL url = new URL(src);
HttpURLConnection connection = (HttpURLConnection) url
.openConnection();
connection.setDoInput(true);
connection.connect();
InputStream input = connection.getInputStream();
// /tuka decode na slika vo pomalecuk kvalitet!
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 3;
Bitmap myBitmap = BitmapFactory
.decodeStream(new FlushedInputStream(input));
Log.e("Bitmap", "returned");
return myBitmap;
} catch (IOException e) {
e.printStackTrace();
Log.e("getBitmapFromURL", e.getMessage());
return null;
}
}
class FlushedInputStream extends FilterInputStream {
public FlushedInputStream(InputStream inputStream) {
super(inputStream);
}
public long skip(long n) throws IOException {
long totalBytesSkipped = 0L;
while (totalBytesSkipped < n) {
long bytesSkipped = in.skip(n - totalBytesSkipped);
if (bytesSkipped == 0L) {
int byteValue = read();
if (byteValue < 0) {
break; // we reached EOF
} else {
bytesSkipped = 1; // we read one byte
}
}
totalBytesSkipped += bytesSkipped;
}
return totalBytesSkipped;
}
}
}
i hope now is more clear.
class OpenWorkTask extends AsyncTask {
#Override
protected Boolean doInBackground(String... params) {
// do something
return true;
}
#Override
protected void onPostExecute(Boolean result) {
// The results of the above method
// Processing the results here
myHandler.sendEmptyMessage(0);
}
}
Handler myHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
switch (msg.what) {
case 0:
// calling to this function from other pleaces
// The notice call method of doing things
break;
default:
break;
}
}
};
You can write your own Delegate to delegate info about finishing the task, using OOP principles:
task_delegate.java
public interface TaskDelegate {
void TaskCompletionResult(String result);
}
main_activity.java
public class MainActivity extends Activity implements TaskDelegate {
//call this method when you need
private void startAsynctask() {
myAsyncTask = new MyAsyncTask(this);
myAsyncTask.execute();
}
//your code
#Override
public void TaskCompletionResult(String result) {
GetSomethingByResult(result);
}
}
my_asynctask.java
public class MyAsyncTask extends AsyncTask<Void, Integer, String> {
private TaskDelegate delegate;
protected MyAsyncTask(TaskDelegate delegate) {
this.delegate = delegate;
}
//your code
#Override
protected void onPostExecute(String result) {
delegate.TaskCompletionResult(result);
}
}
class openWorkTask extends AsyncTask<String, String, Boolean> {
#Override
protected Boolean doInBackground(String... params) {
//do something
return true;
}
#Override
protected void onPostExecute(Boolean result) {
// The results of the above method
// Processing the results here
}
}
I would use a Progress Dialog if I were you. This way users can see that something is happening while the ASyncTask downloads the picture. On PostExecute, call a method from your main code that checks if the pictures are null. Remember you cannot update the UI in the doInBackground method so do any UI work in either onPreExecute or onPostExecute
private class DownloadPictures extends AsyncTask<String, Void, String>
{
ProgressDialog progressDialog;
#Override
protected String doInBackground(String... params)
{
//Download your pictures
return null;
}
#Override
protected void onPostExecute(String result)
{
progressDialog.cancel();
//Call your method that checks if the pictures were downloaded
}
#Override
protected void onPreExecute() {
progressDialog = new ProgressDialog(
YourActivity.this);
progressDialog.setMessage("Downloading...");
progressDialog.setCancelable(false);
progressDialog.show();
}
#Override
protected void onProgressUpdate(Void... values) {
// Do nothing
}
}
I want to catch exception of a thread in doInBackground and print the error message in onPostExcecute. The problem is I don't have the Throwable object in onPostExecute. How to catch Exception in non-UI thread and print the error message in UI-thread?
public class TestTask extends AsyncTask<Void, Void, List<String>> {
#Override
protected List<String> doInBackground(final Void... params) {
try {
...
return listOfString;
} catch(SomeCustomException e) {
...
return null;
}
}
#Override
protected void onPostExecute(final List<String> result) {
if(result == null) {
// print the error of the Throwable "e".
// The problem is I don't have the Throwable object here! So I can't check the type of exception.
}
}
}
Update after Arun's answer:
This is my AsyncTask wrapper class. It intends to do handling Exception in doInBackground but I can't find a good solution to do it.
public abstract class AbstractWorkerTask<Params, Progress, Result>
extends AsyncTask<Params, Progress, Result>
implements Workable {
protected OnPreExecuteListener onPreExecuteListener;
protected OnPostExecuteListener<Result> onPostExecuteListener;
protected ExceptionHappenedListener exceptionHappendedListener;
private boolean working;
#Override
protected void onPreExecute() {
if (onPreExecuteListener != null) {
onPreExecuteListener.onPreExecute();
}
working = true;
}
#Override
protected void onPostExecute(final Result result) {
working = false;
if(/* .........*/ ) {
exceptionHappendedListener.exceptionHappended(e);
}
if (onPostExecuteListener != null) {
onPostExecuteListener.onPostExecute(result);
}
}
#Override
public boolean isWorking() {
return working;
}
public void setOnPreExecuteListener(final OnPreExecuteListener onPreExecuteListener) {
this.onPreExecuteListener = onPreExecuteListener;
}
public void setOnPostExecuteListener(final OnPostExecuteListener<Result> onPostExecuteListener) {
this.onPostExecuteListener = onPostExecuteListener;
}
public void setExceptionHappendedListener(final ExceptionHappenedListener exceptionHappendedListener) {
this.exceptionHappendedListener = exceptionHappendedListener;
}
public interface OnPreExecuteListener {
void onPreExecute();
}
public interface OnPostExecuteListener<Result> {
void onPostExecute(final Result result);
}
public interface ExceptionHappenedListener {
void exceptionHappended(Exception e);
}
}
Change the return type of doInBackground() to Object and when you receive the result in onPostExecute(Object result) use the instanceOf operator to check if the returned result is an Exception or the List<String>.
Edit
Since the result can either be an Exception or else the proper List, you can use the following:
protected void onPostExecute(final Object result) {
working = false;
if(result instanceof SomeCustomException) {
exceptionHappendedListener.exceptionHappended(result);
}
else{
if (onPostExecuteListener != null) {
onPostExecuteListener.onPostExecute(result);
}
}
}
Also change the following statement:
public abstract class AbstractWorkerTask<Params, Progress, Object> extends AsyncTask<Params, Progress, Object>
Just store the Exception into a list and handle it later, as onPostExecute() is always called after doInBackground():
public class TestTask extends AsyncTask<Params, Progress, Result> {
List<Exception> exceptions = new ArrayList<Exception>();
#Override
protected Result doInBackground(Params... params) {
try {
...
} catch(SomeCustomException e) {
exceptions.add(e);
}
return result;
}
#Override
protected void onPostExecute(Result result) {
for (Exception e : exceptions) {
// Do whatever you want for the exception here
...
}
}
}
This is doable but rarely used, as in most situation, we want handle the exception as soon as it get thrown and catched:
public class TestTask extends AsyncTask<Params, Progress, Result> {
#Override
protected Result doInBackground(Params... params) {
try {
...
} catch(SomeCustomException e) {
// If you need update UI, simply do this:
runOnUiThread(new Runnable() {
public void run() {
// update your UI component here.
myTextView.setText("Exception!!!");
}
});
}
return result;
}
}
Hope this make sense.
Changing the return type of doInBackground to Object to possibly pass an Exception and then use instanceof() is a source of code smell (bad programming practice). It is always preferable to restrict your return type to the very specific thing you want returned.
Based on this answer simply add a private member to store the exception thrown in doInBackground and then check for it first thing in onPostExecute.
Only one Exception need be caught because you should stop the actions in doInBackground immediately once the exception is thrown and handle it gracefully in onPostExecute where you have access to the UI elements and so can inform the user of the mishap.
Generic example (body of the AsyncTask):
private Exception mException
#Override
protected Result doInBackground(Params... params) {
try {
// --- Do something --- //
}
catch( SomeException e ){ mException = e; return null; }
}
#Override
protected void onPostExecute(Result result) {
if (mException != null) {
// --- handle exception --- //
return;
}
// --- Perform normal post execution actions --- //
}