AsyncTask concurrency issue - android

i am using Asynctask to do network operation .i am using third party library to fetch data from my database.
Problem
i am hitting query in doInBackgroun method of my asynctask that eventually call a callback method which has result to display.But onPostExecute method get called before the callback method call itslef .Hence data is never attached to adapter which i set in onPostExecute.
Issue:how to wait doInbackground method to return until the callbackmethod get called.So that i can call onPostExecute method after data get available.
below is my asyntTask and call back method is onCompleted.
in my onPostExecute i am using data to display it in adapter.so i havent fully posted it because it is bunch of code.
public class MyReviewLoadingTask extends AsyncTask<Void, Void, List<WYF_User_Items>>
{
ProgressDialog pdilog;
List<WYF_User_Items> result_to_send_to_adapter;
#Override
protected void onPreExecute()
{
// TODO Auto-generated method stub
super.onPreExecute();
pdilog=new ProgressDialog(SingleReviewActivity.this);
pdilog.setIndeterminate(true);
pdilog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
pdilog.setMessage("please wait");
pdilog.setTitle("Review Details");
pdilog.show();
}
#Override
protected List<WYF_User_Items> doInBackground(Void... params)
{
// TODO Auto-generated method stub
getDatabaseTable();
MobileServiceQuery<WYF_User_Items> query=new MobileServiceQuery<WYF_User_Items>();
query.select("review_rating","review_body","unique_user_id","userName");
wyf_user_item_table.where().field("brand_name").eq(review_name).execute(new TableQueryCallback<WYF_User_Items>() {
#Override
public void onCompleted(List<WYF_User_Items> result, int arg1,
Exception arg2, ServiceFilterResponse arg3) {
// TODO Auto-generated method stub
Log.i(TAG, "size is "+result.size());
result_to_send_to_adapter=result;
for(int i=0;i<result.size();i++)
{
Log.i(TAG, "unique user id of all user who has entered review is "+result.get(i).getUnique_user_id()+" and their names are "+result.get(i).getUserName());
}
}
});
wyf_user_item_table.select("review_rating").add(new MobileServiceQuery<WYF_User_Items>());
return result_to_send_to_adapter;
}
#Override
protected void onPostExecute(List<WYF_User_Items> result) {
// TODO Auto-generated method stub
super.onPostExecute(result);
Log.i(TAG, "onPostExecute called");
pdilog.dismiss();

You do need an AsyncTask for this usecase imo. If the MobileQueryService runs on a different Thread already, just implement your logic on the callback onCompleted provided.

Related

How to show an alertDailogue in doInBackground(..) of an AsycncTask running..?

Error: Getting error with UI thread..
when I'm trying to show an alert inside the doInBackground. Is there any posibility do this stuff?
private class LoggingTask extends AsyncTask<String, Void, Integer> {
#Override
protected Integer doInBackground(String... params) {
//Get the sever connection and return the status
if(status==0){
// show an alert here....
}
return status;
}
#Override
protected Integer doInBackground(String... params) {
// Get the sever connection and return the status
publishProgress()
#Override
protected void onProgressUpdate(Void... values) {
// TODO Auto-generated method stub
super.onProgressUpdate(values);
//Do what ever you want
}
Do in background method doesnot allowed for UI changes,if you want to make any UI changes do in onpostexecute method
Do this way
#Override
protected Integer doInBackground(String... params) {
// Get the sever connection and return the status
if (status == 0) {
new Handler().post(new Runnable() {
#Override
public void run() {
// show an alert here....
}
});
}
return status;
}
Make a method that creates the dialog in your activty ( context would be the activity ) not in the AsyncTask. So when your
if ( status == 0 )
returns true, you call the method from the UI thread. In this way you are not creating the dialog in the AsyncTask and it should work.
doInBackground() is not the right place to do the UI related Task. You have to do it in onPostExecute. Or you can can start the dialog in OnPreExecute() and than cancel the dialog onPostExecute().
Async tasks don't run on the ui thread that's why you can't do that. Store a boolean. Then call the alert dialog after the asynchronous task completes in the onpostexecute method.

Start AsyncTask in Method and return its value

I hope the question is I want to create a method which starts an AsyncTask, waits until the Task ends and then return the value which is provided in the onPostExecute method. So from my main I only want to call the method and get the value which is returned by te AsyncTask. Is that possible? And how does this method have to look like?
Just execute AsyncTask and do call the particular method which contains logic onPostExecute() method. See the example code what i have used.
protected void onCreate(Bundle savedInstanceState) {
customContactList = (ListView)findViewById(R.id.listView1);
ContactsAsyncTask newTask = new ContactsAsyncTask(this);
newTask.execute();
}
private class ContactsAsyncTask extends AsyncTask<Void, Void, ArrayList<String> >{
ProgressDialog dialog;
private SecondActivity context;
public ContactsAsyncTask(SecondActivity secondActivity) {
// TODO Auto-generated constructor stub
this.context = secondActivity;
}
protected void onPostExecute(ArrayList<String> result) {
super.onPostExecute(result);
context.useContacts(result);
}
public void useContacts(ArrayList<String> data) {
adapter = new CustomAdapter(SecondActivity.this,data);
customContactList.setAdapter(adapter);
}
Let say you have an instance of AsyncTask called task. In such case you do:
task.execute(parameters);
Result result = task.get();
Method get() will wait until task is completed and will return result from it.
P.S. You are trying to execute asynchronous task synchronously, which raises a question - "Do you need AsyncTask at all"?

listview refresh aynctask in android

I am unable to refresh my listview. I know there are lots of help available for this. But I am unable to get my listview refreshed.
Lemme edit my code a little bit showing the AsyncTask
There are two Activities. The first Activity is having the list view to see what is being shared and the second activity has an edit text box (to input inorder to share) and a button. On clicking the button, it returns me the string which is the json response and I need to add this in the previous activity.
Now the problem is, when I refresh the first page fully hitting the server it gets the response but this is not what I want. It should not go back to the server. It should simply add in the list view adapter.
I have commented the code in the PostExecute(). I have tried the everyway but it is not reflecting.
public class ShareAsyncTask extends AsyncTask<String, Void, ArrayList<EventsStreamBean>> {
public ProgressDialog pd = new ProgressDialog(EventStreamActivity.this);
String success_share_val;
#Override
protected ArrayList<EventsStreamBean> doInBackground(
String... result) {
// TODO Auto-generated method stub
JSONObject jsonobj = new JSONObject(result[0].toString());
success_share_val = jsonobj.getString(Constants.SUCCESS);
//checks the success value
if(success_share_val.equalsIgnoreCase("1")) {
JSONArray events_stream_share_array = jsonobj.getJSONArray("streamArray");
if(events_stream_share_array.length() > 0) {
for(int i=0; i<events_stream_share_array.length(); i++) {
EventsStreamBean events_stream_bean = new EventsStreamBean();
JSONObject events_stream_object = events_stream_share_array.getJSONObject(i);
events_stream_bean.setStreamId(events_stream_object.getString(Constants.STREAM_ID));
events_stream_bean.setStreamType(events_stream_object.getString(Constants.STREAM_TYPE));
events_stream_bean.setUserId(events_stream_object.getString(Constants.USER_ID));
events_stream_bean.setUserName(events_stream_object.getString(Constants.USER_NAME));
events_stream_bean.setUserType(events_stream_object.getString(Constants.USER_TYPE));
events_stream_bean.setUserAvatar(events_stream_object.getString(Constants.USER_AVATAR));
arraylist_events_stream.add(events_stream_bean);
}
}else {
Log.i("Test", "No Events Streams Available");
}
}
}catch(Exception e) {}
return arraylist_events_stream;
}
#Override
protected void onPreExecute() {
// TODO Auto-generated method stub
super.onPreExecute();
this.pd.setMessage("Loading....");
pd.setCanceledOnTouchOutside(false);
pd.setCancelable(false);
this.pd.show();
}
#Override
protected void onPostExecute(final ArrayList<EventsStreamBean> result) {
// TODO Auto-generated method stub
super.onPostExecute(result);
if(this.pd.isShowing()) {
this.pd.dismiss();
}
Toast.makeText(EventStreamActivity.this, "Post shared successfully", Toast.LENGTH_SHORT).show();
new EventsStreamAsyncTask().execute(temp_val);
/*runOnUiThread(new Runnable() {
public void run() {
//EventStream_Customadapter adapter = (EventStream_Customadapter) list_view.getAdapter();
//adapter.clearData();
adapter.updateData(result);
//adapter = new EventStream_Customadapter(EventStreamActivity.this, arraylist_events_stream);
//list_view.setAdapter(adapter);
//adapter.notifyDataSetChanged();
}
});*/
}
}
You should call setAdapter() only once in your entire code.
Then add a method in your adapter that adds more data when you want to add more data or sets adapter item.
public void addMoreData(List<String> newItems) {
this.list.addAll(newItems);
}
public void setList(List<String> newList) {
this.list = newList;
}
Call notifyDataSetChanged() after you set new list or add more data.
as per what you want to achieve there is no need for you to use threads
have a look at the following link it shows how to do it in the same activity
http://wptrafficanalyzer.in/blog/dynamically-add-items-to-listview-in-android/
In this they have done it in a single activity. if you want to do it with 2 activities let me know i will tell you how to do it.

Calling external method from asynctask and updating ProgressDialog with data of this external method

I have a general question:
Is it possible to update a ProgressDialog Message with data coming from a method, that is called by an AsyncTask
doInBackground(Void... arg0)
Purpose:
The method is generating and returning a file. Depending on the amount of data, this may last more or less time. I would like to inform the user about the progress, telling the current page number of the generating file (page number is a value within the external method).
any suggestions how to access the value and showing it in the ProgressDialog?
I tried already:
declaring page value public and static and access it from the
onProgressUpdate(
with the code below the page value is returned its initial value, however its not updating any idea to obtain the updated value?:
public class prepareFile extends AsyncTask<String, String, String> {
#Override
protected void onProgressUpdate(String... values) {
// TODO Auto-generated method stub
super.onProgressUpdate(values);
progressDialog.setMessage(getResources().getString(
R.string.CalcGatheringInformation)+"\n"+Filehandler.pages+" - "+values);
}
#Override
protected String doInBackground(String... arg0) {
// TODO Auto-generated method stub
publishProgress(String.valueOf(Filehandler.pages));
prepareFiles();
return null;
}
#Override
protected void onPostExecute(String result) {
// TODO Auto-generated method stub
super.onPostExecute(result);
progressDialog.dismiss();
}
}
Thanks,
You can refer to this link: A very simple example
http://eliasbland.wordpress.com/2011/03/11/an-example-of-how-to-run-a-background-task-and-report-progress-in-the-status-bar-using-asynctask-on-android/
onProgressUpdate is called after publishProgress and you do that only once, before you even start preparing file with prepareFiles - that's why it is not changing later and shows initial value.
I believe you should do something along
#Override
protected String doInBackground(String... arg0) {
// TODO Auto-generated method stub
while(!allPagesPrepared()){
publishProgress(String.valueOf(Filehandler.pages));
preparePage();
}
return null;
}
or divide prepareFiles job in some other way and call publishProgress every few steps of your loading algorithm.

Error in simple AsyncTask

In my android app, I am trying to make use of ASYNC Task ... whenever I set text of any TextView of EditText in doInBackground(...) .... I get an error , but when I set the same in onCreate , it works .. :(
here is the code :
public class RemoteFiles extends Activity {
EditText etrmm ;
TextView t;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_remote_files);
initVars();
new ConnectToServer().execute(null);
}
protected void initVars(){
etrmm =(EditText)findViewById(R.id.etRM);
etrmm.setText("UnSET");
t=(TextView)findViewById(R.id.RM);
t.setText("UnsET");
}
public class ConnectToServer extends AsyncTask<String, Integer, Void> {
//private ProgressDialog pd = new ProgressDialog(RemoteFiles.this);
private ProgressDialog pdd ;
#Override
protected Void doInBackground(String... params) {
// TODO Auto-generated method stub
for(int i=0;i<20;i++){
publishProgress(5);
try {
Thread.sleep(88);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
etrmm.setText("Edittext SET");
return null;
}
#Override
protected void onPostExecute(Void result) {
// TODO Auto-generated method stub
super.onPostExecute(result);
pdd.dismiss();
}
#Override
protected void onPreExecute() {
// TODO Auto-generated method stub
super.onPreExecute();
// pd.setMessage("Connecting to server... ");
// pd.show();
pdd = new ProgressDialog(RemoteFiles.this);
pdd.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
pdd.setMax(100);
pdd.show();
}
#Override
protected void onProgressUpdate(Integer... values) {
// TODO Auto-generated method stub
super.onProgressUpdate(values);
pdd.incrementProgressBy(values[0]);
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.activity_remote_files, menu);
return true;
}}
here is the layout :
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<TextView
android:id="#+id/RM"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="#dimen/padding_medium"
android:text="#string/hello_world"
tools:context=".RemoteFiles" />
<EditText
android:id="#+id/etRM"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:ems="10" >
<requestFocus />
</EditText>
logcat says android.view.ViewRoot$CalledFromWrongThreadException
doInBackground(String... params) not run on UI Thread, so you can't set text for edittext there
if you want to set edittext value, return the value in doInBackGround and use the parameter value in onPostExecute and set it in onPostExecute()
You can't do UI stuff in doInBackground(). This should be done in any of the other methods. For your purposes, probably onPostExecture()
Take a look at the AsyncDocs, doInBackground() doesn't run on the main (UI) thread
AsyncTask's onpreExecute and onPostExecute methods run o UI Thread. You can make changes to the UI here. doInBackground does not run on UI thread. It is used to do long Running operations. Runs in the background thread. You cannot update ui from the background thread in doinBackground.
Set text in textview in onPostExecute method of asynctask.
The document in the developer site has detailed information regarding the topic under the heading THE 4 STEPS. http://developer.android.com/reference/android/os/AsyncTask.html

Categories

Resources