Im developing an app which is a product catalogue. Users can search for and view products (books). It's all read only and just so allow user's to view products. When the user clicks on a product, the next screen displays
- book title
- book author
- picture of front cover.
It's the picture part that I've a question about. I know one way to present drawables is to have them in the "drawable" direction in my android project and access them (in my xml file) as android:src="#drawable/name".
Only problem is that new products will be added so I can't store drawables in the APK file when I release it. I'll need to read them at runtime. I'm wondering what the best way to approach this is.
I'm thinking of upon (very first) launch of the app executing an AsyncTask which would call
openConnection of HttpURLConnection and would grab down all drawable (from a particular remote directory on a website) and would then store them in the sqllite db (as a blob). Each product in the db could easily be associated with it's specific drawable.
Not sure if there's a better approach to this ? or should I save them to the internal storage of the device (I know the size is an issue with this option). Trying to grab the drawable on demand can take 2-4secs (i.e. to get from remote server). Is there a way to download drawables in an efficent way ?
Update: The only problem with the above approach is the time it takes to grab the remote drawable and render it on the device (between 2-7 seconds). So I can't go with that approach for performance reasons. When the user launches the app for the very first time, it (using an ASynch task) grabs all products (in a csv remotely) and stores it's contents in an SQLLite db. So they've a small acceptable wait on very first launch of the app but none after that. I'd like to do something similiar (i.e. get the drawables too) but not sure should should I store them in internal storage or persist them as BLOB into the db. There max size of 2-3kb each in size but there could be 300 products in total
Any help would be great. I'm developing on Android 4.0.3.
Thanks - Ro
The method you described is the best way to perform such a task. Grab them directly from online so that any time you change the picture it is changed on your phone. Also an easier way, you can directly display images to user no need for storing them into database but before you have to check internet connection.
Function for retrieving images:
public static Bitmap getBitmapFile(String str)
{
Bitmap bmImg=null;
URL myFileUrl;
try {
myFileUrl = new URL(str);
HttpURLConnection conn= (HttpURLConnection)myFileUrl.openConnection();
conn.setDoInput(true);
conn.connect();
InputStream is = conn.getInputStream();
bmImg = BitmapFactory.decodeStream(is);
} catch (Exception e) {
e.printStackTrace();
}
return bmImg;
}
For checking Internet connection:
// declaring variable for holding Internet connection state
boolean connected = false;
// checking connectivity to the Internet through mobile network or WIFI
ConnectivityManager connectivityManager = (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE);
if(connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_MOBILE).getState() == NetworkInfo.State.CONNECTED ||
connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI).getState() == NetworkInfo.State.CONNECTED) {
// Internet connection
connected = true;
}
else
// no Internet connection
connected = false;
Example:
// grab image to display
try {
// Bitmap bmp1;
// String url1;
// ImageView img1;
// in case there is Internet connection display image from online url
if(connected == true)
{
bmp1=MainActivity.getBitmapFile(url1);
img1.setImageBitmap(bmp1);
}
else
{
img1.setImageResource(R.drawable.not_connected);
}
} catch(Exception e) {
e.printStackTrace();
}
Related
I am using the following method to get an image from a given URL.
protected Bitmap doInBackground(String... urls) {
String urlDisplay = urls[0];
Bitmap scaledImage = null;
try {
InputStream in = new java.net.URL(urlDisplay).openStream();
scaledImage = Bitmap.createScaledBitmap(BitmapFactory.decodeStream(in), 380, 250, false);
} catch (Exception e) {
Log.e("Error", e.getMessage());
e.printStackTrace();
}
return scaledImage;
}
Is there anyway to get a scaled image without having to download the full sized image first? It would greatly increase load times.
Sadly, server side manipulations can't be done and before downloading, there's no way to scale it. However, if you still want to save the load time on consecutive refreshes, then you probably can go ahead with saving the bitmap received in a shared preference. This way if the image is already stored in the shared preference, you don't need to download it again and apply scaling to it.
CAUTION: In case the image you are downloading is changing after a while, you can put a check to download it after every "n" (say 7) days and replace the existing stored image with this one.
NOTE: Though there are many answers already available which tells you how to store the image bitmap in Shared Preference / local storage, let me know in case you need that info/ code-snippet too.
You can not perform bitmap operations on a remote image without downloading it first. Therefore there is no way to do what you want to do unless the server you are getting the image from supports different image sizes or a parameter to resize it on the server side.
I'm messing around making a cooking recipe catalogue. Now I'm making a list of recipes of certain category. A little illustration:
-|-----------|-
-| |
-| Thumbnail | RECIPE NAME RECIPE NAME RECIPE NAME RECIPE NAME
-| Image |
-| |
-|-----------|-
What I would like to learn about is whether it is more useful to pull images from web or store them in a folder.
Storing them in a folder is much easier, I guess. But does it pay off, if the downloadable app's size is huge? With downloading the data maybe it is possible to only download the data of the categories you are watching?
You can come out with your own solutions as well.
I hope you get my point...
If targeted application is using Internet, go for fetching the images from web, it would make the application light-weight.
But, if your application is not using internet, and is locally executed, go for a local database, and keep sizes as low as possible.
Also, to fetch from internet, you can do it in a efficient way, by not downloading the image and displaying it.
Alternatively, you can directly show image from web without downloading it. Please check the below function . It will show the images from the web into your image view.
public static Drawable LoadImageFromWebOperations(String url) {
try {
InputStream is = (InputStream) new URL(url).getContent();
Drawable d = Drawable.createFromStream(is, "src name");
return d;
} catch (Exception e) {
return null;
}
}
then set image to imageview using code in your activity.
I am writing an app that is essentially a flipcard that shows word/hint on one side and picture on other side relevant to it.I am using viewflipper for the two views.Problem is that the picture loads from internet.App access the db,extracts url and then loads picture.That means the change in view takes as much time as it takes to download the picture.I want to flip card immediately and load picture so that user do not thinks that app is slow.Rather they should know that picture is being loaded,hence the delay.Pls suggest improvement in code.My code for loading picture in flipcard is:
public void setBMP(String s) //String passed is url extracted from column of db uing
{ //internal db
try{
//String url1 = "c.getString(3)";
String url1= s;
System.out.println(url1);
URL ulrn = new URL(url1);
HttpURLConnection con = (HttpURLConnection)ulrn.openConnection();
InputStream is = con.getInputStream();
Bitmap bmp = BitmapFactory.decodeStream(is);
if (null != bmp)
{
im.setImageBitmap(bmp);
}
else
System.out.println("The Bitmap is NULL");
}catch(Exception e){}
}
}
For changing view, i have set up actionListener.As soon as user touches screen card flips and image loads.
Also is it possible to preload the images in background while user is viewing some other card.Or is it possible to cache the cards viewed?
I would go the asnyctask route, because that way you can load/disable spinners (or wahtever loading animations) as well. Check out this answer for a really simple example. If you want to add spinners you need to start them in the onPreExecute() of the asnyctask (just add it to the example) and disable them in onPostExecute after you image is downloaded.
Using AsyncTask to load Images in ListView
it seems to me that creating a Runnable that gets the bmp and saves it to a hash map file and then, when it's needed if downloaded, it opens the file, and if not it downloads it from the web.
try looking at fedorvlasov's Lazy adapter for reference.
you can use his Image loader
I guess this quesiton has been answered already, buy it doesn't seem to work, and it is very furstrating...
I am just trying to get the size of a remote file in Android.
So far, I have tried the following two approaches, without success:
1)
try
{
file = new File("http://50.19.156.118/feed2/storage/download/a_17/Madagascar.3gp");
a=(int) myFileBeingUploaded.length();
}
catch (Exception j)
{
}
2)
try
{
url = new URL("http://50.19.156.118/feed2/storage/download/a_17/Madagascar.3gp);
urlConnection = (HttpURLConnection) url.openConnection();
a=urlConnection.getContentLength();
}
catch (Exception e)
{
}
getContentLength() returns always 77 !!, while File.length() returns 0
Any ideas?
Many thanks
HTTP is not a filesystem -- it is a protocol for communicating hyperlinked resources. With standard HTTP, the only way to determine the size of a resource is to download that resource. The way to solve your problem, assuming that you want the size before you want the resource, is to implement another resource which tells you the size. True, the Content-Size field of a response tells you the size of the data contained in the response, but only after you request the resource.
e.g. given your web server with image portrait.jpg, you could set up a php script meta.php to which you pass the name of the resource of interest... meta.php?f=portrait.jpg. Then meta.php would ask its filesystem for the size of f and return that number via HTTP.
I would like to use Android's system cache when downloading images as per these previous instructions: android system cache. I was able to get the following code working but the log statements are telling me that the images are never being read from the cache.
try {
//url = new URL("http://some.url.com/retrieve_image.php?user=" + username);
URL url = new URL("http://some.url.com/prof_pics/b4fe7bdfa174ff372c9f26ce6f78f19c.png");
URLConnection connection = url.openConnection();
connection.setUseCaches(true);
Object response = connection.getContent();
if (response instanceof Bitmap) {
Log.i("CHAT", "this is a bitmap");
current_image.setImageBitmap((Bitmap) response);
}
else {
Log.i("CHAT", "this is not a bitmap");
Log.i("CHAT", response.toString());
InputStream is = connection.getInputStream();
BufferedInputStream bis = new BufferedInputStream(is);
current_image.setImageBitmap(BitmapFactory.decodeStream(bis));
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
I have tried two different types of requests, one is to go through a PHP script that returns the image and another that is directly accessing the image file. I refresh the same image multiple times in a row and it never seems to get cached. For the direct image access, I get:
05-31 23:45:12.177 I/CHAT ( 2995): this is not a bitmap
05-31 23:45:12.177 I/CHAT ( 2995): org.apache.harmony.luni.internal.net.www.protocol.http.FixedLengthInputStream#40c1c660`
For the indirect image access, I consistently get:
05-31 23:45:14.550 I/CHAT ( 2995): this is not a bitmap
05-31 23:45:14.550 I/CHAT ( 2995): org.apache.harmony.luni.internal.net.www.protocol.http.ChunkedInputStream#40c02448
I found a better way to do it. If anyone else is having trouble after following the link android system cache, use this Google developer's blog post instead. The source code in that blog post is designed for a ListView but I am using it for all image retrievals. It downloads the image in an AsyncTask, puts a temporary image while downloading, and has an image cache. This last part is listed as a "Future Item" in the blog post, but if you download the source code, the cache is implemented. I had to modify the code slightly because the AndroidHttpClient isn't supported in 2.1. I switched it to a URL connection. So far, this looks to be a great image downloader class. Let's just hope it doesn't impact our already struggling memory management issues.