Android - How to synchronize a background AsyncTask with my main activiy - java

I'm developing an app which connects to a server to download location data in order to add some markers to a Map (Google Map).
My problem is that the map is setted before I download my data, so it is completly empty (with no markers).
That data download is performed in another Thread by an AsyncTask and I don't know how to set up my map AFTER all data have been gathered.
Some code, just in case it helps:
HttpGetWorker.java (in charge of get the data):
...
#Override
protected String doInBackground(String... urls) {
try {
return process(urls[0]); //Private method to get data
} catch (IOException ioe) {
Log.e("HttpGetWorker:", ioe.getLocalizedMessage(), ioe);
return "Unable to retrieve web page. URL may be invalid.";
}
}
#Override
protected void onPostExecute(String result) {
for(AsyncTaskListener<String> listener : listeners) {
/**
* Activities which need the server data have to be listeners
* of this task. this processResult method comes from an own
* interface(AsyncTaskListener) and it is implemented in my "main"
* activity (see below)
*/
listener.processResult(result);
}
progressDialog.dismiss(); //just a progress dialog set in onPreExecute method
}
...
Then the listener of this task, my "main" activity MapsActivity.java:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_maps);
initData(); //Here it is where I get the server Data, complete method below
setUpMapIfNeeded(); // These method set up my map, but before my data is retrieved,
mMap.setOnMarkerClickListener(this);
PreferenceManager.setDefaultValues(this, R.xml.preferences, false);
}
private void initData() {
/**
* This HttpDispatcher just creates an instance of the previous
* HttpGetWorker with its execute() to download the data. The "this"
* argument is refered to the current activity to register it in my
* listeners list, as said before
*/
HttpDispatcher dispatcher = new HttpDispatcher(this);
dispatcher.doGet(this);
}
...
// Interface method, here my net data is process
#Override
public void processResult(String result) {
//stuff to process the result, it does it well, but too late.
}
Hope I explain myself.
Thanks everyone!
EDIT:
Relating to the specific problem, sometimes the easiest solutions are the hardest to see...or my head was just a mess when I posted this. I just change an addMarkers() method to my proccessResult(String s), after all data have been fetched...
Anyway, I think the question itself could be interesting for others (synchronization between an AsyncTask and any other activity which calls it). So I let it here.
Cheers!

Don't set the marker before is AsyncTask finished. When task is finished, set marker from onPostExecute().

Related

Wait for HttpRequest to finish before starting a new activity

so I am trying to learn how to create basic Android applications.
I am stuck on this problem:
The Home Activity has a button that once pressed does two things:
1. Call a REST-Api on my backend-server. The server returns JSON-Objects. The JSON objects are mapped to Java Objects. Finally they are added to a static list.
Start a new intent that launches an Activity with a List Layout.
OnCreate() the ListLayout is filled with data from the static List obtained in step 1.
The Problem is that step 2 does not work as intended because step 1 is asynchronous. So step 2 runs before step 1 finishes to fill the static list with data from the server, resulting in an empty List being displayed on the ListActivity.
How can I wait for step 1 to finish before starting the new Activity so the data is displayed correctly?
Thanks.
Use AsyncTask.
Inside the method doInBackground() put your code for performing API call. After the API call is completed, the method onPostExecute() gets called where you can put the code to go to the next activity.
Check detailed guide here: https://developer.android.com/reference/android/os/AsyncTask
Create an AsyncTask class and override their method as this example :
public class DownloadTask extends AsyncTask<String,String,String>{
#Override
public void onPreExecute()
super.onPreExecute();
{
/// initialize loading animation if you want
}
#Override
public String doInbackGround(String... params)
{
///call your rest request
return resulofyourrequest;
}
#Override
public void onPostExecute(String result)
{
super.onPostExecute(result);
// stop loading animation if you already started one in onPreExecute
///do the stuff you need after you get the result and start your activity here
}
}
and to run your class
new DownloadTask().execute(your_url);

Android Set Video URI In Background Task

My app keeps telling me that I'm doing too much work on the main thread, and if I don't wait long enough when the app first loads before touching the UI, it crashes. Specifically, it seems like what I'm waiting for is the video to load into the videoView, because when I comment out the 'myVideoView.setVideoURI' line, it works totally fine.
I already have an asynctask set up for communicating with the server, so I thought maybe I could some how use an asynctask to set the video in the background and then hide the progress bar when it's done.
I tried putting my entire video loading code below inside the asynctask, but it kept saying 'this must be done on the UI thread'. Of course, I'm probably just misunderstanding the concept of multi threading, but if anyone could help me clarify how I may go about reducing the strain on my main thread, that would be so great. Thank you!
Here is my code sample. All of this is currently inside onCreate.
myVideoView = (VideoView) findViewById(R.id.videoView);
try {
myVideoView.setVideoURI(Uri.parse("android.resource://" + getPackageName() + "/" + R.raw.video));
} catch (Exception e) {
Log.e("Error", e.getMessage());
e.printStackTrace();
}
myVideoView.requestFocus();
myVideoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
public void onPrepared(MediaPlayer mediaPlayer) {
myVideoView.seekTo(0);
}
});
// EMPTY ASYNCTASK
public class LoadVideo extends AsyncTask<String, String, String> {
#Override
protected void onPreExecute() {
super.onPreExecute();
// DO SOMETHING BEFORE IT STARTS
}
protected String doInBackground(String... args) {
// DO HEAVY LIFTING
return null;
}
protected void onPostExecute(String file_url) {
// DO SOMETHING AFTER IT FINISHES
}
}
Yes, there is a solution- use rxJava multithreading. It allow to create request on one thread, perform it on another (computation, for example) and handle result on main thread. It is modern way to deal with multithreading. I use it a lot in my current project.
See comment https://stackoverflow.com/a/38002606/6175778

Best way to execute HTTP GET in onCreate()

I'm coding an Android client that connects to a REST API. Since Android 3.0 it is not allowed to perform blocking network operations on the main thread, so I'm looking for the best way to implement this.
I have managed my objective using AsyncTask but it seems a rather dirty implementation so I'd like to ask for advice.
The data returned from the async task is used to update the UI.
MainActivity.java:
public class MainActivity extends ActionBarActivity{
ListView establishment_list;
CustomListAdapter adapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
establishment_list = (ListView) findViewById(R.id.establishment_list);
adapter = new CustomListAdapter( this, R.layout.establishment_row_layout, new String[]{"Loading data..."} );
establishment_list.setAdapter(adapter);
View header = (View) getLayoutInflater().inflate(R.layout.establishment_headerview, null);
establishment_list.addHeaderView(header);
// GET establishments from REST API
new NonBloquingGET().execute();
}
/* DIRTY IMPLEMENTATION */
private class NonBloquingGET extends AsyncTask<List<Establishment>, Void, List<Establishment>> {
List<Establishment> establishments;
#Override
protected List<Establishment> doInBackground(List<Establishment>... params) {
/* This is a synchronous call using the Retrofit library*/
establishments = Client.getInstance().getEstablishments();
return establishments;
}
#Override
protected void onPostExecute(List<Establishment> result) {
Log.d("ASYNC TASK", result.toString());
List<String> data = new ArrayList<>();
for (Establishment e : result){
data.add(e.getName());
}
adapter.updateDataSet( data.toArray(new String[data.size()]) );
}
#Override
protected void onPreExecute() {
}
#Override
protected void onProgressUpdate(Void... values) {
}
}
}
Is there a better way to do it as I'm planning to add more Activities and adding an AsyncTask class for each seems awkward?
The first thing you can start with is to make your inner AsyncTask class implementation static, otherwise it will hold an implicit reference to the host class (Activity), this means it won't be garbage collected until task is alive (let's imagine execution of NonBloquingGET takes a lot of time (you are sitting with dial-up speed somewhere on a desert island) and you rotate the screen, activities will be kept in memory). The second step you can think of is to implement a pair of IntentService and BroadcastReceiver. After you understand the key concepts behind it, you can take a look on 3rd party libraries, for example Retrofit for network communications, RxJava for events and Otto for event bus.
Using AsyncTask is actually a good thing as the execution of that is not synchronized with the main activity and so when you want to do some background work and need the main UI to be active at the same time always use AsyncTask.
The drawback of doing network operations on the main thread is that it'll make the UI unresponsive for the time being which will look too laggy and is not a good habit.
static {
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
}
With this code you can use network operations on your main thread.

AsyncTask (Asynchronous processes)

I have a problem regarding Async task
Async from android
Using 2 activities "A" and "B"
by entering a word to search from the url and and store value in DTO and then fetching values from getter and setter.
My complication is that i have implemented async in my activity "B" and that activity is fetching value from same DTO.
Problem is that how my post know that do in background have fetched value from DTO and DTO have fetched value from internet...in case of slow internet connection.
I m sending intent from "A" to "B" and showing the results on "B"
PROBLEM:
1. If i remove async then app shows black page and also freezes (in case of slow connection only) but data is displayed
2. If i use aync then sometimes progress dialog show for long time and inspite of knowing that data is already displayed in UI
code links https://www.dropbox.com/s/p27rpokz68sryv3/SearchData.java
https://www.dropbox.com/s/rm3i52djiay327u/SearchData_DTO.java
https://www.dropbox.com/s/2hpufx2a12480on/Search.java
Pls suggest me the possible solution for this
Regards
You need to listen for asyntask complete listener, For that let your activity A impliment interface and call that method from Activity B,s Asyntask,s onpostexecute method
Thus your activity A will come to know that B has finished his task and you can do next thing..
Hope this helps
public interface AsyncTaskCompletedListener {
public void OnResultSucceeded(String result);
}
public class LoginAsyncTask extends AsyncTask<String, Void, String> {
AsyncTaskCompletedListener mAsyncTaskCompletedListener;
#Override
protected String doInBackground(String... arg0) {
// TODO Auto-generated method stub
return null;
}
#Override
protected void onPostExecute(String result) {
// TODO Auto-generated method stub
super.onPostExecute(result);
mAsyncTaskCompletedListener.OnResultSucceeded(result);
}
}
Here is the interface Let Activity A impliment this and from Activity invoke this from onpostexecute
From Activity A
LoginAsyncTask customloginasync = new LoginAsyncTask(getActivity(),
FATCH_USER_LIST, arglist);
customloginasync.execute();
customloginasync.setOnResultsListener(new AsyncTaskCompletedListener() {
#Override
public void OnResultSucceeded(String result, int asyncTaskNo) {
Logger.logInfo("CustomLogin data=========" + result);
ParseAvailableUserData(result);
}
});

Android, async and progress dialogs

I have following piece of code:
public class SomeActivity extends Activity {
Context context;
List<MenuItem> menuItems;
public void importList(View v) {
menuItems = new ArrayList<MenuItem>();
ProgressDialog dialog = ProgressDialog.show(this.context, "TITLE", "MSG");
MyAsyncTask task = new MyAsyncTask(context); // Context is here because I tried to create ProgressDialog inside pre/postExecute, but it doesn't work either
task.execute();
try {
// menuItems = task.get();
} catch(Exception e) {
// : (
}
}
#Override
protected void onCreate(Bundle savedInstanceState) {
// ...
this.context = this;
}
}
When I comment the line, where i get values from AsyncTask ("menuItems = task.get()") everythings work ok. But when I uncomment it, ProgressDialog appears AFTER the task is finished, and value returned. Why is that?
I think that it has sth to do with these contexts (that's why I included onCreate method) but I don't have any idea how to fix it. Obviously, I want ProgressDialog to display BEFORE task is finished, not after.
Not sure if relevant - MyAsyncTask is doing http request and some json parsing.
I think that it has sth to do with these contexts
Not at all. Also, when sending Context from an Activity you don't need to create a variable. Simply use this or ActivityName.this.
MyAsyncTask task = new MyAsyncTask(this);
But when I uncomment it, ProgressDialog appears AFTER the task is finished, and value returned. Why is that?
Calling get() blocks the UI, this is why you don't see the progress until it is done. You don't need to call this. The point of onProgressUpdate() is so the background thread (doInBackground()) can call it to update the UI since doInBackground() doesn't run on the UI.
Remove that line from your code and never look at it again. If there is a reason that you think you need it then please explain and we can help you find a better way.
Edit
See this SO answer on updating when the task is finished

Categories