Download 5 images from urls - java

Im trying to download 5 images from the response of a JSON, i have managed to get the URLs of the images and am able to download the image if i hard code one of the image locations into the code.
How would i do it so that i can download all 5 images.
Below is the request code:
public void getImage(String url, final ImageView imageView) {
ImageRequest requestImage = new ImageRequest(url, new Response.Listener<Bitmap>() {
#Override
public void onResponse(Bitmap response) {
System.out.println("Image Url is: " + response);
imageView.setImageBitmap(response);
System.out.println();
}
}, 0, 0, null, null);
queue.add(requestImage);
}
Below is the code that passes the image Url from the response and sets the image in the xml based on the ID
FYI: bp_promo1 is the hard coded image added into the request
try {
System.out.println("Size of PromoItemsArray is: " + home.promoItemsArray.size());
for (int i = 0; i < home.promoItemsArray.size(); i++) {
String imageUrl = home.promoItemsArray.get(i).imageUrl;
request.getImage(imageUrl, bp_promo1);
}
} catch (Exception e) {
System.out.println("Error is: " + e + " - Exception is it: " + e.getStackTrace()[2].getLineNumber());
}
}
My idea was to add all five images to an array then pass each item in the array to the network call?
Thanks

The way I managed to fix the issue was below?
public void getImage(String url, final Object object) {
ImageLoader.ImageCache imageCache = new BitmapLruCache();
ImageLoader imageLoader = new ImageLoader(queue, imageCache);
imageLoader.get(url, new ImageLoader.ImageListener() {
#Override
public void onResponse(ImageLoader.ImageContainer response, boolean isImmediate) {
Bitmap responseBitmap = response.getBitmap();
ImageView imageView;
ImageButton imageButton;
HorizontalScrollView horizontalScrollView;
if (object instanceof ImageView) {
imageView = (ImageView) object;
imageView.setImageBitmap(responseBitmap);
} else if (object instanceof ImageButton) {
imageButton = (ImageButton) object;
imageButton.setImageBitmap(responseBitmap);
} else if (object instanceof HorizontalScrollView) {
horizontalScrollView = (HorizontalScrollView) object;
horizontalScrollView.setBackground(new BitmapDrawable(getResources(), responseBitmap));
}
}
I just passed through a Object and manipulated the code based on the source of the Object type

Related

Array of images loops itself in each item in my array list of object

Please help me out
I am fetching image from a JSON API to my android app for each item in my arraylist. The images are fetching correctly, but instead of setting only the image that is meant for each list item, it is looping and interchanging all the images in all the list on one item and all the list items respectively, thereby making the image in each list item to be changing to different images in seconds.
See the JSON file
{ "data":[
{
"sno":1,
"id":"3",
"title":"This Is Great Again",
"desc":"The details of how a UUID is generated are determined by the device manufacturer and are specific to the device's platform or model.The details of...",
"free":"Yes",
"image":"http:\/\/app-web.moneyacademy.ng\/uploads\/145277f3d0499ee8e0dafbac384ca9b4.jpg",
"date_added":"2017-10-12 10:26PM",
"no_comment":3,
"comments":[ ]
},
{
"sno":2,
"id":"6",
"title":"Money Makes The World Go Round",
"desc":"On this realm, nothing works without money. You need to get some of it or else you'll be grounded.",
"free":"Yes",
"image":"http:\/\/app-web.moneyacademy.ng\/uploads\/546a4c29a94f3d70ae9a075ce8afcc6b.jpg",
"date_added":"2018-02-18 10:06AM",
"no_comment":0,
"comments":[ ]
},
{
"sno":3,
"id":"7",
"title":"No One Is Destined To Be Poor",
"desc":"You will not be poor.",
"free":"Yes",
"image":"http:\/\/app-web.moneyacademy.ng\/uploads\/8f19b9cebd1ca4dec74fafcfe23ae0f0.jpg",
"date_added":"2018-02-18 01:03PM",
"no_comment":0,
"comments":[ ]
},
{
"sno":4,
"id":"8",
"title":"What Is Your Money?",
"desc":"Understand the true definition of your money.",
"free":"Yes",
"image":"http:\/\/app-web.moneyacademy.ng\/uploads\/49b35ffb5cabcb7e01dab2d452ec6025.jpg",
"date_added":"2018-02-18 01:30PM",
"no_comment":0,
"comments":[ ]
},
Here is my code for fetching each item and the image
private static ArrayList<nauget> extractFeatureFromJson(String freeNaugetJson) {
// If the JSON string is empty or null, then return early.
if (TextUtils.isEmpty(freeNaugetJson)) {
return null;
}
ArrayList<nauget> naugets = new ArrayList<nauget>();
try {
JSONObject baseJsonResponse = new JSONObject(freeNaugetJson);
JSONArray dataArray = baseJsonResponse.getJSONArray("data");
// If there are results in the data array
for (int i = 0; i < dataArray.length(); i++){
String title = dataArray.getJSONObject(i).getString("title");
String body = dataArray.getJSONObject(i).getString("desc");
String totalComments = dataArray.getJSONObject(i).getString("no_comment");
String image = dataArray.getJSONObject(i).getString("image");
int id = dataArray.getJSONObject(i).getInt("id");
ArrayList<Comment> comments = new ArrayList<Comment>();
//fetch each comment detail
if (Integer.parseInt(totalComments) > 0) {
JSONArray commentArray = dataArray.getJSONObject(i).getJSONArray("comments");
for (int j = 0; j < commentArray.length(); j++) {
String userName = commentArray.getJSONObject(j).getString("userName");
String comment_image = commentArray.getJSONObject(j).getString("userPhoto");
String comment = commentArray.getJSONObject(j).getString("comment");
String date = commentArray.getJSONObject(j).getString("date_commented");
comments.add(new Comment(userName, comment_image, comment, date));
}
}
// Create a new nauget object
naugets.add(new nauget(title, body, image, totalComments, comments, id));
}
} catch (JSONException e) {
Log.e(LOG_TAG, "Problem parsing the nauget JSON results", e);
}
return naugets;
}
Here is my custom adapter code where am setting the image and its text data for each list item.
public class NaugetAddapter extends ArrayAdapter<nauget> {
ArrayList<nauget> naugets;
private nauget currentNauget;
private ImageView naugetImage;
private TextView naugetTitle;
private TextView naugetBody;
private TextView commentCount;
public NaugetAddapter(#NonNull Context context, ArrayList<nauget> naugets) {
super(context, 0, naugets);
}
#NonNull
#Override
public View getView(final int position, #Nullable View convertView, #NonNull ViewGroup parent) {
//check if the convert view is null and inflate the view
if (convertView == null){
convertView = LayoutInflater.from(getContext()).inflate(R.layout.free_nauget_item, parent, false);
}
currentNauget = (nauget) getItem(position);
//find the nauget title textView and set the text
naugetTitle = (TextView) convertView.findViewById(R.id.nauget_title);
naugetTitle.setText(currentNauget.getNauget_title());
//find the nauget body textView and set the text
naugetBody = (TextView) convertView.findViewById(R.id.nauget_body);
naugetBody.setText(currentNauget.getNauget_body());
//set the nauget total comment count
commentCount = (TextView) convertView.findViewById(R.id.comment_count);
commentCount.setText(currentNauget.getNaugetTotalComments());
//set the comment text
TextView commentText = (TextView) convertView.findViewById(R.id.comment_text);
commentText.setText(currentNauget.getNaugetCommentText());
//set the nauget image
naugetImage = (ImageView) convertView.findViewById(R.id.nauget_image);
new DownloadImageTask().execute(currentNauget.getImageUrl());
//set the share icon
ImageView shareIcon = (ImageView) convertView.findViewById(R.id.share_icon);
shareIcon.setImageResource(currentNauget.getNaugetShareIcon());
//set share functionality on the share icon
shareIcon.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent shareIntent = new Intent(Intent.ACTION_SEND);
shareIntent.setType("text/plain");
shareIntent.putExtra(Intent.EXTRA_SUBJECT, "My App");
shareIntent.putExtra(Intent.EXTRA_TEXT,
naugetTitle.getText()
+ "\n" + naugetBody.getText()
+ "\n" + naugetImage.getDrawable());
startActivity(getContext(), Intent.createChooser(shareIntent, "Share via"), null);
}
});
return convertView;
}
private class DownloadImageTask extends AsyncTask<String, Void, Bitmap> {
#Override
protected void onPreExecute() {
super.onPreExecute();
// mLoadingIndicator.setVisibility(View.VISIBLE);
}
protected Bitmap doInBackground(String... urls) {
Bitmap image = null;
HttpURLConnection urlConnection = null;
try {URL url = new URL(urls[0]);
urlConnection = (HttpURLConnection) url.openConnection();
int statusCode = urlConnection.getResponseCode();
if (statusCode != 200) {
return null;
}
InputStream inputStream = urlConnection.getInputStream();
if (inputStream != null) {
Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
return bitmap;
}
} catch (Exception e) {
urlConnection.disconnect();
Log.e("Error", e.getMessage());
e.printStackTrace();
}finally {
if (urlConnection != null) {
urlConnection.disconnect();
}
}
return null;
}
protected void onPostExecute(Bitmap result) {
// mLoadingIndicator.setVisibility(View.INVISIBLE);
naugetImage.setImageBitmap(result);
}
}
#NonNull
#Override
public Filter getFilter() {
return new Filter() {
#Override
protected FilterResults performFiltering(CharSequence constraint) {
ArrayList<nauget> filteredResults = new ArrayList<>();
FilterResults results = new FilterResults();
results.values = filteredResults;
return results;
}
#Override
protected void publishResults(CharSequence constraint, FilterResults results) {
}
};
}
void setFilter(ArrayList<nauget> listItem){
naugets = new ArrayList();
naugets.addAll(listItem);
notifyDataSetChanged();
}
}
This should solve the issue! you are trying everything fine but you have the comment ArrayList inside of a loop getting instantiated each time newly just put it before the outer loop as I did here and the error should go! TRY IT
try {
JSONObject baseJsonResponse = new JSONObject(freeNaugetJson);
JSONArray dataArray = baseJsonResponse.getJSONArray("data");
//put it here so you won't get a new array for each comment in the loop
**ArrayList<Comment> comments = new ArrayList<Comment>();**
// If there are results in the data array
for (int i = 0; i < dataArray.length(); i++){
String title = dataArray.getJSONObject(i).getString("title");
String body = dataArray.getJSONObject(i).getString("desc");
String totalComments = dataArray.getJSONObject(i).getString("no_comment");
String image = dataArray.getJSONObject(i).getString("image");
int id = dataArray.getJSONObject(i).getInt("id");
//here after every comment check its making a new comment ArrayList for each comment and filling it out so this can be the cause of the bug! bcz its in the loop
// ArrayList<Comment> comments = new ArrayList<Comment>();
//fetch each comment detail
if (Integer.parseInt(totalComments) > 0) {
JSONArray commentArray = dataArray.getJSONObject(i).getJSONArray("comments");
for (int j = 0; j < commentArray.length(); j++) {
String userName = commentArray.getJSONObject(j).getString("userName");
String comment_image = commentArray.getJSONObject(j).getString("userPhoto");
String comment = commentArray.getJSONObject(j).getString("comment");
String date = commentArray.getJSONObject(j).getString("date_commented");
comments.add(new Comment(userName, comment_image, comment, date));
}
}
// Create a new nauget object
naugets.add(new nauget(title, body, image, totalComments, comments, id));
}
} catch (JSONException e) {
Log.e(LOG_TAG, "Problem parsing the nauget JSON results", e);
}
return naugets;

Improve Large ListView Adapter smooth scroll, sometimes jerky

I'm trying to see what is making my listview jerk sometimes when scroll, at times it's bad especially when the application first launches.
All the conditions I have are necessary, unless there is something I don't know(highly likely).
I'm not running certain tasks on a seperate thread because they are dependent on the data I receive from the backend(I'm coding both, so backend suggestions are welcome as well). Product is in beta but really need to make this a slightly bit smoother. I'm compressing the images, and they are a bit long but it's not the problem because when I upload the images from the device, I also include the width and height of the image and send that along to the backend. These dimensions come back when loading the list.
One thing I wonder is if calculating/converting the dimensions for the specific device's screen is causing the slight lag. Not sure how resource intensive that task is, but without it(without knowing the dimensions, each row would start out flat and then expand to the actual picture size which would cause the list to jump, so I can't run that calculation on the background either.)
Basically the scrolling isn't bad, but I need to improve this somehow.
Here is my Adapter:
public class VListAdapter extends BaseAdapter {
ViewHolder viewHolder;
private boolean isItFromProfile;
/**
* fields For number formating, ex. 1000
* would return 1k in the format method
*/
private static final NavigableMap<Long, String> suffixes = new TreeMap<>();
static {
suffixes.put(1_000L, "k");
suffixes.put(1_000_000L, "M");
suffixes.put(1_000_000_000L, "G");
suffixes.put(1_000_000_000_000L, "T");
suffixes.put(1_000_000_000_000_000L, "P");
suffixes.put(1_000_000_000_000_000_000L, "E");
}
private Context mContext;
private LayoutInflater mInflater;
private ArrayList<Post> mDataSource;
private static double lat;
private static double lon;
public VListAdapter(Context context, ArrayList<Post> items) {
mContext = context;
mDataSource = items;
//mInflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
isItFromProfile = false;
mInflater = LayoutInflater.from(context);
}
public VListAdapter() {
}
public VListAdapter(Context baseContext, ArrayList<Post> posts, boolean b) {
mContext = baseContext;
mDataSource = posts;
//mInflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
isItFromProfile = b;
mInflater = LayoutInflater.from(baseContext);
}
public void addElement(Post post) {
mDataSource.add(0, post);
this.notifyDataSetChanged();
}
#Override
public int getCount() {
return mDataSource.size();
}
#Override
public Object getItem(int position) {
return mDataSource.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
int limit = Math.min(position + 4, getCount());
for (int i = position; i < limit; i++) {
Glide.with(mContext).load(((Post) getItem(i)).getFilename().toString()).preload();
}
// StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder().detectDiskReads()
// .detectDiskWrites().detectNetwork()
// .penaltyLog().build());
View rowView = convertView;
if (rowView == null) {
viewHolder = new ViewHolder();
rowView = mInflater.inflate(R.layout.mylist, parent, false);
viewHolder.titleTextView = (TextView) rowView.findViewById(R.id.usernameinlist);
viewHolder.timeago = (TextView) rowView.findViewById(R.id.timeago);
//viewHolder.sharebutton = (ImageView) rowView.findViewById(R.id.sharebutton);
viewHolder.likesTextView = (TextView) rowView.findViewById(R.id.likestext);
viewHolder.viewcount = (TextView) rowView.findViewById(R.id.viewcount);
viewHolder.distance = (TextView) rowView.findViewById(R.id.distance);
viewHolder.footprints = (TextView) rowView.findViewById(R.id.footprintcount);
viewHolder.postText = (TextView) rowView.findViewById(R.id.posttext);
viewHolder.profilePic = (ImageView) rowView.findViewById(R.id.profilethumb);
viewHolder.caption = (TextView) rowView.findViewById(R.id.captiontext);
viewHolder.moremenu = (ImageView) rowView.findViewById(R.id.dots);
viewHolder.likesPic = (ImageView) rowView.findViewById(R.id.likeimage);
viewHolder.mapitPic = (ImageView) rowView.findViewById(R.id.mapimage);
viewHolder.playbutton = (ImageView) rowView.findViewById(R.id.playbutton);
viewHolder.videoThumb = (ImageView) rowView.findViewById(R.id.videothumb);
viewHolder.listphoto = (ImageView) rowView.findViewById(R.id.listphoto);
viewHolder.rainbow = (ImageView) rowView.findViewById(R.id.rainbow);
rowView.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) rowView.getTag();
}
final Post post = (Post) getItem(position);
int color = Color.parseColor("#dddddd");
viewHolder.likesPic.setColorFilter(color);
viewHolder.mapitPic.setColorFilter(color);
viewHolder.moremenu.setColorFilter(color);
if (Hawk.count() == 0)
initHawkWithDataFromServer();
if (isItFromProfile) {
viewHolder.profilePic.setVisibility(View.GONE);
viewHolder.titleTextView.setVisibility(View.GONE);
viewHolder.distance.setVisibility(View.GONE);
}
viewHolder.titleTextView.setText(post.getUsername());
PrettyTime prettyTime = new PrettyTime();
DateTime dateTime = new DateTime(post.getUploadDate().get$date());
viewHolder.timeago.setText(prettyTime.format(dateTime.toDate()));
viewHolder.likesTextView.setText(String.valueOf(format(post.getLikes())));
viewHolder.footprints.setText(String.valueOf(format(post.getLocation().size() - 1)));
//don't display 0 if there are no likes, just show heart icon
if (viewHolder.likesTextView.getText().equals("0"))
viewHolder.likesTextView.setVisibility(View.GONE);
else
viewHolder.likesTextView.setVisibility(View.VISIBLE);
//don't display 0 if there are no footprints
if (viewHolder.footprints.getText().equals("0"))
viewHolder.footprints.setVisibility(View.GONE);
else
viewHolder.footprints.setVisibility(View.VISIBLE);
double[] loc = post.getLocation().get(0);
viewHolder.distance.setText("~" + PostListFragment.distance(loc[0], loc[1], 'M') + " Miles");
if (post.getViews() != null)
viewHolder.viewcount.setText(format(post.getViews()) + (post.getViews() == 1 ? " View" : " Views"));
String profilePictureS3Url = "https://s3-us-west-2.amazonaws.com/moleheadphotos/" + post.getUsername()
+ ".jpg";
String filename = post.getS3link();
final String videoThumbURL = "https://s3-us-west-2.amazonaws.com/moleheadphotos/" + filename;
Glide.with(mContext).load(profilePictureS3Url).asBitmap().centerCrop().into(new BitmapImageViewTarget(viewHolder.profilePic) {
#Override
protected void setResource(Bitmap resource) {
RoundedBitmapDrawable circularBitmapDrawable =
RoundedBitmapDrawableFactory.create(mContext.getResources(), resource);
circularBitmapDrawable.setCircular(true);
viewHolder.profilePic.setImageDrawable(circularBitmapDrawable);
}
});
int height = ((Post) getItem(position)).getHeight();
int width = ((Post) getItem(position)).getWidth();
if (height != 0 && width != 0) {
ViewGroup.LayoutParams params = viewHolder.listphoto.getLayoutParams();
Resources r = mContext.getResources();
height = (int) getHeight(height, width);
params.height = height;
params.width = ViewGroup.LayoutParams.MATCH_PARENT;
viewHolder.listphoto.setLayoutParams(params);
} else {
ViewGroup.LayoutParams params = viewHolder.listphoto.getLayoutParams();
params.height = ViewGroup.LayoutParams.WRAP_CONTENT;
params.width = ViewGroup.LayoutParams.MATCH_PARENT;
viewHolder.listphoto.setLayoutParams(params);
}
if (post.getType() == null) {
Glide.clear(viewHolder.listphoto);
viewHolder.listphoto.setVisibility(View.GONE);
//Glide.clear(viewHolder.listphoto);
viewHolder.videoThumb.setVisibility(View.VISIBLE);
viewHolder.rainbow.setVisibility(View.VISIBLE);
Glide.with(mContext).load(videoThumbURL).fitCenter()
.diskCacheStrategy(DiskCacheStrategy.ALL).dontAnimate().into(viewHolder.videoThumb);
viewHolder.playbutton.setVisibility(View.VISIBLE);
}
if (post.getType() != null) {
if (post.getType().equals("video")) {
viewHolder.playbutton.setVisibility(View.VISIBLE);
Glide.clear(viewHolder.listphoto);
viewHolder.listphoto.setVisibility(View.GONE);
Glide.clear(viewHolder.postText);
viewHolder.postText.setVisibility(View.GONE);
viewHolder.videoThumb.setVisibility(View.VISIBLE);
viewHolder.rainbow.setVisibility(View.VISIBLE);
Glide.with(mContext).load(videoThumbURL).fitCenter()
.diskCacheStrategy(DiskCacheStrategy.ALL).dontAnimate().into(viewHolder.videoThumb);
}
if (post.getType().equals("image")) {
Glide.clear(viewHolder.videoThumb);
viewHolder.videoThumb.setVisibility(View.GONE);
viewHolder.rainbow.setVisibility(View.GONE);
Glide.clear(viewHolder.playbutton);
viewHolder.playbutton.setVisibility(View.GONE);
Glide.clear(viewHolder.postText);
viewHolder.postText.setVisibility(View.GONE);
viewHolder.listphoto.setVisibility(View.VISIBLE);
viewHolder.listphoto.setBottom(0);
Glide.with(mContext).load(post.getFilename().toString())
.diskCacheStrategy(DiskCacheStrategy.ALL).dontAnimate()
.into(viewHolder.listphoto);
}
if (post.getType().equals("text")) {
Glide.clear(viewHolder.videoThumb);
viewHolder.videoThumb.setVisibility(View.GONE);
viewHolder.rainbow.setVisibility(View.GONE);
Glide.clear(viewHolder.playbutton);
viewHolder.playbutton.setVisibility(View.GONE);
Glide.clear(viewHolder.listphoto);
viewHolder.listphoto.setVisibility(View.GONE);
viewHolder.postText.setVisibility(View.VISIBLE);
viewHolder.postText.setText(post.getText());
}
}
if (Hawk.contains("liked" + post.getId().get$oid())) {
viewHolder.likesPic.clearColorFilter();
Glide.with(mContext).load(R.drawable.heartroundorange).into(viewHolder.likesPic);
((ImageView) viewHolder.likesPic).setColorFilter(Color.parseColor("#ff3a6f"));
} else {
Glide.with(mContext).load(R.drawable.heartroundgray).diskCacheStrategy(DiskCacheStrategy.ALL)
.into(viewHolder.likesPic);
}
if (Hawk.contains("mapped" + post.getId().get$oid())) {
viewHolder.mapitPic.clearColorFilter();
((ImageView) viewHolder.mapitPic).setImageResource(R.drawable.dropmaincolororange);
((ImageView) viewHolder.mapitPic).setColorFilter(Color.parseColor("#444444"));
} else {
Glide.with(mContext).load(R.drawable.dropdarkgray).diskCacheStrategy(DiskCacheStrategy.ALL)
.into(viewHolder.mapitPic);
}
if (!Hawk.contains("mapped" + post.getId().get$oid())) {
viewHolder.mapitPic.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Hawk.put("mapped" + post.getId().get$oid(), 1);
((ImageView) viewHolder.mapitPic).setImageResource(R.drawable.dropmaincolororange);
viewHolder.footprints.setText(String.valueOf(post.getLocation().size() + 1));
post.getLocation().add(new double[]{PostListFragment.lon, PostListFragment.lat});
notifyDataSetChanged();
Thread t = new Thread(new Runnable() {
#Override
public void run() {
postMappedToServer(post.getId().get$oid());
}
});
t.start();
TastyToast.makeText(mContext, "Post dropped off here.", TastyToast.LENGTH_SHORT, TastyToast.CONFUSING);
}
});
} else {
viewHolder.mapitPic.setClickable(false);
}
if (!Hawk.contains("liked" + post.getId().get$oid())) {
viewHolder.likesPic.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Hawk.put("liked" + post.getId().get$oid(), 1);
viewHolder.likesPic.setClickable(false);
((ImageView) viewHolder.likesPic).setImageResource(R.drawable.heartroundorange);
viewHolder.likesTextView.setText(String.valueOf(post.getLikes() + 1));
post.setLikes(post.getLikes() + 1);
notifyDataSetChanged();
Thread t = new Thread(new Runnable() {
#Override
public void run() {
postLikeToServer(post);
}
});
t.start();
}
});
} else {
viewHolder.likesPic.setClickable(false);
}
if (post.getType() == null || post.getType().equals("video"))
viewHolder.videoThumb.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (VListAdapter.this.mContext instanceof ProfileFeed) {
((ProfileFeed) VListAdapter.this.mContext).closeActivity();
}
Intent broadcast = new Intent();
broadcast.setAction("com.molehead.openout.POST");
broadcast.putExtra("postId", post.getFilename().toString());
broadcast.putExtra("hawkId", post.getId().get$oid());
broadcast.putExtra("s3link", post.getS3link());
broadcast.putExtra("username", post.getUsername());
if (Hawk.contains("liked" + post.getId().get$oid()))
broadcast.putExtra("liked", "yes");
else
broadcast.putExtra("liked", "no");
broadcast.putExtra("likecount", post.getLikes().toString());
App.post = post;
LocalBroadcastManager.getInstance(mContext.getApplicationContext()).sendBroadcast(broadcast);
}
});
viewHolder.moremenu.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
PopupMenu popup = new PopupMenu(mContext.getApplicationContext(), viewHolder.moremenu, Gravity.CENTER);
//Inflating the Popup using xml file
popup.getMenuInflater().inflate(R.menu.menu_main, popup.getMenu());
//registering popup with OnMenuItemClickListener
popup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
public boolean onMenuItemClick(MenuItem item) {
switch (item.getItemId()) {
case R.id.action_share:
String postId = post.getId().get$oid();
Intent sharingIntent = new Intent(android.content.Intent.ACTION_SEND);
sharingIntent.setType("text/plain");
String shareBody = postId + ".jpg"; //https://openout.herokuapp.com/posts/" + postId;
String shareSub = "Shared via Molehead";
sharingIntent.putExtra(android.content.Intent.EXTRA_SUBJECT, shareSub);
sharingIntent.putExtra(android.content.Intent.EXTRA_TEXT, shareBody);
sharingIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
Intent new_intent = Intent.createChooser(sharingIntent, "Share");
new_intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
mContext.getApplicationContext().startActivity(new_intent);
break;
}
return true;
}
});
popup.show();
}
});
return rowView;
}
private void initHawkWithDataFromServer() {
SharedPreferences settings = mContext.getApplicationContext().getSharedPreferences("userinfo", 0);
String username = settings.getString("username", "ok");
String password = settings.getString("password", "ok");
LoginService loginService =
ServiceGenerator.createService(LoginService.class, username, password);
final Call<List<Post>> call = loginService.getLikes(username);
Log.i("lonlat", String.valueOf(lon) + " and " + String.valueOf(lat));
call.enqueue(new Callback<List<Post>>() {
#Override
public void onResponse(Call<List<Post>> call, Response<List<Post>> response) {
ArrayList<Post> posts = new ArrayList<>();
posts = (ArrayList<Post>) response.body();
if (!posts.isEmpty())
for (Post p : posts) {
Hawk.put("liked" + p.getId().get$oid(), 1);
}
}
#Override
public void onFailure(Call<List<Post>> call, Throwable t) {
}
});
}
private void postMappedToServer(String oid) {
SharedPreferences settings = mContext.getSharedPreferences("userinfo", 0);
String username = settings.getString("username", "ok");
String password = settings.getString("password", "ok");
LoginService loginService =
ServiceGenerator.createService(LoginService.class, username, password);
Log.i("postlistfraglat", String.valueOf(PostListFragment.lat));
Call<ResponseBody> call = loginService.addLocation(oid, PostListFragment.lon, PostListFragment.lat);
call.enqueue(new Callback<ResponseBody>() {
#Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
if (response.isSuccessful())
Log.i("mapped", "success");
}
#Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
}
});
}
public void postLikeToServer(Post post) {
SharedPreferences settings = mContext.getSharedPreferences("userinfo", 0);
String username = settings.getString("username", "ok");
String password = settings.getString("password", "ok");
LoginService loginService =
ServiceGenerator.createService(LoginService.class, username, password);
Call<ResponseBody> call = loginService.like(post, 1, username);
call.enqueue(new Callback<ResponseBody>() {
#Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
if (response.isSuccessful()) {
try {
Log.i("call", response.body().string());
} catch (IOException e) {
e.printStackTrace();
}
}
}
#Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
Log.i("MFEED", "like request failed");
}
});
}
public static String format(long value) {
//Long.MIN_VALUE == -Long.MIN_VALUE so we need an adjustment here
if (value == Long.MIN_VALUE) return format(Long.MIN_VALUE + 1);
if (value < 0) return "-" + format(-value);
if (value < 1000) return Long.toString(value); //deal with easy case
Map.Entry<Long, String> e = suffixes.floorEntry(value);
Long divideBy = e.getKey();
String suffix = e.getValue();
long truncated = value / (divideBy / 10); //the number part of the output times 10
boolean hasDecimal = truncated < 100 && (truncated / 10d) != (truncated / 10);
return hasDecimal ? (truncated / 10d) + suffix : (truncated / 10) + suffix;
}
static class ViewHolder {
private TextView titleTextView;
private TextView timeago;
private TextView likesTextView;
private TextView viewcount;
private TextView distance;
private TextView footprints;
private ImageView profilePic;
private ImageView moremenu;
private ImageView likesPic;
private ImageView mapitPic;
private ImageView rainbow;
//private ImageView sharebutton;
private TextView caption;
private ImageView listphoto;
private ImageView videoThumb;
private ImageView playbutton;
private TextView postText;
private Post post;
}
private float getHeight(float height, float width) {
WindowManager wm = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();
Point size = new Point();
display.getSize(size);
return (height * size.x / width);
}
}
It is impossible to point to a specific issue because there is so much code in your Adapter. One thing is sure, though - switching to RecyclerView won't help you in this case.
Adapters should not contain business logic - they should only "adapt" input objects to the underlying Views. In your case, it seems like the adapter performs calculations, spawns new threads, performs network requests, etc.
You need to refactor your code such that the adapter will be similar to this:
public class PostsListAdapter extends ArrayAdapter<Post> {
private Context mContext;
public PostsListAdapter(Context context, int resource) {
super(context, resource);
mContext = context;
}
public void bindPosts(List<Post> posts) {
clear();
addAll(posts);
notifyDataSetChanged();
}
#NonNull
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
// assign new View to convertView
// create new ViewHolder
// set ViewHolder as tag of convertView
// set listeners
} else {
// get a reference to existing ViewHolder
}
// populate ViewHolder's elements with data from getItem(position)
// kick off asynchronous loading of images
// NOTE: no calculations allowed here - just simple bidding of data to Views
return convertView;
}
}
Your code needs to be structured in such a way, that business logic that involves calculations and transformation of data executed before you bind a new data to ListView, and Post objects that you pass to bindPosts() method already contain the results of the aforementioned calculations and transformations.
Adapter just "adapts" the final data from Posts to Views - nothing more.
If you're short on time now, and just need to "make it work", then I would start by removing the logic that spawns new threads and makes network requests. See if this improves performance.
Change your implementation to RecyclerView which is more efficient in terms of scrapping views or recycling.
We can also enable optimizations if the items are static and will not change for significantly smoother scrolling:
recyclerView.setHasFixedSize(true);
Create an intent service and register BroadcastReceiver as data return callback or error callback when api request, business rule, data modification completed. Use synchronous call to execute initHawkWithDataFromServer() in advance and after getting result from api continue modifying or applying business logic. After that create new adapter or update existing adapter data set.
Move all the below data calculation or data value formatting logic from adapter's getView() to above intent service.
You can add more getter and setter to existing Post pojo.
DateTime dateTime = new DateTime(post.getUploadDate().get$date());
viewHolder.timeago.setText(prettyTime.format(dateTime.toDate()));
viewHolder.likesTextView.setText(String.valueOf(format(post.getLikes())));
viewHolder.footprints.setText(String.valueOf(format(post.getLocation().size)) - 1)));
Post{
//Your existing property
#Expose(serialize = false, deserialize = false)
//equals neither serialize nor deserialize or
private DateTime uploadedDateTime;
//etc. prettyTime.format, String.valueOf
}
Removes unnecessary reflection:
GsonBuilder builder = new GsonBuilder();
builder.excludeFieldsWithoutExposeAnnotation();
Gson gson = builder.create();
new Retrofit.Builder().addConverterFactory(GsonConverterFactory.create(gson)).build();
and it to your retrofit Service creation class.
You can also use transient(private transient DateTime uploadedDateTime;)
Remove
public void addElement(Post post) { mDataSource.add(0, post);
this.notifyDataSetChanged();}
and whenever you need to notify if a single or more items inserted, deleted etc. Use the below:
notifyItemChanged(int)
notifyItemInserted(int)
notifyItemRemoved(int)
notifyItemRangeChanged(int, int)
notifyItemRangeInserted(int, int)
notifyItemRangeRemoved(int, int)
We can use these from the activity or fragment:
//Add a new contact
items.add(0, new Post("Barney"));
//Notify the adapter that an item was inserted at position 0
adapter.notifyItemInserted(0);
Above methods are more efficient. Every time we want to add or remove items from the RecyclerView, we will need to explicitly inform to the adapter of the event. Unlike the ListView adapter, a RecyclerView adapter should not rely on notifyDataSetChanged() since the more granular actions should be used. See the API documentation for more details
Also, if you are intending to update an existing list, make sure to get the current count of items before making any changes. For instance, a getItemCount() on the adapter should be called to record the first index that will be changed.
// record this value before making any changes to the existing list
int curSize = adapter.getItemCount(); // replace this line with wherever you get new records
ArrayList<Post> newItems = Post.createPostsList(20);
// update the existing list
items.addAll(newItems);
// curSize should represent the first element that got added
// newItems.size() represents the itemCount
adapter.notifyItemRangeInserted(curSize, newItems.size());
Diffing Larger Changes
A new DiffUtil class has been added in the v24.2.0 of the support library to help compute the difference between the old and new list. Details
Don't preload images via glide if your image sizes are different. Try creating your own. Also try looking at.
Create color as the class member
int color = Color.parseColor("#dddddd");
Write View.GONE or View.VISIBLE in Post pojo itself, which will be executed in background thread from Retrofit if IntentService. Try api return boolean in json instead "0" as String.
Move all below to IntentService
//don't display 0 if there are no likes, just show heart icon
if (viewHolder.likesTextView.getText().equals("0"))
viewHolder.likesTextView.setVisibility(View.GONE);
else
viewHolder.likesTextView.setVisibility(View.VISIBLE);
//don't display 0 if there are no footprints
if (viewHolder.footprints.getText().equals("0"))
viewHolder.footprints.setVisibility(View.GONE);
else
viewHolder.footprints.setVisibility(View.VISIBLE);
double[] loc = post.getLocation().get(0);
viewHolder.distance.setText("~" + PostListFragment.distance(loc[0], loc[1], 'M') + " Miles");
All String concatenation also in Post or IntnetService like:
String profilePictureS3Url = "https://s3-us-west-2.amazonaws.com/moleheadphotos/" + post.getUsername() + ".jpg";
Also you can create color filter in advance and one time only. Remove scrollbar from listview as it calculates height to show scroll bar.
Too many things to improve here. Here is some examples.
I see this
if (Hawk.count() == 0)
initHawkWithDataFromServer();
I believe that the method initHawkWithDataFromServer will be called many times during the time the list appears.
This call can be done only once when the activity was created.
Glide.with(mContext).load(videoThumbURL).fitCenter()
But you should refactor your code first, moving the logic to another class. Try to remove some code like this (it should be done by using some layout attribites)
ViewGroup.LayoutParams params = viewHolder.listphoto.getLayoutParams();
Resources r = mContext.getResources();
height = (int) getHeight(height, width);
params.height = height;
params.width = ViewGroup.LayoutParams.MATCH_PARENT;
viewHolder.listphoto.setLayoutParams(params);

ImageView showing black/white background for transparent base64 string image

Im using DisplayingBitmap.zip downloaded from developers android site to load images asynchronously into the imageview. Im receiving base64 strings from webservice. so modified the code to convert base64 to bitmap in ImageFetcher.class from (DisplayingBitmaps) instead of downloading image from url.
NOTE: Im receiving gif images in the form of base64 string.
Converting base64 to Bitmap
public Bitmap convertBase64ToImage(String mBase64String) {
Bitmap bitmap = null;
try {
String imageDataBytes = mBase64String.substring(mBase64String.indexOf(",") + 1);
InputStream stream = new ByteArrayInputStream(Base64.decode(imageDataBytes.getBytes(), Base64.DEFAULT));
bitmap = BitmapFactory.decodeStream(stream);
} catch (Exception e) {
e.printStackTrace();
}
return bitmap;
}
}
Converting base64 bitmap to file inorder to obtain decoded resized bitmap using processBitmap method in ImageFetcher.class(DisplayingBitmaps):
/**
* The main process method, which will be called by the ImageWorker in the AsyncTask background
* thread.
*
* #param data The data to load the bitmap, in this case, a regular http URL
* #return The downloaded and resized bitmap
*/
private Bitmap processBitmap(String data, String imageID) {
if (BuildConfig.DEBUG) {
PrintLog.error(TAG, "processBitmap --- imageID " + imageID);
}
Bitmap bitmap = null;
bitmap = convertBase64ToImage(data);
if (bitmap != null) {
File f = null;
try {
//create a file to write bitmap data
f = new File(mContext.getFilesDir(), imageID);
f.createNewFile();
//Convert bitmap to byte array
ByteArrayOutputStream bos = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.PNG, 100/*ignored for PNG*/, bos);
byte[] bitmapdata = bos.toByteArray();
//write the bytes in file
FileOutputStream fos = new FileOutputStream(f);
fos.write(bitmapdata);
fos.flush();
fos.close();
} catch (Exception e) {
e.printStackTrace();
}
bitmap = decodeSampledBitmapFromFile(f.getAbsolutePath(), mImageWidth, mImageHeight, getImageCache());
}
return bitmap;
}
#Override
protected Bitmap processBitmap(Object data, String imageID) {
return processBitmap(String.valueOf(data), imageID);
}
decodeSampledBitmapFromFile method from ImageResizer.class
public static Bitmap decodeSampledBitmapFromFile(String filename, int reqWidth, int reqHeight, ImageCache cache) {
// First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(filename, options);
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
// If we're running on Honeycomb or newer, try to use inBitmap
if (DeviceUtils.hasHoneycomb()) {
addInBitmapOptions(options, cache);
}
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
return BitmapFactory.decodeFile(filename, options);
}
Implementing ImageFetcher.class(DisplayingBitmaps.zip) in my class
private static final String IMAGE_CACHE_DIR = "clubsCategoryIcons";
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ImageCache.ImageCacheParams cacheParams = new ImageCache.ImageCacheParams(getActivity(), IMAGE_CACHE_DIR);
cacheParams.setMemCacheSizePercent(0.25f); // Set memory cache to 10% of app memory
// The ImageFetcher takes care of loading images into our ImageView children asynchronously
mImageFetcher = new ImageFetcher(getActivity(), getResources().getDimensionPixelSize(R.dimen.image_icon_size));
mImageFetcher.setLoadingImage(R.drawable.settings_clubs);
mImageFetcher.addImageCache(getActivity().getSupportFragmentManager(), cacheParams);
}
passing this mImageFetcher object to adapter class to load images asynchronously for each item.
ClubsCategoryAdapter clubsAdapter = new ClubsCategoryAdapter(getActivity(), new ArrayList<ClubsCategoryParser.ClubsCategory>(), mImageFetcher);
recyclerView.setAdapter(clubsAdapter);
ClubsCategoryAdapter.class
public class ClubsCategoryAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private ImageFetcher mImageFetcher;
public ClubsCategoryAdapter(Context context, ArrayList<ClubsCategoryParser.ClubsCategory> clubsCategoryList, ImageFetcher mImageFetcher ) {
this.context = context;
this.clubsCategoryList = clubsCategoryList;
this.mImageFetcher = mImageFetcher;
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, final int position) {
final ViewHolder viewHolder = (ViewHolder) holder;
final ClubsCategoryParser.ClubsCategory singleItem = clubsCategoryList.get(position);
if (!TextUtils.isNullOrEmpty(singleItem.image_url)) {
mImageFetcher.loadImage(singleItem.image_url, String.valueOf(singleItem.ID), viewHolder.imgCategoryIcon);
}
loadImage method in ImageWorker.class(DisplayingBitmaps)
public void loadImage(Object data, String imageID, ImageView imageView) {
if (data == null) {
return;
}
BitmapDrawable value = null;
if (mImageCache != null) {
value = mImageCache.getBitmapFromMemCache(imageID);
}
if (value != null) {
// Bitmap found in memory cache
imageView.setImageDrawable(value);
} else if (cancelPotentialWork(data, imageView)) {
//BEGIN_INCLUDE(execute_background_task)
final BitmapWorkerTask task = new BitmapWorkerTask(data, imageID, imageView);
final AsyncDrawable asyncDrawable = new AsyncDrawable(mResources, mLoadingBitmap, task);
imageView.setImageDrawable(asyncDrawable);
// NOTE: This uses a custom version of AsyncTask that has been pulled from the
// framework and slightly modified. Refer to the docs at the top of the class
// for more info on what was changed.
task.executeOnExecutor(AsyncTask.DUAL_THREAD_EXECUTOR);
//END_INCLUDE(execute_background_task)
}
}
actual asynctask to process the image asynchronously
/**
* The actual AsyncTask that will asynchronously process the image.
*/
private class BitmapWorkerTask extends AsyncTask<Void, Void, BitmapDrawable> {
private Object mData;
private String imageID;
private final WeakReference<ImageView> imageViewReference;
public BitmapWorkerTask(Object data, String imageID, ImageView imageView) {
mData = data;
this.imageID = imageID;
imageViewReference = new WeakReference<ImageView>(imageView);
}
/**
* Background processing.
*/
#Override
protected BitmapDrawable doInBackground(Void... params) {
//BEGIN_INCLUDE(load_bitmap_in_background)
if (BuildConfig.DEBUG) {
PrintLog.error(TAG, "doInBackground - starting work");
}
final String dataString = String.valueOf(mData);
Bitmap bitmap = null;
BitmapDrawable drawable = null;
// Wait here if work is paused and the task is not cancelled
synchronized (mPauseWorkLock) {
while (mPauseWork && !isCancelled()) {
try {
Log.e("pauseWork", "iswaiting -------------");
mPauseWorkLock.wait();
} catch (InterruptedException e) {
}
}
}
Log.e("pauseWork", "iswaiting end -------------");
// If the image cache is available and this task has not been cancelled by another
// thread and the ImageView that was originally bound to this task is still bound back
// to this task and our "exit early" flag is not set then try and fetch the bitmap from
// the cache
if (mImageCache != null && !isCancelled() && getAttachedImageView() != null && !mExitTasksEarly) {
bitmap = mImageCache.getBitmapFromDiskCache(imageID);
}
// If the bitmap was not found in the cache and this task has not been cancelled by
// another thread and the ImageView that was originally bound to this task is still
// bound back to this task and our "exit early" flag is not set, then call the main
// process method (as implemented by a subclass)
if (bitmap == null && !isCancelled() && getAttachedImageView() != null && !mExitTasksEarly) {
bitmap = processBitmap(mData, imageID);
}
// If the bitmap was processed and the image cache is available, then add the processed
// bitmap to the cache for future use. Note we don't check if the task was cancelled
// here, if it was, and the thread is still running, we may as well add the processed
// bitmap to our cache as it might be used again in the future
if (bitmap != null) {
if (DeviceUtils.hasHoneycomb()) {
// Running on Honeycomb or newer, so wrap in a standard BitmapDrawable
drawable = new BitmapDrawable(mResources, bitmap);
} else {
// Running on Gingerbread or older, so wrap in a RecyclingBitmapDrawable
// which will recycle automagically
drawable = new RecyclingBitmapDrawable(mResources, bitmap);
}
if (mImageCache != null) {
mImageCache.addBitmapToCache(imageID, drawable);
}
}
if (BuildConfig.DEBUG) {
PrintLog.error(TAG, "doInBackground - finished work");
}
return drawable;
//END_INCLUDE(load_bitmap_in_background)
}
/**
* Once the image is processed, associates it to the imageView
*/
#Override
protected void onPostExecute(BitmapDrawable value) {
//BEGIN_INCLUDE(complete_background_work)
// if cancel was called on this task or the "exit early" flag is set then we're done
if (isCancelled() || mExitTasksEarly) {
value = null;
}
final ImageView imageView = getAttachedImageView();
if (value != null && imageView != null) {
if (BuildConfig.DEBUG) {
PrintLog.error(TAG, "onPostExecute - setting bitmap");
}
setImageDrawable(imageView, value);
}
//END_INCLUDE(complete_background_work)
}
#Override
protected void onCancelled(BitmapDrawable value) {
super.onCancelled(value);
synchronized (mPauseWorkLock) {
mPauseWorkLock.notifyAll();
}
}
/**
* Returns the ImageView associated with this task as long as the ImageView's task still
* points to this task as well. Returns null otherwise.
*/
private ImageView getAttachedImageView() {
final ImageView imageView = imageViewReference.get();
final BitmapWorkerTask bitmapWorkerTask = getBitmapWorkerTask(imageView);
if (this == bitmapWorkerTask) {
return imageView;
}
return null;
}
}
Images are showing fine for the first time when installing the app, But after killing the app and loads the same page shows the image with the black/white background.
I have tried many examples and articles.. But nothing helped. I don't know why its coming with the black/white background after killing/exiting the app.
Your app is showing the image fine for the first time and displaying black background after re-openning app because "DisplayingBitmap" app caches the images to the filesystem using JPEG format. As you know JPEG doesn't support transparent mode.
Please open ImageCache class and look at the #68 line:
private static final CompressFormat DEFAULT_COMPRESS_FORMAT = CompressFormat.JPEG;
To avoid black background I changed this value to PNG format:
private static final CompressFormat DEFAULT_COMPRESS_FORMAT = CompressFormat.PNG;
UPDATE:
Also, you can set compressFormat to JPEG:
ImageCache.ImageCacheParams cacheParams = new ImageCache.ImageCacheParams(getActivity(), IMAGE_CACHE_DIR);
cacheParams.setMemCacheSizePercent(0.25f);
cacheParams.compressFormat = Bitmap.CompressFormat.JPEG;
it works for me and hope it helps you.

Parse retrieved image in a ListView Android

I can't figure out a solution to retrieve images from a Parse Table and display it in a Imageview in my Listview.
Here's what i have so far :
if (mSchedule.getCount() == 0) {
ParseQuery<ParseObject> query = ParseQuery.getQuery("sent_report");
query.selectKeys(Arrays.asList("Logo"));
query.selectKeys(Arrays.asList("Couleur"));
query.selectKeys(Arrays.asList("Date"));
query.selectKeys(Arrays.asList("Rog_pic"));
query.findInBackground(new FindCallback<ParseObject>() {
int i = 0;
Bitmap bmp;
public void done(List<ParseObject> names, ParseException e) {
if (e == null) {
for (ParseObject post : names) {
postTexts.add(post.getString("Logo"));
postTexts.add(post.getString("Couleur"));
postTexts.add(post.getString("Date"));
ParseFile image = (ParseFile) post.get("Rog_pic");
image.getDataInBackground(new GetDataCallback() {
public void done(byte[] data, ParseException e) {
if (e == null) {
bmp = BitmapFactory.decodeByteArray(data, 0, data.length);
} else {
Log.d("test", "There was a problem downloading the data.");
}
}
});
map = new HashMap<String, Object>();
map.put("nom", postTexts.get(i));
i++;
map.put("titre", postTexts.get(i));
i++;
map.put("description", postTexts.get(i));
i++;
map.put("img", bmp);
listItem.add(map);
mSchedule.notifyDataSetChanged();
}
} else {
Log.d("score", "Error: " + e.getMessage());
}
}
});
}
mSchedule is the SimpleAdapter. I tried a lot of things to make it work. I checked, and the ParseFile is not null, so why aren't the images displayed in the Imageview ?
Thanks in advance.
Please post the code for your adapter. Thats where the bug is. Are you sure you're performing a setImageBitmap(img) on your image view within the getView on your adapter? We need to see more adapter code to figure this out.

Returning a bitmap file from AsyncTask freezes UI thread

I have created a simple Activity. The activity is responsible for downloading data from parse.com database and populating a linear layout. In the process, I am dynamically creating the linear layout with TextViews and ImageViews according according to the content.
The problem is that, whenever I try to download an image, I use as AsyncTask Downloading class, which results in slowing down the UI thread! I am currently trying to return the bitmap file from the AsyncTask Image downloading class using: returnedBitmap = new LoadImage().execute(src).get(); which might be responsible for slowing down the UI thread. I have to do this because the caller method geneterImageView will return an imageview when it receives the bitmap file.
The complete Activity code:
public class MainActivity extends ActionBarActivity {
ArrayList<String> heightList = new ArrayList<String>();
ArrayList<String> reversedList = new ArrayList<String>();
ImageView imageView1;
Bitmap bitmap;
RelativeLayout parent_layout;
ParseObject user;
#Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// imageView1 = (ImageView)findViewById(R.id.imageView1);
parent_layout = (RelativeLayout) findViewById(R.id.parent_layout);
login("xyz#xyz.com", "xyz");
}
private void loopThroughArrayAndAttach(){
LinearLayout llInner = new LinearLayout(this);
llInner.setOrientation(LinearLayout.VERTICAL);
LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.FILL_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);
parent_layout.addView(llInner);
for (int i = 0; i < heightList.size(); i++) {
if (hasNoImagess(heightList.get(i)) == true) {
// No images.
TextView myText = geneterTextView(heightList.get(i));
llInner.addView(myText);
// geneterTextView(heightList.get(i));
} else {
ImageView myImage = geneterImageView(heightList.get(i));
llInner.addView(myImage);
// geneterImageView(heightList.get(i));
}
}
}
public static boolean hasNoImagess(String contents){
Document doc = Jsoup.parse(contents);
Element element = doc.body();
Elements elements = element.select("img");
if (elements.isEmpty()) {
return true;
} else {
return false;
}
}
public ImageView geneterImageView(String imgContent){
// Will need to run via background thread - like aysnc
// Extract the image file via jsoup
// Insert it into a imagevieww
// Inser that into a layout.
Log.d("IN IMAGE ", " " + imgContent);
Document doc = Jsoup.parse(imgContent);
Elements img = doc.getElementsByTag("img");
Bitmap returnedBitmap = null;
for (Element el : img) {
String src = el.absUrl("src");
System.out.println("src attribute is : " + src);
// new DownloadImageTask((ImageView)
// findViewById(R.id.imageView1)).execute(src);
try {
returnedBitmap = new LoadImage().execute(src).get();
// imageView1.setImageBitmap(returnedBitmap);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ExecutionException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
ImageView iv = new ImageView(this);
iv.setImageBitmap(returnedBitmap);
return iv;
}
public TextView geneterTextView(String textContent){
// Will need to run via background thread.
Log.i("In TEXT ", " " + textContent);
TextView tv = new TextView(this);
tv.setText(Html.fromHtml(textContent));
return tv;
}
// to download images
private class LoadImage extends AsyncTask<String, String, Bitmap> {
#Override
protected void onPreExecute(){
super.onPreExecute();
}
protected Bitmap doInBackground(String... args){
try {
bitmap = BitmapFactory.decodeStream((InputStream) new URL(args[0]).getContent());
} catch (Exception e) {
e.printStackTrace();
}
return bitmap;
}
protected void onPostExecute(Bitmap image){
if (image != null) {
} else {
Toast.makeText(MainActivity.this, "Image Does Not exist or Network Error", Toast.LENGTH_SHORT).show();
}
}
}
// to login to parse
private void login(final String username, String password){
ParseUser.logInInBackground(username, password, new LogInCallback() {
#Override
public void done(ParseUser user, ParseException e){
if (e == null) {
// if login sucess
// Start intent
// loginSuccess();
Toast.makeText(MainActivity.this, "Success", Toast.LENGTH_SHORT).show();
CloudCallStudentPosts(user);
} else {
Toast.makeText(MainActivity.this, "Failure", Toast.LENGTH_SHORT).show();
}
}
});
}
// //to get data from parse
public void CloudCallStudentPosts(ParseObject s){
setRichStory(s);
}
private void setRichStory(ParseObject s){
// Simialr to setStory, once implemented delete setStory()
new AddStoryAsync(s).execute();
}
class AddStoryAsync extends AsyncTask<Void, Object, Void> {
private static final String TAG = "LazyListView";
ParseObject s;
public AddStoryAsync(ParseObject s) {
this.s = s;
Log.w("In richStory", "ParseObject Id: " + s.getObjectId());
}
#Override
protected void onPreExecute(){
}
#Override
protected Void doInBackground(Void... unused){
HashMap<String, Object> params = new HashMap<String, Object>();
params.put("userid", this.s.getObjectId());
params.put("skip", 0);
ParseCloud.callFunctionInBackground("studentsPosts", params, new FunctionCallback<List<List<ParseObject>>>() {
#Override
public void done(List<List<ParseObject>> postList, com.parse.ParseException arg1){
if (postList == null) {
} else {
if (postList.size() > 0) {
// CustomWebView cwb;
for (int i = 0; i < postList.size(); i++) {
// final Post post = new Post();
if (postList.get(i).get(0).get("htmlContent") == null) {
}
if (postList.get(i).get(0).get("htmlContent") != null) {
Log.e("htmlContent parse", postList.get(i).get(0).get("htmlContent").toString());
// Parse HTML String using JSoup library
String HTMLSTring = postList.get(i).get(0).get("htmlContent").toString();
Document html = Jsoup.parse(HTMLSTring);
Elements paragraphs = html.getElementsByTag("p");
for (org.jsoup.nodes.Element paragraph : paragraphs) {
String paragraphText = paragraph.toString();
Log.e("paragraphText", paragraphText);
heightList.add(paragraphText);
}
loopThroughArrayAndAttach();
}
}
}
}
}
});
return (null);
}
#Override
protected void onProgressUpdate(Object... object){
Log.w("onProgressUpdate ", " " + object[0].getClass());
Log.w("adding to arrayPostList ", " " + object[0].getClass());
}
#Override
protected void onPostExecute(Void unused){
}
}
}
Is there any substitute for getting the bitmap from the AsyncTask and set it in the imageview? Should there be a logical alteration in the approach?
try this :
dont call get() #praveen. instead pass the imageview Reference in the constructor
WorkerThread mWorkerThread = new WorkerThread(mImageView);
mWorkerThread.execute(src);
private class WorkerThread extends AsyncTask<String, String, Bitmap> {
private WeakReference<ImageView> imageViewReference;
public WorkerThread(ImageView imageView) {
super();
imageViewReference = new WeakReference<ImageView>(imageView);
}
#Override
protected Bitmap doInBackground(String... args) {
Bitmap bitmap = null;
try {
bitmap = BitmapFactory.decodeStream((InputStream) new URL(args[0]).getContent());
} catch (Exception e) {
e.printStackTrace();
}
return bitmap;
}
#Override
protected void onPostExecute(Bitmap result) {
super.onPostExecute(result);
if (result != null && imageViewReference.get() != null) {
imageViewReference.get().setImageBitmap(result);
}
}
}
Don't call get() method on AsyncTask it makes main thread to wait for AsyncTask to complete. If you really want to start something only after AsyncTask completes put that into onPostExecute() of your AsynTask
As others have mentioned, your code has several design flaws which makes it difficult to provide you a solution to your problem.
The whole purpose of an AsyncTask is to execute on a background thread. Executing networking and bitmap processing on the main thread will never work. You must refactor your code to accommodate this. Consider the following solution to this particular problem at least:
// to download images
private class LoadImage extends AsyncTask<String, Void, Bitmap> {
protected Bitmap doInBackground(String... args) {
String imgContent = args[0];
Document doc = Jsoup.parse(imgContent);
Elements img = doc.getElementsByTag("img");
for (Element el : img) {
String src = el.absUrl("src");
System.out.println("src attribute is : " + src);
try {
return BitmapFactory.decodeStream((InputStream) new URL(src).getContent());
} catch (Exception e) {
// log
}
}
return null;
}
protected void onPostExecute(Bitmap b) {
ImageView iv = new ImageView(MainActivity.this);
iv.setImageBitmap(b);
llInner.addView(iv);
}
}
You can then do something like:
for (int i = 0; i < heightList.size(); i++) {
new LoadImage(heightList.get(i)).execute();
}
However, this may not be desirable depending on how many AsyncTasks you end up creating. But this is the idea.

Categories

Resources