I have this image adapter, that is supposed to handle updating a grid of images. The problem is that I have a BackgroundImageTask running that fetches the bitmap from a URL. The getView method returns the imageView before the Background Task can finish updating it. How Can I force the Background Task to finish before it returns the imageview?
public class ImageAdapter extends BaseAdapter {
private Context mContext;
Bitmap bitmap;
List<Post> postList;
ImageView imageView;
int pos;
public ImageAdapter(Context c, List<Post> p) {
mContext = c;
postList = p;
}
public int getCount() {
return postList.size();
}
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) {
pos=position;
View convert = convertView;
if (convert == null) {
// if it's not recycled, initialize some attributes
imageView = new ImageView(mContext);
imageView.setLayoutParams(new GridView.LayoutParams(GridView.AUTO_FIT, 320));
imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
imageView.setPadding(0, 0, 0, 0);
} else {
imageView = (ImageView) convert;
}
new BackgroundImageTask().execute();
return imageView;
}
public View SetBit(Bitmap b){
imageView.setImageBitmap(b);
return imageView;
}
class BackgroundImageTask extends AsyncTask<Void, Void, Bitmap> {
#Override
protected Bitmap doInBackground(Void... params) {
Bitmap bit1=bitmap;
try {
bit1 = BitmapFactory.decodeStream((InputStream)new URL(postList.get(pos).thumbnail).getContent());
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return bit1;
}
#Override
protected void onPostExecute(Bitmap bit) {
SetBit(bit);
}
}
}
Instead You can pass the ImageView Object to the background Task like
new BackgroundImageTask(imageView).execute();
and
class BackgroundImageTask extends AsyncTask<Void, Void, Bitmap> {
ImageView iv;
BackgroundImageTask(ImageView imageView){
iv = imageView;
}
#Override
protected Bitmap doInBackground(Void... params) {
Bitmap bit1=bitmap;
try {
bit1 = BitmapFactory.decodeStream((InputStream)new URL(postList.get(pos).thumbnail).getContent());
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return bit1;
}
#Override
protected void onPostExecute(Bitmap bit) {
iv.setImageBitmap(bit);
}
}
Related
Iv tried some on the solutions in stack overflow, but was not able to work it out for my case.
I want to get the Bitmap data from onPostExecute or bmp from doInBackground and set it to ImageView imageurl using imageurl.setImageBitmap() in the getView() method
public class BooksAdapter extends ArrayAdapter<Books> {
public BooksAdapter(Activity context, ArrayList<Books> word) {
super(context, 0, word);
}
#NonNull
#Override
public View getView(int position, #Nullable View convertView, #NonNull ViewGroup parent) {
// Check if the existing view is being reused, otherwise inflate the view
View listItemView = convertView;
if (listItemView == null) {
listItemView = LayoutInflater.from(getContext()).inflate(
R.layout.list_item, parent, false);
}
// Get the {#link AndroidFlavor} object located at this position in the list
Books currentbook = getItem(position);
TextView bookView = (TextView) listItemView.findViewById(R.id.bookTittle);
String booktitle = currentbook.getBookName();
bookView.setText(booktitle);
TextView authorView = (TextView) listItemView.findViewById(R.id.authorname);
String authorname = currentbook.getAuthorName();
authorView.setText(authorname);
ImageView imageurl = (ImageView) listItemView.findViewById(R.id.imageView);
String imagelink = currentbook.getImageLink();
ImageAsyncTask task = new ImageAsyncTask();
task.execute(imagelink);
// imageurl.setImageBitmap();
return listItemView;
}
private class ImageAsyncTask extends AsyncTask<String, Void, Bitmap> {
#Override
protected Bitmap doInBackground(String... urls) {
URL url = null;
Bitmap bmp = null;
try {
url = new URL(urls[0]);
} catch (MalformedURLException e) {
Log.e(LOG_TAG, "Error with creating URL ", e);
}
try {
bmp = BitmapFactory.decodeStream(url.openConnection().getInputStream());
} catch (IOException e) {
Log.e(LOG_TAG, "Problem retrieving the earthquake JSON results.", e);
}
return bmp;
}
#Override
protected void onPostExecute(Bitmap data) {
}
}
}
Just pass your ImageView to AsyncTask via constructor and then set image in onPostExecute like this:
ImageAsyncTask task = new ImageAsyncTask(myImageView);
private class ImageAsyncTask extends AsyncTask<String, Void, Bitmap> {
private ImageView img;
ImageAsyncTask(Imageview img){
this.img = img;
}
...
protected void onPostExecute(Bitmap data) {
this.img.setImageBitmap(data);
}
The adapter provides data for a listview. But when you scroll up and down, it shows old images and takes a couple of seconds to finish loading the images. This is true when you open the view for the first time.
public class BooksAdapter extends ArrayAdapter<Books> {
public BooksAdapter(Activity context, ArrayList<Books> word) {
super(context, 0, word);
}
#NonNull
#Override
public View getView(int position, #Nullable View convertView, #NonNull ViewGroup parent) {
// Check if the existing view is being reused, otherwise inflate the view
View listItemView = convertView;
if (listItemView == null) {
listItemView = LayoutInflater.from(getContext()).inflate(
R.layout.list_item, parent, false);
}
// Get the {#link AndroidFlavor} object located at this position in the list
Books currentbook = getItem(position);
TextView bookView = (TextView) listItemView.findViewById(R.id.bookTittle);
String booktitle = currentbook.getBookName();
bookView.setText(booktitle);
TextView authorView = (TextView) listItemView.findViewById(R.id.authorname);
String authorname = currentbook.getAuthorName();
authorView.setText(authorname);
ImageView imageurl = (ImageView) listItemView.findViewById(R.id.imageView);
String imagelink = currentbook.getImageLink();
ImageAsyncTask task = new ImageAsyncTask(imageurl);
task.execute(imagelink);
return listItemView;
}
private class ImageAsyncTask extends AsyncTask<String, Void, Bitmap> {
private ImageView img;
ImageAsyncTask(ImageView img) {
this.img = img;
}
#Override
protected Bitmap doInBackground(String... urls) {
URL url = null;
Bitmap bmp = null;
try {
url = new URL(urls[0]);
} catch (MalformedURLException e) {
Log.e(LOG_TAG, "Error with creating URL ", e);
}
try {
bmp = BitmapFactory.decodeStream(url.openConnection().getInputStream());
} catch (IOException e) {
Log.e(LOG_TAG, "Problem retrieving the earthquake JSON results.", e);
}
return bmp;
}
#Override
protected void onPostExecute(Bitmap data) {
this.img.setImageBitmap(data);
}
#Override
protected void onProgressUpdate(Void... values) {
}
}
}
I will recomend to use Glide for this task and dont invent bicycle. You can just call GlideApp.with(this).load("http://url.com").into(imageView); and Glide will do all work for you.
Glide with default image if actual image not loaded from the server.
Place this in app.gradle
compile 'com.github.bumptech.glide:glide:3.7.0'
Use it like,
Glide.with(this)
.load("your_image_url")
.listener(new RequestListener<String, GlideDrawable>() {
#Override
public boolean onException(Exception e, String model, Target<GlideDrawable> target, boolean isFirstResource) {
e.printStackTrace();
return false;
}
#Override
public boolean onResourceReady(GlideDrawable resource, String model, Target<GlideDrawable> target, boolean isFromMemoryCache, boolean isFirstResource) {
Log.d("d", "onResourceReady");
return false;
}
})
.error("your_default_image")// placed in drawable
.into("your_target_view");
Hope this helps.
User Picasso best way to display image even you can set default image when image is loading see below example..
Picasso.with(context).load(imageUrl).placeholder(R.drawable.default_image).into(imageView);
compile 'com.squareup.picasso:picasso:2.4.0' just add into build.gradle
Here i have two url but when i run this app this images are been loaded to second page means first image will load in second page after few second the second image also adds to same loaction by overlapping. i need to add this to second and third pages these url
viewPager = (ViewPager) findViewById(R.id.splash);
ImageAdapter adapter = new ImageAdapter(this);
viewPager.setAdapter(adapter);
public class ImageAdapter extends PagerAdapter {
Context context;
private int[] GalImages = new int[] {
R.drawable.slider,
R.drawable.slider,
R.drawable.slider,
};
ImageAdapter(Context context){
this.context=context;
}
#Override
public int getCount() {
return GalImages.length;
// return 10;
}
#Override
public boolean isViewFromObject(View view, Object object) {
return view == ((ImageView) object);
}
#Override
public Object instantiateItem(ViewGroup container, int position) {
ImageView imageView = new ImageView(context);
imageView.setScaleType(ImageView.ScaleType.FIT_XY);
imageView.setImageResource(GalImages[position]);
new LoadImage(imageView).execute("http://www.gadgetbaazar.com/wp-content/uploads/2016/12/Top-Mobile-Phones.jpg");
new LoadImage(imageView).execute("https://pisces.bbystatic.com/BestBuy_US/store/ee/2015/com/pm/nav_desktops_1115.jpg");
container.addView(imageView, 0);
return imageView;
}
#Override
public void destroyItem(ViewGroup container, int position, Object object) {
((ViewPager) container).removeView((ImageView) object);
}
private class LoadImage extends AsyncTask<String, String, Bitmap> {
ImageView img=null;
public LoadImage(ImageView img){
this.img=img;
}
#Override
protected void onPreExecute() {
super.onPreExecute();
}
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;
}
protected void onPostExecute(Bitmap image) {
if(image != null){
img.setImageBitmap(image);
}
}
}
}
Try this
#Override
public Object instantiateItem(ViewGroup container, int position) {
ImageView imageView = new ImageView(context);
imageView.setScaleType(ImageView.ScaleType.FIT_XY);
if(position == 0){
imageView.setImageResource(GalImages[position]);
}else if(position == 1){
new LoadImage(imageView).execute("http://www.gadgetbaazar.com/wp-content/uploads/2016/12/Top-Mobile-Phones.jpg");
}else if(position ==2){
new LoadImage(imageView).execute("https://pisces.bbystatic.com/BestBuy_US/store/ee/2015/com/pm/nav_desktops_1115.jpg");
}
container.addView(imageView, 0);
return imageView;
}
I use this code to download and set images from link to an image view
but when i scroll the list view and scroll back to top the images starts to download and clear the first downloaded picture.
I tried to download and save them into a array bitmap then show them but i cant update array bitmap like an array list and show it one by one in list view what can i do ?
class aa extends ArrayAdapter<String> {
public aa() {
super(MainActivity.this, R.layout.home_row, IDS);
}
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
LayoutInflater li = getLayoutInflater();
View row = li.inflate(R.layout.home_row, parent, false);
TextView name=(TextView)row.findViewById(R.id.home_row_name);
ImageView pic=(ImageView)row.findViewById(R.id.home_row_pic);
name.setText(arrayNAME.get(position).toString());
new Download_image(bitmap_PIC,position,pic).execute(PIC[position]);
return (row);
}
}
And here is the download method :
class Download_image extends AsyncTask<String, Void, Bitmap> {
Bitmap[] bitMap;
int position;
ImageView bmImage;
public Download_image(Bitmap[] bitMap,int position,ImageView bmImage) {
this.bitMap = bitMap;
this.position = position;
this.bmImage = bmImage;
}
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) {
Log.e("Error", e.getMessage());
e.printStackTrace();
}
return mIcon11;
}
protected void onPostExecute(Bitmap result) {
bitMap[position]=result;
bmImage.setImageBitmap(bitmap_PIC[position]);
}
}
I can't understand what is happening here. The ide throws this message onPostExecute(Bitmap)' in 'Anonymous class derived from android.os.AsyncTask' clashes with 'onPostExecute(Result)' in 'android.os.AsyncTask'; attempting to use incompatible return type:
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
final View[] v = {convertView};
final Bitmap[] mBitmap = new Bitmap[1];
final Object that = this.resources;
View view = new AsyncTask<Void, Void, Bitmap>() {
protected Bitmap doInBackground(Void... args) {
try {
mBitmap[0] = drawableFromUrl(activity.getString(R.string.test_url));
} catch (IOException e) {
e.printStackTrace();
}
return mBitmap[0];
}
#Override
protected View onPostExecute(Bitmap mBitmap) {
Drawable d = new BitmapDrawable((Resources) that, mBitmap);
final Feed item = feed_items.get(position);
if (v[0] == null) {
LayoutInflater vi =
(LayoutInflater) activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v[0] = vi.inflate(R.layout.grid_item, null);
}
if (item != null) {
v[0].findViewById(R.id.v1).setBackground(d);
v[0].findViewById(R.id.v2).setBackground(d);
}
return v[0];
}
}.execute((Void) null);
return view;
}
I assume you are using getView() in a custom adapater.
But you can't return from an onPostExecute(), so try to inflate the view right away.
Setup the AsyncTask to download the BPM and update the view, but return it normally from getView() even though the data isn't there yet. Once the Async completes it will be there.
public View getView(final int position, View convertView, ViewGroup parent) {
View v1 = convertView;
final Bitmap[] mBitmap = new Bitmap[1];
final Object that = this.resources;
final View v;
if (v1 == null) {
LayoutInflater vi =
(LayoutInflater) activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = vi.inflate(R.layout.grid_item, null);
}
else {
v = v1;
}
new AsyncTask<Void, Void, Bitmap>() {
protected Bitmap doInBackground(Void... args) {
try {
mBitmap[0] = drawableFromUrl(activity.getString(R.string.test_url));
} catch (IOException e) {
e.printStackTrace();
}
return mBitmap[0];
}
#Override
protected void onPostExecute(Bitmap mBitmap) {
Drawable d = new BitmapDrawable((Resources) that, mBitmap);
final Feed item = feed_items.get(position);
v.findViewById(R.id.v1).setBackground(d);
v.findViewById(R.id.v2).setBackground(d);
}
}.execute((Void) null);
return v;
}
The return type from onPostExecute should be void.
See: http://developer.android.com/reference/android/os/AsyncTask.html#onPostExecute%28Result%29