I'm trying to download an image and show it as an ImageView in my infoWindow , working with InfoWindowsAdapter , i put all the necessary code in the getInfoContents() method, but i can't get the image , in fact i can get it but still can't show it .
As i read in the documentation,i have to recall the treatment to set the downloaded image , i have to use showInfoWindow() method because it's the only way to do it . I tried to use it in getInfoContents() just before the return but , it blocks my app , need help !
This is my getInfoContents() :
public View getInfoContents(Marker marker) {
// set the view
View v = (View) getLayoutInflater().inflate(R.layout.info_window,null);
//assign values to the view field
ImageView imagePlace =(ImageView) v.findViewById(R.id.imageview1);
TextView tvLocality = (TextView) v.findViewById(R.id.tv_place);
//setting values with the parameter
Picasso.with(getApplicationContext()).load(url_image_place).into(imagePlace);
tvLocality.setText(marker.getTitle());
//marker.showInfoWindow();
return v;
}
This my downloadIcon() :
private Bitmap downloadIcon(String iconURL) {
Bitmap bmImg = null;
try {
URL url = new URL(iconURL);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setDoInput(true);
conn.connect();
InputStream is = conn.getInputStream();
bmImg = BitmapFactory.decodeStream(is);
} catch (IOException e) {
e.printStackTrace();
bmImg = null;
}
return bmImg;
}
EDIT :
I used picasso to download my image , but the image is shown only after the second click , and any marker's infowindow that use the same image get the image in the first time , it means that the image have to be downloaded first !! i edited my getInfoContents() and i'm not using downloadIcon() anymore !
Using Picasso, this is extremely easy. Simply write:
String url = ...;//Your url
ImageView imageView; //Your ImageView
Picasso.with(context).load(url).into(imageView);
Or, If you want to do it yourself, you can implement an AsyncTask:
Definition:
private class ImageDownloader extends AsyncTask {
#Override
protected Bitmap doInBackground(String... param) {
return downloadIcon(param[0]);
}
#Override
protected void onPostExecute(Bitmap result) {
//Handle your result, i.e. your bitmap
}
}
Execution:
new ImageDownloader().execute(iconURL);
You should not dowmload image by using main UI thread, so you need another thread to do it, something like:
public void setImage(final ImageView img, final String iconURL)
{
Thread thread = new Thread(new Runnable() {
#Override
public void run()
{
Bitmap bmImg;
try {
URL url = new URL(iconURL);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setDoInput(true);
conn.connect();
InputStream is = conn.getInputStream();
bmImg = BitmapFactory.decodeStream(is);
}
catch (IOException e) {
e.printStackTrace();
bmImg = null;
}
//after downloading, then talk to main ui
runOnUiThread(new Runnable()
{
#Override
public void run()
{
img.setImageBitmap(bmImg);
}
}
}}).start();
}
Hope this help!
Related
I have created a listview with a custom adapter. One of the fields is an image to show the avatar of each user. I must obtain those images from an url.
I have created a class that converts an image from URL into a Bitmap.
I think this should be done from an asyntask. The problem is that I do not know how to call this method from a custom adapter.
This is my class:
private class obtAvatar2 extends AsyncTask<Void , Void, Bitmap>{
Bitmap bm;
#Override
protected Bitmap doInBackground(Void... voids) {
try {
URL url = new URL("https://www.bellatores.cl/wp-content/uploads/2018/01/Avatar-Mujer.png");
URLConnection con = url.openConnection();
con.connect();
InputStream is = con.getInputStream();
BufferedInputStream bis = new BufferedInputStream(is);
bm = BitmapFactory.decodeStream(bis);
bis.close();
is.close();
}catch (IOException e){
}
return bm;
}
}
This return a Bitmap.
Then from my custom adapter, i need to put that Bitmap in a ImageView
for example, i'm trying:
ImageView avatarView = (ImageView)view.findViewById(R.id.imageViewAvatarMensa);
avatarView.setImageBitmap(new obtAvatar2().execute());
But, it's wrong :(
any advice?
I suggest to you to either work with Glide or Picasso libaries, they are the most used image library on android application :
To import to you project with gradle :
PICASSO :
dependencies {
compile 'com.squareup.picasso:picasso:2.5.1'
}
GLIDE :
dependencies {
compile 'com.github.bumptech.glide:glide:3.5.2'
}
Usage :
PICASSO :
Picasso.with(myFragment)
.load(url)
.into(myImageView);
GLIDE :
Glide.with(myFragment)
.load(url)
.into(myImageView);
Hope this helps
You can use Glide or Picasso. As those are very helpful libraries for setting image in adapter (here views are reusable).
If you still want to use asynctask then check below:
In adapter each time scroll will lead to new network call, that can be avoided using saving bitmap object.
You are trying to get image by using below code:
ImageView avatarView = (ImageView)view.findViewById(R.id.imageViewAvatarMensa);
avatarView.setImageBitmap(new obtAvatar2().execute());
This will not work as:
new obtAvatar2().execute()
It will execute in background and return response in onPostExucute(). And result is:
avatarView.setImageBitmap(null)
If you want to use asytask then probably you need make your code like:
private class obtAvatar2 extends AsyncTask<Void, Void, Bitmap> {
Bitmap bm;
#Override
protected Bitmap doInBackground(Void... voids) {
try {
URL url = new URL("https://www.bellatores.cl/wp-content/uploads/2018/01/Avatar-Mujer.png");
URLConnection con = url.openConnection();
con.connect();
InputStream is = con.getInputStream();
BufferedInputStream bis = new BufferedInputStream(is);
bm = BitmapFactory.decodeStream(bis);
bis.close();
is.close();
} catch (IOException e) {
}
return bm;
}
#Override
protected void onPostExecute(Bitmap bitmap) {
super.onPostExecute(bitmap);
ImageView avatarView = (ImageView)view.findViewById(R.id.imageViewAvatarMensa);
avatarView.setImageBitmap(bitmap);
//set bitmap to imageview and save in local list, so in future no need to download
}
}
You can pass reference of ImageView in constructor.
First of all you should add obtAvatar2 async task in your custom adapter.
I hope you are using ViewHolder in your customadapter, then in you getView(), before assigning value to your Imageview, call the async task. For example:
public static class ViewHolder {
public ImageView display_adImage;
}
public View getView(final int position, View convertView, ViewGroup parent) {
View vi = convertView;
try {
if (convertView == null) {
vi = inflater.inflate(R.layout.test_layout, null);
holder = new ViewHolder();
holder.display_adImage = vi.findViewById(R.id.IvAdImage);
vi.setTag(holder);
} else {
holder = (ViewHolder) vi.getTag();
}
...
Bitmap b = new GetImageTask().execute().get();
holder.display_adImage.setImageBitmap(b);
}
}
private class obtAvatar2 extends AsyncTask<Void , Void, Bitmap>{
Bitmap bm;
#Override
protected Bitmap doInBackground(Void... voids) {
try {
URL url = new URL("https://www.bellatores.cl/wp-content/uploads/2018/01/Avatar-Mujer.png");
URLConnection con = url.openConnection();
con.connect();
InputStream is = con.getInputStream();
BufferedInputStream bis = new BufferedInputStream(is);
bm = BitmapFactory.decodeStream(bis);
bis.close();
is.close();
}catch (IOException e){
}
return bm;
}
}
I'm trying to load an image from an URL to a Bitmap but I am getting a NetworkOnMainThreadException error but I don't know why.
This is the method I am using:
public Bitmap getBitmapFromURL(String src) {
try {
java.net.URL url = new java.net.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;
}
}
I also tried to load the image to a Target using Picasso library, because in the end, I want to get the dominant color from this image using Palette. This is the code I have using Picasso:
Picasso.with(MovieDetails.this)
.load("https://image.tmdb.org/t/p/w500" + backdrop)
.into(new Target() {
#Override
public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
Palette palette = Palette.from(bitmap).generate();
System.out.println(palette.getVibrantSwatch().toString().substring(16, Math.min(palette.getVibrantSwatch().toString().length(), 22)));
LinearLayout lLayout = (LinearLayout) findViewById(R.id.layout_bg);
lLayout.setBackgroundColor(Color.parseColor("#"+ palette.getVibrantSwatch().toString().substring(16, Math.min(palette.getVibrantSwatch().toString().length(), 22))));
}
#Override
public void onBitmapFailed(Drawable errorDrawable) {
}
#Override
public void onPrepareLoad(Drawable placeHolderDrawable) {
}
});
I put this inside my onCreate method, but I am getting "method does not override method from its superclass" errors in all the three #Override methods.
I managed to solve my problem by using an AsyncTask as it follows:
I put this in the end of my Activity:
public class MyAsync extends AsyncTask<Void, Void, Bitmap>{
#Override
protected Bitmap doInBackground(Void... params) {
try {
URL url = new URL("https://image.tmdb.org/t/p/w500" + backdrop);
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;
}
}
}
Please note that inside this method I put the URL for the image.
To access the Bitmap inside my Activity and get the dominant color using Palette I did this:
MyAsync obj = new MyAsync(){
#Override
protected void onPostExecute(Bitmap bmp) {
super.onPostExecute(bmp);
Bitmap bm = bmp;
if (bm != null && !bm.isRecycled()) {
Palette palette = Palette.from(bm).generate();
System.out.println(palette.getVibrantSwatch().toString().substring(16, Math.min(palette.getVibrantSwatch().toString().length(), 22)));
LinearLayout lLayout = (LinearLayout) findViewById(R.id.layout_bg);
lLayout.setBackgroundColor(Color.parseColor("#"+ palette.getVibrantSwatch().toString().substring(16, Math.min(palette.getVibrantSwatch().toString().length(), 22))));
}
}
};
obj.execute();
This code is inside my onCreate method.
The way to correct the first issue is to perform that action in a Thread or Runnable, There is a flag you can set something like StrictModeEnabled or something like that, but that's bad, don't resort to that.
As far as picasso, i dont know about the overriding methods from superclass thing, i'd try to do it in onViewCreated instead of onCreate
public class MainActivity extends Activity {
ImageView downloadedimg;
public class ImageDownloader extends AsyncTask<String,void,Bitmap> {
#Override
protected Bitmap doInBackground(String... urls) {
try{
URL url=new URL(urls[0]);
HttpURLConnection connection=(HttpURLConnection) url.openConnection();
connection.connect();
InputStream inputStream=connection.getInputStream();
Bitmap mybitmap= BitmapFactory.decodeStream(inputStream);
return mybitmap;
}
catch(Exception e)
{
e.printStackTrace();
}
return null;
}
}
public void downloadImage(View view) {
ImageDownloader task = new ImageDownloader;
Bitmap myImage;
try {
myImage = task.execute("https://www.google.co.in/url?sa=i&rct=j&q=&esrc=s&source=images&cd=&cad=rja&uact=8&ved=0ahUKEwiOw5HvydXOAhVKqo8KHYHfAtIQjRwIBw&url=https%3A%2F%2Fen.wikipedia.org%2Fwiki%2FBart_Simpson&psig=AFQjCNFZSwEG2tjp15Km14uuzEsmZUZ_MQ&ust=1471974330385306");
downloadedimg.setImageBitmap(myImage);
}
catch (Exception e) {
e.printStackTrace();
}
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
downloadedimg=(ImageView)findViewById(R.id.imageView);
}
in the line
myImage = task.execute("some url to image address online");
the complier shows error that
incompatible type
required: android.graphics.Bitmap
found: android.os.AsyncTask "<"java.lang.String,void,android.graphics.Bitmap>
double code infront of java's bracket are not part of statement
#edit Thank you for previous advice i searched and found .get() method
i used task("").get() to return the bitmap image and code compiled without errors but now nothings happens when i click the download image button
AsyncTask.execute does not return the object downloaded. It can't, the entire idea of an AsyncTask is that its asynchronous. Any code that needs to use the result should either be put in onPostExecute (for UI changes) or at the end of doInBackground (for processing data).
I am using a recyclerView to show images using asysnc task. I am getting the images from a web server. My code is
from onBindViewHolder methode I call
new ImageLoadTask(url, holder.imageView).execute();
My ImageLoader asysnc task is
public class ImageLoadTask extends AsyncTask<Void, Void, Bitmap> {
private String url;
private ImageView imageView;
ProgressDialog pDialog;
public ImageLoadTask(String url, ImageView imageView) {
this.url = url;
this.imageView = imageView;
}
#Override
protected Bitmap doInBackground(Void... params) {
try {
URL urlConnection = new URL(url);
HttpURLConnection connection = (HttpURLConnection) urlConnection
.openConnection();
connection.setDoInput(true);
connection.connect();
InputStream input = connection.getInputStream();
Bitmap myBitmap = BitmapFactory.decodeStream(input);
return myBitmap;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(Bitmap result) {
super.onPostExecute(result);
imageView.setImageBitmap(result);
}
}
The problem is when I scroll and skip one or more views before the image is downloaded and that view is recycled the image donwnload reqest is not canceled on those intermediate view resulting in a flash of that/those image(s) before the actual image is loaded in that view.
I tried passing the HttpURLConnection from the adapter and checking if its not null and then calling disconnect on this as shown before from onBindViewHolder methode, but still it happens. I am using the
if (holder.urlConnection != null)
{
holder.urlConnection.disconnect();
try {
holder.urlConnection.getInputStream().close();
}
catch (Exception e) {
e.printStackTrace();
}
holder.urlConnection = null;
}
new ImageLoadTask(url, holder.imageView,holder.viewHolderActivity, holder.urlConnection).execute();
What can I do to cancel the image requests ?
Save ImageLoadTask link in holder
if (holder.urlConnection != null)
{
holder.urlConnection.disconnect();
try {
holder.urlConnection.getInputStream().close();
}
catch (Exception e) {
e.printStackTrace();
}
holder.urlConnection = null;
}
holder.imageTask = new ImageLoadTask(url, holder.imageView,holder.viewHolderActivity, holder.urlConnection);
holder.imageTask.execute();
and cancel it on
//Called when a view created by this adapter has been recycled.
public void onViewRecycled(VH holder){
holder.imageTask.cancel();
}
On your ViewHolder keep a reference to your ImageLoadTask.
in the onBindViewHolder method cancel the existing ImageLoadTask by calling its cancel method and create a new task for the new image. Note that when a AsyncTask is cancelled it will not call the onPostExecute method instead it will call onCancelled.
Try to cancel asynctask using cancel() method in order to cancel the image request:
ImageLoadTask imageLoadTask=new ImageLoadTask(url, holder.imageView);
imageLoadTask.cancel(true);
Use glide:
https://inthecheesefactory.com/blog/get-to-know-glide-recommended-by-google/en
It's a fast and responsive framework for loading images from any given back-end. You can do stuff like setTimeout, cancelRequests, fadeEffects and some other stuff. You don't even have to worry about how to handle the network request. Glide will simply do that for you.
Usage:
Glide.with(context)
.load(imageLoadPath)
.placeholder(imgToShowWhileLoading)
.centerCrop()
.into(imageView);
And then you can set the GlideModule configuration like this:
(Original code snippet: glide image loading timeout increase). Make a custom class to implement GlideModule. In one of it's overriding methods:
#Override
public void registerComponents(Context context, Glide glide) {
final int retryPolicy = 10000;
RequestQueue queue = new RequestQueue(
new DiskBasedCache(new File(context.getCacheDir(), "volley")),
new BasicNetwork(new HurlStack())) {
#Override public <T> Request<T> add(Request<T> request) {
request.setRetryPolicy(new DefaultRetryPolicy(retryPolicy, 1, 1);
return super.add(request);
}
};
queue.start();
glide.register(GlideUrl.class, InputStream.class, new VolleyUrlLoader.Factory(queue));
}
Play with timeout limit all you want, and see how it can meet your needs.
I have to download an image from a url and then show the downloaded image in a imageview on the UI.
For this i am using the code mentioned below:
public class ShowUIData extends AsyncTask<Void, Void, Void> {
String productvalues[];
Drawable productimagebitmap;
#Override
protected Void doInBackground(Void... params) {
productvalues = hb.getProductDetailsWithJson(id + 1);
if (productvalues != null) {
productimagebitmap = getImage(productvalues[3]);
}
return null;
}
#Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
if (productvalues != null) {
// Set the values obtained from the database.
// Check if image returned from URL is not null.
if (productimagebitmap != null) {
ImageView productimage = (ImageView) findViewById(R.id.productimage);
productimage.setImageDrawable(productimagebitmap);
}
}
dismissDialog();
}
// Download image from URL obtained for database.
private Drawable getImage(String address) {
try {
Log.i("product details", "starting image download");
URL url = new URL(address);
URLConnection conn = url.openConnection();
conn.connect();
InputStream is = conn.getInputStream();
Drawable d = Drawable.createFromStream(is, "src name");
is.close();
return d;
} catch (Exception e) {
Log.i("the url", address);
e.printStackTrace();
return getApplicationContext().getResources().getDrawable(
R.drawable.noimage);
}
}
A valid URL is being passed to the getImage function and no exception is being thrown , still the image is not being set on the imageview. When i debug my application, then the image is setting properly.
I believe i need to put a blocking call until the image is download and then call image.setImageDrawable.
What is the problem occuring over here. I am not able to figure out why i am not able to load any images and why only when i debug , i see an image?
thank you in advance.
you should try this example. It runtime fetches images from the url and also displays it in listview. I think this will help you.
Non UI thread can't update UI component. Use handler to update UI component.