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.
Related
I have a listview with a list of appetizers. Once I click on a row item, a single activity will display the name of the recipe, the cook time, the image and a text file converted to string into a textview. I am able to display the name and cook time through an intent, but unable to display the image and text from the text file on parse.
This code goes through the list and displays the last in the list. This is not what I want:
final ParseImageView mImage = (ParseImageView) findViewById(R.id.image);
ParseQuery<ParseObject> getimage = new ParseQuery<>("Appetizers");
getimage.addAscendingOrder("appetizer");
getimage.findInBackground(new FindCallback<ParseObject>() {
#Override
public void done(List<ParseObject> objects, ParseException e) {
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());
}
}
});
Images:
parse.com "Appetizers" class:
List of recipes:
AppetizerRecipe layout XML:
Log:
Out of layout:
Did you get something in the log "test" where you print the url? I mean this line:
Log.d("test", "Get your image..." + fileObject.getUrl());
If so, the problem is not the Parse Server. Instead, check if Picasso is working well.
Please update the question with the code where you read the file.
According the comments for my original response, you have to do something like this.
In your ListViewItem's Listener:
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
int id = listView.getAdapter().getItem(position).id;
Intent descriptionActivity = new Intent(this, DescActivity.class);
descriptionActivity.putExtra("id",id);
startActivity(descriptionActivity);
}
In your DescActivity's onCreate() method:
String id = getIntent().getStringExtra("id");
and finally in your ParseQuery:
getImage.where('objectId',id);
I hope this help.
By adding logging messages as to what was being passed and what not, i was able to fix the problem. Hope this helps someone else.
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 have an app that downloads an image from Parse.com and displays that image in an Image View
The problem is that whenever I exit the app (with the back button) and return the image is gone.
How can I make the image stay?
(For example: when you update your profile pic on Twitter and leave the app and return your profile pic will still be displayed)
Any help would be greatly appreciated this is very important.
MainActivity:
public class MainActivity extends Activity {
Button button;
private ProgressDialog progressDialog;
/** Called when the activity is first created. */
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Get the view from main.xml
setContentView(R.layout.activity_main);
// Show progress dialog
// Locate the button in main.xml
button = (Button) findViewById(R.id.button);
// Capture button clicks
button.setOnClickListener(new OnClickListener() {
public void onClick(View arg0) {
progressDialog = ProgressDialog.show(MainActivity.this, "",
"Downloading Image...", true);
// Locate the class table named "ImageUpload" in Parse.com
ParseQuery<ParseObject> query = new ParseQuery<ParseObject>(
"ImageUploads");
// Locate the objectId from the class
query.getInBackground("h3FvFzrHPr",
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("imageContent");
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.image);
// Set the Bitmap into the
// ImageView
image.setImageBitmap(bmp);
// Close progress dialog
progressDialog.dismiss();
} else {
Log.d("test",
"There was a problem downloading the data.");
}
}
});
}
});
}
});
}
}
Try using an image library that can handle picture caching.
You could try Glide or Picasso.
First add the library to your project. Them instead of downloading the file and decoding by yourself use the library to download and cache the object for you.
(Glide example)
After searching for the object and extracting parsefile use Glide:
ParseFile fileObject = (ParseFile) object.get("imageContent");
String url = fileObject.getUrl();
ImageView image = (ImageView) findViewById(R.id.image);
Glide.with(getContext())
.load(url)
.into(image);
Next time you open the app Glide will search object in cache and only fetch if needed.
try to this way better to use BitMap.
ParseQuery<ParseObject> query = new ParseQuery<ParseObject>("subclass");
query.findInBackground(new FindCallback<ParseObject>() {
#Override
public void done(List<ParseObject> List, ParseException e) {
// TODO Auto-generated method stub
if (e == null) {
// success
if (List.size() > 0) {
for (ParseObject parseObject : List) {
// here fetch image like..
ParseFile image = (ParseFile) parseObject.get("fieldName");
if (image != null) {
Log.e("getting Image", "Image URL " + image.getUrl());
// here add to your adapter array
Picasso.with(getApplicationContext()).load(image.getUrl()).fit().into("imageView");
}
}
// and here call your adapter for fill array data
}
} else {
// e.getMessage() here getting error ...
}
}
});
The answer to this question is here: How To Create An App That Allows For Profile Picture Upload/Change?
I have resolved the problems I have been facing
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
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.