Change an ImageView inside a ListView - android

I saw a code from Android Hive, and I learned how to send array JSON from the PHP script to my Android / Java code. I successfully retrieved all the details from my online database and displayed them in my desired format.
The problem is, I don't know hot to set an image's src when it is inside a ListView.
Here's my code.
ArrayList<HashMap<String, String>> list = new ArrayList<HashMap<String, String>>();
JSONParser jParser = new JSONParser();
JSONObject json = jParser.getJSONFromUrl("http://domain.com/directory/database/retrieveComments.php?placeId=" + stringPlaceId);
try
{
commentsRatingsArray = json.getJSONArray("commentsRatings");
for(int i = 0; i < commentsRatingsArray.length(); i++)
{
JSONObject jsonObject = commentsRatingsArray.getJSONObject(i);
String dbUserFullName = jsonObject.getString(TAG_FULLNAME);
String dbUserEmail = jsonObject.getString(TAG_EMAIL);
String dbComment = jsonObject.getString(TAG_COMMENT);
String dbRating = jsonObject.getString(TAG_RATING);
String dbDate = jsonObject.getString(TAG_DATE);
String dbTime = jsonObject.getString(TAG_TIME);
HashMap<String, String> map = new HashMap<String, String>();
map.put(TAG_FULLNAME, dbUserFullName);
map.put(TAG_EMAIL, dbUserEmail);
map.put(TAG_COMMENT, dbComment);
map.put(TAG_RATING, dbRating);
map.put(TAG_DATE, dbDate);
map.put(TAG_TIME, dbTime);
list.add(map);
}
}
catch (Exception e)
{
e.printStackTrace();
Toast.makeText(getBaseContext(), "Connection to the server is lost. Please check your internet connection.", Toast.LENGTH_SHORT).show();
}
ListAdapter adapter = new SimpleAdapter
(DisplayCommentsRatings.this, list, R.layout.commentrating,
new String[] { TAG_FULLNAME, TAG_EMAIL, TAG_COMMENT, TAG_DATE, TAG_TIME },
new int[] {R.id.tvUserFullName, R.id.tvUserEmail, R.id.tvUserComment, R.id.tvDate, R.id.tvTime });
setListAdapter(adapter);
Please help me, thanks.

For that i would suggest you to define a custom adapter for your ListView.
You can create custom adapter class by extending either BaseAdapter or ArrayAdapter.
override getView() method.
Follow ViewHolder pattern while overiding getView() method.
Here, Ravi has written about: Android custom ListView with Images and Text.
And the best solution so far: Andoid - Lazy Load of Images in ListView

I think you will have to make your own custom adapter (extending BaseAdapter) and update the image inside the getView method. There is a lot of tuts on Google.
Good luck =)

You can set your image with an URL pointing to the SD name of the file for example.
http://developer.android.com/reference/android/widget/SimpleAdapter.html#setViewImage(android.widget.ImageView, int)
But i think that is a lot easier to extend from BaseAdapter and pass your own Map or Array to it and then you can inflate with any image that you want, download it and set it, etc.
This is an example of one Adapter for devices :) you dont need to start with viewHolder pattern.
public class DevicesAdapter extends BaseAdapter {
private LayoutInflater inflater;
private List<Device> devices;
public DevicesAdapter(Context context, List<Device> devices) {
inflater = LayoutInflater.from(context);
this.devices = devices;
}
#Override
public int getCount() {
return devices.size();
}
#Override
public Object getItem(int position) {
return devices.get(position);
}
#Override
public long getItemId(int position) {
return 0;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View row = convertView;
if (row == null) {
row = inflater.inflate(R.layout.account_devices_row, null);
}
TextView description = (TextView) row.findViewById(R.id.device_text);
description.setText(devices.get(position).getLabel());
return row;
}
}
Regards

They are correct above. You will want to extend a BaseAdapter and overwrite the getView method. You will also want to lazy load the image since you are will be downloading them and shouldn't tie up the UI thread while this action is being performed. Below is my Lazy Load class. Simple create a new class (I call mine LazyLoadImage.java) and stick this code in it. Below are the different ways you can use the class:
To lazy load an image with a placeHolder:
new LazyLoadImage(ImageView imageView, String urlString, Bitmap placeHolder);
To lazy load an image without a placeHolder:
new LazyLoadImage(ImageView imageView, String urlString);
To manually clear the cache:
new LazyLoadImage().clearCache();
If you are targeting OS's below 12 then you will need to include "android-support-v4.jar" in the project.
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.support.v4.util.LruCache;
import android.util.Log;
import android.widget.ImageView;
public class LazyLoadImage extends AsyncTask<String, Void, Bitmap> {
ImageView mDestination;
//Set up cache size and cache
private static int mCacheSize = 4 * 1024 * 1024; // 4 mb
private static LruCache<String, Bitmap> mCache = new LruCache<String, Bitmap>(mCacheSize) {
#Override
protected int sizeOf(String key, Bitmap value) {
return value.getRowBytes() * value.getHeight();
}
};
public LazyLoadImage(ImageView destination, String urlString) {
mDestination = destination;
if (mCache.get(urlString) != null) {
mDestination.setImageBitmap(mCache.get(urlString));
}else {
this.execute(urlString);
}
}
public LazyLoadImage(ImageView destination, String urlString, Bitmap placeHolder) {
mDestination = destination;
if (mCache.get(urlString) != null) {
mDestination.setImageBitmap(mCache.get(urlString));
}else {
setPlaceHolder(urlString, placeHolder);
this.execute(urlString);
}
}
public LazyLoadImage() {
}
private void setPlaceHolder(String urlString, Bitmap placeholder) {
mDestination.setImageBitmap(placeholder);
}
public void clearCache() {
mCache.evictAll();
}
#Override
protected Bitmap doInBackground(String... arg0) {
//If the URI that is passed in arg0[0] is already in mCache then I return it without downloading it again
if (mCache.get(arg0[0]) != null) {
return mCache.get(arg0[0]);
}else {
Bitmap lazyImage = null;
URL myFileUrl = null;
try {
myFileUrl= new URL(arg0[0]);
HttpURLConnection conn= (HttpURLConnection)myFileUrl.openConnection();
conn.setDoInput(true);
conn.connect();
InputStream is = conn.getInputStream();
lazyImage = BitmapFactory.decodeStream(is);
//Store the image in mCache for quick assess from anywhere in app
synchronized (mCache) {
if (mCache.get(arg0[0]) == null) {
mCache.put(arg0[0], lazyImage);
}
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return lazyImage;
}
}
#Override
protected void onCancelled(Bitmap result) {
}
#Override
protected void onPostExecute(Bitmap result) {
/*
* The returned image to the ImageView that was passed in on create
* (either from mCache or when downloaded the first time)
*/
mDestination.setImageBitmap(result);
super.onPostExecute(result);
}
}

Related

What is the right coding about Image Loading?

I'm solving my problem about Image Loader and I have some problems..
What I want is to show many images (about 400) in GridView(or ListView).
I don't want to use the Library like Picasso, Glide like that.
and Here is the problem.
When I call the method which convert from url to bitmap?
3.1. before setAdapter, then pass the bitmap array.
3.2. while getView.
two things are working well. but too much slow... maybe cuz of the times to call URLConnection..
Could anyone help me about these problem? How can I speed up? or are there any other solution without Open Source.
Here is my Source.
Now, 3-1.
ShowImage
private void showImages(ArrayList<String> imgUrls) {
ArrayList<Bitmap> bitmaps = new ArrayList<>();
for (int i = 0; i < imgUrls.size(); i++) {
try {
String img_path = imgUrls.get(i);
Bitmap bitmap = new UriToBitmapAsyncTask().execute(img_path).get();
bitmaps.add(bitmap);
} catch (Exception e) {
Toast.makeText(this, e.getMessage(), Toast.LENGTH_SHORT).show();
}
}
CustomAdapter adapter = new CustomAdapter(getApplicationContext(),R.layout.row,bitmaps);
gridView.setAdapter(adapter);
}
and This is the customAdapter's GetView
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder viewHolder;
if (convertView == null) {
convertView = inflator.inflate(rowLayout, parent, false);
viewHolder = new ViewHolder();
viewHolder.imageView = (ImageView) convertView.findViewById(R.id.imageView);
convertView.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) convertView.getTag();
}
viewHolder.imageView.setImageBitmap(bitmaps.get(position));
return convertView;
}
You should really take Reinventing the wheel to heart but if you really want to toture yourself an Approach could be:
use a ThreadPoolExecutor to fetch more images at once, you should read up how to use them
implement a way to cancel threads who load a img for a griditem which isn't displayed anymore
use two sets of data a thumbnail which loads faster for the grid view and a real image which gets loaded when the user clicks on the grid
dont't forget to use a LRU caching method or your device will run out of memory depending on the images
Don't use ArrayList to store bitmaps. Bitmaps usually take consumes a lot of memory. Try using LRUCache like this way,
public class TCImageLoader implements ComponentCallbacks2 {
private TCLruCache cache;
public TCImageLoader(Context context) {
ActivityManager am = (ActivityManager) context.getSystemService(
Context.ACTIVITY_SERVICE);
int maxKb = am.getMemoryClass() * 1024;
int limitKb = maxKb / 8; // 1/8th of total ram
cache = new TCLruCache(limitKb);
}
public void display(String url, ImageView imageview, int defaultresource) {
imageview.setImageResource(defaultresource);
Bitmap image = cache.get(url);
if (image != null) {
imageview.setImageBitmap(image);
}
else {
new SetImageTask(imageview).execute(url);
}
}
private class TCLruCache extends LruCache<String, Bitmap> {
public TCLruCache(int maxSize) {
super(maxSize);
}
#Override
protected int sizeOf(ImagePoolKey key, Bitmap value) {
int kbOfBitmap = value.getByteCount() / 1024;
return kbOfBitmap;
}
}
private class SetImageTask extends AsyncTask<String, Void, Integer> {
private ImageView imageview;
private Bitmap bmp;
public SetImageTask(ImageView imageview) {
this.imageview = imageview;
}
#Override
protected Integer doInBackground(String... params) {
String url = params[0];
try {
bmp = getBitmapFromURL(url);
if (bmp != null) {
cache.put(url, bmp);
}
else {
return 0;
}
} catch (Exception e) {
e.printStackTrace();
return 0;
}
return 1;
}
#Override
protected void onPostExecute(Integer result) {
if (result == 1) {
imageview.setImageBitmap(bmp);
}
super.onPostExecute(result);
}
private Bitmap getBitmapFromURL(String src) {
try {
URL url = new URL(src);
HttpURLConnection connection
= (HttpURLConnection) url.openConnection();
connection.setDoInput(true);
connection.connect();
InputStream input = connection.getInputStream();
Bitmap myBitmap = BitmapFactory.decodeStream(input);
return myBitmap;
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
}
#Override
public void onConfigurationChanged(Configuration newConfig) {
}
#Override
public void onLowMemory() {
}
#Override
public void onTrimMemory(int level) {
if (level >= TRIM_MEMORY_MODERATE) {
cache.evictAll();
}
else if (level >= TRIM_MEMORY_BACKGROUND) {
cache.trimToSize(cache.size() / 2);
}
}
}
get a instance of TCImageLoader and call display method appropriately.

RecyclerView is not populating out, issue might be with getting the adapter to the rv

I have this recyclerview that is running but problem is, it's not populating anything out. So it's a blank fragment. I was follow this tutorial on how to do it and I twitched it to fit my own. Of course, it went wrong.
Tutorial I was following: http://androidcss.com/android/fetch-json-data-android/#comment-56
tutorial was going on a main activity asynctask adapter. I switched it up to fragment asynctask and adapter.
public class FragmentGlobalfeed extends android.support.v4.app.Fragment {
public static final int CONNECTION_TIMEOUT = 10000;
public static final int READ_TIMEOUT = 15000;
private android.support.v7.widget.RecyclerView mRVProfile;
private com.example.admin.quoteme.AdapterProfile mAdapter;
private android.widget.LinearLayout llLayout;
#Override
public void onCreate(android.os.Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//background doesn't seem to be able to launch so i am gonna take an alt step and try methods to update
//BackgroundFeed backgroundFeed = new BackgroundFeed(getActivity());
//backgroundFeed.execute();
/*AsyncLogin asyncLogin = new com.example.admin.quoteme.FragmentGlobalfeed.AsyncLogin();
asyncLogin.execute();*/
new com.example.admin.quoteme.FragmentGlobalfeed.AsyncLogin().execute();
}
#Override
public android.view.View onCreateView(android.view.LayoutInflater inflater, android.view.ViewGroup container, android.os.Bundle savedInstanceState) {
// Inflate the layout for this fragment
android.view.View view = inflater.inflate(com.example.admin.quoteme.R.layout.fragmentglobalfeed, null);
java.util.List<Profile> data = new java.util.ArrayList<>();
//recyclerview
mRVProfile = (android.support.v7.widget.RecyclerView) view.findViewById(com.example.admin.quoteme.R.id.recyclerViewGlobal);
mRVProfile.setLayoutManager(new android.support.v7.widget.LinearLayoutManager(getActivity()));
mAdapter = new AdapterProfile(getActivity(), data);
mRVProfile.setAdapter(mAdapter);
return view;
}
private class AsyncLogin extends android.os.AsyncTask<String, String, String> {
java.net.HttpURLConnection conn;
java.net.URL url = null;
#Override protected void onPreExecute(){
super.onPreExecute();
}
#Override
protected String doInBackground(String... params) {
try{
//enter url address where ur json file is
url = new java.net.URL("http:http://192.168.0.100/Quoteme/getfeed.php");
} catch (java.net.MalformedURLException e){
e.printStackTrace();
return e.toString();
}
try {
conn = (java.net.HttpURLConnection) url.openConnection();
conn.setReadTimeout(READ_TIMEOUT);
conn.setConnectTimeout(CONNECTION_TIMEOUT);
conn.setRequestMethod("GET");
conn.setDoOutput(true);
} catch (java.io.IOException e1) {
e1.printStackTrace();
return e1.toString();
}
try{
int response_code = conn.getResponseCode();
if(response_code == java.net.HttpURLConnection.HTTP_OK){
//read data
java.io.InputStream input = conn.getInputStream();
java.io.BufferedReader reader = new java.io.BufferedReader(new java.io.InputStreamReader(input));
StringBuilder result = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
result.append(line);
}
return (result.toString());
} else {
return("unsuccessful");
}
} catch (java.io.IOException e){
e.printStackTrace();
return e.toString();
} finally {
conn.disconnect();
}
}
#Override
protected void onPostExecute(String result){
java.util.List<Profile> data = new java.util.ArrayList<>();
try {
org.json.JSONArray jArray = new org.json.JSONArray(result);
//extraction
for(int i= 0; i<jArray.length(); i++){
org.json.JSONObject json_data = jArray.getJSONObject(i);
Profile profile = new Profile();
profile.setUser_id(json_data.getString("user_id"));
profile.setQuote_points(json_data.getInt("quote_points"));
profile.setQuote(json_data.getString("quote_description"));
data.add(profile);
}
//setup and hand data over to rv // adapter
/*mRVProfile = (android.support.v7.widget.RecyclerView)llLayout.findViewById(com.example.admin.quoteme.R.id.recyclerViewGlobal);
mAdapter = new AdapterProfile(getActivity(), data);
mRVProfile.setAdapter(mAdapter);
mRVProfile.setLayoutManager(new android.support.v7.widget.LinearLayoutManager(getActivity()));*/
} catch (org.json.JSONException e){
android.widget.Toast.makeText(getActivity(),e.toString(), android.widget.Toast.LENGTH_LONG);
}
}
}
There are also some commented out codes that are my past experiments. Please ignore the commented out ones. Also i have tried to initialise the adapters both in asyncTask and also in onCreate, both did not work. I wonder.
And my adapter class.
public class AdapterProfile extends android.support.v7.widget.RecyclerView.Adapter<android.support.v7.widget.RecyclerView.ViewHolder>{
private android.content.Context context;
private android.view.LayoutInflater inflater;
java.util.List<Profile> data = java.util.Collections.emptyList();
com.example.admin.quoteme.Profile current;
int currentPos = 0;
public AdapterProfile(android.content.Context context, java.util.List<com.example.admin.quoteme.Profile> data){
this.context=context;
inflater= android.view.LayoutInflater.from(context);
this.data=data;
}
#Override
public android.support.v7.widget.RecyclerView.ViewHolder onCreateViewHolder(android.view.ViewGroup parent, int viewType){
android.view.View view = inflater.inflate(com.example.admin.quoteme.R.layout.feed_layout_v2, parent, false);
MyHolder holder = new com.example.admin.quoteme.AdapterProfile.MyHolder(view);
return holder;
}
#Override
public void onBindViewHolder(android.support.v7.widget.RecyclerView.ViewHolder holder, int position) {
// Get current position of item in recyclerview to bind data and assign values from list
MyHolder myHolder= (MyHolder) holder;
com.example.admin.quoteme.Profile current=data.get(position);
myHolder.name.setText(current.getUser_id());
myHolder.quote.setText(current.getQuote());
myHolder.points.setText(current.getQuote_points() + "Points");
// load image into imageview using glide
/*Glide.with(context).load("http://192.168.1.7/test/images/" + current.fishImage)
.placeholder(R.drawable.ic_img_error)
.error(R.drawable.ic_img_error)
.into(myHolder.ivFish);*/
}
#Override
public int getItemCount() {
return data.size();
}
class MyHolder extends android.support.v7.widget.RecyclerView.ViewHolder{
private android.widget.TextView name;
private android.widget.TextView quote;
private android.widget.TextView points;
// create constructor to get widget reference
public MyHolder(android.view.View itemView) {
super(itemView);
name = (android.widget.TextView)itemView.findViewById(com.example.admin.quoteme.R.id.name);
quote = (android.widget.TextView)itemView.findViewById(com.example.admin.quoteme.R.id.quote);
points = (android.widget.TextView)itemView.findViewById(com.example.admin.quoteme.R.id.points);
}
}
I think these two class will suffice to fish out the error. I am stuck trying to populate this recyclerview out.
In onCreateView you have-> mAdapter = new AdapterProfile(getActivity(), data);
But data is just empty varibale there. Later in the Async task you build up new local data variable that you dont use. The commented block in the post execute should be working- is there error messages in the log?
You're populating the data ArrayList in the AsyncTasks' onPostExecute method but you never set it to the adapter...
Uncomment the creation of the adapter and setting it to the recyclerview. Why is it commented out? Any errors?
Hey your data object size must be null as seeing your code
#Override
protected void onPostExecute(String result){
java.util.List<Profile> data = new java.util.ArrayList<>();
try {
org.json.JSONArray jArray = new org.json.JSONArray(result);
//extraction
for(int i= 0; i<jArray.length(); i++){
org.json.JSONObject json_data = jArray.getJSONObject(i);
Profile profile = new Profile();
profile.setUser_id(json_data.getString("user_id"));
profile.setQuote_points(json_data.getInt("quote_points"));
profile.setQuote(json_data.getString("quote_description"));
data.add(profile);
}
//setup and hand data over to rv // adapter
/*mRVProfile = (android.support.v7.widget.RecyclerView)llLayout.findViewById(com.example.admin.quoteme.R.id.recyclerViewGlobal);
mAdapter = new AdapterProfile(getActivity(), data);
mRVProfile.setAdapter(mAdapter);
mRVProfile.setLayoutManager(new android.support.v7.widget.LinearLayoutManager(getActivity()));*/
} catch (org.json.JSONException e){
android.widget.Toast.makeText(getActivity(),e.toString(), android.widget.Toast.LENGTH_LONG);
}
}
}
Here you are creating a local data ArrayList . But you set a different list named the same data to the adapter with instantiated but with zero size.
You should execute the AssyncTask from onCreateView() method and set the adapter from onPostExecute() method.
* Also use the same data variable to be set in Adapter. Better to make it field of Fragment class.

How to cancel an Async task in gallery View in android using position index?

i have an galleyview which loads images from server album. but my album has many images [more than 500]. so once i scroll the galleyview more fast the number of background task is getting high so the app is getting crashed.so i am planning to kill [cancel] some old tasks based on the position in the galleryview. so please suggest some solution.The source code is provided below.
Task invoking:
DownloadImageTask downloadTask = new DownloadImageTask(
ShowGallery.this, view,position);
// cancel some task to avoid the crash - need to implement
// cancelPotentialDownload(position);
downloadTask.execute( THUMB_PREFIX + picture.getFileName(),
picture.getForceExtension(), thumbUrl,albumName, bitmapsCache, position, picture,null);
private static boolean cancelPotentialDownload(int position) {
// need to implement.
}
Downloadimage task
public class DownloadImageTask extends AsyncTask<Object, Void, Bitmap> {
Context activity;
private ImageView view;
public int position;
public DownloadImageTask(Context context, ImageView imageView, int imagePosition) {
super();
activity = context;
view = imageView;
position = imagePosition;
}
#Override
protected Bitmap doInBackground(Object... parameters) {
String fileName = (String) parameters[0];
String extension = (String) parameters[1];
String thumbUrl = (String) parameters[2];
Integer currentAlbumName = (Integer) parameters[3];
Map<Integer, Bitmap> bitmapsCache = (Map<Integer, Bitmap>) parameters[4];
Integer position = (Integer) parameters[5];
Picture picture = (Picture) parameters[6];
Album album = (Album) parameters[7];
Bitmap downloadImage = null;
File imageFileOnExternalDirectory = null;
try {
imageFileOnExternalDirectory = FileUtils.getInstance()
.getFileFromGallery(activity, fileName, extension,
thumbUrl, true, currentAlbumName);
downloadImage = BitmapFactory
.decodeFile(imageFileOnExternalDirectory.getPath());
if (picture != null) {
// only for showgallery activity
picture.setThumbImageCachePath(imageFileOnExternalDirectory
.getPath());
bitmapsCache.put(position, downloadImage);
} else if (album != null) {
// only for albumadapter
album.setAlbumCoverCachePath(imageFileOnExternalDirectory
.getPath());
}
} catch (GalleryConnectionException e) {
// Log.v(TAG, e.getMessage());
} catch (FileHandlingException e) {
// Log.v(TAG, e.getMessage());
}
return downloadImage;
}
#Override
protected void onPostExecute(Bitmap downloadImage) {
if (downloadImage != null) {
view.setImageBitmap(downloadImage);
}
}
}
Look at the example on this link. You are not downloading images from the web, so just replace this functionality with reading the image from gallery

Android - Trouble setting up async thread to download array of images from the internet

I've read dozens of posts about this and tried as many solutions, but I can't seem to get anything to work. I am populating a listview from a JSON response, which includes numerous (sometimes over 100) rows. Each row has an associated (and different) image.
In a performance test, when I didn't download/display the images, 134 rows from a JSON response were processed and displayed in less than 2 seconds. Awesome! However, when I turned the image downloads/displays back on, it took about 10 years.
It's painfully obvious that I need to use a background thread to download the images, but every solution I've found online has been unsuccessful (assuming some error on my part at this point).
I think I have an idea where I need to process the images in the background, but I'm not exactly sure how to go about setting it up.
Right now, the images (along with all the other data) is loaded into an array. Each image gets downloaded inline right now, hence the incredible performance nightmare.
Here is some code excerpts from my main activity class...
InputStream is = null;
//http post
try{
postQuery = "my api path";
HttpClient httpclient = new DefaultHttpClient();
HttpPost httppost = new HttpPost(postQuery);
HttpResponse response = httpclient.execute(httppost);
HttpEntity entity = response.getEntity();
is = entity.getContent();
}catch(Exception e){
Log.e("log_tag", "Error in http connection "+e.toString());
}
//convert response to string
try{
BufferedReader reader = new BufferedReader(new InputStreamReader(is,"iso-8859-1"),8);
StringBuilder sb = new StringBuilder();
String line = null;
while ((line = reader.readLine()) != null) {
sb.append(line + "\n");
}
is.close();
result=sb.toString();
}catch(Exception e){
Log.e("log_tag", "Error converting result "+e.toString());
}
m_bottles = new ArrayList<Bottles>();
this.m_adapter = new BottleAdapter(this, R.layout.bottlelistimagelayout, m_bottles);
setListAdapter(this.m_adapter);
viewBottles = new Runnable(){
public void run() {
getBottles();
}
};
Thread thread = new Thread(null, viewBottles, "MagentoBackground");
thread.start();
m_ProgressDialog = ProgressDialog.show(SpiritsBottles.this,
"Please wait...", "Retrieving data ...", true);
public class Bottle{
public String name_abbrArray;
}
private void getBottles(){
try{
JSONObject row = new JSONObject(result);
array = row.getJSONArray("bottles");
m_bottles = new ArrayList<Bottles>();
for(int i=0;i<array.length();i++){
row = array.getJSONObject(i);
bottleID = row.getInt("id");
name_abbr = row.getString("name_abbr");
bottlePicture = row.getString("image");
Bottles o = new Bottles();
o.setbottleID(bottleID);
o.setname_abbr(name_abbr);
o.setbottlePicture(bottlePicture);
m_bottles.add(o);
Log.i("ARRAY", "" + m_bottles.size() + " - " + i + " / " + array.length()+"m_bottles size = "+m_bottles.size());
}
} catch (Exception e) {
Log.e("PROC - bottleid = "+bottleNamesMap.get("bottlePicture2"), e.getMessage());
}
runOnUiThread(returnRes);
}
private Runnable returnRes = new Runnable() {
public void run() {
if(m_bottles != null && m_bottles.size() > 0){
m_adapter.notifyDataSetChanged();
for(int i=0;i<m_bottles.size();i++)
m_adapter.add(m_bottles.get(i));
}
m_ProgressDialog.dismiss();
m_adapter.notifyDataSetChanged();
}
};
private class BottleAdapter extends ArrayAdapter<Bottles> {
private ArrayList<Bottles> items;
public BottleAdapter(Context context, int textViewResourceId, ArrayList<Bottles> items) {
super(context, textViewResourceId, items);
this.items = items;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View v = convertView;
if (v == null) {
LayoutInflater vi = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = vi.inflate(R.layout.bottlelistimagelayout, null);
}
Bottles o = items.get(position);
if (o != null) {
final TextView bottlenametv = (TextView) v.findViewById(R.id.bottlename);
final ImageView iv = (ImageView) v.findViewById(R.id.icon);
if (bottlenametv != null) {
bottlenametv.setText(o.getname_abbr());
bottlenametv.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Intent intent = new Intent(getApplicationContext(), SingleBottleDisplay.class);
intent.putExtra("name", bottlenametv.getText());
startActivityForResult(intent,0);
}
});
}
if(iv != null){
iv.setImageBitmap(o.getbottlePicture());
iv.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Intent intent = new Intent(getApplicationContext(), SingleBottleDisplay.class);
intent.putExtra("name", bottlenametv.getText());
startActivityForResult(intent,0);
}
});
}
}
return v;
}
}
Here is my bottles class where I am currently downloading each row's image inline (which is my performance problem).
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.util.Log;
public class Bottles {
private int bottleID;
private String name_abbr;
private Bitmap bottlePicture;
public int getbottleID() {
return bottleID;
}
public void setbottleID(Integer bottleID) {
this.bottleID = bottleID;
}
public String getname_abbr() {
return name_abbr;
}
public void setname_abbr(String name_abbr) {
this.name_abbr = name_abbr;
}
public void setbottlePicture(String bottlePicture) throws MalformedURLException, IOException {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize=6;
Bitmap bitmap = BitmapFactory.decodeStream((InputStream)new URL(bottlePicture).getContent(), null, options);
this.bottlePicture = bitmap;
}
public Bitmap getbottlePicture() {
return bottlePicture;
}
}
I'm really, really hoping someone can help me out with this as I'm at the end of my rope and almost out of coffee... :)
I think it would be best if you were to put the downloading of the image in the second snippet into a thread.
See http://developer.android.com/resources/articles/painless-threading.html for more detail on threading, but basically you would create a method like 'private Bitmap downloadImage(url) {...}' inside which would be something like this:
new Thread(new Runnable() {
public void run() {
final Bitmap b = BitmapFactory.decodeStream((InputStream)new URL(url).getContent());
mImageView.post(new Runnable() {
public void run() {
return b;
}
});
}
}).start();
That code is untested, but it should work :)
This is a classic issue with listviews that need to load images. The accepted pattern is "lazy loading" the images, which essentially means that in getView (in your adapter) you start an AsyncTask which loads the image. The view is returned and the UI thread continues, so you don't have a performance issue. Later, the AsyncTask completes, and it adds the downloaded image to the view that was returned previously.
Googling "lazy load listview" will return a ton of results.
This is also a better solution because all of the images aren't loaded at once, which can cause out-of-memory issues when your list becomes too large.
An additional performance gain can be realized by making a cache of images, so that you don't need to reload the image if it's in the cache. This may be overkill but a HashMap of imagename => SoftReference(Bitmap) can provide this functionality. If the key exists in the cache, and the SoftReference is still valid, use the Bitmap there; otherwise use the async task to reload the image (and save it to the cache...)
Finally -- there is an interesting wrinkle to all this. As you can see, getView() sometimes will recycle a view -- that is, when a particular list item scrolls out of the display, it is sometimes reused (to avoid the cost of recreating a new view). So, an async task may be running which references a view which is currently being used for some other new object. the lazy load pattern generally sets the tag on the view, and if that tag is unchanged when the async task returns, it goes ahead and adds the image to the view. Otherwise, the implication is that the image is no longer needed.
Thanks very much for the info Todd and Elijah. What I ended up doing is using the UniversalImageLoader library provided by nostra13 here.
My implementation of the code was in getView() of the first snippet above and ended up looking like this...
final ImageView iv = (ImageView) v.findViewById(R.id.icon);
if(iv != null){
//iv.setImageBitmap(o.getbottlePicture());
ImageLoader imageLoader = ImageLoader.getInstance();
imageLoader.init(ImageLoaderConfiguration.createDefault(getContext()));
imageLoader.displayImage(o.getbottlePicture(), iv);
iv.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Intent intent = new Intent(getApplicationContext(), SingleBottleDisplay.class);
intent.putExtra("name", bottlenametv.getText());
startActivityForResult(intent,0);
}
});
}
It works perfectly! Many thanks to nostra13 for the fantastic library!!

asynchronus image loading in gridview

I'm loading images in gridviev asynchronusly.But my gridview displaying only a single image in the last cell of gridview.My adapter class and asynchronus class is given below, thanks.
Adapter class:
class OrderAdapter extends ArrayAdapter<String>
{
LayoutInflater inflater;
String name3[];
public OrderAdapter(Context context,int resource,LayoutInflater inflater,String name2[])
{
super(context, resource,R.id.img,name2);
this.inflater=inflater;
this.name3=name2;
}
public View getView(int position, View convertView, ViewGroup parent)
{
View row=inflater.inflate(R.layout.row,parent,false);
final ImageView img=(ImageView)row.findViewById(R.id.img);
String imgurl=name3[position];
Log.e("urlchandan",name3[position]);
AsyncImageLoaderv asyncImageLoaderv=new AsyncImageLoaderv();
Bitmap cachedImage = asyncImageLoaderv.loadDrawable(imgurl, new AsyncImageLoaderv.ImageCallback()
{
public void imageLoaded(Bitmap imageDrawable, String imageUrl) {
img.setImageBitmap(imageDrawable);
}
});
img.setImageBitmap(cachedImage);
return row;
}
}
Asynchronous class
public class AsyncImageLoaderv {
private HashMap<String, SoftReference<Bitmap>> imageCache;
public AsyncImageLoaderv() {
imageCache = new HashMap<String, SoftReference<Bitmap>>();
}
public Bitmap loadDrawable(final String imageUrl, final ImageCallback imageCallback) {
if (imageCache.containsKey(imageUrl)) {
SoftReference<Bitmap> softReference = imageCache.get(imageUrl);
Bitmap drawable = softReference.get();
if (drawable != null) {
return drawable;
}
}
final Handler handler = new Handler() {
#Override
public void handleMessage(Message message) {
imageCallback.imageLoaded((Bitmap) message.obj, imageUrl);
}
};
new Thread() {
#Override
public void run() {
try{
Log.d("ur",imageUrl);
Bitmap drawable = loadImageFromUrl(imageUrl);
imageCache.put(imageUrl, new SoftReference<Bitmap>(drawable));
Message message = handler.obtainMessage(0, drawable);
handler.sendMessage(message);
}catch(Exception e){Log.e("thread stellent",e.toString());}
}
}.start();
return null;
}
public static Bitmap loadImageFromUrl(String url) {
InputStream inputStream;Bitmap b;
try {
inputStream = (InputStream) new URL(url).getContent();
BitmapFactory.Options bpo= new BitmapFactory.Options();
bpo.inSampleSize=2;
b=BitmapFactory.decodeStream(new PatchInputStream(inputStream), null,bpo );
return b;
} catch (IOException e) {
throw new RuntimeException(e);
}
//return null;
}
public interface ImageCallback {
public void imageLoaded(Bitmap imageBitmap, String imageUrl);
}
}
You can't do it the way you're trying. You need to have your asynchronous loader store the resulting image in some data structure your adapter can access by position (e.g. a list, a hashmap, whatever). Your getView() should then simply pull the image from the correct position. Your asynchronous loader will populate the data structure and perform a notifyDataSetChanged() to have the list redraw itself with the newly loaded image.
I got the solution by making the ImageView img in adatper inflater as final because it avoids
the images to display at a single cell in gridview . And my images was of big size and got the error decoder return false and this error is solved by taking another class
--
import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
public class PatchInputStream extends FilterInputStream {
public PatchInputStream(InputStream in) {
super(in);
}
public long skip(long n) throws IOException {
long m = 0L;
while (m < n) {
long _m = in.skip(n-m);
if (_m == 0L) break;
m += _m;
}
return m;
}
}
this class is used in AsyncImageLoaderv given above .
b=BitmapFactory.decodeStream(new PatchInputStream(inputStream), null,bpo );

Categories

Resources