I am using this code to get Strings of names and ages from my ParseObject
in Parse. I assumed I can do the same for imagefiles as well. But this code doesn't work for the images. I may have done it wrong. or maybe I need to do something totally different. Can someone help me to get my imagefile from parseObject?
Thank you
public class MyAdapter extends ArrayAdapter<ParseObject> {
protected Context mContext;
protected List<ParseObject> MyPerson;
public MyAdapter (Context context, List<ParseObject> MyPerson){
super(context, R.layout.scustomlayout, MyPerson);
mContext = context;
mPerson = MyPerson;
}
#Override
public View getView (final int position, View convertView, ViewGroup Parent){
final ViewHolder holder;
if(convertView == null) {
convertView = LayoutInflater.from(mContext).inflate(R.layout.personcustomlayout, null);
holder = new ViewHolder();
holder.NameMain = (TextView) convertView.findViewById(R.id.NameHP);
holder.AgeMain = (TextView) convertView.findViewById(R.id.AgeHP);
holder.ImageMain = (ImageView) convertView.findViewById(R.id.ImageHP);
convertView.setTag(holder);
}else {
holder = (ViewHolder) convertView.getTag();
}
ParseObject personObject = mPerson.get(position);
//name
String name = personObject.getString("Name");
holder.NameMain.setText(name);
//Age
String age = personObject.getString("Age");
holder.AgeMain.setText(age);
ParseFile image = (ParseFile) personObject.get("Image");
image.getDataInBackground(new GetDataCallback() {
public void done(byte[] data, ParseException e) {
if (e == null) {
// Decode the Byte[] into bitmap
Bitmap bmp = BitmapFactory.decodeByteArray(data, 0, data.length);
// Set the Bitmap into the imageView
holder.ImageMain.setImageBitmap(bmp);
} else {
Log.d("test", "There was a problem downloading the data.");
}
}
});
return convertView;
}
public static class ViewHolder {
ImageView ImageMain;
TextView NameMain;
TextView AgeMain;
}
}
ParseFile image = (ParseFile) personObject.get("Image");
image.getDataInBackground(new GetDataCallback() {
public void done(byte[] data, ParseException e) {
if (e == null) {
// Decode the Byte[] into bitmap
Bitmap bmp = BitmapFactory.decodeByteArray(data, 0,data.length);
// Set the Bitmap into the imageView
holder.ImageMain.setImageBitmap(bmp);
} else {
Log.d("test", "There was a problem downloading the data.");
}
}
});
Also, add this to the imports:
import com.parse.ParseException;
An easier and better option would be to get the file URL and load it into the ImageView via a third party library such as Picasso or Glide. This way, your code is less cumbersome, your ListView will scroll smoothly and your won't encounter OOM error too often.
ParseFile image = (ParseFile) personObject.get("Image");
String url = image.getUrl();
// With Picasso
Picasso.with(mContext).load(url).into(holder.ImageMain);
// With Glide
Glide.with(mContext).load(url).into(holder.ImageMain);
There is no need to create the new String object url, you could do it directly, I just did it to make it easier to understand.
Also, it would be better to save the URL to the MyPerson object when you run the ParseQuery, this will make your images load faster
Related
I'm solving my problem about Image Loader and I have some problems..
What I want is to show many images (about 400) in GridView(or ListView).
I don't want to use the Library like Picasso, Glide like that.
and Here is the problem.
When I call the method which convert from url to bitmap?
3.1. before setAdapter, then pass the bitmap array.
3.2. while getView.
two things are working well. but too much slow... maybe cuz of the times to call URLConnection..
Could anyone help me about these problem? How can I speed up? or are there any other solution without Open Source.
Here is my Source.
Now, 3-1.
ShowImage
private void showImages(ArrayList<String> imgUrls) {
ArrayList<Bitmap> bitmaps = new ArrayList<>();
for (int i = 0; i < imgUrls.size(); i++) {
try {
String img_path = imgUrls.get(i);
Bitmap bitmap = new UriToBitmapAsyncTask().execute(img_path).get();
bitmaps.add(bitmap);
} catch (Exception e) {
Toast.makeText(this, e.getMessage(), Toast.LENGTH_SHORT).show();
}
}
CustomAdapter adapter = new CustomAdapter(getApplicationContext(),R.layout.row,bitmaps);
gridView.setAdapter(adapter);
}
and This is the customAdapter's GetView
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder viewHolder;
if (convertView == null) {
convertView = inflator.inflate(rowLayout, parent, false);
viewHolder = new ViewHolder();
viewHolder.imageView = (ImageView) convertView.findViewById(R.id.imageView);
convertView.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) convertView.getTag();
}
viewHolder.imageView.setImageBitmap(bitmaps.get(position));
return convertView;
}
You should really take Reinventing the wheel to heart but if you really want to toture yourself an Approach could be:
use a ThreadPoolExecutor to fetch more images at once, you should read up how to use them
implement a way to cancel threads who load a img for a griditem which isn't displayed anymore
use two sets of data a thumbnail which loads faster for the grid view and a real image which gets loaded when the user clicks on the grid
dont't forget to use a LRU caching method or your device will run out of memory depending on the images
Don't use ArrayList to store bitmaps. Bitmaps usually take consumes a lot of memory. Try using LRUCache like this way,
public class TCImageLoader implements ComponentCallbacks2 {
private TCLruCache cache;
public TCImageLoader(Context context) {
ActivityManager am = (ActivityManager) context.getSystemService(
Context.ACTIVITY_SERVICE);
int maxKb = am.getMemoryClass() * 1024;
int limitKb = maxKb / 8; // 1/8th of total ram
cache = new TCLruCache(limitKb);
}
public void display(String url, ImageView imageview, int defaultresource) {
imageview.setImageResource(defaultresource);
Bitmap image = cache.get(url);
if (image != null) {
imageview.setImageBitmap(image);
}
else {
new SetImageTask(imageview).execute(url);
}
}
private class TCLruCache extends LruCache<String, Bitmap> {
public TCLruCache(int maxSize) {
super(maxSize);
}
#Override
protected int sizeOf(ImagePoolKey key, Bitmap value) {
int kbOfBitmap = value.getByteCount() / 1024;
return kbOfBitmap;
}
}
private class SetImageTask extends AsyncTask<String, Void, Integer> {
private ImageView imageview;
private Bitmap bmp;
public SetImageTask(ImageView imageview) {
this.imageview = imageview;
}
#Override
protected Integer doInBackground(String... params) {
String url = params[0];
try {
bmp = getBitmapFromURL(url);
if (bmp != null) {
cache.put(url, bmp);
}
else {
return 0;
}
} catch (Exception e) {
e.printStackTrace();
return 0;
}
return 1;
}
#Override
protected void onPostExecute(Integer result) {
if (result == 1) {
imageview.setImageBitmap(bmp);
}
super.onPostExecute(result);
}
private Bitmap getBitmapFromURL(String src) {
try {
URL url = new URL(src);
HttpURLConnection connection
= (HttpURLConnection) url.openConnection();
connection.setDoInput(true);
connection.connect();
InputStream input = connection.getInputStream();
Bitmap myBitmap = BitmapFactory.decodeStream(input);
return myBitmap;
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
}
#Override
public void onConfigurationChanged(Configuration newConfig) {
}
#Override
public void onLowMemory() {
}
#Override
public void onTrimMemory(int level) {
if (level >= TRIM_MEMORY_MODERATE) {
cache.evictAll();
}
else if (level >= TRIM_MEMORY_BACKGROUND) {
cache.trimToSize(cache.size() / 2);
}
}
}
get a instance of TCImageLoader and call display method appropriately.
I need to update the list with images retrieved in the background using Parse service. Using below code, I could retrieve images and display but interaction is quite slow. Is there any better way to update the ListView dynamically without impacting user interaction speed?
ParseQuery<ParseObject> userFeedQuery = ParseQuery.getQuery("Offers");
userFeedQuery.findInBackground(new FindCallback<ParseObject>() {
#Override
public void done(List<ParseObject> objects, ParseException e) {
if (e == null){
if (objects.size() > 0){
for (ParseObject object:objects){
final String offerName = object.getString("offerName");
final String offerDetail = object.getString("offerDetails");
final Bitmap[] offerImage = new Bitmap[1];
ParseFile file = (ParseFile) object.getParseFile("offerImage");
file.getDataInBackground(new GetDataCallback() {
#Override
public void done(byte[] data, ParseException e) {
if (e == null){
offerImage[0] = BitmapFactory.decodeByteArray(data,0,data.length);
offerModelList.add(new OfferModel(offerName,offerDetail, offerImage[0]));
adapter.notifyDataSetChanged();
}
}
});
}
}
adapter = new OffersAdapter(getApplicationContext(),R.layout.offers_table,offerModelList);
offersListView.setAdapter(adapter);
}
}
});
Yes, you can replace ParseImageView with Picaso or Glide, but i prefere Picaso.
Replace
ParseFile file = (ParseFile) object.getParseFile("offerImage");
With this
String OfferImageUrl = object.getParseFile("offerImage");
if (!TextUtils.isEmpty(OfferImageUrl)) {
Picasso.with(this) // use getContext or contex for fragments or adapter
.load(OfferImageUrl)
.error(android.R.drawable.error) // your own error image
.into(mOfferImage); // mOfferImage = (ImageView) findViewById(R.id.offer_image);
}
Hope this help. Let me know for any assistance about this question.
I am trying to download the image from parse.com and display in a image view in an Activity extending AppCompatActivity.
I got this code from one of many searches:
ParseImageView mImage = (ParseImageView) findViewById(R.id.image);
ParseObject object = new ParseObject("Appetizers"); // class name
ParseFile postImage = object.getParseFile("imageFiles"); // column name
String imageUrl = postImage.getUrl() ;//live url
Uri imageUri = Uri.parse(imageUrl);
Picasso.with(getBaseContext()).load(imageUri.toString()).into(mImage);
File format: jpg
Here's my solution. On my activity, extending AppCompatActivity, this is the code to download an image inside ImageView:
ImageLoader.ImageCache imageCache = new BitmapLruCache();
ImageLoader imageLoader = new ImageLoader(Volley.newRequestQueue(getApplicationContext()), imageCache);
NetworkImageView headshot = (NetworkImageView) findViewById(R.id.speaker_headshot);
headshot.setImageResource(R.drawable.loading);
headshot.setImageUrl("http://www.anydomain.com/anyimage.jpg", imageLoader);
As you see you will need an addicional class in your project, a file named BitmapLruCache.java. Here is the entire content of it:
public class BitmapLruCache extends LruCache<String, Bitmap> implements ImageLoader.ImageCache {
public BitmapLruCache() { this(getDefaultLruCacheSize()); }
public BitmapLruCache(int sizeInKiloBytes) { super(sizeInKiloBytes); }
#Override
protected int sizeOf(String key, Bitmap value) { return value.getRowBytes() * value.getHeight() / 1024; }
#Override
public Bitmap getBitmap(String url) { return get(url); }
#Override
public void putBitmap(String url, Bitmap bitmap) { put(url, bitmap); }
public static int getDefaultLruCacheSize() {
final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
final int cacheSize = maxMemory / 8;
return cacheSize;
}
}
Finally, for this to work you have to setup a special ImageView inside your layout XML:
<com.android.volley.toolbox.NetworkImageView
android:id="#+id/speaker_headshot"
android:layout_width="match_parent"
android:layout_height="150dp"
android:scaleType="centerCrop"/>
EDIT: For all of this to work you have to import:
1) the Volley library. Do this on your Android Studio: menu File/Project Structure/Modules-app/Tab Dependencies. There you add (+ sign) a Library Dependency and find or search for com.android.volley:volley:1.0.0. That's it. OR simple include this in your build.gradle (module app) file:
dependencies {
compile 'com.android.volley:volley:1.0.0'
}
If you already have a "dependencies" section then just include the line inside it.
AND
2) Put a copy of disklrucache-2.0.2.jar into your "libs" folder ( get the .jar from here https://search.maven.org/remote_content?g=com.jakewharton&a=disklrucache&v=LATEST ) OR insert another "compile" directive inside your "dependencies":
compile 'com.jakewharton:disklrucache:2.0.2'
try on this way.
ParseObject object = new ParseObject("Appetizers"); // class name
ParseFile postImage = object.getParseFile("imageFiles"); // column name
ParseQuery<ParseObject> getimage = new ParseQuery<ParseObject>("Appetizers"); // class
getimage.findInBackground(new FindCallback<ParseObject>() {
#Override
public void done(List<ParseObject> objects, ParseException e) {
// TODO Auto-generated method stub
if (e == null) {
// success
for (ParseObject parseObject : objects) {
ParseFile fileObject = (ParseFile) parseObject.get("imageFiles");
Log.d("test", "get your image ... " + fileObject.getUrl());
Picasso.with(getBaseContext()).load(fileObject.getUrl()).placeholder(R.drawable.ic_launcher)
.into(mImage);
}
} else {
// fail
Log.d("test", "error Message... " + e.getMessage());
}
}
});
your have not set picasso place holder for clear catch memory form picasso lib.
I figured it out by debugging and setting logs everywhere ...
In the sending class:
ParseObject po = mAppetizers.get(position); // get position
String ID = po.getObjectId().toString();
Intent intent = new Intent(Appetizer.this, AppetizerRecipe.class);
intent.putExtra("ID", ID);
startActivity(intent);
In the receiver's class:
final ParseImageView mImage = (ParseImageView) findViewById(R.id.image);
String ID = getIntent().getStringExtra("ID");
ParseQuery<ParseObject> getimage = new ParseQuery<>("Appetizers");
getimage.addAscendingOrder("appetizer");
getimage.whereEqualTo("ID", ID);
Log.d("AppetizerRecipe2", "object: " + ID);
getimage.getInBackground(ID, new GetCallback<ParseObject>() {
#Override
public void done(ParseObject object, ParseException e) {
if (e == null) {
Log.v("what is e?", "e = " + e);
// success
final ParseFile fileObject = (ParseFile)object.get("imageFiles");
fileObject.getDataInBackground(new GetDataCallback() {
public void done(byte[] data, ParseException e) {
if (e == null) {
Log.d("test", "We've got data in data.");
// use data for something
Log.d("test", "Get your image..." + fileObject.getUrl());
Picasso.with(getBaseContext()).load(fileObject.getUrl()).placeholder
(R.drawable.ic_launcher).into(mImage);
} else {
Log.d("test", "There was a problem downloading the data.");
}
}
});
} else {
// fail
Log.d("test", "Error Message..." + e.getMessage());
}
}
});
I'm trying to find a ParseObject by " objectId ", then retrieve the image " ImageFile " and then Load it to the imageview, it doesn't work and i'm getting the USER String, can you help me out with this, it works when i use another query like : query.find()
ParseImageView mealImage = (ParseImageView) findViewById(R.id.icon);
ParseQuery<ParseObject> query1 = ParseQuery.getQuery("Annonces");
query1.getInBackground("ux3Af0cwEx", new GetCallback<ParseObject>() {
public void done(ParseObject Annonces, ParseException e) {
photoFile = (ParseFile) Annonces.get("ImageFile");
text1.setText((CharSequence) Annonces.get("USER"));
}
});
mealImage.setParseFile(photoFile);
mealImage.loadInBackground(new GetDataCallback() {
#Override
public void done(byte[] data, ParseException e) {
}
});
}
The code for displaying image in imageview:
ParseFile image = (ParseFile) userData.getParseFile("user_image");
then call following function.
loadImages( photoFile, mealImage);
private void loadImages(ParseFile thumbnail, final ImageView img) {
if (thumbnail != null) {
thumbnail.getDataInBackground(new GetDataCallback() {
#Override
public void done(byte[] data, ParseException e) {
if (e == null) {
Bitmap bmp = BitmapFactory.decodeByteArray(data, 0, data.length);
img.setImageBitmap(bmp);
} else {
}
}
});
} else {
img.setImageResource(R.drawable.menu);
}
}// load image
If you are using Picasso or Glide for image loading and don't want to change the image loading logic, you can extract image url from ParseFile and load it in background.
Like:
ParseFile thumbnail = parseObject.getParseFile("image");
if(thumbnail != null) {
String imageUrl = thumbnail.getUrl();
Picasso.with(mContext).load(imageUrl).into(imageView);
}
No need to load thumbnail ParseFile data separately.
I'm saving 5 images to my class in parse.com. I'm able to download one image based on objectid in a imageView. I need to download all 5 images to my 5 ImageViews. How can I do this. Any help would be appreciated. Thanks
ParseQuery<ParseObject> query = new ParseQuery<ParseObject>("Footer");
// Locate the objectId from the class
query.getInBackground("tNp607WyQD", new GetCallback<ParseObject>() {
public void done(ParseObject object,ParseException e) {
// TODO Auto-generated method stub
// Locate the column named "ImageName" and set
// the string
ParseFile fileObject = (ParseFile) object.get("imageFile");
fileObject.getDataInBackground(new GetDataCallback() {
public void done(byte[] data,ParseException e) {
if (e == null) {
Log.d("test","We've got data in data.");
// Decode the Byte[] into
// Bitmap
Bitmap bmp = BitmapFactory.decodeByteArray(data, 0,data.length);
// Get the ImageView from main.xml
//ImageView image = (ImageView) findViewById(R.id.ad1);
ImageView ad1=(ImageView) findViewById(R.id.ad1);
// Set the Bitmap into the
// ImageView
ad1.setImageBitmap(bmp);
// Close progress dialog
progressDialog.dismiss();
} else {
Log.d("test",
"There was a problem downloading the data.");
}
}
});
}
});
}}
I'm able to resolve this with help of imageloader class:
public class Login extends Activity {
public ImageLoader imgl;
EditText fullname, mobilenumber, occupation;
Button save;
ImageView ad1,ad2,ad3,ad4,ad5,ad6;
List<ParseObject> ob;
private ImageView[] imgs = new ImageView[5];
ProgressDialog progressDialog;
int i=0;
HorizontalScrollView horizontalScrollView1;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.userdata);
imgl=new ImageLoader(getApplicationContext());
fullname = (EditText) findViewById(R.id.fullname) ;
mobilenumber = (EditText) findViewById(R.id.mobile) ;
occupation = (EditText) findViewById(R.id.occupation) ;
save=(Button) findViewById(R.id.btnSave);
horizontalScrollView1=(HorizontalScrollView) findViewById(R.id.horizontalScrollView1);
ad1=(ImageView) findViewById(R.id.ad1);
ad2=(ImageView) findViewById(R.id.ad2);
ad3=(ImageView) findViewById(R.id.ad3);
ad4=(ImageView) findViewById(R.id.ad4);
ad5=(ImageView) findViewById(R.id.ad5);
ad6=(ImageView) findViewById(R.id.ad6);
imgs[0] = ad2;
imgs[1] = ad3;
imgs[2] = ad4;
imgs[3] = ad5;
imgs[4] = ad6;
progressDialog= ProgressDialog.show(Login.this, "","Downloading Image...", true);
// Locate the class table named "Footer" in Parse.com
ParseQuery<ParseObject> query = new ParseQuery<ParseObject>(
"Footer");
query.orderByDescending("updatedAt");
try {
ob = query.find();
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
for (ParseObject country : ob) {
ParseFile image = (ParseFile) country.get("imageFile");
imgl.DisplayImage(image.getUrl(), imgs[i]);
i=i+1;
System.out.println("the urls are"+image.getUrl());
progressDialog.dismiss();
}
}
}
How about this? (Maybe it's a very crude way)
Since you have 5 (defined) imageviews, create an array of imageviews.
private ImageView iv1, iv2, iv3, iv4, iv5;
private ImageView[] imgs;
In onCreate(),
imgs = new ImageView[5];
iv1 = (ImageView) findViewById(R.id.iv1);
iv2 = (ImageView) findViewById(R.id.iv2);
iv3 = (ImageView) findViewById(R.id.iv3);
and so on
then set the imageview array, like this,
imgs[0] = iv1;
imgs[1] = iv2;
imgs[2] = iv3;
//so on
In your ParseQuery, assuming you get the required list of ParseObjects (5, I believe),
in done method of GetCallBack,
public void done(List<ParseObject> objects,ParseException e) {
for(int i =0 ; i < objects.size(); i++){
ParseObject object = objects.get(i);
ParseFile fileObject = (ParseFile) object.get("imageFile");
fileObject.getDataInBackground(new GetDataCallback() {
public void done(byte[] data,ParseException e) {
if (e == null) {
Bitmap bmp = BitmapFactory.decodeByteArray(data, 0,data.length);
imgs[i].setImageBitmap(bmp);
} else {
Log.d("test",
"There was a problem downloading the data.");
}
}
});
}
progressDialog.dismiss();
}
In the ParseQuery, to get images in ascending order of createdAt, use
query.orderByAscending("createdAt");
Just incase if you face any problem with the variable 'i' in the ParseQuery, (particularly, you may not be allowed to use i inside done() and will ask you to declare it as final), let me know!
You need to refactor your code in such a way that you can create a customised instance of your download task.
For example, create a FooterQuery class which wraps the ParseQuery. When you construct the object, you pass in the parseId and the resource id of the ImageView that it should be loaded into.
If the ImageView is controlled by an AdapterView (list a List or Grid view), it is going to be more complex.