Images in gridview get replaced on scrolling - android

I have coded to display few images in gridview. The images are getting displayed from urls.
The problem i am facing is that the images get replaced when i scroll.. and the order of images keeps on changing once started.. this leads to delay in display of full image if i click on any image in grid..
Please help !
code :
public class ImageAdapter extends BaseAdapter {
private Context mContext;
private TextView txtUrl;
private String response;
public ImageView imageView;
public static String[] mThumbIds;
public ImageAdapter(Context c,String resp) {
mContext = c;
response = resp.trim();
mThumbIds = resp.split(",");
}
public int getCount() {
return mThumbIds.length;
}
public Object getItem(int position) {
return null;
}
public long getItemId(int position) {
return 0;
}
// create a new ImageView for each item referenced by the Adapter
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) { // if it's not recycled, initialize some attributes
imageView = new ImageView(mContext);
imageView.setLayoutParams(new GridView.LayoutParams(95, 95));
imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
imageView.setPadding(6, 6, 6, 6);
} else {
imageView = (ImageView) convertView;
}
try {
new LoadImageGrid(imageView).execute(mThumbIds[position]);
} catch(Exception e) {
txtUrl.setText("Error: Exception");
}
return imageView;
}
class LoadImageGrid extends AsyncTask<String, Void, Drawable>
{
ImageView imageView;
public LoadImageGrid(ImageView im){
imageView = im;
}
#Override
protected Drawable doInBackground(String... args) {
String url = args[0];
Drawable d = null;
try {
d = Drawable.createFromStream((InputStream) new URL(url).getContent(), "src");
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return d;
}
#Override
protected void onPostExecute(Drawable d) {
imageView.setImageDrawable(d);
}

When you scroll your grid view, image views that are not visible returns to getView() as convertView parameter. But your asyncTask doesn't stop, and call
imageView.setImageDrawable(d);
leads to applying downloaded image to the view on wrong position. Because now you reuse the same imageView. Quick fix is not to use convertView. But it'll slow down your app a bit.

This seems to be related to convert view. When you reuse the space for an image using convert view then you should use the Imageview within that scope. I would suggest to find the imageview by its id within your current class code and then popultae it.

Related

The images in my listview changes when I scroll

This is my code:
public class GetAllCategoriesListViewAdapter extends BaseAdapter{
private JSONArray dataArray;
private Activity activity;
private static final String baseUrlForCategoryImage = "link here";
private static LayoutInflater inflater = null;
public GetAllCategoriesListViewAdapter(JSONArray jsonArray, Activity a){
this.dataArray = jsonArray;
this.activity = a;
inflater = (LayoutInflater) this.activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
#Override
public int getCount() {
return this.dataArray.length();
}
#Override
public Object getItem(int position) {
return position;
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
final ListCell cell;
if(convertView == null){
convertView = inflater.inflate(R.layout.get_all_categories_list_view_cell, null);
cell = new ListCell();
cell.category_name = (TextView) convertView.findViewById(R.id.category_name);
cell.category_image = (ImageView) convertView.findViewById(R.id.category_image);
cell.category_image.setTag(cell);
convertView.setTag(cell);
}else{
cell = (ListCell) convertView.getTag();
}
try{
JSONObject jsonObject = this.dataArray.getJSONObject(position);
cell.category_name.setText(jsonObject.getString("category_name"));
String nameOfImage = jsonObject.getString("category_image");
String urlForImageInServer = baseUrlForCategoryImage + nameOfImage;
new AsyncTask<String, Void, Bitmap>(){
protected Bitmap doInBackground(String... params){
String url = params[0];
Bitmap icon = null;
try{
InputStream in = new java.net.URL(url).openStream();
icon = BitmapFactory.decodeStream(in);
}catch (MalformedURLException e){
e.printStackTrace();
}catch (IOException e){
e.printStackTrace();
}
return icon;
}
#Override
protected void onPostExecute(Bitmap result) {
cell.category_image.setImageBitmap(result);
}
}.execute(urlForImageInServer);
}catch (JSONException e){
e.printStackTrace();
}
return convertView;
}
private class ListCell{
private ImageView category_image;
private TextView category_name;
}
}
The code gets the images from my webhost and place it in every cell in my listvew. The problem is everytime I scroll, the images are shuffled and returns in few seconds. How to stop the images from changing when I scroll? I tried to use the solution on other post but it won't work. Please help.
Looks like you are new to android. So you are fetching the images in the getView method. The getView method is called every time a new list item is drawn. So For every image, a new request is made to internet. SO that will be a lot of requests . You should firstly get your images and get them in some ArryayList . Then pass that Arraylist to your adapter. Here is tutorial for you
Using AsyncTask
http://www.devexchanges.info/2015/04/android-custom-listview-with-image-and.html
Using Volley
https://www.androidhive.info/2014/07/android-custom-listview-with-image-and-text-using-volley/
Go for Volley for better performance. Cheers!

Show images from the internet in ListView

I want that this 200 Pictures are in every row of the ListView.
Where I have to copy this code which collect the pictures from the internet in my CustomAdapter?
for(int i = 1; i <= 200; i++){
final int ii = i;
final ImageView imageView = new ImageView(CustomListView.this);
RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT,RelativeLayout.LayoutParams.WRAP_CONTENT);
//linearLayout.addView(imageView,lp);
Thread thread = new Thread(){
#Override
public void run(){
final Bitmap bm = getBitmapFromURL("http://ruthe.de/cartoons/strip_"+getPictureName(ii)+".jpg");
runOnUiThread(new Runnable() {
#Override
public void run() {
if(bm !=null){
imageView.setImageBitmap(bm);
}
else {
//linearLayout.removeView(imageView);
}
}
});
}
};thread.start ();
}
This is my CustomAdapter:
public class CustomAdapter extends BaseAdapter implements View.OnClickListener {
/*********** Declare Used Variables *********/
private Activity activity;
private ArrayList data;
private static LayoutInflater inflater=null;
public Resources res;
ListModel tempValues=null;
int i=0;
/************* CustomAdapter Constructor *****************/
public CustomAdapter(Activity a, ArrayList d,Resources resLocal) {
/********** Take passed values **********/
activity = a;
data=d;
res = resLocal;
/*********** Layout inflator to call external xml layout () ***********/
inflater = ( LayoutInflater )activity.
getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
/******** What is the size of Passed Arraylist Size ************/
public int getCount() {
if(data.size()<=0)
return 1;
return data.size();
}
public Object getItem(int position) {
return position;
}
public long getItemId(int position) {
return position;
}
/********* Create a holder Class to contain inflated xml file elements *********/
public static class ViewHolder{
public TextView text;
public TextView text1;
public TextView textWide;
public ImageView image;
}
/****** Depends upon data size called for each row , Create each ListView row *****/
public View getView(int position, View convertView, ViewGroup parent) {
View vi = convertView;
ViewHolder holder;
if(convertView==null){
/****** Inflate tabitem.xml file for each row ( Defined below ) *******/
vi = inflater.inflate(R.layout.tabitem, null);
/****** View Holder Object to contain tabitem.xml file elements ******/
holder = new ViewHolder();
holder.text = (TextView) vi.findViewById(R.id.text);
holder.text1=(TextView)vi.findViewById(R.id.text1);
holder.image=(ImageView)vi.findViewById(R.id.image);
/************ Set holder with LayoutInflater ************/
vi.setTag( holder );
}
else
holder=(ViewHolder)vi.getTag();
if(data.size()<=0)
{
holder.text.setText("No Data");
}
else
{
/***** Get each Model object from Arraylist ********/
tempValues=null;
tempValues = ( ListModel ) data.get(position);
/************ Set Model values in Holder elements ***********/
holder.text.setText(tempValues.getCompanyName());
holder.text1.setText( tempValues.getUrl() );
holder.image.setImageResource(
res.getIdentifier(
"com.androidexample.customlistview:drawable/"+tempValues.getImage(),null,null));
/******** Set Item Click Listner for LayoutInflater for each row *******/
vi.setOnClickListener(new OnItemClickListener( position ));
}
return vi;
}
#Override
public void onClick(View v) {
Log.v("CustomAdapter", "=====Row button clicked=====");
}
/********* Called when Item click in ListView ************/
private class OnItemClickListener implements View.OnClickListener{
private int mPosition;
OnItemClickListener(int position){
mPosition = position;
}
#Override
public void onClick(View arg0) {
CustomListView sct = (CustomListView)activity;
/**** Call onItemClick Method inside CustomListViewAndroidExample Class ( See Below )****/
sct.onItemClick(mPosition);
}
}
//My own code
public static Bitmap getBitmapFromURL(String src) {
try {URL url = new URL(src);
return BitmapFactory.decodeStream(url.openConnection().getInputStream());
}
catch(Exception e){
e.printStackTrace();
}
return null;
} //PICTURE BITMAP
public String getPictureName (int i){
String in = ""+i+"";
if(in.length() == 1){
return "000"+in;
}
else if(in.length() == 2){
return "00"+in;
}
else if(in.length() == 3){
return "0"+in;
}
else{
return in;
}
}
I searched on the whole internet but I dont found something which explains how to get pictures from the Internet into every row of a ListView...
PICASsO allows for hassle-free image loading in your application—often in one line of code!
for the library check this link http://square.github.io/picasso/
and at the bottom of page you can download jar file and just paste it in the libs folder
Picasso.with(context).load("YOUR IMAGE URL").into(imageView);
int your getView method
do it like
holder.image=(ImageView)vi.findViewById(R.id.image);
and then
Picasso.with(context).load("YOUR IMAGE URL").into(holder.image);
Take a look at the Picasso library. It makes it extremely easy.
http://square.github.io/picasso/
To use it, simply find your ImageView with the standard findViewById, then use the following code:
Picasso.with(context).load("www.google.com/images/1").into(imageView);
Simply input the URL and the ImageView, and Picasso will async load the image and put it in the imageview.
Im currently using it to show a list of over 400 images in a listview, works perfectly.
Except for the thread you can use the bitmap object inside the adapter itself and initialize the image view with the bitmap object, using position integer instead of (ii).
Hi i have found a workaround for my app: i have create a class type:
public class myClass {
....
...
private Bitmap imguser;
.. and into costructor i have added objects for async task like Future and i send image name
received from server side....
public myClass(..., ..,..,String userid, ...){
Future<Bitmap> futureimguser;
ExecutorService executor = Executors.newCachedThreadPool();
getImgFromSite getimguserfromsite = new getImgFromSite(userid,"imguser");
futureico = executor.submit(geticofromsite);
futureimguser = executor.submit(getimguserfromsite)
.......
this.imguser = futureimguser.get();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ExecutionException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
this.icopoi = futureico.get();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ExecutionException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
executor.shutdown();
next i have a method like below which loads images from my site.
private final class getImgFromSite implements Callable<Bitmap> {
String imgsrc = new String();
String imgtipo = new String();
public getImgFromSite(String srcimg,String imgtipo) {
this.imgsrc = srcimg;
this.imgtipo = imgtipo;
}
#Override
public Bitmap call() throws Exception {
String imgpath;
if(imgtipo.compareTo("imguser") == 0){
imgpath = "http://mysite/assets/imgcomics/"+imgsrc+".jpg";
}
else{
imgpath = "http://mysite/"+imgsrc;
}
Bitmap myBitmap;
URL url = new URL(imgpath);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setDoInput(true);
connection.connect();
InputStream input = connection.getInputStream();
myBitmap= BitmapFactory.decodeStream(input);
return myBitmap;
}
}
Hope that i have help you!

Getting itemid from list<string>

i'm working on wallpaper app
i implemented this code in order to load my pictures from assets
loading-images-from-assets-folder
it's working great but i have issue with getting itemid from the list to use the id to display one of these images in fullscreenactivity or setting wallpaper
public long getItemId(int position) {
return position ;
}
here is my code
public class ImageAdapter extends BaseAdapter{
private Context mContext;
private List<String> list;
private AssetManager assetManager;
public ImageAdapter(Context c, List<String> list) {
mContext = c;
this.list = list;
}
public int getCount() {
return list.size();
}
public Object getItem(int position) {
return position;
}
public long getItemId(int position) {
return position;
}
public View getView(int position, View view, ViewGroup parent) {
ImageView imageView = new ImageView(mContext);
try {
InputStream is = mContext.getAssets().open(list.get(position));
Bitmap bm = BitmapFactory.decodeStream(is);
imageView.setImageBitmap(bm);
imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
imageView.setLayoutParams(new GridView.LayoutParams(80, 80));
} catch (IOException e) {
e.printStackTrace();
}
// TODO Auto-generated method stub
return imageView;
}
public class Gs3Wallpaper extends Activity {
private ImageButton Gs3Button;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
GridView gridView = (GridView) findViewById(R.id.GridView1);
try {
gridView.setAdapter(new ImageAdapter(this ,getImage()));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
public List<String> getImage()throws IOException {
AssetManager assetManager = getAssets();
String[] files = assetManager.list("gallary");
List<String> list = new ArrayList<String>();
for (String it : files) {
list.add("gallary"+File.separator + it);
}
return list;
i don't know how to get the id from the list i tried to use list.get(position) but it returns string not int so i can't pass that to setImageResource for example
any suggestions?
What you can do is set the image or a path to the image, depending on how you are doing it, in a HashMap in getView() when you set the list item. Use the position for the key and the image as the value
public class MyClass
{
HashMap<String, Bitmap> imageMap = new HashMap<String, Bitmap>();
...
then set it in your getView()
public View getView(int position, View view, ViewGroup parent) {
ImageView imageView = new ImageView(mContext);
try {
InputStream is = mContext.getAssets().open(list.get(position));
Bitmap bm = BitmapFactory.decodeStream(is);
imageView.setImageBitmap(bm);
imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
imageView.setLayoutParams(new GridView.LayoutParams(80, 80));
String posString = String.valueOf(position);
imageMap.put(posString, bm);
} catch (IOException e) {
....
}
Something like this should work for you. Then just use the position to get that bitmap out of the HashMap

Progress Dialog in GridView

My code as follows:
public class wall extends Activity {
GridView webgridview;
Button web;
ProgressDialog pd;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.wall);
pd = ProgressDialog.show(wall.this,"Loading", "Please Wait...",true);
new Thread() {
public void run() {
try {
webgridview.setAdapter(new WebImageAdapter(wall.this));
}catch(Exception e)
{
}
handler.sendEmptyMessage(0);
pd.dismiss();
}
}.start();
private Handler handler = new Handler() {
public void handleMessage(Message msg) {
Toast.makeText(wall.this, "finished", 1).show();
}
};
And my adapter class as follows. I code progress dialog in above class only.
public class WebImageAdapter extends BaseAdapter {
private Context mContext;
public static String[] myRemoteImages = {
"http://www.evergreenhits.com/ad/wallpapers/3d_1.jpg",
"http://www.evergreenhits.com/ad/wallpapers/3d_2.jpg",
"http://www.evergreenhits.com/ad/wallpapers/3d_3.jpg",
"http://www.evergreenhits.com/ad/wallpapers/3d_4.jpg",
"http://www.evergreenhits.com/ad/wallpapers/3d_5.jpg"
};
public WebImageAdapter(Context c) {
mContext = c;
}
public int getCount() {
//return animals.length;
return this.myRemoteImages.length;
}
public Object getItem(int position) {
return position;
}
public long getItemId(int position) {
return position;
}
// create a new ImageView for each item referenced by the Adapter
public ImageView getView(int position, View convertView, ViewGroup parent) {
ImageView imageView;
imageView = new ImageView(mContext);
if (convertView == null) {
imageView.setLayoutParams(new GridView.LayoutParams(85, 85));
imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
imageView.setPadding(8, 8, 8, 8);
} else {
imageView = (ImageView) convertView;
}
try {
URL aURL = new URL(myRemoteImages[position]);
URLConnection conn = aURL.openConnection();
conn.connect();
InputStream is = conn.getInputStream();
BufferedInputStream bis = new BufferedInputStream(is);
Drawable d=Drawable.createFromStream(bis, "src Name");
bis.close();
is.close();
imageView.setImageDrawable(d);
} catch (IOException e) {
Log.e("DEBUGTAG", "Remote Image Exception", e);
}
imageView.setScaleType(ImageView.ScaleType.FIT_CENTER);
imageView.setLayoutParams(new GridView.LayoutParams(150, 150));
return imageView;
}
The progress Dialog doesnt work properly. It shows and suddenly gone before the images loaded in gridview. Please help me asap.
Use AsyncTask:
calling:
dialog=ProgressDialog.show(wall.this,"Loading", "Please Wait...",true);
doback dob=new doback();
dob.execute();
Class
class doback extends AsyncTask<URL, Integer, Long>
{
#Override
protected Long doInBackground(URL... arg0)
{
try
{
//getImagepaths from Server
}
catch(Exception e)
{
}
return null;
}
protected void onProgressUpdate(Integer... progress)
{
}
protected void onPostExecute(Long result)
{
try
{
webgridview.setAdapter(new WebImageAdapter(wall.this));
dialog.dismiss();
}
catch(Exception e)
{
e.printStackTrace();
dialog.dismiss();
}
}
}
Adapter Code is some like this:
class WebImageAdapter extends BaseAdapter{
// #Override
public int getCount() {
return names.length;
}
// #Override
public Object getItem(int position) {
return null;
}
// #Override
public long getItemId(int position) {
return 0;
}
// #Override
public View getView(int pos, View convertView, ViewGroup parent) {
View row=getLayoutInflater().inflate(R.layout.nameitem,null);
ImageView image=(ImageView)row.findViewById(R.id.image);
image.setImageBitmap(convertImage(myRemoteImages[position]))// convertImage is to convert url to bitmap
return row;
}
}
Edit - From the Android Developer Documentation:ProgressDialog
This class was deprecated in API level 26.
ProgressDialog is a modal
dialog, which prevents the user from interacting with the app. Instead
of using this class, you should use a progress indicator like
ProgressBar, which can be embedded in your app's UI. Alternatively,
you can use a notification to inform the user of the task's progress.
setAdapter(), do not take more time, its getView() of Adapter class on each time hit web and taking time. So using of progressDialog on setAdapter is not appropriate. On scroll of your grids it took lot of time by using your code, as getView() call automatically on scrolling view.
you should have a reference from LazyList for loading image from web and placing them in ImageView.

android issue with populating the list item in a ListView

In my application, to populating a ListView i am using custom adapter, because one listitem consists of 3 TextViews and 1 ImageView.
Everytime images are fetched from url.
So when i am launching this activity its taking much time,because its downloading all images then populating the lists.
So i want without images list should populate first having only Textviews and after that only images should come.
How can i do that?
By loading your images with an AsyncTask
example directly from documentation:
public void onClick(View v) {
new DownloadImageTask().execute("http://example.com/image.png");
}
private class DownloadImageTask extends AsyncTask<String, Void, Bitmap> {
/** The system calls this to perform work in a worker thread and
* delivers it the parameters given to AsyncTask.execute() */
protected Bitmap doInBackground(String... urls) {
return loadImageFromNetwork(urls[0]);
}
/** The system calls this to perform work in the UI thread and delivers
* the result from doInBackground() */
protected void onPostExecute(Bitmap result) {
mImageView.setImageBitmap(result);
}
}
you have to create a lazy image loader using async task.
by doing that, all your list view will be populated. and when the images are fetched, they are updated into the list views asynchronously.
Here is a link - http://iamvijayakumar.blogspot.com/2011/06/android-lazy-image-loader-example.html
You can use lazy load images like this:
https://github.com/thest1/LazyList
Lazy load of images in ListView
The basic Idea is to have a loading image already within your app.
Then use an asyncTask or a thread to load image.
Some code to start with :
Adapter
public class ImageAdapter extends BaseAdapter {
private static final String TAG = "Image Adapter";
int mGalleryItemBackground;
private Context mContext;
private GridView mView;
/** URL-Strings to some remote images. */
private String[] mRemoteImagesURL ;
private Bitmap[] loadedImages;
public ImageAdapter(Context c,String[] remoteImagesURL,GridView v) {
mContext = c;
TypedArray attr = mContext.obtainStyledAttributes(R.styleable.HelloGallery);
mGalleryItemBackground = attr.getResourceId(R.styleable.HelloGallery_android_galleryItemBackground, 0);
attr.recycle();
mView = v;
mRemoteImagesURL=remoteImagesURL;
loadedImages = new Bitmap[mRemoteImagesURL.length];
}
public int getCount() {
return mRemoteImagesURL.length;
}
public Object getItem(int position) {
return position;
}
public long getItemId(int position) {
return position;
}
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
LayoutInflater infalInflater = (LayoutInflater) mContext
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = infalInflater.inflate(R.layout.gallery_item, null);
}
ImageView imageView = (ImageView) convertView.findViewById(R.id.FrontImageView);
/* when image is already down-loaded then load that image */
if(loadedImages[position]!=null)
imageView.setImageBitmap(loadedImages[position]);
else
imageView.setImageResource(R.drawable.loading);
imageView.setBackgroundResource(mGalleryItemBackground);
return convertView;
}
public void loadImage(int position){
Bitmap bm;
try {
/* Open a new URL and get the InputStream to load data from it. */
URL aURL = new URL(mRemoteImagesURL[position]);
URLConnection conn = aURL.openConnection();
conn.connect();
InputStream is = conn.getInputStream();
/* Buffered is always good for a performance plus. */
BufferedInputStream bis = new BufferedInputStream(is);
/* Decode url-data to a bitmap. */
bm = BitmapFactory.decodeStream(bis);
bis.close();
is.close();
loadedImages[position] =bm;
} catch (Exception e) {
Log.e(TAG, "Remote Image Load Exception"+e);
}
}
public void setLoadedImage(int position)
{
Log.d(TAG, "Position "+position);
View childView= mView.getChildAt(position);
if(loadedImages[position]!=null && childView != null)
{
ImageView imageView= (ImageView) childView.findViewById(R.id.FrontImageView);
imageView.setImageBitmap(loadedImages[position]);
}
}
}
private void updateImagesAsThread() {
Thread t = new Thread()
{
public void run()
{
try {
for(int i=0;i<imageAdapter.getCount();i++)
{
imageAdapter.loadImage(i);
listAdapterHandler.sendEmptyMessage(i);
}
}
catch (Exception e) {
// TODO: handle exception
Log.e(TAG,"UpdateImageAsThread "+e);
}
}
};
t.start();
}
private Handler listAdapterHandler = new Handler()
{
#Override
public void handleMessage(Message msg)
{
switch (msg.what)
{
case -1:
Log.d(TAG, "here in the handle...");
break;
default:
Log.d(TAG, "here in the handle default...");
imageAdapter.setLoadedImage(msg.what);
//imageAdapter.notifyDataSetChanged();
break;
}
}
};

Categories

Resources