Update data from within AsyncTask - android

How can I add elements to an Array or ArrayList from the AsyncTask class(Inner) , from where I am receiving data from server .
I tried adding elements from doInBackgroud() and printing them in onPostExecute() ,it works fine then .
But the Array and List are both empty when I am trying to access them outside the AsyncTask class.
Code :-
public String[][] mov_details ;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.vpmovies);
mov_details=new String[NUM_OF_MOVIES][9];
new MyHttpMovies().execute();
Toast.makeText(this,mov_details[0][2],Toast.LENGTH_LONG).show(); //prints blank
doInBackgroud() and onPostExecute() -
for(int i=0; i < jsonArray.length(); i++){
JSONObject jsonObject = jsonArray.getJSONObject(i);
//parsing some json
mov_details[i][0] = (jsonObject.optString("name").toString());
mov_details[i][1] = (jsonObject.optString("lang").toString());
mov_details[i][2] = (jsonObject.optString("genre").toString());
.
.
.
.
return mov_details;
}
protected void onPostExecute(String[][] strings) {
super.onPostExecute(strings);
Toast.makeText(VPmovies.this,strings[0][1],Toast.LENGTH_LONG).show();
// prints successfully
}

public class MainActivity extends AppCompatActivity {
ArrayList<String> list;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public class fetchData extends AsyncTask<Void,Void,Void> {
#Override
protected Void onPreExecute() {
super.onPreExecute();
list = new ArrayList<String>();
}
#Override
protected Void onPostExecute(Void... params) {
...
list.add("bla bla");
...
return null;
}
}
}

Use publishProgress("data") inside your doInBackgroung and pass data from AsyncTask to your Activity/Fragment. Keep in mind doInBackgroung runs in separate thread you can not directly update your main GUI from doInBackgroung, if you will call some methods directly from doInBackgroung than your calling method should run in main thread.
#Override
protected void onProgressUpdate(String... values) {
super.onProgressUpdate(values);
// send data to your required location its recommended to use interfaces for communication
}

Solved by simply using the get() method on the AsyncTask instance that would return the output/result of the AsyncTask backgroud thread.
mov_details = new MyHttpMovies().execute().get(); //returns 2d array
and instead of using mov_details variable inside doInBackground() , I used some other 2d array variable local to the just AsyncTask.

Related

Fetch data from server and display listview in seprate thread

I want to access and populate a ListView from seprate thread... But its object has not its scope in new thread... What is the solution for it?
ListView FilesListView;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
FilesListView= (ListView)findViewById(R.id.remoteFilesListView);
new Thread ( new Runnable() {
#Override
public void run() {
// fetch data from server…
String xmlFormServer = Worker.getXmlresponse();
Log.d("Response from Serever", xmlFormServer;
// FilesListView object of Listview is not accessable in this thread to populate data…
}
}).start();
}
You cannot populate populate ListView/RecyclerView or any other view or component on another thread.
That has to be on the MainThread(UIThread).
Checkout this link for more info about UIThread in android and how its works.
What is the Android UiThread (UI thread)
However, you can put the logic or IO operation on different thread asynchronously and then you can put populate the result on UI thread.
One approach would be to use AsyncTask.
https://developer.android.com/reference/android/os/AsyncTask.html
Something like this..
new AsyncTask<Void, Void, String >() {
// Runs on Worker thread
#Override
protected String doInBackground(Void... params) {
String xmlFormServer = Worker.getXmlresponse();
return xmlFormServer;
}
// Runs on Ui thread
#Override
protected void onPostExecute(String data) {
if(data != null){
adapter.setDate(data);
adapter.notifyDataSetChanged();
}
}
}.execute();
You should to implement adapter for your ListView
Try to follow pattern below
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
FilesListView = (ListView) findViewById(R.id.remoteFilesListView);
adapter = new SimpleAdapter(/*...*/); // implement your custom adapter or use native
// 1. set adapter into FileListView
FilesListView.setAdapter(adapter);
new AsyncTask<Void, Void, List>() {
#Override
protected List doInBackground(Void... params) {
String xmlFormServer = Worker.getXmlresponse();
Log.d("Response from Serever", xmlFormServer;
// 2. READ YOUR DATA HERE
List result = null; //
// 3. send result to ui thread
return result;
}
#Override
protected void onPostExecute(List list) {
// the method executes on ui thread
// 4. put your data into adapter
// you should implement the method or create native adapter
adapter.setDate(list);
// 5. refresh list - only UI THREAD can do this
adapter.notifyDataSetChanged();
super.onPostExecute(list);
}
}.execute();
}

Safely insert data on SQLite database

I need to load a data coming from a service in a table on the SplashScreenActivity. I've followed this tutorial and everything works just fine. I have also added a custom AsyncTask to run the insert loop in the background.
The problem is that if a configuration change happens in the middle of the insert (e.g. screen rotation) everything blows up and I get corrupted data saved on the database.
I've read stuff about CursorLoader but that's only for querying the database. I've also looked at ContentProviders but they don't solve the problem.
Any ideas on how to handle this problem?
What I basically need is:
Access database from a background thread to keep the UI responsive.
Handle configuration changes when doing inserts on the database.
UPDATE:
public class SplashScreenActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_splash_screen);
...
// Create a Volley Request and fetch data
}
When I get the Response object I start the AsyncTask:
new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
if (response.optString("lastrunstatus").equals(
"success")) {
JSONObject results = response
.optJSONObject("results");
JSONArray objects = results
.optJSONArray("objects");
new HandleResponseAsyncTask().execute(objects);
}
}
In the AsyntTask, I insert all objects:
private class HandleResponseAsyncTask extends
AsyncTask<JSONArray, String, Void> {
#Override
protected void onPreExecute() {
mDataSource.open();
}
#Override
protected Void doInBackground(JSONArray... params) {
publishProgress("Deleting data...");
mProductosDataSource.deleteAll();
publishProgress("Saving data...");
JSONArray objects = params[0];
for (int i = 0; i < objects.length(); i++) {
JSONObject object = objects.optJSONObject(i);
// Get each column value from JSON
...
mDataSource.insert(id, name, description);
}
return null;
}
#Override
protected void onProgressUpdate(String... messages) {
mTextViewLoading.setText(messages[0]);
}
#Override
protected void onPostExecute(Void result) {
mDataSource.close();
// Go to main
startMainActivity();
}
}
NOTE: mDataSource holds an instance of a helper class that calls the methods in my custom SQLiteOpenHelper class.

How to load EditText fields with data fetched from server

I've got an Activity where before showing the Text/EditText fields, I want to make a call to the server to get the details and then setText of the fields based on the data gotten back from the server.
Below is what I'm doing but the fields don't seem to have the data fetched from the server. I think because I am calling an AsyncTask which gets run in the background and in the mean time the fields are shown to the user.
Question
How does android deal with this? What pattern should I be using?
This activity gets called from MainActivity.java like so:
Intent act = new Intent(getApplicationContext(), MySecondActivity.class);
create.putExtra("theId", "138");
startActivity(create);
in MySecondActivity.java i do the following:
public class MySecondActivity extends SherlockActivity {
private EditText fieldOne;
private EditText fieldTwo;
private MyObj obj = new MyObj();
private int id;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.shared_activity);
fieldOne = (EditText)findViewById(R.id.field_one);
fieldTwo = (EditText)findViewById(R.id.field_two);
id = Integer.parseInt(getIntent().getStringExtra("theId"));
new FetchDetail().execute();
//If I put the below two lines inside the AsyncTask then I get an error:
//"Only the original thread that created a view hierarchy can touch its views."
fieldOne.setText(obj.getOne()); //
fieldTwo.setText(obj.getTwo()); //
}
class FetchDetail extends AsyncTask<String, String, String> {
#Override
protected String doInBackground(String... strings) {
final RestAdapter restAdapter = new
RestAdapter.Builder().setServer("http://10.0.2.2:8080").build();
final MyTaskService apiManager = restAdapter.create(MyTaskService.class);
final MyObj obj = apiManager.getDetails(id);
return null;
}
}
}
If I put the below two lines inside the AsyncTask then I get an error
Have these in onPostExcute
fieldOne.setText(obj.getOne());
fieldTwo.setText(obj.getTwo());
Do your background computation in doInbackground. Return result in doInbackground. The result of doInbackground computation is a pram to onPostExecute.
So you can update ui in onPostExecute which is invoked on the ui thread
Example:
protected String doInBackground(String... params)
{
// background computation
return "hello"; // return string
}
#Override
protected void onPostExecute(String result) // string
{
super.onPostExecute(result);
fieldOne.setText(result); // hello is set to field One
}
For more info read the topic under The4Steps in the docs
http://developer.android.com/reference/android/os/AsyncTask.html
AsyncTask has 3 methods to override:
1: onPreExecute
Executes on UI thread. So do what you want to do on UI before service call here(Ex: show a progress dialog).
2: doInBackground
Executes in background so perform long running task like fetching data from server.
3: onPostExecute
Executes on UI thread and gets called once doInBackground is completed you can process the result here and update the UI
Ex:
public class RestServiceTask extends AsyncTask<String, Void, String> {
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected String doInBackground(String... params) {
}
#Override
protected void onPostExecute(String result) {
}
}

objects not added to arraylist (asynctask)

In my main activity I got an arraylist called data. I call an asynctask and do some stuff that gives me a different arraylist called values.
In the post execute of the asynctask I want to use items in 'values' to add some objects to 'data'. However, when debugging I noticed that the objects dont get added.
public class MainActivity extends Activity
{
ArrayList<DataItem> data;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
data = new ArrayList<DataItem>();
update();
}
public void update()
{
AsyncCallAWS thisTask = new AsyncCallAWS();
thisTask.execute();
}
private class AsyncCallAWS extends AsyncTask<String, Void, Void>
{
ArrayList<String> values = new ArrayList<String>();
protected void onPostExecute(Void result)
{
Log.i(TAG, "onPostExecute");
DataItem d;
for(String s : values)
{
d = new DataItem();
d.setValue(s);
d.setDataStreamName("test");
data.add(d);
}
}
//code to fill array
I'm guessing it's because I try to add items from the asynctask? Idk how to solve this, I need the data arraylist for a listview.
In AsyncTask class override method onProgressUpdate(), where you will add elements to array. Then in doInBackground() call publishProgress() for sending elements to onProgressUpdate(). Here http://developer.android.com/reference/android/os/AsyncTask.html -is great example.
private class TestAsyncTask extends AsyncTask<Object, String, Object> {
#Override
protected Object doInBackground(Object... params) {
String item = "";
//Do some stuff
publishProgress(item);
return null;
}
#Override
public void onProgressUpdate(String... value) {
data.add(value[0]);
}
#Override
protected void onPostExecute(Object result) {
}
}
I dont think you should create objects in the onPostExecute-method. Instead create it in the doInBackground-method of the class that extends AsyncTask, and then use set-methods in the onPostExecute-metod.

how do i send data back from onPostExecute in an AsyncTask?

my issue is the same as this
Instance variable of Activity not being set in onPostExecute of AsyncTask or how to return data from AsyncTask to main UI thread
but i want to send the data back to the same calling activity. Doesnt startActivity for intents always restart the activity
On option is to use listeners, where you create an interface that your activity implents, something like:
public interface AsyncListener {
public void doStuff( MyObject obj );
}
That way, if you're subclassing AsyncTask, it is easy to add this listener, then in onPostExecute(), you could do something like:
protected void onPostExecute( MyObject obj ) {
asyncListener.doStuff(obj);
}
This depends on your class structure, but if your AsyncTask is a class within your Activity then you can reference methods of that activity.
What you would do is in your onPostExecute method call a function of your Activity that passes some data that was retrieved in the AsyncTask to the activity where you can then use it..
The code would look like this
class YourActivity extends Activity {
private static final int DIALOG_LOADING = 1;
public void onCreate(Bundle savedState) {
setContentView(R.layout.yourlayout);
showDialog(DIALOG_LOADING);
new LongRunningTask1().execute(1,2,3);
}
protected Dialog onCreateDialog(int dialogId) {
switch(dialogId) {
case DIALOG_LOADING:
ProgressDialog pDialog = new ProgressDialog(this);
pDialog.setTitle("Loading Data");
pDialog.setMessage("Loading Data, please wait...");
return pDialog;
default:
return super.onCreateDialog(dialogId);
}
}
private void onBackgroundTaskDataObtained(List<String> results) {
dismissDialog(DIALOG_LOADING);
//do stuff with the results here..
}
private class LongRunningTask extends AsyncTask<Long, Integer, List<String>> {
#Override
protected void onPreExecute() {
//do pre execute stuff
}
#Override
protected List<String> doInBackground(Long... params) {
List<String> myData = new ArrayList<String>();
for (int i = 0; i < params.length; i++) {
try {
Thread.sleep(params[i] * 1000);
myData.add("Some Data" + i);
} catch(InterruptedException ex) {
}
}
return myData;
}
#Override
protected void onPostExecute(List<String> result) {
YourActivity.this.onBackgroundTaskDataObtained(result);
}
}
}
So the typical flow is like this, set the view of the current page, and then show a progress dialog. Right after that start the async task (or whenever, it doesn't matter really).
After your async task is complete, call a function of the activity and pass it the data.
Don't use shared data within the async task or you risk issues with threading.. Instead once you are done with it pass it to the activity. If you want to update the view progressively while doing work you can use on onProgressUpdate

Categories

Resources