Parse| can't save retrieved objects after findInBackground is done - android

I'm trying to retrieve String objects from Parse. I do able to get the objects back - but only inside the 'done' method. I wish to send the data i retrieve to another function\class. I tried to do this with some different public function in the same class or even to save the String in public field, but in the moment the callback is done, the data remains blank.
what can i do in order to keep the retrieved data?
this is my code:
public void done(List<ParseObject> parseObjects, com.parse.ParseException e) {
if (e == null) {
'myFieldArray' = new String[parseObjects.size()][3];
String text = "";
int index =0;
for(ParseObject po : parseObjects){
text = po.getString("Fact");
Toast.makeText(context,theFact, Toast.LENGTH_SHORT).show();
'myFieldArray'[index][0] = text;
index++;
}
}

Well,
after few tries, i realized that the Parse query probably goes inside the block twice - and ones when there are no objects returned - thats mean the array will be initialized again - and thats the reason its remains null.
the part i should have added is
if (e == null && parseObject.size()>0)

Related

Custom ListView Displaying Last value

I have a custom listView with 200 values coming from Cloud DB. All the values are received properly and added in ArrayList(hotelList). When I am passing to the ArrayList(hotelList) to Custom Adapter class, showing all the values as last element. Many stackOverflow questions found here related to this I tried them too. None worked for me. How should I fix this?
The code is,
#Override
protected void onPostExecute(String result) {
try {
Log.d("Inside Post", "message");
root = new JSONObject(result);
validation = root.getInt("response");
message = root.getString("message");
JSONArray data=root.getJSONArray("data");
data.length();
if(validation==1) {
hgs=new HotelGetSetter();//Getting and setting class
for(int i=0;i<data.length();i++){
hgs.setName(data.getJSONObject(i).getString("hotel_name"));
hgs.setPlace(data.getJSONObject(i).getString("city"));
hotelList.add(hgs);//While Debugging, all the 200 values from db received and added in the ArrayList(hotelList) values also there correctly
}
//But after the loop all the values here changed to last element value(debugged).
mainMethod();
}
}
catch (JSONException e) {
e.printStackTrace();
}
}
public void mainMethod(){
HotelCustomAdapter hca=new HotelCustomAdapter(HotelMaster.this,hotelList);
list_hotel.setAdapter(hca);
//list_hotel.setAdapter(new HotelCustomAdapter(this, hotel_id1,hotel_name1,hotel_place1));
}
you initialize variable hgs=new HotelGetSetter(); out of for loop and then you are always editing the same instance
You are changing the values for the same object hsg through the loop instead of creating different objects for each set of values. Therefore the 200 same objects.
Just move the hgs=new HotelGetSetter(); into the loop and it should work.

How to fetch object and array fields with Parse?

I'm unable to properly fetch a ParseObject that contains a field of type 'Object' : after changing manually the 'Object' field value in the Parse DataBrowser and then fetch the ParseObject from the app, the fetched ParseObject still provide the old value for the 'Object' field, but provide the right new value for the 'String' field.
Here is the sample code I use :
public class MainActivity extends ActionBarActivity {
ParseObject object;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
object = ParseObject.createWithoutData("Test", "tvgTg8jAXz");
}
#Override
protected void onResume() {
super.onResume();
object.fetchInBackground().onSuccess(new Continuation<ParseObject, Object>() {
#Override
public Object then(Task<ParseObject> task) throws Exception {
JSONObject data = task.getResult().getJSONObject("data");
String name = task.getResult().getString("name");
Log.d("OBJECT", data.toString());
Log.d("OBJECT", name);
return null;
}
}).continueWith(new Continuation<Object, Object>() {
#Override
public Object then(Task<Object> task) throws Exception {
if (task.getError() != null) {
Log.e("OBJECT", task.getError().getLocalizedMessage());
}
return null;
}
});
}
}
After I change both 'data' and 'name' fields in the DataBrowser, if 'onResume()' is called without a previous call to 'onCreate()' (after locking/unlocking screen for example) then the logs shows the old value for 'data' and the new value for 'name'.
This is a simple code example to highlight the problem I encounter in a bigger project.
Is this a known issue of the Parse Android SDK ? Is there a workaround ?
Thanks
Now that I learned that you have turned on the local datastore I can come with an, at least partial, answer.
Turning on the local datastore has some side effects. One being that only one instance of each object exists locally. So when you call fetchInBackground the second time, object is already populated with data. The problem then (i think) is that the API no longer override 'complex' types (pointers, objects, arrays), perhaps because it could mess up internal relationships in the data store. Since the fact that the data store will recursively save an object (and pointers) so suddenly swapping a pointer might leave objects 'hanging'. (again, only guessing).
Now I must admit that it still confuses me a bit looking at your code, cause it does not seem that you at any point write your object to the data store, however..
What should work is to unpin the object before 'refreshing' it:
object.unpinInBackground.onSuccess(new Continuation<>{
...
// when done call fetch
});
According to Parse, this is a known issue that they will not fix for now : https://developers.facebook.com/bugs/1624269784474093/
We must use the following methods to retrieve JSON objects/arrays fields from a ParseObject :
getMap() instead of getJSONObject()
getList() instead of getJSONArray()
These methods will return Map and List objects respectively.
I found that managing Map and List in my project instead of JSONObjet and JSONArray is not a problem and is even clearer.

return an object Android

I want to return an object with some things in them.
Here is the declaration;
Object user_det = get_user_det();
Here is the function code:
private Object get_user_det() {
Firebase f_user = new Firebase("https://myapp.firebaseio.com/User/");
f_user.addListenerForSingleValueEvent(new ValueEventListener(){
#Override
public void onDataChange(DataSnapshot snap_user) {
// TODO Auto-generated method stub
Iterable<DataSnapshot> rs = snap_user.getChildren();
Iterator<DataSnapshot> irs = rs.iterator();
long allNum2 = snap_user.getChildrenCount();
int maxNum2 = (int)allNum2;
int count_user = 1;
while(irs.hasNext())
{
if(count_user <= maxNum2)
{
Firebase user_data = new Firebase("https://myapp.firebaseio.com/");
AuthData authData = user_data.getAuth();
Map<String, Object> nPost = (Map<String, Object>) irs.next().getValue();
String db_email = nPost.get("email_addr").toString();
if (authData != null) {
String usr_email = authData.getProviderData().get("email").toString();
if(usr_email.equals(db_email))
{
//NB: I WANT TO ADD THE FOLLOWING INTO THE OBJECT
String disp_name = nPost.get("disp_name").toString();
String real_name = nPost.get("real_name").toString();
}
} else {
System.out.println("Failed");
}
}
count_user++;
}
}
#Override
public void onCancelled(FirebaseError arg0) {
// TODO Auto-generated method stub
}
});
return null; //NB: I NEED TO RETURN THE OBJECT HERE.
}
I want to return the string disp_name and real_name but they are inside the addListenerForSingleValueEvent, so how do I get them out and return it to the function.
I have wrote "NB" in the code where I need help with.
Thanks for your time.
If you want to return an object from your method in java, do it like this:
The Object class:
This contains the structure of your Object, and defines what data will be in it. Also includes methods to easily get the data.
private class myObject {
private String name;
private String realName;
//The constructor, so you can set the data when creating the Object.
public myObject (String disp_name, String real_name) {
name = disp_name;
realName = real_name;
}
//Getter methods, to get the data.
public String getRealName() {return realName;}
public String getDisplayName() {return name;}
}
Your code:
private Object get_user_det() {
myObject o; //Declare it, so it can be returned.
...
String disp_name = nPost.get("disp_name").toString();
String real_name = nPost.get("real_name").toString();
o = new myObject(disp_name, real_name); //create it and set the data.
...
return myobject; //return the new Object with the data.
}
To get the data from the Object:
myObject o = get_user_det(); //Call the metod which return our Object.
String realName = o.getRealName(); //Get the data from the Object.
String displayName = o.getDisplayName;
In your case, it would be much easier to use a String array.
Hope this helps.
It's probably easiest to see what's going on, if you add some printlns to your code:
private Object get_user_det() {
Firebase f_user = new Firebase("https://myapp.firebaseio.com/User/");
System.out.println("Adding listener");
f_user.addListenerForSingleValueEvent(new ValueEventListener(){
#Override
public void onDataChange(DataSnapshot snap_user) {
System.out.println("Data received");
}
#Override
public void onCancelled(FirebaseError arg0) {
// TODO Auto-generated method stub
}
});
System.out.println("Returning");
return null; //NB: I NEED TO RETURN THE OBJECT HERE.
}
If you execute this code, you will see that it logs:
Adding listener
Returning
Data received
Most likely, this is not what you expected. But hopefully, it makes sense if you read my explanation below.
Asynchronous loading
When you register your listener:
f_user.addListenerForSingleValueEvent(new ValueEventListener(){
You tell Firebase to start listening for events. It goes off and starts retrieving the data from the server.
Since retrieving the data may take some time, it does this retrieval asynchronously so that your thread isn't blocked. Once the data is completely retrieved, Firebase calls the onDataChange method in your listener.
Between the time you start listening and the time onDataChange is called, your code continues executing. So there is no way to return data that is loaded asynchronously, because by the time your function returns, the data isn't loaded yet.
Solutions
Disclaimer: I am not an expert at solving this problem in Java, so there may be problems with my solutions. If^H^HWhen you find any, please report them in the comments.
I know of three possible solutions to the problem:
force the code to wait for the data to be returned
return a Future that at some point will contain the data
pass a callback into get_user_det and call that function once the data is available
You will probably be tempted to selected option 1, since it matches most closely with your mental modal of loading data. While this is not necessarily wrong, keep in mind that there is a good reason that the loading is done asynchronously. It might be worth taking the "learning how to deal with asynchronicity" penalty now.
Instead of writing up examples for all solutions, I'll instead refer to some relevant questions:
Retrieving data from firebase returning NULL (an answer that uses approach 3)
Is waiting for return, ok?
Java wait() & notify() vs Android wait() & notify() (a question from a user taking approach 1)
How it works:
Firebase uses reflection to build a JSON tree object to save to the database. When you retrieve this JSON tree, you can cast it back to your original object. Just like serializing and deserializing. This means you do not need to handle the keys and values when trying to "rebuild" your object like you are. It can all be done like so:
YourObject object = (YourObject) dataSnapshot.getValue(YourObject.class);
Notice the YourObject.class in the getValue(). This tells firebase to reflect through this class and find the appropriate accessors with the dataSnapshot.
How to do it
Be sure that your object has:
Accessors Appropriate getters and setters for ALL fields - (or annotated with #JsonIgnore if you wish to not save a particular field)
Empty constructor. Your object must provide a constructor that does not modify itself at all.
What your object should look like:
public class YourObject {
private String displayName;
private String realName;
public YourObject() { /*Empty constructor needed for Firebase */ }
// Accessors
public void setRealName(String realName){
this.realName = realName;
}
public String getRealName(){
return this.realName;
}
public String getDisplayName(){
return this.displayName;
}
public void setDisplayName(String displayName){
this.displayName = displayName;
}
}
Then, in any of the firebase callbacks, you can just cast your DataSnapshot in to your object:
public void onDataChange(DataSnapshot snap_user) {
YourObject object = new Object;
if(snap_user.getValue() != null) {
try {
object = (YourObject) snap_user.getValue(YourObject.class); <-- Improtant!!!
} catch(ClassCastException ex) {
ex.printStackTrace();
}
}
return object;
}
Also
It seems you are retrieving many objects. When doing this, I find it best to use the onChildEventListener then for each of the YourObjects in that node, onChildAdded(DataSnapshot ds, String previousChild); will be called.

Prevent duplicate entries parse.com

I'm using Parse.com as my backend and while there seems to be a method, saveInBackgroundWithBlock, to prevent duplicate entries. It doesn't appear to exist on Android. I'd like to upload only unique entries but can't figure out a way to do so.
The only thing I can think of is to query then insert if the entry doesn't exist, but that's doing twice as many network calls and I feel like it needs to.
Thanks
As I had mentioned in the comment earlier, I had faced the same problem. Ended up writing a query to find the existing objects and then save only the non-existing ones. Like below.
//Say you have a list of ParseObjects..this list contains the existing as well as the new objects.
List<ParseObject> allObjects = new ArrayList<ParseObject>();
allObjects.add(object); //this contains the entire list of objects.
You want to find out the existing ones by using the field say ids.
//First, form a query
ParseQuery<ParseObject> query = ParseQuery.getQuery("Class");
query.whereContainedIn("ids", allIds); //allIds is the list of ids
List<ParseObject> Objects = query.find(); //get the list of the parseobjects..findInBackground(Callback) whichever is suitable
for (int i = 0; i < Objects.size(); i++)
existingIds.add(Objects.get(i).getString("ids"));
List<String> idsNotPresent = new ArrayList<String>(allIds);
idsNotPresent.removeAll(existingIds);
//Use a list of Array objects to store the non-existing objects
List<ParseObject> newObjects = new ArrayList<ParseObject>();
for (int i = 0; i < selectedFriends.size(); i++) {
if (idsNotPresent.contains(allObjects.get(i).getString(
"ids"))) {
newObjects.add(allObjects.get(i)); //new Objects will contain the list of only the ParseObjects which are new and are not existing.
}
}
//Then use saveAllInBackground to store this objects
ParseObject.saveAllInBackground(newObjects, new SaveCallback() {
#Override
public void done(ParseException e) {
// TODO Auto-generated method stub
//do something
}
});
I had also tried using beforeSave method on ParseCloud. As you may know, before saving the objects this method is called on the ParseCloud and is ideal to make any validation required. But, it didn't quite run well. Let me know if you need something from the ParseCloud code.
Hope this helps!
I'm not sure I understand your question, but you can get the same functionality as saveInBackgroundWithBlock in Android like this:
myObject.saveInBackground(new SaveCallback() {
public void done(ParseException e) {
if (e == null) {
myObjectSavedSuccessfully();
} else {
myObjectSaveDidNotSucceed();
}
}
});

Passing arrayadapter and arraylist between fragments

I have an activity that contains two fragments. I would like to pass data (an ArrayAdapter and an ArrayList) between the two fragments. User operations in Fragment 1 modifies both datatypes, which then need to be passed onto Fragment 2. Similarly, user operations in Fragement 2 also modify the two datatypes, which then need to be passed back to Fragment 1.
Can you please guide on the most elegant way to do it? I have been looking into parcelable and interface. Since, I do not have much experience with Java (let alone android) I was not able to discern the limitations of two approach.
I'd suggest holding a reference to your data object in each fragment (as I'm sure you are) and do something like the following:
public void onResume()
{
mDataObject = getFragmentManager.getFragmentByTag("Fragment1").getDataObject1();
super.onResume();
}
you can run this in Frag 1 and Frag 2 and it should update the model. If you have sub objects you will need to compare them and determine if the sub-objects are different in a function something like this.
public void determineIfDifferent(DataObject mData1)
{
Field mData1Fields[] = mData1.getClass().getFields();
Field mData2Fields[] = mData2.getClass().getFields();
for (int i = 0; i < mData1Fields.length; i++)
{
try
{
if (mDataFields[i].get(mData) != null && tempFields[i].get(PS)!= null)
{
String mDataValue = mDataFields[i].get(mData).toString().trim();
String tempValue = tempFields[i].get(PS).toString().trim();
if (!mDataValue.equals(tempValue))
{
differenceList.add(tempValue);
}
}
}
catch (IllegalArgumentException e)
{
Logger.logStackTrace(getClass().getSimpleName(), e);
}
catch (IllegalAccessException e)
{
Logger.logStackTrace(getClass().getSimpleName(), e);
}
}
}
This obviously can be modified if the type is not a String - this is just what I had at hand
You can put them into Intent.putExtra() and vice versa

Categories

Resources