nested AsyncTask and onPostExecute - android

I am using a AsyncTask (1) in another AsyncTask (2).
AsyncTask 1 fetches online user data, counts the number of entries in the response and for each entry, in onPostExecute displays a username and runs a new AsyncTask (2) to fetch a image from a server and load it into a ImageView. This all happens in onPostExecute.
This is working flawlessly, the user data is fetched and shown, and the images are shown one by one for each entry.
However, the itteration through the array and the updating of the TextView in AsyncTask 1's onPostExecute happens so fast, it basically only shows the last user name in the array, the other ones are loaded, but impossible to detect with the human eye :)
Meanwhile, AsyncTask 2 is still fetching images from online, and showing profile images for the wrong users.
The problem I have here obviously, is these 2 need to be in sync.
So I thought I just wait for the output in AsyncTask 2 with the get() method, but now nothing is updated at all anymore, no TextView...this is unexpected behaviour for me.
So, the question is how to sync the 2 AsyncTasks?
bit of code to clarify, if it's still needed
//instantiate first AsyncTask
new AsyncRequest().execute(bundle);
private class AsyncRequest extends AsyncTask<Bundle, Void, String> {
protected String doInBackground(Bundle... bundle) {
String data = null;
try {
data = request(null, bundle[0]); //request the data
return data;
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return data;
}// end method
protected void onPostExecute(String response) {
JSONArray data = null;
try {
JSONObject response2 = Util.parseJson(response);
data = response2.optJSONArray("data");
int amount = data.length();
TextView s1 = (TextView) findViewById(R.id.some_id);
s1.setText("" + amount); //displays number of items
//display the data
for(int i=0; i<amount; i++){
String email = "";
String id = "";
JSONObject json_obj = data.getJSONObject(i);
Log.d("JSONObject ", ""+json_obj);
String name = json_obj.getString("name");
if (json_obj.has("email")){
email = json_obj.getString("email");
}
if (json_obj.has("id")){
id = json_obj.getString("id");
}
String picture = "http://www.domain.com/"+id+"/picture";
TextView s2 = (TextView) findViewById(R.id.name_placeholder);
s2.setText(name);
//here we do a new AsynTask for each entry and wait until the data is fetched
new DownloadProfileImageTask().execute(picture, name).get();
}
} catch (JSONException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}// end method

It is not quite clear why you are calling setText of the single TextView with the name of multiple names. As you have mentioned, although you had setText of all the names, you only see a single name. May be you need to use a ListView or something like that.
Now regarding your question: probably you don't need two AsyncTasks. You can do everything in a single AsyncTask. The code will be something like below:
//Create a Holder class as a data holder.
//For simplicity, public attributes are used
class Holder{
public String name;
public String email;
public String id;
public BitmapDrawable imageDrawable;
}
//instantiate the AsyncTask
new AsyncRequest().execute(bundle);
private class AsyncRequest extends AsyncTask<Bundle, Holder, Integer> {
protected Integer doInBackground(Bundle... bundle) {
int amount = 0;
try {
data = request(null, bundle[0]); //request the data
JSONArray data = null;
JSONObject response2 = Util.parseJson(response);
data = response2.optJSONArray("data");
amount = data.length();
//display the data
for(int i=0; i<amount; i++){
Holder holder = new Holder();
holder.email = "";
holder.id = "";
JSONObject json_obj = data.getJSONObject(i);
Log.d("JSONObject ", ""+json_obj);
holder.name = json_obj.getString("name");
if (json_obj.has("email")){
holder.email = json_obj.getString("email");
}
if (json_obj.has("id")){
holder.id = json_obj.getString("id");
}
String picture = "http://www.domain.com/"+id+"/picture";
//Fetch the image and create a Drawable from it - Synchronously
holder.imageDrawable = getImageDrawable(picture, name);
publishProgress(holder);
}
} catch (Exception e) {
e.printStackTrace();
}
return amount;
}// end method
protected void onProgressUpdate(Holder... holder) {
//Update the user name and image
TextView s2 = (TextView) findViewById(R.id.name_placeholder);
s2.setText(holder[0].name);
ImageView imgView = (ImageView) findViewById(R.id.imageViewId);
imgView.setImageDrawable(holder[0].imageDrawable);
}
protected void onPostExecute(Integer amount) {
TextView s1 = (TextView) findViewById(R.id.some_id);
s1.setText(amount.toString()); //displays number of items
}// end method

Related

Why image receive slow from server json formate?

here i am receiving some picture from json in the form of json and display that picture in listview, but the problem is that images receive smoothly slow, mean display 1 pic and after3,4 second display one more and simillarly.
i want picture should display atonce,so what sholud i do? here is some code
protected void onPostExecute(String result){
String s = result.trim();
loadingDialog.dismiss();
JSONObject respObject;
try {
respObject = new JSONObject(s);
String active = respObject.getString("status_message");
if(active.equalsIgnoreCase("success")){
JSONArray array = respObject.getJSONArray("response");
for (int i =0; i<array.length();i++){
JSONObject jsonObject = array.getJSONObject(i);
String icon= jsonObject.getString("image");
String name = jsonObject.getString("title");
String date = jsonObject.getString("date");
id = jsonObject.getString("id");
platformno = jsonObject.getString("platform");
//this is for integer datatype receving
// id = jsonObject.getInt("id");
//platformno = jsonObject.getInt("platform");
listitem.add(new Latest_list(icon,name,date,id,platformno));
}
lv.setAdapter(new Latest_customAdpater(LatestNews.this, listitem));
}else {
Toast.makeText(LatestNews.this, "services received Fail", Toast.LENGTH_LONG).show();
}
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
And here is custom adapter code
holder.icon=(ImageView)convertView.findViewById(R.id.NewsIconID);
holder.name=(TextView) convertView.findViewById(R.id.txt_newsNameID);
holder.date=(TextView) convertView.findViewById(R.id.txt_newsDateID);
holder.id= (TextView) convertView.findViewById(R.id.txt_hiddenID);
holder.platform=(TextView) convertView.findViewById(R.id.txt_hidden2);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
Latest_list services=newslist.get(position);
Picasso.with(context).load(services.getNews_icon()).into(holder.icon);
Log.d("Url",services.getNews_icon());
holder.name.setText(services.getNews_name());
holder.date.setText(services.getNews_date());
holder.id.setText(services.getNews_id());
holder.platform.setText(services.getNews_platform());

Queue of AsyncTasks on Listview, how to get rid of no longer needed ones?

I am using AsyncTasks to load data to items in a listview to avoid a laggy scroll, I am getting everything from webservices including bitmaps but I have that part covered.
From what I gather, items with running threads won't be recycled, only when the thread stops, the thread at least keeps running, I placed a few system.out.println to keep track of what's happening and I noticed that if I scroll down the listview quickly, say 20 events, even though I am only seeing 3 or 4 I see the outputs on the logcat of all the System.out.println, one every 1/4 second or so which is roughly the time it takes to load each image and other text stuff.
So I need to wait an unacceptable amount of time til it gets to the currently visible items since there can be only one AsyncTask running at any given moment, I know there are ways to run multiple threads but I want to avoid that path since I am afraid it may overload the phone and in this case I am pretty sure it would result in a out.of.memory error.
If I scroll too fast I will scroll items that have not even been loaded yet, still their threads jump to the queue, I am running AsyncTask inside custom adapters, every time a item gets created the thread starts or their threads get queued and when scrolling fast some items that are no longer visible still have their threads queued and they end up delaying the ones visible for nothing just to be destroyed immediately after the thread is finished.
I already tried using a setRecyclerListener inside the custom adapter but only the initial visible items got loaded and when scrolling down nothing would show up.
If you have any suggestion don't bother going through the code but I'll leave it here anyway but what I was really looking for was ideas to avoid this, they may require minor adjustments to my code or rebuilding the whole class as long as they work.
On the code I am posting is with the recyclerListener, one thing that I may be missing is that to use the listener I had to associate it to a listview and I am inside the custom adapter class so on the listview main class I declared the listview as a public variable and got it into the custom adapter class that way.
/////////////////////////////////
class CustomAdapterEvents extends ArrayAdapter<String>{
private AsyncTask<String, Void, JSONObject> listviewTextAssembler;
private AsyncTask<String, Void, Bitmap> listviewImageAssembler;
public CustomAdapterEvents(Context context, ArrayList<String> IDlist) {
super(context, R.layout.custom_row_events, IDlist);
}
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = LayoutInflater.from(getContext());
LayoutInflater inflater2 = LayoutInflater.from(getContext());
final View customView = inflater.inflate(R.layout.custom_row_events, parent, false);
final View customView2 = inflater2.inflate(R.layout.custom_row_trending, parent, false);
//Trending Items
final TextView trendingTitle = (TextView) customView2.findViewById(R.id.trendingEventTitle);
final TextView trendingDate = (TextView) customView2.findViewById(R.id.trendingEventDate);
final TextView trendingHour = (TextView) customView2.findViewById(R.id.trendingEventHour);
final TextView trendingSpot = (TextView) customView2.findViewById(R.id.trendingEventSpot);
ImageView trendingImage = (ImageView) customView2.findViewById(R.id.trendingEventImage);
//Trending Items
final TextView listviewTitle = (TextView) customView.findViewById(R.id.listEventTitle);
final TextView listviewDate = (TextView) customView.findViewById(R.id.listEventDate);
final TextView listviewHour = (TextView) customView.findViewById(R.id.listEventHour);
final TextView listviewSpot = (TextView) customView.findViewById(R.id.listEventSpot);
final ImageView listviewImage = (ImageView) customView.findViewById(R.id.listEventImage);
///////////////
final RotateAnimation anim = new RotateAnimation(0f, 359f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
final ImageView loading = (ImageView) customView.findViewById(R.id.loadingView);
anim.setInterpolator(new LinearInterpolator());
anim.setRepeatCount(Animation.INFINITE);
anim.setDuration(700);
loading.startAnimation(anim);
TypeFaceUtil.overrideFont(getContext(), "SERIF", "fonts/lato-reg.ttf");
MainScreen.listview.setRecyclerListener(new AbsListView.RecyclerListener() {
#Override
public void onMovedToScrapHeap(View view) {
System.out.println("cancel that *%$# for *%#!'s sake!");
listviewImageAssembler.cancel(true);
listviewTextAssembler.cancel(true);
}
});
///LISTVIEW PROCESS
listviewTextAssembler = new AsyncTask<String, Void, JSONObject>(){
protected JSONObject doInBackground(String... params) {
int position = Integer.parseInt(params[0]);
//GET JSON
String result = "";
WebConnector connector = new WebConnector();
try {result = connector.getResponseText("listview/1");}
catch (MalformedURLException e) {}
catch (IOException e){}
/////////
JSONArray jsonArray = new JSONArray();
JSONObject completeJson = new JSONObject();
String thumbnail = "";
JSONObject eventJson = new JSONObject();
try {
completeJson = new JSONObject(result);
jsonArray = completeJson.getJSONArray("eventos");
eventJson = jsonArray.getJSONObject(position-1);
thumbnail = eventJson.getString("thumbnail");
}catch (JSONException e){e.printStackTrace();}
System.out.println("EVENT > "+eventJson);
return eventJson;
}
#Override
protected void onProgressUpdate(Void... values) {
}
#Override
public void onPostExecute(JSONObject eventJson)
{
loading.setAnimation(null);
loading.setVisibility(View.GONE);
String id = "";
String title = "";
String date = "";
String hour = "";
String address = "";
Bitmap image = null;
try{
title = eventJson.getString("title");
date = eventJson.getString("date");
hour = eventJson.getString("time");
address = eventJson.getString("city");
}catch (JSONException e){e.printStackTrace();}
listviewTitle.setText(title);
listviewDate.setText(date);
listviewHour.setText(hour);
listviewSpot.setText(address);
}
};
listviewImageAssembler = new AsyncTask<String, Void, Bitmap>(){
protected Bitmap doInBackground(String... params) {
int position = Integer.parseInt(params[0]);
//GET JSON
String result = "";
WebConnector connector = new WebConnector();
try {result = connector.getResponseText("listview/1");}
catch (MalformedURLException e) {}
catch (IOException e){}
/////////
JSONArray jsonArray = new JSONArray();
JSONObject completeJson = new JSONObject();
String thumbnail = "";
JSONObject eventJson = new JSONObject();
try {
completeJson = new JSONObject(result);
jsonArray = completeJson.getJSONArray("eventos");
eventJson = jsonArray.getJSONObject(position);
thumbnail = eventJson.getString("thumbnail");
}catch (JSONException e){e.printStackTrace();}
System.out.println("EVENT > "+eventJson);
Bitmap image = connector.drawable_from_url(thumbnail);
return image;
}
#Override
public void onPostExecute(Bitmap image)
{
listviewImage.setImageBitmap(image);
image = null;
}
};
String pos = ""+position;
listviewTextAssembler.execute(pos);
listviewImageAssembler.execute(pos);
return customView;
}
}
I ended up using:
listviewTextAssembler.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, pos);
instead of:
listviewTextAssembler.execute(pos);
pos is just a string i pass along...
This is what i was trying to avoid but it will have to do for now... Will be looking forward for suggestions though on how to kill running threads that are no longer useful or remove others from the queue or use a Last in First out model and limit the number of threads to 5 which is the maximum items that are visible at once. Not short of ideas, just short on know-how but i guess it's all part of the learning curve.
Cheers

how to maintain array list for new added element?

Hello every one i am working on app which is similar to the facebook.In that currently i am stuck in one point like we have posts in facebook which shows on our wall in that all the post is shows in bulk like 20 20 fashion that same thing i want to apply in my app. For that thing i use listview which get value form server and create view according to that i also get all value but the problem is that when i add 1st 20 value then it work fine but when i add another 20 value it will delete the previous data in listview.
any idea how i can do this thing in my app and thanks in advance....
my function get value from the server
private void getPostnew(String start) {
String URL = start;
System.out.println("start value new :" + start);
final String usernamefor = "";
aq = new AQuery(getParent());
listitem = new ArrayList<BeanTop>();
aq.ajax(URL, JSONObject.class, 10 * 1000,
new AjaxCallback<JSONObject>() {
#Override
public void callback(String url, JSONObject json1,
AjaxStatus status) {
System.out.println("json " + json1);
if (json1 == null) {
} else {
try {
JSONArray jarray = json1
.getJSONArray("subject");
for (int j = 0; j < jarray.length(); j++) {
try {
JSONObject j1 = jarray.getJSONObject(j);
try {
listcount = j1
.getString("likecount");
} catch (Exception e) {
listcount = "0";
}
AddObject(j1.getString("text"),
j1.getString("leftpic"),
j1.getString("rightpic"),
j1.getString("rightvotecount"),
j1.getString("leftvotecount"),
j1.getString("textleft"),
j1.getString("textright"),
j1.getString("date_created"),
j1.getString("voteid"),
j1.getString("user"),
j1.getString("dom"),
j1.getString("Isvoted"),
j1.getString("Islike"),
j1.getString("profilepic"),
listcount,
j1.getString("commentcount"));
} catch (Exception e) {
e.printStackTrace();
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
FriendlistAdapter ad = new FriendlistAdapter(Top.this,
listitem);
subjectlist.setAdapter(ad);
ad.notifyDataSetChanged();
}
});
}
method for save the data in bean class
private void AddObject(String string1, String string2, String string3,
String string5, String string6, String string7, String string8,
String string9, String string10, String string11,
String usernamefor, String isvoted, String isliked,
String profilepic, String likecount, String commentcount) {
BeanTop ib = new BeanTop();
Date date = null;
try {
System.out.println("date " + string9);
date = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(string9);
} catch (Exception e) {
e.printStackTrace();
}
ib.setText(string1);
ib.setLeftpic(string2);
ib.setRightpic(string3);
ib.setRightVote(string5);
ib.setLeftVote(string6);
ib.setLefttext(string7);
ib.setRighttext(string8);
ib.setDate(string9);
ib.setDate1(date);
ib.setVoteid(string10);
ib.setUsername(string11);
ib.setDom(usernamefor);
ib.setIsvoted(isvoted);
ib.setIsliked(isliked);
ib.setProfilepic(profilepic);
ib.setLikecount(likecount);
ib.setCommentcount(commentcount);
List<BeanTop> bookingList = new ArrayList<BeanTop>();
bookingList.addAll(listitem);
Collections.sort(bookingList, new Comparator<BeanTop>() {
public int compare(BeanTop m1, BeanTop m2) {
return m1.getDate().compareTo(m2.getDate());
}
});
Collections.reverse(bookingList);
try {
listitem.clear();
} catch (Exception e) {
e.printStackTrace();
}
listitem.addAll(bookingList);
try {
bookingList.clear();
} catch (Exception e) {
e.printStackTrace();
}
listitem.add(ib);
}
Cant say without seeing your code, but I can show you general way of doing this...
First you should maintain a list, say at class level like...
List<MyPost> posts = ArrayList<MyPost>();
Then you can create you adapter by passing 'posts' list in it.
And just call '.addAll(xxx)' to you 'posts' list everytime you get items from server like,
posts.addAll(newItems);
and right after that, call yourAdapter.notifyDatasetChanged(); so that list can redraw/update its views...
And in you code...use,
if (listitem == null) {
listitem = new ArrayList<BeanTop>();
}
in you getPostnew() instead of only listitem = new ArrayList<BeanTop>();.
Hope this helps...
You are re-initializing listitem = new ArrayList<BeanTop>(); eveytime the getPostnew methood is called. This is why your old posts are lost. Try change that line to:
if (listitem == null) {
listitem = new ArrayList<BeanTop>();
}
you should use a global variable to store the data which you get from server ,in your method
getPostnew(String start) every time you execute it ,the listitem will be recreated;so the last data will be lost.

Getting BLOB from JSON Object in Android

I want to read a data from php and I used JSON Object to get the data. And one of the data I want to get from the database is BLOB. I tried by myself with the following code.
products = new JSONArray(getJSONUrl(url));
// looping through product
for (int i = 0; i < products.length(); i++) {
JSONObject jsonObj = products.getJSONObject(i);
try {
placeName = jsonObj.getString(String.valueOf(TAG_PlaceName));
placeDesc = jsonObj.getString(TAG_PlaceDesc);
Blob blob = (Blob) jsonObj.get(TAG_placeIcon);
byte[] byteBlob = blob.getBytes(0, (int) blob.length());
Bitmap bmp = BitmapFactory.decodeByteArray(byteBlob, 0, byteBlob.length);
rowItems.add(new RowItem(placeName, placeDesc, bmp));
} catch (SQLException e) {
e.printStackTrace();
}
}
RowItem is the class that I keep the data.
Can anyone point out what is wrong in my code. I tried to look around for like many hours but I still can't find a solution.
By the way when I tried running the app, It seems that UI doesn't have any problem. Only that the listview that I use to show the data seems to have nothing in it.
use this code
#Override
protected Bitmap doInBackground(String... params) {
String id = params[0];
String add = "http://user localhost/ImageUpload/getImage.php?id="+id;
URL url = null;
Bitmap image = null;
try {
url = new URL(add);
image = BitmapFactory.decodeStream(url.openConnection().getInputStream());
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return image;
}

Android - Populate list with AsycTaskLoader & MySql

I want to fill a ListFragment with certain objects loaded from my MySql database.
It has to load the first 10 'objects' from my ResultSet.
I want to use an AsyncTaskLoader for this and put the loaded object in a ListItem each time I retreive it from the database.
Can anybody help me with this one? Tried searching for good examples or tutorials but I haven't really found something that's really useful...
Create your adapter with a new list in your preexecute method. Set that adapter to your listview.
Then in doInBackground read your database, create objects to fit in your list, but don't add them. Pas each object after made as parameter for your publishprogress method.
In onProgressUpdate add your object to the list and notify your adapter that the dataset is changed.
Below is an example for how I do it reading a twitter call.
private class parseTwitterTask extends AsyncTask<Void, TCListObject2, List<TCListObject2>> {
TCListObjectAdapter2 adapter;
List<TCListObject2> list;
#Override
protected void onPreExecute() {
list = new ArrayList<TCListObject2>();
ListView lv = (ListView)findViewById(R.id.twitterlist);
adapter = new TCListObjectAdapter2(list);
lv.setAdapter(adapter);
super.onPreExecute();
}
#Override
protected List<TCListObject2> doInBackground(Void... params) {
try {
String url = social.get("twittersearchurl");//"http://search.twitter.com/search.json?q=" + social.get("twitter");
String json = Internet.request(url, null);
JSONObject jo = new JSONObject(json);
if(jo.has("results")) {
JSONArray ar = jo.getJSONArray("results");
for(int i = 0; i < ar.length(); i++) {
TCListObject2 tweet = new TCListObject2();
JSONObject jobj = (JSONObject) ar.get(i);
tweet.id = "false";
tweet.img = jobj.getString("profile_image_url");
String text = jobj.getString("text");
text = Html.fromHtml(text).toString();
tweet.params.put(R.id.sub2, text);
String name = jobj.getString("from_user");
name = Html.fromHtml(name).toString();
tweet.params.put(R.id.text, name);
String time = jobj.getString("created_at");
tweet.params.put(R.id.sub1, Converter.timeToTimeAgo(time));
try {
tweet.time = new Date(time);
} catch(Exception e) {
e.printStackTrace();
}
tweet.celLayout = R.layout.cell_tweetobject;
publishProgress(tweet);
}
}
} catch(Exception e) {
e.printStackTrace();
}
return list;
}
#Override
protected void onProgressUpdate(TCListObject2... values) {
list.add(values[0]);
adapter.notifyDataSetChanged();
super.onProgressUpdate(values);
}

Categories

Resources