Cannot run new instance of async task at android 4.2 - java

I have code, which perfectly runs on android 2.3.3, but doesn't run on android 4.2. When activity is starting, it should call instance of Initialize class which extends AsyncTask. But, at first activity start - it works, when I go to other activity and back - progress spinner is rotating and nothing happens, even exception isn't throwing.
I tried to debug this, it go to calling of execute() of new instance of Initialize and doesn't go inside doInBackground() of Initialize
Is this a problem only with android 4.2 or problem in other?
protected void onStart() {
super.onStart();
if (orders != null) {
try {
spinner.setVisibility(View.GONE);
progress.setVisibility(View.VISIBLE);
new Initialize().execute();
} catch (Exception e) {
spinner.setVisibility(View.VISIBLE);
progress.setVisibility(View.GONE);
Log.d("Error","exception: " + e.getMessage());
}
}
}
Initialize
private class Initialize extends AsyncTask<Void, Void, Void> {
#Override
protected Void doInBackground(Void... params) {
try {
if (orders == null || orders.isEmpty()) {
orders = new ArrayList<Order>();
BaseProcess Proc = new BaseProcess(MainActivity.this);
orders.addAll(Proc.getOrdersFromBase());
Proc.database.close();
Proc.close();
}
} catch (Exception ex) {
Log.d("Error","exception " + ex.getMessage());
}
return null;
}
#Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
adapter.notifyDataSetChanged();
update();
}
}

there are others AsyncTasks, what should I do?
First, only use AsyncTask for fairly short bits of work. AsyncTask is not suitable for where the work may take an indefinite amount of time (e.g., listening on a socket for incoming chat messages for a chat app).
Beyond that, use executeOnExecutor() on API Level 11+ to opt into the THREAD_POOL_EXECUTOR, which is the default behavior for execute() between API levels 4 and 10.

Related

Replicating Swift completion handler on Android & Java

After years, I'm trying to develop an Android app, using Firebase Firestore. I'm basically trying to replicate this Swift function:
func getCategories(onCompletion completionBlock: #escaping (_ categories: [Category]?, _ error: Error?) -> Void) {
firestore.collection("cats").getDocuments { (snap, error) in
guard let snap = snap else {
completionBlock(nil, error ?? anUnknownError)
return
}
var categories: [Category] = []
for document in snap.documents {
let cat = Category.init(data: document.data())
categories.append(cat)
}
completionBlock(categories, nil)
}
}
But I have no idea what is the equivalent of swift's blocks, even don't know if it exists.
I checked Firebase source codes. Query.get() returns Task<QuerySnapshot> so I tried to return a Task<List<Category>> without luck.
Any Help? Thank you.
EDIT: Android code added to clarify what I'm trying to do.
public class FirestoreService {
private static volatile FirestoreService singleton = new FirestoreService();
public static FirestoreService getInstance() {
return singleton;
}
private FirebaseFirestore firestore() {
// default firestore instance
FirebaseFirestore db = FirebaseFirestore.getInstance();
// default firestore settings
FirebaseFirestoreSettings settings = db.getFirestoreSettings();
// firestore settings builder
FirebaseFirestoreSettings.Builder builder = new FirebaseFirestoreSettings.Builder(settings);
// enable timstamps
builder.setTimestampsInSnapshotsEnabled(true);
// set new settings to db instance
db.setFirestoreSettings(builder.build());
// return db with new settings.
return db;
}
public void getProductCategories(Handler? handler) {
Task<QuerySnapshot> task = firestore().collection("coll").get();
task.addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
#Override
public void onComplete(#NonNull Task<QuerySnapshot> task) {
try {
if (task.isSuccessful()) {
List<Category> cats = new ArrayList<>();
for (QueryDocumentSnapshot doc : task.getResult()) {
String id = doc.getId();
Map<String, Object> data = doc.getData();
Category cat = new Category(id, data);
cats.add(cat);
}
// now I need completion handler
} else {
Log.w("ERROR", "Error getting categories", task.getException());
}
} catch (Exception e) {
Log.e("ERROR", e.getMessage());
}
}
});
}
}
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
FirestoreService.getInstance().getCategories().addCompletionListener(
// handle List<Category> and respresent in UI
);
}
}
Thank you very much four your help and lead #Daniel-b.
I've solved my issue now.
First I created an Interface for handling results; as you suggested.
public interface ResultHandler<T> {
void onSuccess(T data);
void onFailure(Exception e);
}
Then in the service class, I added ResultHandler to the function's input parameters :
public void getUserInfo(String id, ResultHandler<UserInfo> handler) {
firestore().collection("userInfo").document(id).get().addOnCompleteListener(snap -> {
if (snap.isSuccessful()) {
try {
// failable constructor. use try-catch
UserInfo info = new UserInfo(snap.getResult().getId(), snap.getResult().getData());
handler.onSuccess(info);
} catch (Exception e) {
handler.onFailure(e);
}
} else {
handler.onFailure(snap.getException())
}
});
}
And called service in Activity
FirestoreService.getInstance().getUserInfo("ZsrAdsG5HVYLTZDBeZtkGDlIBW42", new ResultHandler<UserInfo>() {
#Override
public void onSuccess(UserInfo data) {
Log.i("UserInfo", data.id);
}
#Override
public void onFailure(Exception e) {
// getting data failed for some reason
}
});
Using AsyncTask
You can use an AsyncTask. It has 3 steps to it.
1. onPreExecute() - things you want to do before running doInBackground(). This happens in the UI main thread.
2. doInBackground()- the AsyncTask, will do operations in a background thread (the background thread is created by Android so you don't need to worry about it).
3.onPostExecute() - here you can receive any data from the doInBackground method. The postExecute method is executed again, in the UI main thread.
So you can do any I/O operations in doInBackground(), and return the value you received from the server or any other data source, and onPostExecute(), is the equivalent of a completion block in swift.
How to Declare
To use AsyncTask, you need to extend the Android AsyncTask.
So your own AsyncTask declaration will look like this:
private class MyAsyncTask extends AsyncTask<Void, Void, Void> { ... }
What are the 3 generic arguments you ask?
1. Params - the type of the parameters sent to the task upon execution.
2. Progress - the type of the progress units published during the background computation. (Almost always will be Void, unless you care about the actual progress of the operation. Notice this is Void with a capital letter, and not void as the return type).
3. Result - the type of the result of the background computation.
Full Example
private class LongOperation extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... params) {
for (int i = 0; i < 5; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
Thread.interrupted();
}
}
return "Executed";
}
#Override
protected void onPostExecute(String result) {
TextView txt = findViewById(R.id.output);
txt.setText(result);
}
}
In the example, I create a fake, long operation, that you can not run on the UI main thread (because it is a blocking operation).
When the operation is finished, it returns a String, and that same String is received in the onPostExecute() method (and remember, onPostExecute() runs on the UI main thread again). So you can change your UI with the String value you received from the long,blocking operation.
If you want the documentation, here it is:
https://developer.android.com/reference/android/os/AsyncTask
Using Observer Pattern
You can also use the observer pattern in your situation.
Create an interface, that has a method onSuccess(). Have an object implement that interface, and whenever you need it, you can call the onSuccess() method.
Example:
public Interface SuccessInterface{
void onSuccess()
}
public class SuccessHandler implements SuccessInterface{
public void onSuccess(){
//success code goes here
}
}
then in your code, have a SucessHandler instantiated, and call onSuccess() when you need to.
For API 26,
CompletionHandler is available.
Check https://developer.android.com/reference/java/nio/channels/CompletionHandler

update marker position every x time in asynctask

I wanted to mock location of a marker on map. I have list of LatLng values store in ArrayList. I use this value to update on map every second. I need this function to works in AsyncTask so that my UI thread will still responsive.
Initially, I tried using Thread.sleep() but made application not responsive.
protected String doInBackground(Void... voids) {
new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
#Override
public void run() {
for (int i = 0; i < waypoint.size(); i++) {
marker = googleMap.addMarker(new MarkerOptions().position(waypoint.get(0)));
marker.setPosition(waypoint.get(i));
try {
Thread.sleep(1000); // Thread sleep made application not responsive.
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}, 500);
return null;
}
I also tried using .postDelayed but the integer i needs to get declared final which is a problem because I need the integer to change value.
protected String doInBackground(Void... voids) {
for (int i = 0; i < waypoint.size(); i++) {
new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
#Override
public void run() {
marker = googleMap.addMarker(new MarkerOptions().position(waypoint.get(0)));
marker.setPosition(waypoint.get(i)); // Integer i needs to declare final.
}
}, 1000);
}
return null;
}
Is there any way to do this? Thank you.
The Thread.sleep() approach is OK if you can spare a worker thread. The problem in your code is that the thread you are pausing is the UI Thread, that's why your application freezes. You have to understand that what your doing there is just publishing a runnable to the UI Thread using the Handler construct, nothing more.
In your second approach, you can dump the Handler part and use publishProgress (called from the background) after you override onProgressUpdate (delivered in UI thread) in your AsyncTask based class. It does effectively the same but with less boilerplate. Take a look at https://developer.android.com/reference/android/os/AsyncTask for details.
Finally, to circumvent the final requirement in anonymous classes, you can declare a final array of one element and use position 0 to read/write the value. Hopefully, you won't need to do this too often.
The fastest (but not the most correct when working with MultiThreading) way is:
protected String doInBackground(Void... voids) {
for (final TYPE_OF_WAYPOINT cWaypoint : waypoint) {
new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
#Override
public void run() {
marker = googleMap.addMarker(new MarkerOptions().position(waypoint.get(0)));
marker.setPosition(cWaypoint);
}
}, 1000);
}
return null;
}
I don't know what was the Type of "waypoint" List, so I wrote "TYPE_OF_WAYPOINTS" as placeholder.
#emandt answer does not work but the idea he gave could work. So I tried and it is working flawlessly with some modified from his answer:
protected String doInBackground(Void... voids) {
for (final TYPE_OF_WAYPOINT cWaypoint : waypoint) {
new Handler(Looper.getMainLooper()).post(new Runnable() {
#Override
public void run() {
marker = googleMap.addMarker(new MarkerOptions().position(waypoint.get(0)));
marker.setPosition(cWaypoint);
}
});
try {
Thread.sleep(1000);
} catch (Exception e) {
// catch exception here
}
}
return null;
}
Firstly, I have change the .postDelayed to .post. Then, to delay the operation by one second, I have added Thread.sleep(1000) inside for (...) but outside new Handler(Looper.getMainLooper()).post(...));.
Now, the application could do the process in the background with user still be able to interact with the UI. Thanks.

java - make if for async task time limit

here is my piece of code:
Thread one = new Thread() {
public void run() {
try {
new LongOperation(finalJson)
.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR)
.get(30000, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
}
}
};
one.start();
i want to say if AsyncTask past 30000 MILLISECONDS and didn't finish the job return a message, how i can code this? thanks
I would prefer doing it using an AsyncTask.
Copy-pasting from the link:
AsyncTask enables proper and easy use of the UI thread. This class
allows you to perform background operations and publish results on the
UI thread without having to manipulate threads and/or handlers.
AsyncTask is designed to be a helper class around Thread and Handler
and does not constitute a generic threading framework. 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.
Said this, configuring an AsyncTask is pretty simple, just create a class like the following:
private class LongOperation extends AsyncTask<String, Void, String> {
#Override
protected void onPreExecute() {
super.onPreExecute();
//this method works on the UI thread.
//this is the first to run before "doInBackground"
mTextView.setText("we start!");
}
#Override
protected String doInBackground(String... params) {
try {
//do whatever your async task needs to do. This method works async
//you can also call an UI callback from here with the publishProgress method. This will call the "onProgressUpdate" method, and it has to respect his type.
publishProgress("we go on!");
} catch (InterruptedException e) {
Thread.interrupted();
}
return "Executed";
}
#Override
protected void onPostExecute(String result) {
//this method works on the UI thread
//it get the "doInBackground" return value.
mTextView.setText(result);
}
#Override
protected void onPreExecute() {}
#Override
protected void onProgressUpdate(String... values) {
//this method works on UI thread, so it can access UI components and ctx
mTextView.setText(values[0]);
}
}
This is a basic example on how to create an AsyncTask, you can use it like this (form activity/fragment):
AsyncTaskExample asyncTask = new AsyncTaskExample();
asyncTask.get(30000, TimeUnit.MILLISECONDS);
This will set a timeout on your async operation. Look here for the exact Exception/return
For any further question, ask freely. Hope this helps
Edit:
I just noticed you have an AsyncTask inside your thread. Since AsyncTask is already async, I would avoid doing this and simply call the AsyncTask with the method I gave you before. In that way the AsyncTask will run up to the given TimeSpan :)
See the code below: It may help you.
CountDownTimer timer = new CountDownTimer(3000,1000) {
#Override
public void onTick(long l) {
}
#Override
public void onFinish() {
//return a message here;
}
};
timer.start();
And if you have an async task. Then do like below in doInBackground method:
#Override
protected Void doInBackground(Void... voids) {
//simply do your job
CountDownTimer timer = new CountDownTimer(3000,1000) {
#Override
public void onTick(long l) {
}
#Override
public void onFinish() {
//return a message here;
return message;
}
};
timer.start();
return your_reult;
}

AsyncTask stops after some time

I have a CustomAsyncTask class that enables infinite barcode scanner and I execute it in CustomApplication.
Unfortunately CustomAsyncTask::doInBackground stops after some time (minute or two).
private class ScanAsync extends AsyncTask<Void, String, Void>
{
boolean blocked = false;
#Override
protected Void doInBackground(Void... params)
{
while(true)
{
if (!blocked)
{
String received = GlobalAccess.scan.scan(500);
if (received != null && !received.isEmpty())
{
blocked = true;
publishProgress(received);
}
}
else
{
try
{
Thread.sleep(500);
}
catch (InterruptedException ex)
{
ex.printStackTrace();
}
}
}
}
#Override
protected void onProgressUpdate(String... values)
{
super.onProgressUpdate(values);
//TODO: something with received value
blocked = false;
}
}
I need this background task to be always on. Is there any good solution for this? I have tried IntentService, but the result was the same - after some time it stopped working.
EDIT
I have created this Service, although it block my main thread, but it should work in background right? Also If I put a breakpoint on if(!blocked) and press F9 it works fine (scanning part), but if I remove breakpoint and let it run - after few seconds it just turns off (scanner), but if I put a breakpoint again - it works again (sic!).
public class ScanService extends Service
{
boolean blocked = false;
public ScanService()
{
}
#Nullable
#Override
public IBinder onBind(Intent intent)
{
return null;
// TODO: Return the communication channel to the service.
//throw new UnsupportedOperationException("Not yet implemented");
}
#Override
public int onStartCommand(Intent intent, int flags, int startId)
{
while(true)
{
if (!blocked)
{
String received = GlobalAccess.scan.scan(500);
if (received != null && !received.isEmpty())
{
//blocked = true;
}
}
else
{
try
{
Thread.sleep(500);
}
catch (InterruptedException ex)
{
ex.printStackTrace();
}
}
}
}
}
Use a Service instead of AsyncTask. AsyncTasks are only designed to run with shorter background tasks. Keep in mind that whatever you run in a Service will execute on the main thread, so you should use a background thread within your Service.
Can you tell why the AsyncTask or IntentService is stopping? With an IntentService, with your while(true) loop, it should run indefinitely unless the app gets shut down for some reason.
Edit -
You need to do this to prevent your loop from blocking the main thread -
#Override
public int onStartCommand(Intent intent, int flags, int startId)
{
Thread t = new Thread(new Runnable() {
#Override
public void run() {
while(true) {
// your code here
}
}
});
t.start();
}
I don't know why your Service is stopping. You need to be looking at your Logcat output. Set the filter to Error and you're crash should show up there.
Yes, there is an elegant solution for this type of thing. Use a service. In particular, the JobScheduler api is meant to handle this kind of stuff. Reason for using this is, as you stated, you have a long running task and you don't want to have to manage it dying. In addition, the JobScheduler is built to handle side effects of the OS. I assume that you want your job to run, but allow the app to perform its normal set of operations. Though, as a note, the API is smart in considering factors, such as battery levels, OS resources being used, wifi connectivity, so the jobs can be deferred.
The official documentation is here https://developer.android.com/reference/android/app/job/JobScheduler.html
An example of how to use it can be found here
https://code.tutsplus.com/tutorials/using-the-jobscheduler-api-on-android-lollipop--cms-23562

kills an Android AsyncTask with a timeout

So my problem is that i have a AsyncTask that scraps html from a page on a server so i used Jsoup as a library .
so the problem is that i want to set a timeout to cancel the Task if i don't receive any data from the page and display that there is a "communication error " on a toast
is there anyway to kill or stop the asynctask within it self and return a result on onPostExecute
{
private class getPageTitle extends AsyncTask<Void, Void, String> {
String title;
#Override
protected void onPreExecute() {
super.onPreExecute();
connectServerProgressDialog = new ProgressDialog(LoginScreen.this);
connectServerProgressDialog.setTitle("CheckingServer");
connectServerProgressDialog.setMessage("Loading...");
connectServerProgressDialog.setIndeterminate(true);
connectServerProgressDialog.show();
}
#Override
protected String doInBackground(Void... params) {
try {
// Connect to the web site
Document document = Jsoup.connect(CONNECT_URL).get();
title = document.title();
} catch (IOException e) {
e.printStackTrace();
}
return null ;
}
#Override
protected void onPostExecute(String result) {
if(result!=null){
switch (title) {
case "0":
Toast.makeText(LoginScreen.this,"offline",Toast.LENGTH_SHORT).show();
connectServerProgressDialog.dismiss();
break;
case "1":
connectServerProgressDialog.dismiss();
Toast.makeText(LoginScreen.this,"Connected",Toast.LENGTH_SHORT).show();
break;
}}else{
Toast.makeText(LoginScreen.this,"Communication error",Toast.LENGTH_SHORT).show();
}
}
}}
I have a convention that I use for AsyncTask subclasses.
Define an inner interface for the client to use. This decouples the client class so that the AsyncTask can be re-used. The interface is named in the form blahblahListener.
The interface has two methods of the form blahblahCompleted() and blahblahException().
Accept a callback object (listener) that is an implementation of that interface. This is either passed in the AsyncTask constructor or set with a setListener() method.
Hold that listener reference in a WeakReference field so that if the listener goes away before the task completes, the listener can still be garbage-collected.
Define a field to hold an Exception. If an exception occurs in the background method, this field remembers the exception in order to report it to the client.
In the onPostExecute() method, check if the Exception field is null. If it is, call blahblahCompleted() with the result. If it isn't, call blahblahException() with the exception. Also check if the WeakReference is still valid.
For killing the task, you can have a timeout set on your connection. Then when your connection times out, you will get an exception, which is remembered and reported.
So using that convention, your code would look like this:
public class WebPageTitleRemoteTask extends AsyncTask<URL, Void, String> {
private WeakReference<WebPageTitleRetrievalListener> mListener;
private Exception mException;
public WebPageTitleRemoteTask(WebPageTitleRetrievalListener listener) {
super();
mListener = new WeakReference<WebPageTitleRetrievalListener>(listener);
}
#Override
protected String doInBackground(URL... params) {
String title = null;
try {
// Connect to the web site
Document document = Jsoup.connect(params[0]).get();
title = document.title();
} catch (IOException e) {
mException = e;
}
return title;
}
#Override
protected void onPostExecute(String result) {
WebPageTitleRetrievalListener listener = mListener.get();
if (listener != null) {
if (mException == null) {
listener.webPageTitleRetrieved(result);
} else {
listener.webPageTitleRetrievalException(mException);
}
}
}
public static interface WebPageTitleRetrievalListener {
public void webPageTitleRetrieved(String title);
public void webPageTitleRetrievalException(Exception e);
}
}
And your client code would look something like this, with your Activity implementing that inner interface:
.
.
.
connectServerProgressDialog = new ProgressDialog(LoginScreen.this);
connectServerProgressDialog.setTitle("CheckingServer");
connectServerProgressDialog.setMessage("Loading...");
connectServerProgressDialog.setIndeterminate(true);
connectServerProgressDialog.show();
new WebPageTitleRemoteTask(this).execute(url);
.
.
.
#Override
public void webPageTitleRetrieved(String title) {
if (isFinishing()) return;
connectServerProgressDialog.dismiss();
Toast.makeText(this, "title = " + title, Toast.LENGTH_SHORT).show();
}
#Override
public void webPageTitleRetrievalException(Exception e) {
if (isFinishing()) return;
connectServerProgressDialog.dismiss();
Toast.makeText(this, e.getMessage(), Toast.LENGTH_SHORT).show();
}
NOTE: Because the listener is held in a WeakReference, you can't use an anonymous inner class for the listener, because the reference will go away almost immediately and be eligible for garbage collection.
I use this convention consistently, and the extra boilerplate code in the AsyncTask subclass makes it a lot cleaner to use in the client class.

Categories