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);
Related
Please help me out
I am fetching image from a JSON API to my android app for each item in my arraylist. The images are fetching correctly, but instead of setting only the image that is meant for each list item, it is looping and interchanging all the images in all the list on one item and all the list items respectively, thereby making the image in each list item to be changing to different images in seconds.
See the JSON file
{ "data":[
{
"sno":1,
"id":"3",
"title":"This Is Great Again",
"desc":"The details of how a UUID is generated are determined by the device manufacturer and are specific to the device's platform or model.The details of...",
"free":"Yes",
"image":"http:\/\/app-web.moneyacademy.ng\/uploads\/145277f3d0499ee8e0dafbac384ca9b4.jpg",
"date_added":"2017-10-12 10:26PM",
"no_comment":3,
"comments":[ ]
},
{
"sno":2,
"id":"6",
"title":"Money Makes The World Go Round",
"desc":"On this realm, nothing works without money. You need to get some of it or else you'll be grounded.",
"free":"Yes",
"image":"http:\/\/app-web.moneyacademy.ng\/uploads\/546a4c29a94f3d70ae9a075ce8afcc6b.jpg",
"date_added":"2018-02-18 10:06AM",
"no_comment":0,
"comments":[ ]
},
{
"sno":3,
"id":"7",
"title":"No One Is Destined To Be Poor",
"desc":"You will not be poor.",
"free":"Yes",
"image":"http:\/\/app-web.moneyacademy.ng\/uploads\/8f19b9cebd1ca4dec74fafcfe23ae0f0.jpg",
"date_added":"2018-02-18 01:03PM",
"no_comment":0,
"comments":[ ]
},
{
"sno":4,
"id":"8",
"title":"What Is Your Money?",
"desc":"Understand the true definition of your money.",
"free":"Yes",
"image":"http:\/\/app-web.moneyacademy.ng\/uploads\/49b35ffb5cabcb7e01dab2d452ec6025.jpg",
"date_added":"2018-02-18 01:30PM",
"no_comment":0,
"comments":[ ]
},
Here is my code for fetching each item and the image
private static ArrayList<nauget> extractFeatureFromJson(String freeNaugetJson) {
// If the JSON string is empty or null, then return early.
if (TextUtils.isEmpty(freeNaugetJson)) {
return null;
}
ArrayList<nauget> naugets = new ArrayList<nauget>();
try {
JSONObject baseJsonResponse = new JSONObject(freeNaugetJson);
JSONArray dataArray = baseJsonResponse.getJSONArray("data");
// If there are results in the data array
for (int i = 0; i < dataArray.length(); i++){
String title = dataArray.getJSONObject(i).getString("title");
String body = dataArray.getJSONObject(i).getString("desc");
String totalComments = dataArray.getJSONObject(i).getString("no_comment");
String image = dataArray.getJSONObject(i).getString("image");
int id = dataArray.getJSONObject(i).getInt("id");
ArrayList<Comment> comments = new ArrayList<Comment>();
//fetch each comment detail
if (Integer.parseInt(totalComments) > 0) {
JSONArray commentArray = dataArray.getJSONObject(i).getJSONArray("comments");
for (int j = 0; j < commentArray.length(); j++) {
String userName = commentArray.getJSONObject(j).getString("userName");
String comment_image = commentArray.getJSONObject(j).getString("userPhoto");
String comment = commentArray.getJSONObject(j).getString("comment");
String date = commentArray.getJSONObject(j).getString("date_commented");
comments.add(new Comment(userName, comment_image, comment, date));
}
}
// Create a new nauget object
naugets.add(new nauget(title, body, image, totalComments, comments, id));
}
} catch (JSONException e) {
Log.e(LOG_TAG, "Problem parsing the nauget JSON results", e);
}
return naugets;
}
Here is my custom adapter code where am setting the image and its text data for each list item.
public class NaugetAddapter extends ArrayAdapter<nauget> {
ArrayList<nauget> naugets;
private nauget currentNauget;
private ImageView naugetImage;
private TextView naugetTitle;
private TextView naugetBody;
private TextView commentCount;
public NaugetAddapter(#NonNull Context context, ArrayList<nauget> naugets) {
super(context, 0, naugets);
}
#NonNull
#Override
public View getView(final int position, #Nullable View convertView, #NonNull ViewGroup parent) {
//check if the convert view is null and inflate the view
if (convertView == null){
convertView = LayoutInflater.from(getContext()).inflate(R.layout.free_nauget_item, parent, false);
}
currentNauget = (nauget) getItem(position);
//find the nauget title textView and set the text
naugetTitle = (TextView) convertView.findViewById(R.id.nauget_title);
naugetTitle.setText(currentNauget.getNauget_title());
//find the nauget body textView and set the text
naugetBody = (TextView) convertView.findViewById(R.id.nauget_body);
naugetBody.setText(currentNauget.getNauget_body());
//set the nauget total comment count
commentCount = (TextView) convertView.findViewById(R.id.comment_count);
commentCount.setText(currentNauget.getNaugetTotalComments());
//set the comment text
TextView commentText = (TextView) convertView.findViewById(R.id.comment_text);
commentText.setText(currentNauget.getNaugetCommentText());
//set the nauget image
naugetImage = (ImageView) convertView.findViewById(R.id.nauget_image);
new DownloadImageTask().execute(currentNauget.getImageUrl());
//set the share icon
ImageView shareIcon = (ImageView) convertView.findViewById(R.id.share_icon);
shareIcon.setImageResource(currentNauget.getNaugetShareIcon());
//set share functionality on the share icon
shareIcon.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent shareIntent = new Intent(Intent.ACTION_SEND);
shareIntent.setType("text/plain");
shareIntent.putExtra(Intent.EXTRA_SUBJECT, "My App");
shareIntent.putExtra(Intent.EXTRA_TEXT,
naugetTitle.getText()
+ "\n" + naugetBody.getText()
+ "\n" + naugetImage.getDrawable());
startActivity(getContext(), Intent.createChooser(shareIntent, "Share via"), null);
}
});
return convertView;
}
private class DownloadImageTask extends AsyncTask<String, Void, Bitmap> {
#Override
protected void onPreExecute() {
super.onPreExecute();
// mLoadingIndicator.setVisibility(View.VISIBLE);
}
protected Bitmap doInBackground(String... urls) {
Bitmap image = null;
HttpURLConnection urlConnection = null;
try {URL url = new URL(urls[0]);
urlConnection = (HttpURLConnection) url.openConnection();
int statusCode = urlConnection.getResponseCode();
if (statusCode != 200) {
return null;
}
InputStream inputStream = urlConnection.getInputStream();
if (inputStream != null) {
Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
return bitmap;
}
} catch (Exception e) {
urlConnection.disconnect();
Log.e("Error", e.getMessage());
e.printStackTrace();
}finally {
if (urlConnection != null) {
urlConnection.disconnect();
}
}
return null;
}
protected void onPostExecute(Bitmap result) {
// mLoadingIndicator.setVisibility(View.INVISIBLE);
naugetImage.setImageBitmap(result);
}
}
#NonNull
#Override
public Filter getFilter() {
return new Filter() {
#Override
protected FilterResults performFiltering(CharSequence constraint) {
ArrayList<nauget> filteredResults = new ArrayList<>();
FilterResults results = new FilterResults();
results.values = filteredResults;
return results;
}
#Override
protected void publishResults(CharSequence constraint, FilterResults results) {
}
};
}
void setFilter(ArrayList<nauget> listItem){
naugets = new ArrayList();
naugets.addAll(listItem);
notifyDataSetChanged();
}
}
This should solve the issue! you are trying everything fine but you have the comment ArrayList inside of a loop getting instantiated each time newly just put it before the outer loop as I did here and the error should go! TRY IT
try {
JSONObject baseJsonResponse = new JSONObject(freeNaugetJson);
JSONArray dataArray = baseJsonResponse.getJSONArray("data");
//put it here so you won't get a new array for each comment in the loop
**ArrayList<Comment> comments = new ArrayList<Comment>();**
// If there are results in the data array
for (int i = 0; i < dataArray.length(); i++){
String title = dataArray.getJSONObject(i).getString("title");
String body = dataArray.getJSONObject(i).getString("desc");
String totalComments = dataArray.getJSONObject(i).getString("no_comment");
String image = dataArray.getJSONObject(i).getString("image");
int id = dataArray.getJSONObject(i).getInt("id");
//here after every comment check its making a new comment ArrayList for each comment and filling it out so this can be the cause of the bug! bcz its in the loop
// ArrayList<Comment> comments = new ArrayList<Comment>();
//fetch each comment detail
if (Integer.parseInt(totalComments) > 0) {
JSONArray commentArray = dataArray.getJSONObject(i).getJSONArray("comments");
for (int j = 0; j < commentArray.length(); j++) {
String userName = commentArray.getJSONObject(j).getString("userName");
String comment_image = commentArray.getJSONObject(j).getString("userPhoto");
String comment = commentArray.getJSONObject(j).getString("comment");
String date = commentArray.getJSONObject(j).getString("date_commented");
comments.add(new Comment(userName, comment_image, comment, date));
}
}
// Create a new nauget object
naugets.add(new nauget(title, body, image, totalComments, comments, id));
}
} catch (JSONException e) {
Log.e(LOG_TAG, "Problem parsing the nauget JSON results", e);
}
return naugets;
I'm working on uploading multiple images. I can pick an image from my phone's sd card but when I'm trying to upload it to my database, the progress dialog shows "Uploading" only and after that it is being dismissed. Honestly, I'm not sure on my php code. Hope someone can help me :)
Here's my uploadActivity.java:
#SuppressLint("NewApi")
public class MainActivity extends Activity {
private Button upload, pick;
private ProgressDialog dialog;
MultipartEntity entity;
GridView gv;
int count = 0;
public ArrayList<String> map = new ArrayList<String>();
Bundle b;
TextView noImage;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder()
.permitAll().build();
StrictMode.setThreadPolicy(policy);
b = getIntent().getExtras();
noImage = (TextView) findViewById(R.id.noImage);
upload = (Button) findViewById(R.id.btnUpload);
pick = (Button) findViewById(R.id.btnPicture);
gv = (GridView) findViewById(R.id.gridview);
gv.setAdapter(new ImageAdapter(this));
if (b != null) {
ArrayList<String> ImgData = b.getStringArrayList("IMAGE");
for (int i = 0; i < ImgData.size(); i++) {
map.add(ImgData.get(i).toString());
}
} else {
noImage.setVisibility(View.VISIBLE);
}
upload.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
new ImageUploadTask()
.execute(count + "", "pk" + count + ".jpg");
}
});
pick.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Intent i3 = new Intent(MainActivity.this, UploadActivity.class);
startActivity(i3);
}
});
}
class ImageUploadTask extends AsyncTask<String, Void, String> {
String sResponse = null;
#Override
protected void onPreExecute() {
// TODO Auto-generated method stub
super.onPreExecute();
dialog = ProgressDialog.show(MainActivity.this, "Uploading",
"Please wait...", true);
dialog.show();
}
#Override
protected String doInBackground(String... params) {
try {
String url = "http://iguideph-001-btempurl.com/uploads.php";
int i = Integer.parseInt(params[0]);
Bitmap bitmap = decodeFile(map.get(i));
HttpClient httpClient = new DefaultHttpClient();
HttpContext localContext = new BasicHttpContext();
HttpPost httpPost = new HttpPost(url);
entity = new MultipartEntity();
ByteArrayOutputStream bos = new ByteArrayOutputStream();
bitmap.compress(CompressFormat.JPEG, 100, bos);
byte[] data = bos.toByteArray();
entity.addPart("user_id", new StringBody("199"));
entity.addPart("club_id", new StringBody("10"));
entity.addPart("club_image", new ByteArrayBody(data,
"image/jpeg", params[1]));
httpPost.setEntity(entity);
HttpResponse response = httpClient.execute(httpPost,
localContext);
sResponse = EntityUtils.getContentCharSet(response.getEntity());
System.out.println("sResponse : " + sResponse);
} catch (Exception e) {
if (dialog.isShowing())
dialog.dismiss();
Log.e(e.getClass().getName(), e.getMessage(), e);
}
return sResponse;
}
#Override
protected void onPostExecute(String sResponse) {
try {
if (dialog.isShowing())
dialog.dismiss();
if (sResponse != null) {
Toast.makeText(getApplicationContext(),
sResponse + " Photo uploaded successfully",
Toast.LENGTH_SHORT).show();
count++;
if (count < map.size()) {
new ImageUploadTask().execute(count + "", "hm" + count
+ ".jpg");
}
}
} catch (Exception e) {
Toast.makeText(getApplicationContext(), e.getMessage(),
Toast.LENGTH_LONG).show();
Log.e(e.getClass().getName(), e.getMessage(), e);
}
}
}
public Bitmap decodeFile(String filePath) {
// Decode image size
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
BitmapFactory.decodeFile(filePath, o);
// The new size we want to scale to
final int REQUIRED_SIZE = 1024;
// Find the correct scale value. It should be the power of 2.
int width_tmp = o.outWidth, height_tmp = o.outHeight;
int scale = 1;
while (true) {
if (width_tmp < REQUIRED_SIZE && height_tmp < REQUIRED_SIZE)
break;
width_tmp /= 2;
height_tmp /= 2;
scale *= 2;
}
BitmapFactory.Options o2 = new BitmapFactory.Options();
o2.inSampleSize = scale;
Bitmap bitmap = BitmapFactory.decodeFile(filePath, o2);
return bitmap;
}
private class ImageAdapter extends BaseAdapter {
private Context mContext;
public ImageAdapter(Context c) {
mContext = c;
}
public int getCount() {
return map.size();
}
public Object getItem(int position) {
return null;
}
// create a new ImageView for each item referenced by the Adapter
public View getView(int position, View convertView, ViewGroup parent) {
ImageView imageView;
if (convertView == null) { // if it's not recycled, initialize some
// attributes
imageView = new ImageView(mContext);
imageView.setLayoutParams(new GridView.LayoutParams(85, 85,
Gravity.CENTER));
imageView.setScaleType(ImageView.ScaleType.FIT_XY);
imageView.setPadding(1, 1, 1, 1);
} else {
imageView = (ImageView) convertView;
}
imageView
.setImageBitmap(BitmapFactory.decodeFile(map.get(position)));
return imageView;
}
#Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return 0;
}
}
#Override
public void onBackPressed() {
// TODO Auto-generated method stub
super.onBackPressed();
MainActivity.this.finish();
}
}
and here's my uploads.php:
<?php
if($_SERVER['REQUEST_METHOD']=='POST'){
$image = $_POST['club_image'];
$userid=$_POST['user_id'];
$clubid=$_POST['club_id'];
require_once('connection.php');
$sql ="SELECT * FROM photos ORDER BY id ASC";
$res = mysqli_query($con,$sql);
$id = 0;
while($row = mysqli_fetch_array($res)){
$id = $row['id'];
}
$path = "uploads/$id.jpg";
$actualpath = "http://iguideph-001-site1.btempurl.com/PhotoUpload/$path";
$sql = "INSERT INTO photos (image) VALUES ('$actualpath')";
if(mysqli_query($con,$sql)){
file_put_contents($path,base64_decode($image));
echo "Successfully Uploaded";
}
mysqli_close($con);
}else{
echo "Error";
}
?>
I'm using universal image loader, to load images for custom info windows on my Google map. But in most cases it doesn't load images, it shows picture for empty uri.
Here's my code
In MainActivity:
initImageLoader();
markers = new Hashtable<String, String>();
imageLoader = ImageLoader.getInstance();
options = new DisplayImageOptions.Builder()
.showStubImage(R.drawable.loading)
.showImageForEmptyUri(R.drawable.empty)
.showImageOnFail(R.drawable.error)
.cacheInMemory(true)
.cacheOnDisc(true).bitmapConfig(Bitmap.Config.RGB_565)
.build();
map.setInfoWindowAdapter(new CustomInfoWindowAdapter());
ReadXML readXml = new ReadXML();
readXml.getXml(camera);
for (int i = 0; i<camera.size(); i++) {
Camera cam = camera.get(i);
LatLng coord = new LatLng(cam.lat, cam.lon);
String title = Integer.toString(cam.id);
String place = cam.place;
String url = cam.img;
Marker mark = map.addMarker(new MarkerOptions()
.position(coord)
.title(title)
.snippet(place)
.icon(BitmapDescriptorFactory
.fromResource(R.drawable.green)));
markers.put(mark.getId(), url);
}
Custom Info Window Adapter:
private class CustomInfoWindowAdapter implements InfoWindowAdapter
{
private View view;
public CustomInfoWindowAdapter()
{
view = getLayoutInflater().inflate(R.layout.custom_info_window,
null);
}
#Override
public View getInfoContents(Marker marker)
{
if (MyMapActivity.this.marker != null && MyMapActivity.this.marker.isInfoWindowShown())
{
MyMapActivity.this.marker.hideInfoWindow();
MyMapActivity.this.marker.showInfoWindow();
}
return null;
}
#Override
public View getInfoWindow(final Marker marker)
{
MyMapActivity.this.marker = marker;
String url = markers.get(marker.getId());
final ImageView image = ((ImageView) view.findViewById(R.id.badge));
imageLoader.displayImage(url, image, options,
new SimpleImageLoadingListener() {
#Override
public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage)
{
super.onLoadingComplete(imageUri, view, loadedImage);
getInfoContents(marker);
}
});
final String title = "Камера №" + marker.getTitle();
final TextView titleUi = ((TextView) view.findViewById(R.id.title));
if (title != null) {
titleUi.setText(title);
} else {
titleUi.setText("");
}
final String snippet = marker.getSnippet();
final TextView snippetUi = ((TextView) view
.findViewById(R.id.snippet));
if (snippet != null) {
snippetUi.setText(snippet);
} else {
snippetUi.setText("");
}
return view;
}
}
And Universal Image Loader:
private void initImageLoader()
{
int memoryCacheSize;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ECLAIR) {
int memClass = ((ActivityManager)
getSystemService(Context.ACTIVITY_SERVICE))
.getMemoryClass();
memoryCacheSize = (memClass / 8) * 1024 * 1024;
} else {
memoryCacheSize = 2 * 1024 * 1024;
}
final ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(
this).threadPoolSize(5)
.threadPriority(Thread.NORM_PRIORITY - 2)
.memoryCacheSize(memoryCacheSize)
.memoryCache(new FIFOLimitedMemoryCache(memoryCacheSize-1000000))
.denyCacheImageMultipleSizesInMemory()
.discCacheFileNameGenerator(new Md5FileNameGenerator())
.tasksProcessingOrder(QueueProcessingType.LIFO).writeDebugLogs()
.build();
ImageLoader.getInstance().init(config);
}
Have you taken a look at what the following line actually sets the sring to?
String url = markers.get(marker.getId());
I would suspect if this works like other google maps implementations that marker is a json string/object with multiple pieces of information and that you need to get it and then get the url from it. Try and do some logcat logging to be sure, you've posted a lot of code so it's hard to tell which parts are relevant.
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 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;
}
}