I have a class which reads the calllog. This could last some minutes. So I have to use a thread if I don't want to block the gui thread.
In C# I start a thread, notify the gui thread with a event when the data is ready and give the data to the gui within the event.
But how should I do it with android? What I read so far told me that's the best to use AsyncTask with android. I use it in this way (Pseudo code):
class MyClass{
private myClassVariable;
private coid startTask(){
GetDataTask data = new GetDataTask();
data.execute(varibale);
}
private void displayData{
doAnythingUsefullHere;
}
class GetDataTask extends AsyncTask<variables>{
protected variable doInBackground(variable){
return = CallLog.getData();
}
protected void onPostExecute(variable){
myclassVariable = variable;
displayData;
}
}
}
Works fine so far, but I can't cancel the thread in this way. I could cancel the task, but I have to check within the data collect loop of the calllog class if the onCancelled is called but this function is only known in the class GetDataTask and not in CallLog.
Is there a way to use AsyncTask and make "outside" classes cancelable? Or have I switch to Threads and events? What's the best way in this situation?
Could this be what you are looking for: Ideal way to cancel an executing AsyncTask ?
Related
I have a small Android application in which I need to do some FTP stuff every couple of seconds.
After learning the hard way that running network stuff on the UI thread is something Android does not really like, I've come to this solution:
// This class gets declared inside my Activity
private class CheckFtpTask extends AsyncTask<Void, Void, Void> {
protected Void doInBackground(Void... dummy) {
Thread.currentThread().setName("CheckFtpTask");
// Here I'll do the FTP stuff
ftpStuff();
return null;
}
}
// Member variables inside my activity
private Handler checkFtpHandler;
private Runnable checkFtpRunnable;
// I set up the task later in some of my Activitiy's method:
checkFtpHandler = new Handler();
checkFtpRunnable = new Runnable() {
#Override
public void run() {
new CheckFtpTask().execute((Void[])null);
checkFtpHandler.postDelayed(checkFtpRunnable, 5000);
}
};
checkFtpRunnable.run();
Is this good practice to perform a recurring task that cannot run on the UI thread directly?
Furthermore, instead of creating a new AsyncTask object all the time by calling
new CheckFtpTask().execute((Void[])null);
would it be an option to create the CheckFtpTask object once and then reuse it?
Or will that give me side effects?
Thanks in advance,
Jens.
would it be an option to create the CheckFtpTask object once and then reuse it? Or will that give me side effects?
No, there will be side-effects. Quoting the docs Threading Rules:
The task can be executed only once (an exception will be thrown if a second execution is attempted.)
You will just need to create a separate instance of the task each time you want to run it.
And I'm not sure why you need the Runnable or Handler. AsyncTask has methods that run on the UI Thread (all but doInBackground(), actually) if you need to update the UI.
Check this answer if you need a callback to update the UI when the task has finished.
You should create a new Async task for every call.
See the Android Documentation: AsyncTask. According to this documentation:
The task can be executed only once (an exception will be thrown if a second execution is attempted.)
Specifically check out the threading rules section. There is a similar answer here, https://stackoverflow.com/a/18547396/2728623
Java ThreadPools and the ExecutorFramework allows you to execute threads as needed and reduces thread creation overhead. Check out the singleThreadExecutor. The thread pool usage is pretty easy too!
I also faced with the NetworkOnMainThreadException in my application but I don't see how to resolve it.
I have a class with a getter method. Like:
public ArrayList<News> get(int i){
// get the list of news from a HTML on the net. The news are split up into web pages on the site
// and i is the page number
return NewsParser(i);
}
Since Android throws the exception I come up with an idea of a downloader class which downloads the HTML content in a separate thread
pubic ArrayList<News> get(int i){
Downloader dl = new Downloader(i);
String HTMLcontent = dl.getContent(); <-- AsyncTask starts in getContent()
return NewsParser(HTMLcontent); <-- What happens here in the main thread???
}
Any ideas/best practices for this problem?
Just looking at your code and your question, it seems like you don't have a very solid understanding of how AsyncTask (or threads in general) works.
I would recommend reading this article.
Basically, your AsyncTask should query the web URL and download the data. Once the data is complete, your AsyncTask should send the HTMLContent to a handler object. The handler will be running on your main thread, so you can display the information to the user at that point.
You shouldn't be calling
dl.getContent();
to retrieve the content. AsyncTask runs on a separate thread, so you can't just call methods like this from your main thread. You need to create the Downloader object (like you did) and then call
dl.execute();
to start the AsyncTask.
run the get method inside a thread,
new Thread(new Runnable() {
#Override
public void run() {
// call get method here
}
}).start();
Since Honeycomb (Android 3.0) you can't use Networking Operations in the MainThread to avoid freezes on the Phone. This is important in order to make your app responsive.
More info:
NetworkOnMainThreadException
Responsiveness
Ok, I have read a lot of questions here on StackOverflow but i still can't understand so i'm opening a new question.
I made a class which function connects to internet and fetches json as string. It works fine in normal Java Application but i can't get it work in my android project.
I'm getting next error: android.os.NetworkOnMainThreadException
So to my understanding I have to use AsyncTask but I don't know how to wrap my function into it.
Function looks like this:
public static String get(String url){
//connect and get data to string
// return string
}
Like I said it works fine in normal JavaApplication but not in android project.
Thx for help!
http://developer.android.com/reference/android/os/AsyncTask.html
Look at the sample
private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> {
}
Your "get" function must be splitted into 2 separate function in this class
what you want to get in, put in
doInBackground
And what you want to do with data which you receive into
onPostExecute
As I understand you use AndroidHttpClient -> so you can not even try to perform your network operations in the UI thread - > so create separate thread for this purpose. You can either use AsynchTask, Thread + Handler or HandlerThread for this purpose, or you can try to experiment here with java.util.concurrent package.
NetworkOnMainThreadException | Android Developers
developer.android.com/... -
Class Overview. The exception that is thrown when an application attempts to perform a networking operation on its main thread. This is only thrown for ...
You can create the thread method which extends AsyncTask (as you correctly understood), and execute it with .execute().
Exactly how you set it up is up to you. Here's a link with a tutorial on spinning these threads:
http://www.vogella.com/articles/AndroidPerformance/article.html#concurrency_threads
How to set value to TextView from class which is out of activity? The value we get at an undetermined time, so it is important to set the value from that class.
All advice would be helpful. Thank you.
P.S.:
For example, in Actvity I have method, which sets the value to a TextView.
public void textViewSetText (String value){
tv.setText(value);
} //how correctly to transfer value from my class to get the desired effect?
If you dont have hold of your Activity, then its not possible because TextView is available in Activity. So when you dont have reference to activity, you cant alter it's contents too. In case you pass your activity reference to a static method, then its possible for that method to do the modifications.
Normally, the content of TextView should only be set inside a activity. Though you can set that value outside of the activity, it is not quite useful.
As for your question, you got the value at an undetermined time, there are some choices.For example, you can register a callback to that class, and when the other class got that value, you can send a message through that callback. But be careful about the threading problem, setting a value to a TextView is a UI operation, which should only be done in a UI thread.
Do not access the Android UI toolkit from outside the UI thread
AsyncTask allows you to perform asynchronous work on your user interface. It performs the blocking operations in a worker thread and then publishes the results on the UI thread, without requiring you to handle threads and/or handlers yourself.
Here is an example:
public void onClick(View v) {
new SomeTask().execute(something);
}
private class SomeTask extends AsyncTask<Something, Void, String> {
/** The system calls this to perform work in a worker thread and
* delivers it the parameters given to AsyncTask.execute() */
protected Bitmap doInBackground(Something something) {
return string; // the TextView's text
}
/** The system calls this to perform work in the UI thread and delivers
* the result from doInBackground() */
protected void onPostExecute(String result) {
textView.setText(result);
}
}
However, if you don't give your case more detailed, no exact answer may satisfy you.
You can use an external Static Class to save the value of the String to modify (and set the value once you return to your TextView_Class), only access to the Static Class to get the value.
You may also save the "this" (Activity) in the Static Class and access to that Activity from everywhere, so you can modify the TextView. (I don't thinks this would be recommended).
Depending the case (you didnt explained enought), the normal thing to do is to Bundle the String if they're parent-child classes.
I m not sure about your question but
try like this may be it will work
((MainActivity) activity).textViewSetText();
public void textViewSetText (String value){
tv.setText(value);
}
but your activity have to extends The MainActivity.
This is a problem that I keep running into often with using Asyntask. The way to contact the UI thread is to call publishProgress() & this method accepts an array of only one TYPE of parameter.
A thread running in the background doing complicated computations might need to update the UI at different points using different types of object.
Let me illustrate with an example:
...do some processing...
// Send UI thread the integer values of the width & height of the image
...do some more processing...
// Send UI thread a String with custom message.
...do some more processing...
// Send UI thread an instance of MyObject so it can extract & display certain values
...do some cleanup job & finish...
However, onProgressUpdate() accepts an array of only one type.
So do I make that an all encompassing Object type? How do I know how to downcast it since this method can be called from line 1, 2 or 3 so which time is it?
Surely there must be a good way to achieve this?
EDIT: What I'd really love to see, if it were possible in Android, would be some way of defining publishProgress1(user-defined args1), publishProgress2(user-defined args2), publishProgress3(user-defined args3) ...
In your 3rd case...
// Send UI thread an instance of MyObject
...there's an argument to say you would do this in onPostExecute() although that depends on what you meant from your illustration.
You could easily do as you suggest in passing an all encompassing object. The object could have various fields (integer, string, object) plus an 'action' to take describing which of those fields are valid and need to be processed.
You could simply pass an int enum such as PROCESS_INT_WIDTH_AND_HEIGHT, PROCESS_STRING_MESSAGE, PROCESS_OBJECT etc. There's nothing to stop you doing this...
private static class MyAsyncTask extends AsyncTask<String, int, Void> {
private int width;
private int height;
private String customMessage;
private MyObject myObject;
#Override
protected Void doInBackground(String... params) {
width = 10;
height = 10;
publishProgress(PROCESS_INT_WIDTH_AND_HEIGHT);
}
protected void onProgressUpdate(int... progress) {
if (progress == PROCESS_INT_WIDTH_AND_HEIGHT)
// Process width and height
}
}
In other words, the onProgressUpdate() method simply responds to a 'command' and processes the relevant private fields accordingly.
If you want to stick with AsyncTask, another option is use a different class at different times, and test the type with instanceof.
However, this sounds like a relatively complex task, so I'd suggest looking at using Handler and posting it [Runnable]s2 from a regular Thread, or using runOnUiThread.
You might also want to read Painless Threading
Hope this helps,
Phil Lello
I don't think there is any other way of doing this. Create a base class with a getType method and then use this as your type for appropriate casting.
Would a generic type work in this scenario? You could typecast the values as needed. Example AsyncTask prototype:
new AsyncTask<String, Object, List<?>>(){
...
I also recall reading that AsyncTask is most suited only for short tasks. Consider the other thread models for complex and long-running operations.
If the values you're returning have a corresponding state in the AsyncTask processing, you could create a private member inside the AsyncTask for each datum/type you need, then assign an integer to each state and in onProgressUpdate(Integer...) put a switch(state) that does the job based on the int state it gets from publishProgress(state).
(this might not be the clearest answer I gave)