I use a customize listview control to display image and other informations. The listview control is little slow when I scroll it to display more content.
After I test the control, I find the function SetControlsValue to do many works. I must to do some work to improve it.
The Method 1 is my way, is it correct? is there other the better way?
Method 1
private void SetControlsValue(ViewHolder holder,int position){
holder.mCheckBox.setChecked(mListCheckedStatus.get(position));
new BMPOperation().execute(position,holder);
new LongOperation().execute(position,holder);
}
private class BMPOperation extends AsyncTask<Object, Void, Bitmap> {
private ViewHolder myHolder;
#Override
protected Bitmap doInBackground(Object... params) {
int position=(Integer)params[0];
myHolder=(ViewHolder)params[1];
Bitmap mBitmap=mListVideo.get(position).GetBitmapOfVideo();
return mBitmap;
}
#Override
protected void onPostExecute(Bitmap mBitmap) {
try {
if (mBitmap != null) {
myHolder.imageViewthumb.setImageBitmap(mBitmap);
}
}catch (Exception e){
Utility.LogError(e.getMessage());
}
}
#Override
protected void onPreExecute() {}
#Override
protected void onProgressUpdate(Void... values) {}
}
private class LongOperation extends AsyncTask<Object, Void, String> {
private ViewHolder myHolder;
#Override
protected String doInBackground(Object... params) {
int position=(Integer)params[0];
myHolder=(ViewHolder)params[1];
String s=mListVideo.get(position).fileName
+"\n"+mContext.getResources().getString(R.string.TitleResolution)+ mListVideo.get(position).GetResolution()
+"\n"+mContext.getResources().getString(R.string.TitleSize)+mListVideo.get(position).GetSize()
+"\n"+mContext.getResources().getString(R.string.TitleDuration)+mListVideo.get(position).GetDuration();
return s;
}
#Override
protected void onPostExecute(String result) {
myHolder.tvInfo.setText(result);
}
#Override
protected void onPreExecute() {}
#Override
protected void onProgressUpdate(Void... values) {}
}
The Function SetControlsValue
private void SetControlsValue(ViewHolder holder,int position){
holder.mCheckBox.setChecked(mListCheckedStatus.get(position));
Bitmap mBitmap=mListVideo.get(position).GetBitmapOfVideo();
try {
if (mBitmap != null) {
holder.imageViewthumb.setImageBitmap(mBitmap);
}
}catch (Exception e){
Utility.LogError(e.getMessage());
}
String s=mListVideo.get(position).fileName
+"\n"+mContext.getResources().getString(R.string.TitleResolution)+ mListVideo.get(position).GetResolution()
+"\n"+mContext.getResources().getString(R.string.TitleSize)+mListVideo.get(position).GetSize()
+"\n"+mContext.getResources().getString(R.string.TitleDuration)+mListVideo.get(position).GetDuration();
holder.tvInfo.setText(s);
}
ListVideoAdapter.java
public class ListVideoAdapter extends BaseAdapter {
private Context mContext;
private LayoutInflater mInflater;
private List<Video> mListVideo;
private List<Boolean> mListCheckedStatus;
public ListVideoAdapter (Context context){
mContext=context;
mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
mListVideo= VideoHelper.ListVideo(mContext);
}
#Override
public int getCount() {
// TODO Auto-generated method stub
return mListVideo.size();
}
#Override
public Object getItem(int arg0) {
// TODO Auto-generated method stub
return arg0;
}
#Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null) {
holder = new ViewHolder();
convertView = mInflater.inflate(R.layout.layout_adapter_video, null);
IniControls(holder,convertView);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
SetControlsPosition(holder,position);
SetControlsValue(holder,position);
SetControlsEvent(holder);
return convertView;
}
private void IniControls(ViewHolder holder,View convertView){
holder.mCheckBox=(CheckBox) convertView.findViewById(R.id.chSelect);
holder.imageViewthumb=(ImageView)convertView.findViewById(R.id.imageViewVideo);
holder.tvInfo = (TextView) convertView.findViewById(R.id.tvInfo);
holder.imageViewTrim=(ImageView)convertView.findViewById(R.id.imageViewTrim);
holder.imageViewShare=(ImageView)convertView.findViewById(R.id.imageViewShare);
holder.imageViewInfo=(ImageView)convertView.findViewById(R.id.imageViewInfo);
holder.imageViewDelete=(ImageView)convertView.findViewById(R.id.imageViewDelete);
}
private void SetControlsPosition(ViewHolder holder,int position){
holder.id=position;
holder.mCheckBox.setId(position);
holder.imageViewthumb.setId(position);
holder.tvInfo.setId(position);
holder.imageViewTrim.setId(position);
holder.imageViewShare.setId(position);
holder.imageViewInfo.setId(position);
holder.imageViewDelete.setId(position);
}
private void SetControlsValue(ViewHolder holder,int position){
holder.mCheckBox.setChecked(mListCheckedStatus.get(position));
Bitmap mBitmap=mListVideo.get(position).GetBitmapOfVideo();
try {
if (mBitmap != null) {
holder.imageViewthumb.setImageBitmap(mBitmap);
}
}catch (Exception e){
Utility.LogError(e.getMessage());
}
String s=mListVideo.get(position).fileName
+"\n"+mContext.getResources().getString(R.string.TitleResolution)+ mListVideo.get(position).GetResolution()
+"\n"+mContext.getResources().getString(R.string.TitleSize)+mListVideo.get(position).GetSize()
+"\n"+mContext.getResources().getString(R.string.TitleDuration)+mListVideo.get(position).GetDuration();
holder.tvInfo.setText(s);
}
private void SetControlsEvent(final ViewHolder holder) {
}
}
class ViewHolder {
int id;
CheckBox mCheckBox;
ImageView imageViewthumb;
TextView tvInfo;
ImageView imageViewTrim;
ImageView imageViewShare;
ImageView imageViewInfo;
ImageView imageViewDelete;
}
Added
I have read the sample code of UniversalImageLoader.
I don't think UniversalImageLoader control fit my requirement.
ImageLoader need to pass URL par
ImageLoader.getInstance().displayImage(IMAGE_URLS[position], imageView, options);
but in my app, there are other two codes which spend much time.
Bitmap mBitmap=mListVideo.get(position).GetBitmapOfVideo();
String s=mListVideo.get(position).fileName +"\n"+mContext.getResources().getString(R.string.TitleResolution)+ mListVideo.get(position).GetResolution() +"\n"+mContext.getResources().getString(R.string.TitleSize)+mListVideo.get(position).GetSize() +"\n"+mContext.getResources().getString(R.string.TitleDuration)+mListVideo.get(position).GetDuration();
so I think I need the other better way to improve code.
BTW, in my function Bitmap mBitmap=mListVideo.get(position).GetBitmapOfVideo() not only get the thumbnail of a video, but also I need merger a Play icon to the thumbnail, so I don't think I can use ImageLoader.getInstance().displayImage("file:///mnt/sdcard/myvideo.mp4", imageView).
Here are suggestion to improve the performance:
Use recyclerview instead of Listview - Recycler view recycles the child items which is out of the screen and thus freeing up the memory
Use picasso image loader - It loads images on other thread and thus doesn't block your UI thread. Also it caches the image in file/memory (you can configure it) so when user tries to play with scroll your UI doesn't get stuck. This means images which has been already downloaded from network will be reloaded from cache automatically. ( http://square.github.io/picasso/)
Showing Bitmaps on UiThread is a lazy operation. So you should you UniversalImageLoader to display your bitmaps/thumbnails of videos in SetControlsValue function.
Hope this helps.
Related
I have a ListView of elements composed with ImageView. I get a new image using an AsyncTask and in the onPostExecute(Object result) method I set the image using setImageUri(Uri uri) but it doesn't gets updated.
If I change of activity or between apps, image is shown perfectly, but I want to show the image immediately.
I tried calling invalidate() with all the combinations of the ImageView, the extended BaseAdapter, the parent ListView, but nothing worked. I tried many other techniques like calling setImageResource(0), setImageUri(null), but no results...
EDITED:
Here, part of the code:
public class ThingItemAdapter extends BaseAdapter {
protected List<Thing> things;
LayoutInflater inflater;
public ThingItemAdapter(Context context, List<Thing> things) {
this.things = things;
this.inflater = LayoutInflater.from(context);
}
#Override
public int getCount() {
return things.size();
}
#Override
public Thing getItem(int position) {
return things.get(position);
}
#Override
public long getItemId(int position) {
return things.get(position).getId();
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
final int pos = position;
final ViewHolder holder;
if (convertView == null) {
holder = new ViewHolder();
convertView = this.inflater.inflate(R.layout.thing_list_item, parent, false);
holder.thingImageView = (ImageView) convertView.findViewById(R.id.thing_preview);
holder.button = (ImageButton) convertView.findViewById(R.id.apply_button);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
final Thing thing = things.get(position);
final long thingId = thing.getId();
final Uri thingUri = thing.getPicture();
holder.thingImageView.setImageURI(thingUri);
holder.button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// generate new file
final TypedFile typedFile = new TypedFile("multipart/form-data", new File(thingUri.getPath()));
new ReadAndStorePictureTask()
.execute(new Object[] { typedFile, holder.thingImageView, thing });
}
});
// item detailed view listener
holder.thingImageView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent = new Intent((ThingApplication) ThingApplication.getContext(), ThingActivity.class);
intent.putExtra(ThingActivity.EXTRA_THING_ID, thingId);
context.startActivity(intent);
}
});
return convertView;
}
private class ViewHolder {
ImageView thingImageView;
ImageButton button;
}
private class ReadAndStorePictureTask extends AsyncTask<Object, Void, Void> {
ImageView imageView;
Thing thing;
ViewGroup parent;
protected Void doInBackground(Object... params) {
final TypedFile typedFile = (TypedFile) params[0];
imageView = (ImageView) params[1];
thing = (Thing) params[2];
((ThingApplication) ThingApplication.getContext()).getClient().apply(typedFile,
new Callback<Response>() {
#Override
public void failure(RetrofitError error) {
...
}
#Override
public void success(Response nothing, Response response) {
try {
byte[] bytes = ThingApplication.getBytesFromStream(response.getBody().in());
Uri newImageURI = Uri.parse("uri://valid_uri"); // whatever, it exists in real code
thing.setPicture(newImageURI);
File file = ((ThingApplication) ThingApplication.getContext())
.getFileFromURI(newImageURI); // this method works
ThingApplication.saveBytesToFile(bytes, file.getAbsolutePath());
thingService.storeThing(thing);
} catch (Exception e) {
...
}
}
});
return null;
}
#Override
protected void onPostExecute(Void result) {
imageView.setImageURI(thing.getPicture());
// force redraw. FIXME not working
/*
* ANSWER HERE, PLEASE
*/
}
}
}
How can I show the updated URI immediately inside onPostExecute(Object result) method?
onPostExecute you update the list of images that it's linked to the ListView adapter and after that you notify the adapter that you changed the items in the list by calling:
adapter.notifyDataSetChanged();
You can do something like this:
-Change third parameter in asynctask call.
new ReadAndStorePictureTask().execute(
new Object[] { typedFile, holder.thingImageView, pos });
-Then, modify the list items inside asynctask and refresh.
private class ReadAndStorePictureTask extends AsyncTask<Object, Void, Void> {
ImageView imageView;
int position;
ViewGroup parent;
protected Void doInBackground(Object... params) {
final TypedFile typedFile = (TypedFile) params[0];
imageView = (ImageView) params[1];
position = (Integer) params[2];
((ThingApplication) ThingApplication.getContext()).getClient().apply(typedFile,
new Callback<Response>() {
#Override
public void failure(RetrofitError error) {
...
}
#Override
public void success(Response nothing, Response response) {
try {
byte[] bytes = ThingApplication.getBytesFromStream(response.getBody().in());
Uri newImageURI = Uri.parse("uri://valid_uri"); // whatever, it exists in real code
things.get(position).setPicture(newImageURI);
File file = ((ThingApplication) ThingApplication.getContext())
.getFileFromURI(newImageURI); // this method works
ThingApplication.saveBytesToFile(bytes, file.getAbsolutePath());
thingService.storeThing(things.get(position));
} catch (Exception e) {
...
}
}
});
return null;
}
#Override
protected void onPostExecute(Void result) {
notifyDataSetChanged();
}
}
Good luck!
Hi please forgive me if I am mistaking when explaining the problem . I have a Custom Base adapter in which there is two imageView and two TextView and I am usning an Async task to set the image from the URL. it sets the image but changes the image again automatically.
below is the code for the adapter .
public class SharedPhotosAdapter extends BaseAdapter{
Context context;
LayoutInflater inflater;
public static ArrayList<HashMap<String, String>> data;
ImageLoader imageLoader;
private static final String BRANCH="Branch";
private static final String DATE="DateTime";
private static final String STARS="Stars";
private static final String IMAGE_URL="URL";
private static final String USER_NAME="UserName";
TextView name,date,comment;
ImageView pro_image,shared_image;
public SharedPhotosAdapter(Context con,ArrayList<HashMap<String, String>> result) {
// TODO Auto-generated constructor stub
context=con;
data=result;
inflater = (LayoutInflater)context.getApplicationContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
imageLoader=new ImageLoader(context);
}
#Override
public int getCount() {
// TODO Auto-generated method stub
return data.size();
}
#Override
public Object getItem(int arg0) {
// TODO Auto-generated method stub
return null;
}
#Override
public long getItemId(int arg0) {
// TODO Auto-generated method stub
return 0;
}
#Override
public View getView(int position, View rowView, ViewGroup parent) {
// TODO Auto-generated method stub
ViewHolder holder;
Bitmap bitmap=null;
ImageView image = null;
HashMap<String, String> result=data.get(position);
if(rowView==null)
{
rowView=inflater.inflate(R.layout.shared_photos_item, null);
holder=new ViewHolder();
holder.name=(TextView)rowView.findViewById(R.id.textView1);
holder.date=(TextView)rowView.findViewById(R.id.textView4);
holder.comment=(TextView)rowView.findViewById(R.id.textView3);
holder.pro_image=(ImageView)rowView.findViewById(R.id.imageView1);
holder.shared_image=(ImageView)rowView.findViewById(R.id.imageView2);
rowView.setTag(holder);
}
else
{
holder = (ViewHolder)rowView.getTag();
}
new DownloadImageTask(holder.shared_image).execute(result.get(IMAGE_URL));
holder.name.setText(result.get(USER_NAME));
holder.date.setText(result.get(DATE));
holder.comment.setText(result.get(BRANCH));
return rowView;
}
public class ViewHolder
{
TextView name,date,comment;
ImageView pro_image,shared_image;
}
}
Here is the Async task that i am using for setting the image from the url
public class DownloadImageTask extends AsyncTask<String, Void, Bitmap> {
ImageView bmImage;
public DownloadImageTask(ImageView bmImage) {
this.bmImage = bmImage;
}
#Override
protected void onPreExecute() {
// TODO Auto-generated method stub
super.onPreExecute();
}
protected Bitmap doInBackground(String... urls) {
String urldisplay = urls[0];
Bitmap mIcon11 = null;
try {
InputStream in = new java.net.URL(urldisplay).openStream();
mIcon11 = BitmapFactory.decodeStream(in);
} catch (Exception e) {
}
return mIcon11;
}
#Override
protected void onPostExecute(Bitmap result) {
super.onPostExecute(result);
bmImage.setImageBitmap(result);
}
}
it setting randomly any image to the image view just cant figure out where i am going wrong.
A little help will be appreciable.
thanks
I would suggest you to try Picasso to remove the hassle of downloading images/caching etc.
Once you have the jar in your workspace, all you need to do in the getView() method of the adapter class is this.
Picasso.with(context).load(result.get(IMAGE_URL)).into(holder.shared_image);
No need of the DownloadAsyncTask.
As #zapl also suggested in the comment, there are other libraries like Volley and UniversalImageLoader, but I liked Picasso. You can also easily apply transformations like rounded-image using the Transformation interface provided by Picasso.
I implemented my ListView using custom adapter extended from ArrayAdapter.
My problem is sometimes ListView is loaded slowly. That means a blank activity is loaded first without the ListView, then the ListView comes out. At worst case, I am prompted to "force closed or wait". I like to improve that slow loading as it is annoying to the user.
But sometimes, loading is fast and almost immediate.
But I like to make sure my ListView design is correct and the design does not have any problem with that slow loading. So that this discussion will be useful for other people who are facing the same problem as mine.
My ListView is designed as follow.
Each ListItem has three components, thumbnail image, ID text, and arrow image as shown in the figure attached .
In loading process of the ListView, (1)All ID text are retrieved from the database and populated into a ListArray List<String> listIDs
public class MyListFragment extends ListFragment implements OnItemClickListener {
dbHelper = new TrackerDBAdapter(getActivity());
dbHelpLatLong = new LatLogDBAdapter(getActivity());
dbHelpNotification = new NotificationDatabaseAdapter(getActivity());
dbHelper.open();
Cursor cursor = dbHelper.fetchAllTrackerInTheList();
listIDs = new ArrayList<String>();
activationStatus = new ArrayList<String>();
thisListFragmentContext = getActivity();
for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) {
listIDs.add(cursor.getString(1));
}
dbHelper.close();
(2)Then my custom list adapter is called.
adapter = new customList_Adaptor(thisListFragmentContext,
R.layout.list_row, listIDs, this);
}
That is the loading process inside my `ListFragment`.
(3) The following class is my custom ArrayAdapter and I implemented to load thumbnail ImageView using AsyncTask. My query are
(i)I still have retrieving ID text from database, and loading arrow image. Should I put those processes into AsyncTask as well?
(ii)If I need it, should I implement another AsyncTask or use the same AsyncTask used for thumbnail image loading?
(iii)Among these, which aspect of the program design I still can improve that is suspicious to my slow loading?
public class customList_Adaptor extends ArrayAdapter<String>{
protected static final int CAMERA_REQUEST = 0;
private TrackerDBAdapter dbHelper;
private Context context;
private List<String> listIDs = new ArrayList<String>();
private List<String> activationState = new ArrayList<String>();
public MyListFragment mMyListFragment;
public customList_Adaptor(Context context, int textViewResourceId,
List<String> objects, List<String> activationStatus, MyListFragment mMyListFragment) {
super(context, textViewResourceId, objects);
this.setContext(context);
this.listIDs = objects;
this.activationState = activationStatus;
this.mMyListFragment= mMyListFragment;
dbHelper = new TrackerDBAdapter(context);
}
#Override
public int getCount() {
// TODO Auto-generated method stub
if(listIDs != null)
return listIDs.size();
else
return 0;
}
#Override
public String getItem(int arg0) {
// TODO Auto-generated method stub
if(listIDs != null)
return listIDs.get(arg0);
else
return null;
}
#Override
public long getItemId(int arg0) {
// TODO Auto-generated method stub
return arg0;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View vi=convertView;
ViewHolder viewHolder=new ViewHolder();
LayoutInflater inflater = (LayoutInflater) this.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
if(vi==null){
vi = inflater.inflate(R.layout.list_row, parent, false);
viewHolder.id=(TextView)vi.findViewById(R.id.title);
viewHolder.thumbnailImage=(ImageView)vi.findViewById(R.id.list_image);
viewHolder.activationStatus = (TextView)vi.findViewById(R.id.activated);
//lazy load image
BitmapWorkerTask task = new BitmapWorkerTask(viewHolder.thumbnailImage);
task.execute(position);
viewHolder.arrow=(ImageView)vi.findViewById(R.id.list_arrow);
vi.setTag(viewHolder);
}
else
viewHolder=(ViewHolder) vi.getTag();
viewHolder.thumbnailImage.setOnClickListener(new onMyClick(position));
// Setting all values in listview
viewHolder.id.setText(listIDs.get(position));
if(activationState.get(position).equals("Not activated yet")){
viewHolder.activationStatus.setText(activationState.get(position));
viewHolder.activationStatus.setTextColor(android.graphics.Color.GRAY);
}
else if(activationState.get(position).equals("Activated"))
viewHolder.activationStatus.setText("");
return vi;
}
public class onMyClick implements OnClickListener {
private final int pos;
public onMyClick(int pos) {
this.pos = pos;
}
#Override
public void onClick(View v) {
MyListFragment.clickedimageView = (ImageView) v.findViewById(R.id.list_image);
mMyListFragment.imagepos(pos);
}
}
public Context getContext() {
return context;
}
public void setContext(Context context) {
this.context = context;
}
//Lazy image update
class BitmapWorkerTask extends AsyncTask<Integer, Void, Bitmap> {
private final WeakReference<ImageView> imageViewReference;
private int data = 0;
public BitmapWorkerTask(ImageView imageView) {
// Use a WeakReference to ensure the ImageView can be garbage collected
imageViewReference = new WeakReference<ImageView>(imageView);
}
// Decode image in background.
#Override
protected Bitmap doInBackground(Integer... params) {
setData(params[0]);
Bitmap bitmap = null;
dbHelper.open();
Cursor mCursor = dbHelper.getImagebyIDnumber(getData());
byte[] img_bytes = mCursor.getBlob(13);
bitmap = BitmapFactory.decodeByteArray(img_bytes, 0, img_bytes.length);
dbHelper.close();
return bitmap;
}
// Once complete, see if ImageView is still around and set bitmap.
#Override
protected void onPostExecute(Bitmap bitmap) {
if (imageViewReference != null && bitmap != null) {
final ImageView imageView = imageViewReference.get();
if (imageView != null) {
imageView.setImageBitmap(bitmap);
}
}
}
public int getData() {
return data;
}
public void setData(int data) {
this.data = data;
}
}
}
public class ViewHolder {
TextView id;
TextView activationStatus;
ImageView thumbnailImage;
ImageView arrow;
}
I did a few things to make it faster in loading the app.
I am not sure which one is the solution.
(1) I load all data from sql database including text and thumbnail images using AsyncTask.
(2) I change thumbnail image format from png to jpg.
(3) Then I clear the cache manually.
The app looks like faster in loading, but sometimes it is still slow. Most of the times, it is faster than before.
I am still making improvement to my app.
Thanks
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.
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.