I want when i press a specific Button an Image (like a map) to be displayed. What is more light-weight for my application? Getting this from a url or having it on the drawable folder and just display it?
If I choose the second one, and want to implement a "back" button I will have to put the whole thing in an extra class or not?
My application needs connection to the Internet, regardless of this.
I'd go with a drawable, purely for this reason, what happens when the user starts the app with no wifi/3g/etc. or an extremely slow connection. You say your application needs a connection, but that doesn't necessarily mean the user will have it enabled when they start the app.
Its also a lot easier with a drawable, simply put it into the drawable folder then specify it as source for your ImageView (if you are using a clickable imageview)
<ImageView android:layout_height="wrap_content" android:id="#+id/imageView1"
android:layout_width="wrap_content" android:src="#drawable/your_image">
</ImageView>
or as the background if you are using a Button in the xml file.
<Button android:text="" android:id="#+id/button1"
android:layout_width="wrap_content" android:layout_height="wrap_content"
android:background="#drawable/your_image">
</Button
though you may want to use a selector to change between 2 images (pressed and unpressed state)
and instead specify the selector xml file as the background/source
ie android:background="#drawable/back_button_selector"
Downloading an image needs to be done in a background thread (such as an AsycnTask) or the UI will not respond while the image is downloading.
But if you decide to download the image for some reason (ie. you want to have the image change without putting out an update and just changing it on the server) here's an AsyncTask to download an image (you can use it as an inner class)
public class GetImage extends AsyncTask<ImageView, Void, ImageView> {
String url = null;
Bitmap thumbnail = null;
public GetImage(String url){
this.url = url;
}
#Override
protected void onPreExecute() {
}
#Override
protected ImageView doInBackground(ImageView... params) {
try {
thumbnail = BitmapFactory.decodeStream((InputStream) new URL(url).getContent());
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return params[0];
}
#Override
public void onPostExecute(ImageView result) {
result.setImageBitmap(thumbnail);
}
}
Related
I'm making a project Android application that takes an image URL, downloads the image and displays the image. In case of an image of bigger size i want to show the user an indeterminate progress that the image is being downloading.
Java Code:
public class MainActivity extends AppCompatActivity {
ImageView downloadedImg;
ProgressBar progressBar;
Handler handler;
public void downloadImage(View view){
progressBar.setVisibility(View.VISIBLE);
ImageDownloader task = new ImageDownloader();
Bitmap myimage;
try {
myimage = task.execute("http://wallpaperswide.com/download/high_tech_earth-wallpaper-2880x1800.jpg").get();
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);
progressBar = (ProgressBar)findViewById(R.id.pbar);
handler = new Handler();
}
public class ImageDownloader extends AsyncTask<String,Void,Bitmap>{
protected void onPreExecute(){
super.onPreExecute();
//progressBar.setVisibility(View.VISIBLE);
}
#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;
}
#Override
protected void onPostExecute(Bitmap bitmap) {
super.onPostExecute(bitmap);
handler.post(new Runnable() {
#Override
public void run() {
progressBar.setVisibility(View.GONE);
downloadedImg.setVisibility(View.VISIBLE);
}
});
}
}
public void reset(View view){
downloadedImg.setVisibility(View.GONE);
progressBar.setVisibility(View.INVISIBLE);
}
}
XML code:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="match_parent"
tools:context="com.example.syeddanish.downloadingimages.MainActivity">
<Button
android:id="#+id/button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:onClick="downloadImage"
android:text="Download Image" />
<Button
android:id="#+id/button1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#+id/button"
android:onClick="reset"
android:text="Reset" />
<ProgressBar
android:id="#+id/pbar"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:indeterminate="true"
android:visibility="invisible" />
<ImageView
android:id="#+id/imageView"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:visibility="gone"
android:layout_below="#+id/button1" />
</RelativeLayout>
The issue i'm facing is that i want the progress bar to become visible when the download starts(i.e when "Download Image button is pressed"). I'm trying to do this in two ways i.e
By using progressbar.setVisibility(View.VISIBLE); in the start of
the onClick method of "Download Image" button.
or
By using progressbar.setVisibility(View.VISIBLE); in theonPreExecute() method of the ASyncTask but the progress bardoes not shows up using any of the above mentioned ways.
Can anyone please point out what i am doing wrong?
Does this code compile and run without NetworkOnMainThreadException?
Your problem is the usage of get()
In this part:
Bitmap myimage;
try {
myimage = task.execute("http://wallpaperswide.com/download/high_tech_earth-wallpaper-2880x1800.jpg").get();
downloadedImg.setImageBitmap(myimage);
}
you try to get an image from task.execute(...), but task.get() as per docu:
[...]Waits if necessary for the computation to complete, and then retrieves its result.[...]
So you are waiting for your "task" to execute on the main thread and blocking it, until done. Because of that, your progress
is never visible, because the UI-Thread is blocked. And once your task finishes,
the progress is set back to be invisible.
Moreover, do not reinvent the weel. Use one of the libraries available out there
for image downloading and caching.
For example: Picasso, Glide
Both also provide the functionality to use a (1) fallback and (2) loading image.
If you still like to try it on your own, then do not do the Pokémon- "gotta catch'em all" way of catching your exceptions, but instead, handle specific Exceptions that might occur and display a message to the user, send it your crash tracker, etc. Only catch exceptions that you expect to be thrown, otherwise...let it crash.
I do not see, why you should catch an exception there.
AsyncTask, Activities and memory leaks
Next is, that AsyncTasks are not tidily coupled to the Activities
life cycle. When you run your task and it executes in background, but
your activity finishes, this task will still be alive and leaks a reference to your activity. This causes the memory leaks, because the GC can't properly do it's job, to clean after you.
Make your AsyncTask at least a static class and stop/kill the task, once your activity finishes.
Multiple Tasks
Next thing, check if you already download the image, once the user clicked the button, or you're going to create multiple tasks.
So, make your ImageDownloader a member of your activity and check if it is already executing or done. (Take it out of your method and put it below the activity class head). When your activity calls onPause() or onDestroy(), kill the task with fire.
Be aware of orientation changes, too.
Android Task API instead of AsyncTask
I highly recommend to use the android task api. (com.google.android.gms.tasks)
It works very well for tasks, both running on the Main- or Workerthreads. Include continuations, provides Future like functionality and can be coupled with Activities.
References: gms Task API Doc
try put downloadedImg.setImageBitmap(myimage); inside onPostExecute(Bitmap bitmap)handler and change:
myimage = task.execute("http://wallpaperswide.com/download/high_tech_earth-wallpaper-2880x1800.jpg").get();
to:
task.execute("http://wallpaperswide.com/download/high_tech_earth-wallpaper-2880x1800.jpg");
also put Bitmap myimage; as global variable on your Asynctask class and change:
Bitmap mybitmap = BitmapFactory.decodeStream(inputStream);
return mybitmap;
to:
myimage= BitmapFactory.decodeStream(inputStream);
on doInBackground
Consider using pBar.setAlpha(1f);
It helped when I'm stuck on a similar problem.
In the following situation: What is my alternative to using an AsyncTask?
I am using AsyncTask to load images into an adapter. The adapter row has a number of TextViews and one ImageView. The ImageView is where I load the image. The image is being loaded from the internet. The problem is that when I scroll, the wrong image would show in a row/cell -- until the correct image has had time to arrive. How do I prevent this image mismatching from ever happening? I am asking this question because I want to understand how this works: I don't just want to get some library that might do the work for me (many libraries I have already tried, have failed).
Once again, the problem: the AsyncTask causes images to load into the wrong row so that the user can clearly see that the images are looking for their final destination.
I hope the question is clear. For completeness, below is the method that I am calling inside the getView method of the adapter to load each image. The method is also inside the adapter. What is my alternative to using an AsyncTask?
private void loadImage(final ImageView photo, String imageUrl) {
new AsyncTask<String, String, Bitmap>() {
#Override
protected Bitmap doInBackground(String... param) {
try {
Bitmap b = callToServer(imageUrl);//takes long
return b;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
#Override
protected void onPostExecute(Bitmap ret) {
if (ret != null) {
photo.setImageBitmap(ret);
}
}
}.execute(imageUrl);
}
The most common approach is using the setTag(...) and getTag(...) methods of the view that you create in the adapter. Once created, you add a tag that you need to link to the image that is then asynchronously loaded. When that task is finished, you can check the tag of the view and if it's still the same as when the async task has started you can set the image. Otherwise you can dismiss the image. Remember that the same view is re-used instead of created when you scroll. So the tag will have changed then.
Here's a pretty good example: Asynchronous Image Loader in Android ListView
The problem is that the rows get recycled and so does the image view. Then when the server response returns the image view already belongs to another data object.
There are different approaches to this. My solution is to extend ImageView and keep track of the image you want to load.
class RemoteImageView extends ImageView {
private String _uri;
public synchronized void loadRemoteImage(String uri) {
_uri = uri;
loadImage(this, uri) ; //this is your async call
}
private synchronized void onImageLoaded(String uri, Bitmap image) {
if(uri.equals(_uri)) { //this will set only the correct image
setImageBitmap(image);
}
}
}
As for your loading function:
private void loadImage(final ImageView photo, final String imageUrl) {
new AsyncTask<String, String, Bitmap>() {
#Override
protected Bitmap doInBackground(String... param) {
try {
Bitmap b = callToServer(imageUrl);//takes long
return b;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
#Override
protected void onPostExecute(Bitmap ret) {
if (ret != null) {
photo.onImageLoaded(imageUri, ret);
}
}
}.execute(imageUrl);
}
And then withing your adapter you should call the loadRemoteImage(imageUri)
I also suggest you combine this with a bitmap cache so as to acccelerate the process of fetching the image and the addition of placeholders :)
I would like to load a large/complex svg image file into my imageView. Loading the svg takes time to load on my HTC Desire S and Lenovo a60. About 5 Second and 10 seconds respectively.
Right now my app becomes unresponsive for about 5 seconds until the imageView is fully loaded
I load the image using this simple code..
svg = SVGParser.getSVGFromResource(getResources(), R.raw.gf);
mImageView.setImageDrawable(svg.createPictureDrawable());
I was looking something like (webView)
webView.setWebViewClient(new WebViewClientEx(MainActivity.this, DEBUG) {
#Override
public void onPageFinished(final WebView view, String url) {
...........
.............}
});
which I used in my previous project...
Finally my questions:
1.) What is the best approach to make the app look responsive?
I was planning to use asynctask but don't know how to use it... Is it applicable here?
2.) Is there listener after the image is fully loaded?
My approach here is to show the progressDialog by the time I load the imageView and hide it after the imageView has fully loaded.
another other suggestions which you think is better to use for showing/hiding progressDialog ? Thanks!
Use an async task here. (a Loader would work aswell but async task is a bit easier to explain.)
private class LoadSVGTask extends AsyncTask<Integer, Void, Drawable> {
protected Drawable doInBackground(Integer... res) {
mProgressBar.setVisibility(View.Visible);
svg = SVGParser.getSVGFromResource(getResources(),res);
Drawable d = svg.createPictureDrawable();
return d;
}
// gets executed in main thread
protected void onPostExecute(Drawable result) {
mProgressBar.setVisibility(View.Gone);
mImageView.setImageDrawable(result);
}
}
Launch the Task with:
new LoaderSVGTask().execute(R.raw.gf, null, null);
see: http://developer.android.com/reference/android/os/AsyncTask.html
Just refer AsyncTask in that
protected void onPreExecute (){
progressDialog.show(......);
}
protected abstract Result doInBackground (Params... params){
//load your image from here
}
protected void onPostExecute (Result result){
progressDialog.dismiss();
}
I am relatively new to android development and i am trying to create a custom ListView with an ImageView and TextView. I am converting a URL into a bitmap image and then trying to display the image in an imageView. However I am getting an error and my application crashes immediately. The was able to display a drawable in my imageView and I made some modifications and tried to display a bitmap and then my application crashed. Any help would be greatly appreciated. Here are my 3 classes :
EDIT I used an asynctask to obtain the bitmap image on a separate thread and now my app does not crash anymore. But it does not display the listview when I start the activity. Here is my updated code.
EDIT I changed my code again and I am only passing an imageView in the execute method of my async task. I am now able to see the text in my listview, but I do not see the image. here is my edited code.
EDIT I used the debugger to find out why the bitmap wasn't getting displayed and i found out that my bitmap variable was null. This was because I had not added internet permissions. After adding the permissions my app started to crash at the given line :
b = BitmapFactory.decodeStream(image_url.openConnection() .getInputStream());
I had gotten a RuntimeException due to an OutofMemory error. I am not sure how to solve this. i would appreciate any help. thanks !
Here is my Loadimage AsyncTask Class:
public class LoadImage extends AsyncTask<String, Integer, Bitmap>{
Context callingContext = null;
Bitmap b = null;
ImageView view;
public LoadImage(ImageView view){
this.view = view;
}
#Override
protected Bitmap doInBackground(String... arg0) {
// TODO Auto-generated method stub
String p_url = "http://java.sogeti.nl/JavaBlog/wp-content/uploads/2009/04/android_icon_256.png";
Bitmap b = null;
try {
URL image_url = new URL(p_url);
b = BitmapFactory.decodeStream(image_url.openConnection() .getInputStream());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return b;
}
#Override
protected void onPostExecute(Bitmap result) {
// TODO Auto-generated method stub
super.onPostExecute(result);
view.setImageBitmap(result);
}
}
Your code is crashing because you are loading the image file off the server on the UI thread while in strict mode. This is generally considered bad practice because if the image takes a long time to download, your app will appear to have locked up.
Strict mode is forcing the crash (its throwing an exception). If you disable strict mode, it should let your app work fine. However the problem with doing network I/O on your UI thread remains.
The better long term solution is to use something like an AsyncTask. This will load your image on a different thread, thus keeping your app responsive. The documentation for AsyncTask has a simple example for downloading the image, and this helper page has more information.
For an example, I'd probably change your code to something like this (please note I'm writing this without a test run, so there maybe a few bugs):
I'd change your List entry to be:
public class CustomList {
public String iconUrl;
public String title;
public CustomList(){
super();
}
public CustomList(String icon, String title) {
super();
this.icon = icon;
this.title = title;
}
}
And then only pass in the icon URL's to your list.
Next create an AsyncTask:
public class ImageDownloader extends AsyncTask<String, Integer, Bitmap> {
public ImageDownloader(ImageView view){
mView = view;
}
protected Bitmap doInBackground(String... url) {
Bitmap b = null;
try {
URL image_url = new URL(url);
b = BitmapFactory.decodeStream(image_url.openConnection() .getInputStream());
list_data = new CustomList[]{
new CustomList(b,"Android")};
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return b;
}
protected void onPostExecute(Bitmap result) {
mView.setImageBitmap(result);
}
ImageView mView;
}
And then for your Adapter, instead of setting the image, do:
new ImageDownloader(holder.thumbnail).execute(cl.icon);
That should be enough to get you started. Please note that there are a couple of issues with this sample:
There is a potential memory leak. Generally speaking you should
not hold onto reference to either Views or Activities (or other such
objects) in an AsyncTask like I did.
If you rotate the phone and
the list changes, you might have old thumbnails show up.
If a
view is recycled, an old thumbnail might show up.
I have a code below, this code works perfectly fine when you are trying to load one or two images. However, the problem is, when you have a lot of images in one Activity, all images must load first before you can get in. My question is, what is the best way to handle this images? I want the images to load one by one and not simultaneously. I want it to load just like the ListView made by Fedor "http://stackoverflow.com/questions/541966/android-how-do-i-do-a-lazy-load-of-images-in-listview" (Note: I'm not using a ListView, I just want my images to load like that). Please help me, I would really appreciate it a lot. Thanks in advance!
class ImageDownlaodThread extends Thread {
ImageDownloadMessageHandler imageDownloadMessageHandler;
String imageUrl;
#Override
public void run() {
Drawable drawable = LoadImageFromWebOperations(imageUrl);
Message message = imageDownloadMessageHandler.obtainMessage(1, drawable);
System.out.println("Message sent");
}
}
class ImageDownloadMessageHandler extends Handler {
View imageTextView;
}
#Override
public void handleMessage(Message message) {
progressBar.setVisibility(View.GONE);
imageTextView.setVisibility(View.VISIBLE);
}
}
Drawable LoadImageFromWebOperations(String url) {
Drawable d = null;
InputStream is = null;
try {
} catch (IOException e) {
e.printStackTrace();
}
return d;
}
Would this tutorial help [TUT] ImageView with Loading Spinner:
http://www.anddev.org/novice-tutorials-f8/imageview-with-loading-spinner-t49439.html
It basically show's a spinner until the image has loaded from the remote site :-)
You could strip the code to show a blank space / whatever you want till it loads.
If you don't want anything to happen till it all loads, you could have a count of how many images there are and then increment this each time an image has loaded.
IMO, AsyncTask is the easiest way to do this; in fact, it was basically built for this sort of task.
There's really too much to discuss in a StackOverflow answer. Just see Painless Threading to get started.