I need to parse the json output in my xml. Parsing is done but the image is not seen in the xml. Android log says this -
12-22 14:26:34.472: I/System.out(6037): resolveUri failed on bad bitmap uri: "base_url"/sites/default/files/pictures/picture-6175010166.jpg
Is there anything wrong in my below code can any body suggest me ?
HashMap<String, String> listview = new HashMap<String, String>();
String title = "";
String teaser="";
String createdon = "";
String profile_image = "";
try {
title = jListview.getString("title");
teaser = jListview.getString("teaser");
createdon = jListview.getString("created");
profile_image = jListview.getString("profile_image");
listview.put("title", title);
listview.put("teaser", teaser);
listview.put("created", createdon);
listview.put("profile_image", profile_image);
//listview.put("profile_image", picture);
} catch (JSONException e) {
System.out.println( "Bad Error" + e.toString());
e.printStackTrace();
}
return listview;
This is my main activity code where iam showing the result
try{
/** Getting the parsed data as a List construct */
lists = listJsonParser.parse(obj);
int imageCount = lists.size();
}
}catch(Exception e){
Log.d("Exception Main",e.toString());
}
/** Keys used in Hashmap */
String[] from = { "title","teaser","created","profile_image"};
/** Ids of views in listview_layout */
int[] to = { R.id.title,R.id.teaser,R.id.createdon,R.id.list_image};
/** Instantiating an adapter to store each items
* R.layout.listview_layout defines the layout of each item
*/
SimpleAdapter adapter = new SimpleAdapter(getBaseContext(), countries, R.layout.home_layout, from, to);
return adapter;
LoGcat:12-22 14:26:34.382: I/System.out(6037): resolveUri failed on bad bitmap uri:
your Error says Below:
12-22 14:26:34.472: I/System.out(6037): resolveUri failed on bad bitmap uri: "base_url"/sites/default/files/pictures/picture-6175010166.jpg
you need to download the image and then set it as bitmap. HERE is one of the many examples.
you can not set Direct web url to ImageView for setting ImageView src. you first create an custom Adapter by extending BaseAdapter for ListView and in getView you will need to first download image from Url as Bitmap and then set it to ImageView as:
public class CustomAdapter extends BaseAdapter{
#Override
public View getView(int position, View convertView,
ViewGroup parent) {
if(convertView == null){
LayoutInflater layoutInflater = (LayoutInflater)
getSystemService(LAYOUT_INFLATER_SERVICE);
convertView = layoutInflater.
inflate(R.layout.layout_row, null);
}
Bitmap test = getbitpam(maptemp.get("profile_image"));
imgview=(ImageView) convertView.findViewById(R.id.img_list);
imgview.setImageBitmap(test);
return convertView;
}
}
//get image from server
public Bitmap getbitpam(String url) {
Bitmap bitmap = null;
InputStream in = null;
BufferedOutputStream out = null;
try {
in = new BufferedInputStream(new URL(url).openStream(), IO_BUFFER_SIZE);
final ByteArrayOutputStream dataStream = new ByteArrayOutputStream();
out = new BufferedOutputStream(dataStream, IO_BUFFER_SIZE);
copy(in, out);
out.flush();
final byte[] data = dataStream.toByteArray();
BitmapFactory.Options options = new BitmapFactory.Options();
//options.inSampleSize = 1;
bitmap = BitmapFactory.decodeByteArray(data, 0, data.length,options);
} catch (IOException e) {
Log.e(TAG, "Could not load Bitmap from: " + url);
} finally {
closeStream(in);
closeStream(out);
}
return bitmap;
}
}
Related
Here in my code I'm setting a picture into an ImageView in my MyTask class which is using AsyncTask, but as I run my code just one or two ImageViews has pictures and the others are empty showing the default picture.
Is there any problems with the thread?
Here is my code:
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
Log.e("sara" , "this part takes time");
LayoutInflater inflater = getLayoutInflater();
convertView = getLayoutInflater().inflate(R.layout.gallery_gridsq, parent, false);
iv = (ImageView) convertView.findViewById(R.id.icon);
file = new File(Uri.parse(getItem(position).toString()).getPath());
new myTask().execute();
return convertView;
}
private class myTask extends AsyncTask <Void , Void ,Bitmap> {
#Override
protected Bitmap doInBackground(Void... params) {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
try {
BitmapFactory.decodeStream(new FileInputStream(file), null, options);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
options.inJustDecodeBounds = false;
options.inSampleSize = 2;
try {
bmp = BitmapFactory.decodeStream(new FileInputStream(file), null, options);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
return bmp;
}
#Override
protected void onPostExecute(Bitmap aVoid) {
iv.setImageBitmap(aVoid);
}
}
This is because you are overriding the iv(imageview) object every time when getView() method is called and because MyTask is an asynch task in which doInBackground() is called asynchronously on background thread and onPostExecute() called on main thread after that. So the onPostExecute will only update the current imageview. You have to set the bitmap on every image view of grid. This solution should work for you:
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
Log.e("sara" , "this part takes time");
LayoutInflater inflater = getLayoutInflater();
convertView = getLayoutInflater().inflate(R.layout.gallery_gridsq, parent, false);
ImageView iv = (ImageView) convertView.findViewById(R.id.icon);
File file = new File(Uri.parse(getItem(position).toString()).getPath());
new myTask(iv, file).execute();
return convertView;
}
private class MyTask extends AsyncTask <Void , Void ,Bitmap> {
Imageview iv;
File file;
public void MyTask(Imageview iv, File file)
{
this.iv=iv;
this.file= file;
}
#Override
protected Bitmap doInBackground(Void... params) {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
try {
BitmapFactory.decodeStream(new FileInputStream(file), null, options);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
options.inJustDecodeBounds = false;
options.inSampleSize = 2;
try {
bmp = BitmapFactory.decodeStream(new FileInputStream(file), null, options);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
return bmp;
}
#Override
protected void onPostExecute(Bitmap aVoid) {
iv.setImageBitmap(aVoid);
}
}
i consider that you are try to load an image using a url
you can user image loader reference (such as universal image loader) which is best for loading images
here is the code you can have
first of download the universal image loader library from the below
https://github.com/nostra13/Android-Universal-Image-Loader
You have to add this method your application level class so you don't need to write multiple times
public static void initImageLoader(Context context) {
// This configuration tuning is custom. You can tune every option, you
// may tune some of them,
// or you can create default configuration by
// ImageLoaderConfiguration.createDefault(this);
// method.
ImageLoaderConfiguration.Builder config = new ImageLoaderConfiguration.Builder(
context);
config.threadPriority(Thread.NORM_PRIORITY - 2);
config.denyCacheImageMultipleSizesInMemory();
config.diskCacheFileNameGenerator(new Md5FileNameGenerator());
config.diskCacheSize(50 * 1024 * 1024); // 50 MiB
config.tasksProcessingOrder(QueueProcessingType.LIFO);
config.writeDebugLogs(); // Remove for release app
// Initialize ImageLoader with configuration.
ImageLoader.getInstance().init(config.build());
}
Then in Adapter class you have to just add the below code to load image
// For Image Display options - Failed , Success and Error
// Add this is in your adapter constructor
DisplayImageOptions userimgoptions = new DisplayImageOptions.Builder()
.showImageOnLoading(R.drawable.profile_pic_no_border)
.showImageForEmptyUri(R.drawable.profile_pic_no_border)
.showImageOnFail(R.drawable.profile_pic_no_border).cacheInMemory(true)
.cacheOnDisk(true).bitmapConfig(Bitmap.Config.RGB_565).build();
// in you getview method just use this signle line code to load image
ImageLoader.getInstance().displayImage(modelFeeds.getUserAvatarOriginal(), myHolder.img_profilepicture, userimgoptions);
i hope this will help you
Set the Imageview using Glide Library
Step1: Include the Dependencies in your build.gradle file
compile 'com.github.bumptech.glide:glide:3.7.0'
Step2: Include the Glide in Java file
String fileName = "1.jpg";
String completePath = Environment.getExternalStorageDirectory() + "/" +
fileName;
File file = new File(completePath);
Uri imageUri = Uri.fromFile(file);
Glide.with(this)
.load(imageUri)
.placeholder(R.drawable.no_media)
.into(imgView);
I am working on an Android project in which I am loading images from our server while loading other information about restaurants. The problem is, it is taking a lot of time to load and whenever I try to load the information again or move the mobile from landscape to potrait or vice-versa, I get out of memory errors.
As I checked on net, the problem users say is because of bitmaps. On the server-side, I am converting the PNG's to Strings and transmitting them, and the String is then converted to bitmap and then displayed. Why is the whole loading time around 4-5 seconds and crashes. Can anyone help me.
Android code :
RestaurantList Activity :
public class getListOfRestaurantsForUser extends AsyncTask<Double,Void,ResponseEntity<RestRestaurant[]>>{
RestaurantList restaurantList = null;
getListOfRestaurantsForUser(RestaurantList restaurantList){
this.restaurantList = restaurantList;
}
#Override
protected ResponseEntity<RestRestaurant[]> doInBackground(Double... doubles) {
double longitude = doubles[0];
double latitude = doubles[1];
Log.d("Longitude",String.valueOf(longitude));
final RestTemplate restTemplate = StaticRestTemplate.getRest();
HttpHeaders requestHeaders = new HttpHeaders();
requestHeaders.add("Cookie", "JSESSIONID=" + StaticRestTemplate.jsessionid);
requestHeaders.setAccept(Collections.singletonList(new MediaType("application", "json")));
HttpEntity<?> requestEntity = new HttpEntity<Object>(requestHeaders);
restTemplate.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
return restTemplate.exchange(restaurantListURL+longitude+"/"+latitude, HttpMethod.GET, requestEntity, RestRestaurant[].class);
}
#Override
protected void onPostExecute(ResponseEntity<RestRestaurant[]> responseEntity){
RestRestaurant[] restRestaurantList = responseEntity.getBody();
Collections.addAll(restosAsList, restRestaurantList);
ArrayList<HashMap<String, String>> restaurantsArrayHashList = new ArrayList<>();
for(RestRestaurant restRestaurant : restosAsList){
HashMap<String, String> restDisplay = new HashMap<>();
restDisplay.put(restaurantid, String.valueOf(restRestaurant.getRestaurantId()));
restDisplay.put(restaurantName, restRestaurant.getRestaurantName());
restDisplay.put(restaurantDistance, String.valueOf(restRestaurant.getDistanceFromUser()));
restDisplay.put(restaurantDetails,restRestaurant.getRestaurantDetails());
restDisplay.put(restoProfilePicture,restRestaurant.getProfilePicture());
restaurantsArrayHashList.add(restDisplay);
}
listView = (ListView) findViewById(R.id.restosList);
restaurantListAdapter = new RestaurantListAdapter(restaurantList, restaurantsArrayHashList);
listView.setAdapter(restaurantListAdapter);
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
int restaurantId = restosAsList.get(position).getRestaurantId();
Intent intent = new Intent(RestaurantList.this, MenuCardList.class);
intent.putExtra("restaurantid", restaurantId);
startActivity(intent);
finish();
}
});
}
}
RestaurantList adapter :
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = convertView;
if (convertView == null) {
view = inflater.inflate(R.layout.individual_restaurant_detail, null);
TextView restaurantName = (TextView) view.findViewById(R.id.resturantName);
TextView distanceFromUser = (TextView) view.findViewById(R.id.distanceFromUser);
TextView restaurantDetails = (TextView) view.findViewById(R.id.restaurantDetails);
ImageView restoImage = (ImageView) view.findViewById(R.id.resturantImage);
HashMap<String, String> restaurantList;
restaurantList = data.get(position);
restaurantName.setText(restaurantList.get(RestaurantList.restaurantName));
restaurantName.setTypeface(Typeface.DEFAULT_BOLD);
restaurantName.setTextSize(TypedValue.COMPLEX_UNIT_SP, 15);
double distance = Double.valueOf(restaurantList.get(RestaurantList.restaurantDistance));
if(distance < 1000) {
distanceFromUser.setText("Entfernung " + restaurantList.get(RestaurantList.restaurantDistance)+"m");
}else {
distanceFromUser.setText("Entfernung " + String.valueOf(distance/1000) +"km");
}
restaurantDetails.setText(restaurantList.get(RestaurantList.restaurantDetails));
restoImage.setImageBitmap(convertByteArrayToBitmap(restaurantList.get(RestaurantList.restoProfilePicture)));
}
return view;
} #Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = convertView;
if (convertView == null) {
view = inflater.inflate(R.layout.individual_restaurant_detail, null);
TextView restaurantName = (TextView) view.findViewById(R.id.resturantName);
TextView distanceFromUser = (TextView) view.findViewById(R.id.distanceFromUser);
TextView restaurantDetails = (TextView) view.findViewById(R.id.restaurantDetails);
ImageView restoImage = (ImageView) view.findViewById(R.id.resturantImage);
HashMap<String, String> restaurantList;
restaurantList = data.get(position);
restaurantName.setText(restaurantList.get(RestaurantList.restaurantName));
restaurantName.setTypeface(Typeface.DEFAULT_BOLD);
restaurantName.setTextSize(TypedValue.COMPLEX_UNIT_SP, 15);
double distance = Double.valueOf(restaurantList.get(RestaurantList.restaurantDistance));
if(distance < 1000) {
distanceFromUser.setText("Entfernung " + restaurantList.get(RestaurantList.restaurantDistance)+"m");
}else {
distanceFromUser.setText("Entfernung " + String.valueOf(distance/1000) +"km");
}
restaurantDetails.setText(restaurantList.get(RestaurantList.restaurantDetails));
restoImage.setImageBitmap(convertByteArrayToBitmap(restaurantList.get(RestaurantList.restoProfilePicture)));
}
return view;
}
private Bitmap convertByteArrayToBitmap(String string){
try {
byte [] encodeByte= Base64.decode(string, Base64.DEFAULT);
return BitmapFactory.decodeByteArray(encodeByte, 0, encodeByte.length);
} catch (Exception ignored){}
return null;
}
Server side code :
#Override
public List<Restaurant> getNearbyRestaurants(double longitude, double latitude) {
BASE64Encoder base64Encoder = new BASE64Encoder();
final int R = 6371; // Radius of the earth
List<Restaurant> restaurantList = this.listRestaurants();
List<Restaurant> nearbyRestaurantList = new ArrayList<>();
for(Restaurant restaurant : restaurantList){
Double latDistance = toRad(latitude-restaurant.getLatitude());
Double lonDistance = toRad(longitude-restaurant.getLongitude());
Double a = Math.sin(latDistance / 2) * Math.sin(latDistance / 2) +
Math.cos(toRad(latitude)) * Math.cos(toRad(restaurant.getLatitude())) *
Math.sin(lonDistance / 2) * Math.sin(lonDistance / 2);
Double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
Double distance = R * c;
restaurant.setDistanceFromUser(distance);
if(distance < 10){
restaurant.setDistanceFromUser((restaurant.getDistanceFromUser()*1000));
nearbyRestaurantList.add(restaurant);
}
String restaurantIdentifierImageString = this.restaurantImageService.getProfileIdentifierForRestaurant(restaurant.getRestaurantId());
if(!(restaurantIdentifierImageString == null)){
try {
try {
File imagePath = new File(restaurantImagePath + restaurantIdentifierImageString +".png");
BufferedImage bufferedImage = ImageIO.read(imagePath);
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ImageIO.write(bufferedImage, "png", byteArrayOutputStream);
restaurant.setProfilePicture( base64Encoder.encode(byteArrayOutputStream.toByteArray()));
} catch (Exception e) {
File imagePath = new File(defaultProfilePath);
BufferedImage bufferedImage = ImageIO.read(imagePath);
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ImageIO.write(bufferedImage, "png", byteArrayOutputStream);
restaurant.setProfilePicture(base64Encoder.encode(byteArrayOutputStream.toByteArray()));
}
}catch (Exception e){
e.printStackTrace();
}
}
}
Collections.sort(nearbyRestaurantList, new Comparator<Restaurant>() {
#Override
public int compare(Restaurant o1, Restaurant o2) {
if(o1.getDistanceFromUser() > o2.getDistanceFromUser()){
return 1;
}
if(o1.getDistanceFromUser() < o2.getDistanceFromUser()){
return -1;
}
return 0;
}
});
return nearbyRestaurantList;
}
Error log :
Caused by: java.lang.OutOfMemoryError: Failed to allocate a 13176356 byte allocation with 370616 free bytes and 361KB until OOM
at java.lang.AbstractStringBuilder.<init>(AbstractStringBuilder.java:83)
at java.lang.StringBuilder.<init>(StringBuilder.java:67)
at com.fasterxml.jackson.core.util.TextBuffer.contentsAsString(TextBuffer.java:346)
at com.fasterxml.jackson.core.json.UTF8StreamJsonParser._finishAndReturnString(UTF8StreamJsonParser.java:2412)
at com.fasterxml.jackson.core.json.UTF8StreamJsonParser.getText(UTF8StreamJsonParser.java:285)
at com.fasterxml.jackson.databind.deser.std.StringDeserializer.deserialize(StringDeserializer.java:32)
If any more information is required, kindly let me know. Thank you.
Update
Image retrieval method :
#RequestMapping(value = "/restaurantimage/{identifier}")
public HttpEntity<byte[]> getPhoto(#PathVariable String identifier) {
boolean flag = false;
try {
byte[] image;
try {
image = org.apache.commons.io.FileUtils.readFileToByteArray(new File(restaurantImagePath + identifier +".png"));
} catch (FileNotFoundException e) {
flag = true;
image = org.apache.commons.io.FileUtils.readFileToByteArray(new File(defaultProfilePath));
e.printStackTrace();
}
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.IMAGE_PNG);
headers.setContentLength(image.length);
return new HttpEntity<>(image, headers);
} catch (IOException ignored) {
}
return null;
}
I don't know what is the requirement at your server side, but for Mobile applications, the memory allocated to the application is very limited. The bitmap which you maybe sending must be of some kilobytes, when it is received, you store that in String or byte array and then write it up in a String.
This consumes a lot of memory of your application and also can create performance issues.
As an alternate approach for it, you can just give the url of the image from your server in a json string and then pass that url to the method of some Imagehelper/Lazyloading library like Volley.
I was finally able to solve the problem by loading the image from Picaso and just sending the URL of the image from the server-side.
Code :
Picasso.with(view.getContext())
Picasso.load(StaticRestTemplate.baseURL+"restaurantimage/"+restaurantList.get(RestaurantList.restoProfilePicture))
.config(Bitmap.Config.RGB_565)
.fit()
.centerInside()
.into(restoImage);
I'm using asynctask to download image to listview with custom cursoradapter. The images are downloaded to the first item in the list and when I scroll down to the second and so on. It's not synchronize and it's not the right picture. What am I doing wrong?
I cant upload pictures so here is my code:
class DownloadItemdPoster extends AsyncTask {
#Override
protected Bitmap doInBackground(String... params) {
// get the address from the params:
String address = params[0];
HttpURLConnection connection = null;
InputStream stream = null;
ByteArrayOutputStream outputStream = null;
// the bitmap will go here:
Bitmap b = null;
try {
// build the URL:
URL url = new URL(address);
// open a connection:
connection = (HttpURLConnection) url.openConnection();
// check the connection response code:
if (connection.getResponseCode() != HttpURLConnection.HTTP_OK) {
// not good..
return null;
}
// the input stream:
stream = connection.getInputStream();
// get the length:
int length = connection.getContentLength();
// tell the progress dialog the length:
// this CAN (!!) be modified outside the UI thread !!!
// progressDialog.setMax(length);
// a stream to hold the read bytes.
// (like the StringBuilder we used before)
outputStream = new ByteArrayOutputStream();
// a byte buffer for reading the stream in 1024 bytes chunks:
byte[] buffer = new byte[1024];
int totalBytesRead = 0;
int bytesRead = 0;
// read the bytes from the stream
while ((bytesRead = stream.read(buffer, 0, buffer.length)) != -1) {
totalBytesRead += bytesRead;
outputStream.write(buffer, 0, bytesRead);
// notify the UI thread on the progress so far:
// publishProgress(totalBytesRead);
Log.d("TAG", "progress: " + totalBytesRead + " / " + length);
}
// flush the output stream - write all the pending bytes in its
// internal buffer.
outputStream.flush();
// get a byte array out of the outputStream
// theses are the bitmap bytes
byte[] imageBytes = outputStream.toByteArray();
// use the BitmapFactory to convert it to a bitmap
b = BitmapFactory.decodeByteArray(imageBytes, 0, length);
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (connection != null) {
// close connection:
connection.disconnect();
}
if (outputStream != null) {
try {
// close output stream:
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return b;
}
#Override
protected void onPostExecute(Bitmap result) {
ImageView itemPoster = (ImageView) findViewById(R.id.imageViewItemPoster);
if (result == null) {
// no image loaded - display the default image
itemPoster.setBackgroundResource(R.drawable.defaultitembackground);
Toast.makeText(MainActivity.this, "Error Loading Image",
Toast.LENGTH_LONG).show();
} else {
// set the showactivitybackground to the poster:
itemPoster.setImageBitmap(result);
}
};
}
public class MovieAdapter extends CursorAdapter {
public MovieAdapter(Context context, Cursor c) {
super(context, c);
}
#Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
return getLayoutInflater().inflate(R.layout.movies_item_layout,
parent, false);
}
#Override
public void bindView(View view, Context context, Cursor cursor) {
String movieName = cursor.getString(cursor
.getColumnIndex(DbConstants.MOVIE_NAME));
String movieGenre = cursor.getString(cursor
.getColumnIndex(DbConstants.MOVIE_GENRE));
String itemPoster = cursor.getString(cursor
.getColumnIndexOrThrow(DbConstants.MOVIE_POSTER));
String movieRuntime = cursor.getString(cursor
.getColumnIndex(DbConstants.MOVIE_RUNTIME));
String movieRating = cursor.getString(cursor
.getColumnIndex(DbConstants.MOVIE_RATING));
String movieReleasedYear = cursor.getString(cursor
.getColumnIndex(DbConstants.MOVIE_YEAR_RELEASD));
TextView name = (TextView) view
.findViewById(R.id.textViewMovieName);
TextView genre = (TextView) view
.findViewById(R.id.textViewMovieGenre);
TextView runtime = (TextView) view
.findViewById(R.id.textViewMovieRuntime);
TextView rating = (TextView) view
.findViewById(R.id.textViewMovieRating);
TextView year = (TextView) view
.findViewById(R.id.textViewMovieYear);
ImageView setItemPoster = (ImageView) view
.findViewById(R.id.imageViewItemPoster);
setItemPoster.setTag(1);
name.setText(movieName);
genre.setText("*" + movieGenre);
runtime.setText("*" + movieRuntime);
rating.setText("*" + "R:" + " " + movieRating);
year.setText("*" + movieReleasedYear);
if (setItemPoster != null) {
new DownloadItemdPoster().execute(itemPoster);
adapter.notifyDataSetChanged();
}
You can use Glide library to load image from server.Example :
Glide.with(mContext).load(url).into(myImageView);
You must have to use image loader lib(picasso , volley , universal loader lib) rather than make aysntask to load image from server.
UniversalLoaderLib
Example:-
Initiate below code in your adapter or activity once.
DisplayImageOptions options = new DisplayImageOptions.Builder().showImageOnLoading(R.drawable.loading_icon).showImageForEmptyUri(R.drawable.ic_error_transparent).showImageOnFail(R.drawable.ic_error_transparent)
.cacheOnDisc(true).bitmapConfig(Bitmap.Config.RGB_565)/*.considerExifParams(true)*/.build();
ImageLoader.getInstance().init(ImageLoaderConfiguration.createDefault(activity.getBaseContext()));
Use below code where you want to load image from server.
ImageLoader.getInstance().displayImage(urladdress, imageview, options);
I am creating an app with many products being loaded from a JSON file. Everything is working fine, but I have a small problem and I am having difficulty finding an answer to it. On a click of a button, I get all data from JSON file located on a server (it contains a URL value to get the picture of the product). When the button is clicked I would like to move to a list of products straight away and only load visible images. Instead it takes about 8 seconds to load and it loads all images before hand. Could somebody please tell me what am I doing wrong? I read online I should use something like so: imageLoader.DisplayImage(data[position], image);, but I am using a Hashmap, not just a string.
Here is my code, any help would be greatly appreciated:
LazyAdapter
public class LazyAdapter extends BaseAdapter {
private Activity activity;
private ArrayList<HashMap<String, String>> data;
private static LayoutInflater inflater=null;
public ImageLoader imageLoader;
public LazyAdapter(Activity a, ArrayList<HashMap<String, String>> d) {
activity = a;
data=d;
inflater = (LayoutInflater)activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
imageLoader=new ImageLoader(activity.getApplicationContext());
}
public int getCount() {
return data.size();
}
public Object getItem(int position) {
return position;
}
public long getItemId(int position) {
return position;
}
public View getView(int position, View convertView, ViewGroup parent) {
View vi=convertView;
if(convertView==null)
vi = inflater.inflate(R.layout.list_row, null);
TextView brand = (TextView)vi.findViewById(R.id.brand); // title
TextView name = (TextView)vi.findViewById(R.id.name); // artist name
TextView price = (TextView)vi.findViewById(R.id.price); // duration
TextView imgValue = (TextView)vi.findViewById(R.id.imgValue);
//TextView rating = (TextView)vi.findViewById(R.id.rating); // rating
ImageView thumb_image=(ImageView)vi.findViewById(R.id.list_image); // thumb image
HashMap<String, String> products = new HashMap<String, String>();
products = data.get(position);
// Setting all values in listview
brand.setText(products.get(CustomizedListView.TAG_BRAND));
name.setText(products.get(CustomizedListView.TAG_NAME));
price.setText("£" + products.get(CustomizedListView.TAG_MIN_GBP));
imgValue.setText(products.get(CustomizedListView.TAG_IMG));
imgValue.setVisibility(View.GONE);
//rating.setText("Rating: " + song.get(CustomizedListView.TAG_RATING_NO) + "/5");
imageLoader.DisplayImage("http://debenhams.scene7.com/is/image/Debenhams/" + imgValue.getText() + "?hei=440&op_usm=1.1,0.5,0,0", thumb_image);
return vi;
}
}
ListView
public class CustomizedListView extends Activity {
// All static variables
static final String link = "https://dl.dropboxusercontent.com/u/142838353/productlist.json";
// XML node keys
static final String TAG_PRODUCTS = "Products";
static final String TAG_PRODNUM = "prodnum";
static final String TAG_BRAND = "brand";
static final String TAG_NAME = "name"; // parent node
static final String TAG_MIN_GBP = "minGBP";
static final String TAG_IMG = "img";
static final String TAG_RATING_NO = "rating_number";
JSONArray products = null;
ListView list;
LazyAdapter adapter;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.shop);
// Hashmap for ListView
ArrayList<HashMap<String, String>> productList = new ArrayList<HashMap<String, String>>();
// Creating JSON Parser instance
JSONParser jParser = new JSONParser();
// getting JSON string from URL
JSONObject json = jParser.getJSONFromUrl(link);
try {
// Getting Array of Contacts
products = json.getJSONArray(TAG_PRODUCTS);
// looping through All Contacts
for(int i = 0; i < products.length(); i++){
JSONObject c = products.getJSONObject(i);
// Storing each json item in variable
// String prodnum = c.getString(TAG_PRODNUM);
String brand = c.getString(TAG_BRAND);
String name = c.getString(TAG_NAME);
String img = c.getString(TAG_IMG);
String price = c.getString(TAG_MIN_GBP);
//String ratingNo = c.getString(TAG_RATING_NO);
// creating new HashMap
HashMap<String, String> map = new HashMap<String, String>();
// adding each child node to HashMap key => value
map.put(TAG_MIN_GBP, price);
map.put(TAG_BRAND, brand);
map.put(TAG_NAME, name);
map.put(TAG_IMG, img);
//map.put(TAG_RATING_NO, ratingNo);
// adding HashList to ArrayList
productList.add(map);
}
} catch (JSONException e) {
e.printStackTrace();
}
list=(ListView)findViewById(R.id.list);
// Getting adapter by passing xml data ArrayList
adapter=new LazyAdapter(this, productList);
list.setAdapter(adapter);
// Click event for single list row
list.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
String brand = ((TextView) view.findViewById(R.id.brand)).getText().toString();
String name = ((TextView) view.findViewById(R.id.name)).getText().toString();
String imgValue = ((TextView) view.findViewById(R.id.imgValue)).getText().toString();
String price = ((TextView) view.findViewById(R.id.price)).getText().toString();
//String imgVal = ((ImageView) view.findViewById(R.id.list_image)).;
//String imgVal = ((ImageView) view.findViewById(R.id.img)).getResources().toString();
// Starting new intent
Intent in = new Intent(getApplicationContext(), ProductActivity.class);
in.putExtra(TAG_BRAND, brand);
in.putExtra(TAG_NAME, name);
in.putExtra(TAG_IMG, imgValue);
in.putExtra(TAG_MIN_GBP, price);
startActivity(in);
}
});
}
#Override
public void onDestroy()
{
list.setAdapter(null);
super.onDestroy();
}
}
ImageLoader
public class ImageLoader {
MemoryCache memoryCache=new MemoryCache();
FileCache fileCache;
private Map<ImageView, String> imageViews=Collections.synchronizedMap(new WeakHashMap<ImageView, String>());
ExecutorService executorService;
Handler handler=new Handler();//handler to display images in UI thread
public ImageLoader(Context context){
fileCache=new FileCache(context);
executorService=Executors.newFixedThreadPool(5);
}
final int stub_id=R.drawable.default_image;
public void DisplayImage(String url, ImageView imageView)
{
imageViews.put(imageView, url);
Bitmap bitmap=memoryCache.get(url);
if(bitmap!=null)
imageView.setImageBitmap(bitmap);
else
{
queuePhoto(url, imageView);
imageView.setImageResource(stub_id);
}
}
private void queuePhoto(String url, ImageView imageView)
{
PhotoToLoad p=new PhotoToLoad(url, imageView);
executorService.submit(new PhotosLoader(p));
}
private Bitmap getBitmap(String url)
{
File f=fileCache.getFile(url);
//from SD cache
Bitmap b = decodeFile(f);
if(b!=null)
return b;
//from web
try {
Bitmap bitmap=null;
URL imageUrl = new URL(url);
HttpURLConnection conn = (HttpURLConnection)imageUrl.openConnection();
conn.setConnectTimeout(30000);
conn.setReadTimeout(30000);
conn.setInstanceFollowRedirects(true);
InputStream is=conn.getInputStream();
OutputStream os = new FileOutputStream(f);
Utils.CopyStream(is, os);
os.close();
conn.disconnect();
bitmap = decodeFile(f);
return bitmap;
} catch (Throwable ex){
ex.printStackTrace();
if(ex instanceof OutOfMemoryError)
memoryCache.clear();
return null;
}
}
//decodes image and scales it to reduce memory consumption
private Bitmap decodeFile(File f){
try {
//decode image size
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
FileInputStream stream1=new FileInputStream(f);
BitmapFactory.decodeStream(stream1,null,o);
stream1.close();
//Find the correct scale value. It should be the power of 2.
final int REQUIRED_SIZE=256;
int width_tmp=o.outWidth, height_tmp=o.outHeight;
int scale=1;
while(true){
if(width_tmp/2<REQUIRED_SIZE || height_tmp/2<REQUIRED_SIZE)
break;
width_tmp/=2;
height_tmp/=2;
scale*=2;
}
//decode with inSampleSize
BitmapFactory.Options o2 = new BitmapFactory.Options();
o2.inSampleSize=scale;
FileInputStream stream2=new FileInputStream(f);
Bitmap bitmap=BitmapFactory.decodeStream(stream2, null, o2);
stream2.close();
return bitmap;
} catch (FileNotFoundException e) {
}
catch (IOException e) {
e.printStackTrace();
}
return null;
}
//Task for the queue
private class PhotoToLoad
{
public String url;
public ImageView imageView;
public PhotoToLoad(String u, ImageView i){
url=u;
imageView=i;
}
}
class PhotosLoader implements Runnable {
PhotoToLoad photoToLoad;
PhotosLoader(PhotoToLoad photoToLoad){
this.photoToLoad=photoToLoad;
}
#Override
public void run() {
try{
if(imageViewReused(photoToLoad))
return;
Bitmap bmp=getBitmap(photoToLoad.url);
memoryCache.put(photoToLoad.url, bmp);
if(imageViewReused(photoToLoad))
return;
BitmapDisplayer bd=new BitmapDisplayer(bmp, photoToLoad);
handler.post(bd);
}catch(Throwable th){
th.printStackTrace();
}
}
}
boolean imageViewReused(PhotoToLoad photoToLoad){
String tag=imageViews.get(photoToLoad.imageView);
if(tag==null || !tag.equals(photoToLoad.url))
return true;
return false;
}
//Used to display bitmap in the UI thread
class BitmapDisplayer implements Runnable
{
Bitmap bitmap;
PhotoToLoad photoToLoad;
public BitmapDisplayer(Bitmap b, PhotoToLoad p){bitmap=b;photoToLoad=p;}
public void run()
{
if(imageViewReused(photoToLoad))
return;
if(bitmap!=null)
photoToLoad.imageView.setImageBitmap(bitmap);
else
photoToLoad.imageView.setImageResource(stub_id);
}
}
public void clearCache() {
memoryCache.clear();
fileCache.clear();
}
}
If you're not averse to using a library to do it, I had a lot of success with Universal Image Loader. It takes a lot of the complexity of the problem away and is pretty easy to get set up. There's some discussion of the problem from a while back with a few other implementations (I'm not sure if any of them are maintained though). Even if you don't use the library, their design patterns might be a useful starting point.
I want to read images from URL and show it in android gallery widget.
so I wrote below code in onCreate() method .
list = GuideDAO.getAllImages(businessId);
Gallery g = (Gallery) findViewById(R.id.gallery);
g.setSpacing(2);
// Set the adapter to our custom adapter (below)
if(list.size() > 0)
{
g.setAdapter(new ImageAdapter(this,list));
}
This is my ImageAdapter
public class ImageAdapter extends BaseAdapter {
List<Images> glist = null;
private String url;
public ImageAdapter(Context c,List<Images> lst) {
mContext = c;
glist = lst;
int i=0;
for (Images id : glist) {
url = id.getImageURL(); // Getting URL
InputStream inStream = null;
if (url.startsWith("http")) {
url = url.replace(" ", "%20");
HttpURLConnection conn;
try {
conn = (HttpURLConnection)new URL(url).openConnection();
conn.setDoInput(true);
conn.connect();
inStream = conn.getInputStream();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
} else {
try {
inStream = new FileInputStream(url);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
BitmapFactory.Options options = new BitmapFactory.Options();
options.inPreferredConfig = Bitmap.Config.RGB_565;
options.inPurgeable = true;
Bitmap b = BitmapFactory.decodeStream(inStream, null, options);
mImageCollection[i]=b;
i++;
}
}
public int getCount() {
return mImageIds.length;
}
public Object getItem(int position) {
return position;
}
public long getItemId(int position) {
return position;
}
public View getView(int position, View convertView, ViewGroup parent) {
ImageView i = new ImageView(mContext);
i.setImageBitmap(mImageCollection[position]);
i.setScaleType(ImageView.ScaleType.FIT_XY);
i.setLayoutParams(new Gallery.LayoutParams(136, 88));
return i;
}
private Context mContext;
private String[] mImageURLs = {};
private Bitmap[] mImageCollection = {};
}
This throw error because it not in Thread. How can I change this code so that URL reading and image loads in background?
So I have changed my ImageAdapter by using SmartImageView , which handles background thread and caching.
public class ImageAdapter extends BaseAdapter {
List<ImageGallery> glist = null;
private String url;
public ImageAdapter(Context c,List<ImageGallery> lst) {
mContext = c;
glist = lst;
int i=0;
al = new ArrayList<String>();
for (ImageGallery id : glist) {
al.add(id.getImageURL());
}
}
public int getCount() {
return mImageIds.length;
}
public Object getItem(int position) {
return position;
}
public long getItemId(int position) {
return position;
}
public View getView(int position, View convertView, ViewGroup parent) {
Log.d("deepak", "getview gallery");
SmartImageView i = new SmartImageView(mContext);
i.setImageUrl(al.get(position));
i.setScaleType(ImageView.ScaleType.FIT_XY);
i.setLayoutParams(new Gallery.LayoutParams(136, 88));
return i;
}
private Context mContext;
private String[] mImageURLs = {};
private ArrayList<String> al;
private Bitmap[] mImageCollection = {};
private Integer[] mImageIds = {};
}
But my getView() is not getting called now.
you can make use of Smart Image view. SmartImageView is a drop-in replacement for Android’s standard ImageView which additionally allows images to be loaded from URLs or the user’s contact address book. Images are cached to memory and to disk for super fast loading.
Please refer the following link for more info https://github.com/loopj/android-smart-image-view .hope this may help u to accomplish ur task
I'd suggest writing an AsyncImageLoader class and having it handle image downloads from http. This way you can cache and manage everything on separate threads and have it set the image to the view once the loading is complete. Also you could use this class throughout the application if you want to download images elsewhere.
you could call something like mImageLoader.loadImage(myImageView, Url) in your adapter and it would drop it in once it was finished loading.
if you want more details let me know :)