AsyncTask UI Update - java

I am tried to search about AsyncTack. How to Update UI after asyntack execute.
Example : I have 2 java file.
file 1 : Myfragment.java, file 2 : MyAsyntack.java
in this case, i'm execute MyAsyntack on MyFragment. after Execute, I want to update UI.
On MyAsyntack, I'am updating database (doing in background). Any body can help?

You can set an interface in AsyncTask and call it in onPostExecute of it to update UI.
public inteface UpdateUI()
{
public void update();
}
then in your AsyncTask declare an updateUI like this:
UpdateUI updater;
public MyAsyntack (UpdateUI updater)
{
this.updater = updater;
}
#Override
protected void onPostExecute(String result)
{
super.onPostExecute(result);
updater.update();
}
and finally in your activity:
MyAsyntack myAsyncTask = new MyAsyntack(new UpdateUI(){
//how you want to update UI
}
);
myAsyncTask.execute();

doInBackground() is on worker thread and can be used to do heavy tasks like network calls to server.
When data is fetched, you can update the UI from onPostExecute(..) which is on the UI thread.
p.s. return of doInBackground will be argument to onPostExecute(..)

Related

AsyncTask.execute() and change UI

In my case, I use AsyncTask.execute() method to connect to the Room database and change UI elements:
AsyncTask.execute(() -> {
Database db = Room.databaseBuilder(this.getApplicationContext(),
Database.class, "name-database").build();
Dao dao = db.getDao();
if (dao.findByNumber(1).isOpen) { // get data from the database
button.setBackgroundResource(R.drawable.active_button_shape) // change UI-element
}
});
Is this a thread-safe solution?, or need to create a separate class with an overridden onPostExecute() method for change UI? Thanks in advance!
SOLUTION
On the advice of Priyankagb I began to use runOnUiThread():
if (dao.findByNumber(1).isOpen) {
runOnUiThread(() -> button.setBackgroundResource(R.drawable.active_button_shape));
}
No this is not thread-safe. You have to use onPostExecute() or also you can use runOnUiThread() to change a button background into direct execute()
like...
runOnUiThread(new Runnable() {
#Override
public void run() {
button.setBackgroundResource(R.drawable.active_button_shape)
}
});

When is onPostExecuted of AsyncTask executed?

Consider the following example Activity:
public class ExampleActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_info);
new ExampleTask().execute("");
// code line 1
// code line 2
// code line 3
// code line 4
}
public class ExampleTask extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... address) {
// some long-running stuff
return "";
}
protected void onPostExecute(String text) {
}
}
}
With
new ExampleTask().execute("");
we start an AsyncTask which runs off the UI thread. We can not predict when it will be finished. The AsyncTask's onPostExecute method runs on the UI thread again.
Let's say the AsyncTask is done while code line 2 of the onCreate method is being executed.
When will the onPostExecute method be executed? Does it wait until onCreate is done or will it be executed immediately?
I think this question could be generalized to how Java (or at least Android) handles Threads that run off the main thread but return to the main thread and how Java/Android schedules two sequences of code that are 'competing' for immediate excution.
Thus it would be nice if an answer would provide a little general insight.
you can see it all for your self here:
https://android.googlesource.com/platform/frameworks/base/+/refs/heads/master/core/java/android/os/AsyncTask.java
// that's on the background thread
line #288: return postResult(doInBackground(mParams));
private Result postResult(Result result) {
#SuppressWarnings("unchecked")
Message message = sHandler.obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult<Result>(this, result));
// here it sends the message to the intenral UI handler
message.sendToTarget();
return result;
}
that means:
the AsyncTask post a message to its own internal UI handler, that means that onPostExecute will only be executed after everything else that is queued on the UI Looper gets executed
It will be called after onCreate() finishes because any callbacks on the UI thread are processed sequentially. So, first goes onCreate() then onPostExecute()
However, it seems, this is an implementation detail and you should not rely on that.
onPostExecute will be called, immediately after the task completion in the doInBackground method. see details about AsyncTask
Let's say the AsyncTask is done while code line 2 of the onCreate method is being executed. When will the onPostExecute method be executed? Does it wait until onCreate is done or will it be executed immediately?
Yes it does wait for onCreate completion, onPostExecute will be called after the onCreate method.

Removing location updates using a thread

I have a service that constantly polls a webservice for some options. These options basically restart a LocationManager. This restart is done using a custom event which gets fired from a method used inside a thread.
Here is my custom event
public class OptionsChangedEvent extends EventObject {
public OptionsChangedEvent(Object o){
super(o);
}
}
and the custom listener
public interface OptionsChangedListener extends EventListener {
public void optionsChanged(OptionsChangedEvent evt);
}
the thread that runs in the service and polls for new options is the following
private Thread optionsThread = new Thread() {
public void run() {
//Looper.prepare();
while(true) {
String opts = getOptsFromServer();
if(!opts.equals(currentOpts)) updateOpts(opts); //the prob is here
//Looper.loop();
Thread.sleep(10 * 1000) // sleep 10sec
}
}
}
Finally here is how I implement the listener inside my tracker.
locOpts.addOptionsChangedListener(new OptionsChangedListener() {
#Override
public void optionsChanged(OptionsChangedEvent event) {
Log.d("LOCATION_OPTIONS_CHANGED", "SUCCESS");
mLocationManager.removeUpdates(mLocationListener);
mLocationManager.requestLocationUpdates(
provider,
update,
0, mLocationListener
);
}
});
I had the following error which basically says that I need to use Looper.loop and Looper.prepare inside my thread.
12-03 11:31:39.544 26751-26843/com.test.location E/AndroidRuntime﹕ FATAL EXCEPTION: Thread-10370
Process: com.test.location, PID: 26751
java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
at android.os.Handler.<init>(Handler.java:200)
at android.os.Handler.<init>(Handler.java:114)
at android.location.LocationManager$ListenerTransport$1.<init>(LocationManager.java:221)
at android.location.LocationManager$ListenerTransport.<init>(LocationManager.java:221)
at android.location.LocationManager.wrapListener(LocationManager.java:844)
at android.location.LocationManager.requestLocationUpdates(LocationManager.java:857)
at android.location.LocationManager.requestLocationUpdates(LocationManager.java:454)
at com.test.location.trackers.LocationTracker$2.optionsChanged(LocationTracker.java:93)
at com.test.location.options.LocationTrackerOptions.notifyListeners(LocationTrackerOptions.java:22)
at com.test.location.options.LocationTrackerOptions.fromJSON(LocationTrackerOptions.java:34)
at com.test.location.MainService$5.run(MainService.java:219)
If I uncomment the Looper parts the thread works only once and I cant figure out why this happens.
update
After some investigation I found that code that needs the message queue and creates this problem. Does anyone needed to do something like this? I would like to not change my design here if it possible.
private synchronized void notifyListeners(Object obj) {
for (OptionsChangedListener listener : listeners) {
listener.optionsChanged(new OptionsChangedEvent(obj));
}
}
Do you try to update the UI in your callback method updateOpts ?
Looper prepare & loop using in other way, in case when you want to send tasks from UI thread to the backround thread, so you send message to the thread, and inside the thread process that message in handlemessage event of Handler.
try to avoid UI calls directly from your thread, maybe also try using runOnUIThread(...)
or AsyncTasks onPost to make the proper callback to the UI thread.
The solution was actually very simple. I was missing the callback function.
locOpts.addOptionsChangedListener(new OptionsChangedListener() {
#Override
public void optionsChanged(OptionsChangedEvent event) {
Log.d("LOCATION_OPTIONS_CHANGED", "SUCCESS");
mLocationManager.removeUpdates(mLocationListener);
mLocationManager.requestLocationUpdates(
provider,
update,
0, mLocationListener,
Looper.getMainLooper() // this was the problem
);
}
});

Android wait till async task has finished to do specific method

I have been searching for the answer but no one really answers because there is no point using async task for that. In Android API 11 or above it will force to code it you do network requests on the main thread so I have to do async task. So, here is the question: Is it possible to wait untill the async task is finished then continue? Because I need the data to be there for the calling method etc.
Here is my code:
public JSONObject getJSONFromUrl(String url) {
this.url = url;
new loadURL().execute();
// Do this when ASYNC HAS FINISHED
return jObj;
}
class loadURL extends AsyncTask <Void, Void, Void> {
protected void onPreExecute() {
}
protected Void doInBackground(Void... unused) {
//do stuff in background
return (null);
}
}
}
Any questions to answer just leave a comment. Thanks for helping.
yes you use the onPostExecute method of the AsyncTask to do whatever you want to do after. That method gets called after the doInBackground is finished
If the operation won't take long (less than a few seconds) you can use the progress bar to keep from allowing the user to do anything. Set something like this in your AsyncTask
ProgressDialog progress = ProgressDialog.show(LoginScreen.this, "Downloading Users", "Please wait while users are downloaded");
#Override
protected void onPreExecute()
{
progress.setCancelable(false);
progress.isIndeterminate();
progress.show();
}
You will still want to call your method from onPostExecute() as this will just keep the user from being able to do anything but it won't keep any code from running that is in the method you calling the AsyncTask from
This can be done with wait(), notify() and notifyAll() methods of objects. Or You can use custom callbacks via interfaces. Just call proper method via callback when you complete getting required data.
You can perform Network related operation inside doInBackground() method because onPostExecute() method is used only for UI updation only in android

Android Twitter asyncTask "cant create handler..." error

i bascially have an activity
that calls an async task to set up the twitter classes, provided via twitter4j.
But i recieve an error regarding "cant create handler inside thread that has not called looper.prepare "
which is orginating from the TwitterApp class where there is a handler...
how can i get around this? successfully setting up the class no on the main UI thread as i used to have before (which worked perfectly but slowed down the app);
im basically doing:
new SetUpAsyncTaskt().execute();
within the asynctask all im doing is:
TwitterApp mTwitter;
postToTwitter = true;
String twitter_consumer_key="bllaalaa";
String twitter_secret_key="blaa"
private class SetUpAsyncTask extends AsyncTask<Void, Void, Void> {
#Override
protected Void doInBackground(Void... params) {
mTwitter = new TwitterApp(context, twitter_consumer_key,twitter_secret_key);
mTwitter.setListener(mTwLoginDialogListener);
return null;
}
#Override
protected void onPostExecute(Void result) {
if(!mTwitter.hasAccessToken()){
postToTwitter=false;
}
}
}
Thanks for any help!
UPDATE: After doing more testing, it seems the problem is due to the context, as if i remove all context based data within the class it works, but what i dont get is if i pass in the context from the UI thread, it still occurs ?? :S
UPDATE2: Found another way around it, thanks to all who replied.
Look here for the documentation: http://developer.android.com/reference/android/os/AsyncTask.html
some rules:
The task instance must be created on the UI thread.
execute(Params...) must be invoked on the UI thread.
My guess is you are executing the task on some different thread. To Execute it on UI thread create a Handler in onCreate and:
mHandler.post(new Runnable(){
//insert task creation & execution here
});
In this way the result that are in onPostExecute will be returned on the UI Thread too.
You can use runOnUiThread() to make the non-UI task run on the UI,
Try this,
#Override
protected Void doInBackground(Void... params) {
mTwitter = new TwitterApp(context, twitter_consumer_key,twitter_secret_key);
Activity_name.this.runOnUiThread(new Runnable() {
#Override
public void run() {
mTwitter.setListener(mTwLoginDialogListener);
}
});
return null;
}

Categories

Resources