I am working on an Android project and I have a thread which is posting to a PHP API and does checks with the response.
Before the thread starts I show a progress dialog which can be cancelled. When the cancel is pressed I call thread.stop() but this shows up as deprecated.
Everything I have found on Google suggest that I have a flag and check the flag within the while loop and come out of the thread cleanly, however in my circumstances there is no loop, so how should I go about doing this?
The problem you are facing is know problem because, threads are not supposed to be stopped by calling thread.stop(); method.
Also Android discourages the use of Java Threads in Android, and Conveniently, Android has some additional support for when it comes to communicating between Threads, The Handler class provides a neat queued message mechanism, and Looper provides a handy method for processing same.
But as you mentioned you want to show a progress dialog which can be cancelled. When the cancel is pressed, so this type of functionality can be achieved using AsyncTask.
As AsyncTask is one of the easiest ways to implement parallelism in Android without having to deal with more complex methods like Threads.
Though it offers a basic level of parallelism with the UI thread, it should not be used for longer operations (of, say, not more than 2 seconds).
Mainly AsyncTask should handle your problem, Since:
It provides easy and standard recommended mechanism to publish background progress (see the Usage section here:
http://developer.android.com/reference/android/os/AsyncTask.html)
It provides method cancel(boolean); for cancelling a task(see the Cancelling a task section here:
http://developer.android.com/reference/android/os/AsyncTask.html
AsyncTask has four methods to do the task:
onPreExecute();
doInBackground();
onProgressUpdate();
onPostExecute();
And cancel(); method to handle the cancellation of the background work.
Where doInBackground() is the most important as it is where background computations are performed.
Code:
Here is a skeletal code outline with explanations:
public class AsyncTaskTestActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// This starts the AsyncTask
// Doesn't need to be in onCreate()
new DownloadFilesTask().execute(url1);
}
// Here is the AsyncTask class:
//
// AsyncTask<Params, Progress, Result>.
// Params – the type (Object/primitive) you pass to the AsyncTask from .execute()
// Progress – the type that gets passed to onProgressUpdate()
// Result – the type returns from doInBackground()
// Any of them can be String, Integer, Void, etc.
private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> {
protected Long doInBackground(URL... urls) {
int count = urls.length;
long totalSize = 0;
for (int i = 0; i < count; i++) {
totalSize += Downloader.downloadFile(urls[i]);
publishProgress((int) ((i / (float) count) * 100));
// Escape early if cancel() is called
if (isCancelled()) break;
}
return totalSize;
}
protected void onProgressUpdate(Integer... progress) {
setProgressPercent(progress[0]);
}
protected void onPostExecute(Long result) {
showDialog("Downloaded " + result + " bytes");
}
}
}
For more in depth knowledge visit following links:
https://blog.nikitaog.me/2014/10/11/android-looper-handler-handlerthread-i/
http://developer.android.com/reference/android/os/AsyncTask.html
Related
This question already has an answer here:
Using AsyncTask
(1 answer)
Closed 8 years ago.
I want to use an AsyncTask in my app, but I am having trouble finding a code snippet with a simple explanation of how things work. I just want something to help me get back up to speed quickly without having to wade through the documentation or lots of Q&As again.
AsyncTask is one of the easiest ways to implement parallelism in Android without having to deal with more complex methods like Threads. Though it offers a basic level of parallelism with the UI thread, it should not be used for longer operations (of, say, not more than 2 seconds).
AsyncTask has four methods
onPreExecute()
doInBackground()
onProgressUpdate()
onPostExecute()
where doInBackground() is the most important as it is where background computations are performed.
Code:
Here is a skeletal code outline with explanations:
public class AsyncTaskTestActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// This starts the AsyncTask
// Doesn't need to be in onCreate()
new MyTask().execute("my string parameter");
}
// Here is the AsyncTask class:
//
// AsyncTask<Params, Progress, Result>.
// Params – the type (Object/primitive) you pass to the AsyncTask from .execute()
// Progress – the type that gets passed to onProgressUpdate()
// Result – the type returns from doInBackground()
// Any of them can be String, Integer, Void, etc.
private class MyTask extends AsyncTask<String, Integer, String> {
// Runs in UI before background thread is called
#Override
protected void onPreExecute() {
super.onPreExecute();
// Do something like display a progress bar
}
// This is run in a background thread
#Override
protected String doInBackground(String... params) {
// get the string from params, which is an array
String myString = params[0];
// Do something that takes a long time, for example:
for (int i = 0; i <= 100; i++) {
// Do things
// Call this to update your progress
publishProgress(i);
}
return "this string is passed to onPostExecute";
}
// This is called from background thread but runs in UI
#Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
// Do things like update the progress bar
}
// This runs in UI when background thread finishes
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
// Do things like hide the progress bar or change a TextView
}
}
}
Flow Diagram:
Here is a diagram to help explain where all the parameters and types are going:
Other helpful links:
What arguments are passed into AsyncTask<arg1, arg2, arg3>?
Slidenerd Android AsyncTask Tutorial: Android Tutorial For Beginners
Understanding AsyncTask – Once and Forever
Dealing with AsyncTask and Screen Orientation
How to pass multiple parameters to AsynkTask
how to pass in two different data types to AsyncTask, Android
I have a class annotated with #Rest and I use its methods in another with an instance of this, annotated with #RestService. When I call some method of the Rest client class, NetworkOnMainThreadException error appears. I thought that AndroidAnnotations managed the threading in these cases.
AndroidAnnotations does not make the implementation to use a background thread. Actually it should not have to, since it is uncertain whether the call is already on a background thread or not, etc. But you can easily put calls to a background thread with the #Background annotation. With the usage of that, you can simply avoid the AsyncTask boilerplate.
You are calling a RESTful web service, which is a network operation. As Android architecture says, network operation should be done on another thread than UI thread. For this you have to start another thread to do that operation, but the best practice is to use AsyncTask
The exception that is thrown when an application attempts to perform a networking operation on its main thread.
This is only thrown for applications targeting the Honeycomb SDK or higher. Applications targeting earlier SDK versions are allowed to do networking on their main event loop threads, but it's heavily discouraged. See the document Designing for Responsiveness.
The most effecive way to create a worker thread for longer operations is with the AsyncTask class. Simply extend AsyncTask and implement the doInBackground() method to perform the work. To post progress changes to the user, you can call publishProgress(), which invokes the onProgressUpdate() callback method. From your implementation of onProgressUpdate() (which runs on the UI thread), you can notify the user. For example:
private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> {
// Do the long-running work in here
protected Long doInBackground(URL... urls) {
int count = urls.length;
long totalSize = 0;
for (int i = 0; i < count; i++) {
totalSize += Downloader.downloadFile(urls[i]);
publishProgress((int) ((i / (float) count) * 100));
// Escape early if cancel() is called
if (isCancelled()) break;
}
return totalSize;
}
// This is called each time you call publishProgress()
protected void onProgressUpdate(Integer... progress) {
setProgressPercent(progress[0]);
}
// This is called when doInBackground() is finished
protected void onPostExecute(Long result) {
showNotification("Downloaded " + result + " bytes");
}
}
To execute this worker thread, simply create an instance and call execute():
new DownloadFilesTask().execute(url1, url2, url3);
there are ANR when I play some net clip, and I can't handle the error msg from MediaPlayer.
Can I handle ANR msg from system and change the dialog? the default dialog is not comfort to user.
You cannot handle ANR in your own application. You should try your best to avoid the ANR.
According to Android dev guide pages, the ANR is triggered by the following conditions:
No response to an input event (such as key press or screen touch events) within 5 seconds.
A BroadcastReceiver hasn't finished executing within 10 seconds.
So, you should look cat the logcat traces and the ANR traces to target the position where ANR occurs and check the source code to find any possible 'long-running operations' that might be blocking the main thread.
Try to use AsyncTask to carry the task in the background to avoid ANR, which is recommend by Android official site. Take the downloading for example:
private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> {
// Do the long-running work in here
protected Long doInBackground(URL... urls) {
int count = urls.length;
long totalSize = 0;
for (int i = 0; i < count; i++) {
totalSize += Downloader.downloadFile(urls[i]);
publishProgress((int) ((i / (float) count) * 100));
// Escape early if cancel() is called
if (isCancelled()) break;
}
return totalSize;
}
// This is called each time you call publishProgress()
protected void onProgressUpdate(Integer... progress) {
setProgressPercent(progress[0]);
}
// This is called when doInBackground() is finished
protected void onPostExecute(Long result) {
showNotification("Downloaded " + result + " bytes");
}
}
To execute this worker thread, simply create an instance and call execute():
new DownloadFilesTask().execute(url1, url2, url3);
I have an app which load ads from two networks and sets a flash file to webview when started.This is making it too slow on startup, forums told me to use asynctask.Can some one make this code an asynctask.
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
airpush=new Airpush(getApplicationContext());
airpush.startPushNotification(false);
airpush.startIconAd();
airpush.startDialogAd();
airpush.startAppWall();
mWebView = (WebView) findViewById(R.id.webview);
mWebView.getSettings().setJavaScriptEnabled(true);
mWebView.getSettings().setPluginsEnabled(true);
mWebView.setScrollBarStyle(WebView.SCROLLBARS_OUTSIDE_OVERLAY);
mWebView.setBackgroundColor(Color.parseColor("#000000"));
mWebView.loadUrl("file:///android_asset/game.swf");
AdView adView = (AdView)this.findViewById(R.id.adView);
adView.loadAd(new AdRequest());
It will be much more helpful for you to spend a little bit of time understanding the architecture of an AsyncTask than for someone to simply make one for you.
An AsyncTask is actually a fairly simple class to extend and use. An AsyncTask can, in its simplest form, be code that runs in the background (off the UI thread -- this is what causes lockup), but is set up to allow for some code to run in the background, some code to execute before/after, and some code to execute as a progress update if necessary.
You will need to create your own class that extends AsyncTask as shown below. Your task will take three parameters. The first will get passed into the doInBackground function that runs in the background, the second is a type for a parameter that can be passed into a progress update function, and the third is a type to be passed into your onPostExecute fn that runs on the UI thread after the background function has completed. In the simple example below I will not include types to be passed to a post execute function or a progress update function, so they will be of type Void.
private class YourTask extends AsyncTask<byte[], Void, Void> {
protected Long doInBackground(byte[]... data) {
//get the array
byte[] array = data[0];
//do something with it.
HERE IS WHERE YOU RUN YOUR CODE IN THE BACKGROUND THAT IS TAKING TOO LONG ON THE UI THREAD
//return null because this type needs to match the last type for returning to the postexec fn
return null;
}
}
When you want to run your task you call the following:
new YourTask().execute(someByteArray);
So oftentimes you can stick the code that is taking a long time into that doInBackground function, but you have to be careful because it is off the UI thread and some code does have to be run on the UI thread.
I would recommend doing some profiling to see what code specifically is choking up your UI thread, and run THAT in the background using an AsyncTask. You can do that by using DDMS in Eclipse and use method profiling. Another way would be to use the Debug class and call Debug.startMethodTracing("tracefilename"); when you want to start and Debug.stopMethodTracing();. You can read more about that here. However, your code does load a url (mWebView.loadUrl) so I would assume this may be a big bottleneck!
Just as an addendum, if you want a more in depth example of an AsyncTask, here is one I C&Pd from this useful documentation:
private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> {
protected Long doInBackground(URL... urls) {
int count = urls.length;
long totalSize = 0;
for (int i = 0; i < count; i++) {
totalSize += Downloader.downloadFile(urls[i]);
publishProgress((int) ((i / (float) count) * 100));
// Escape early if cancel() is called
if (isCancelled()) break;
}
return totalSize;
}
protected void onProgressUpdate(Integer... progress) {
setProgressPercent(progress[0]);
}
protected void onPostExecute(Long result) {
showDialog("Downloaded " + result + " bytes");
}
}
The above example has code to both exemplify updating progress on the UI during the background task as well as passing a parameter that is then used by the UI thread-running post execute fn.
I can't just make your code an AsyncTask but I can give you an example and some help. This is an example of AsyncTask
public class TalkToServer extends AsyncTask<String, String, String> {
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected void onProgressUpdate(String... values) {
super.onProgressUpdate(values);
}
#Override
protected String doInBackground(String... params) {
//do your work here
return something;
}
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
// do something with data here-display it or send to mainactivity
}
All of your network stuff you will put in doInBackground() then if you need to update the UI you did that in the other methods. After finishing the network stuff you can update UI in onPostExecute().
This is how you would call the task
TalkToServer myAsync = new TalkToServer() //can add params if you have a constructor
myAsync.execute() //can pass params here for `doInBackground()` method
If it is an inner class of your MainActivity then it will have access to member variables of MainActivity. If its a separate class then you can pass context to constructor like
TalkToServer myAsync = new TalkToServer(this);
and create a constructor to accept Context and any other params you want
I strongly suggest going through the docs below and make sure you understand how it works. Maybe the biggest thing to understand when getting started is that doInBackground() doesn't run on the UI so you don't want to try and update any Views here but in the other AsyncTask methods or by passing data back to the MainActivity and update there
AsyncTask
I have a table called student which I want to populate from the server. In my activity I show a progress bar and call ContentProvder.requestSync(Content URI of student..). Now if I understand correctly as per Virgil's talk I should add an observer on the ContentURI of the student to be notified later by the ContentProvider when the sync finishes. But what happens if say there was a network error. The student table will never be populated and my progress dialog will never be removed.
I understand the
"broadcast receiver approach"
mentioned in another thread but that deviates from Virgil's approach which I consider ideal.
Also on those lines why doesn't the requestSync allow to pass a ResultReceiver as part of the extras. Isn't that generally a Service talks back to an Activity?
A SyncAdapter is not meant to be used for this kind of scenario. SyncAdapter is meant for background sync of data, invisible to the user.
Your case sounds like perfect for a AsyncTask. With that you can use publishProgress() to update your progress bar while your network task happens in another thread. You can find a lot of information and examples on AsyncTask online.
Example from the link above:
private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> {
protected Long doInBackground(URL... urls) {
int count = urls.length;
long totalSize = 0;
for (int i = 0; i < count; i++) {
totalSize += Downloader.downloadFile(urls[i]);
publishProgress((int) ((i / (float) count) * 100));
// Escape early if cancel() is called
if (isCancelled()) break;
}
return totalSize;
}
protected void onProgressUpdate(Integer... progress) {
setProgressPercent(progress[0]);
}
protected void onPostExecute(Long result) {
showDialog("Downloaded " + result + " bytes");
}
}
run it by executing it like so:
new DownloadFilesTask().execute(url1, url2, url3);
Here is another example, with tutorial (simply found by google):
http://androidresearch.wordpress.com/2012/03/17/understanding-asynctask-once-and-forever/