I'm using the Parse SDK on Android. There doesn't seem to be any documentation on using the ParseObject.saveAll(List<ParseObject>) method. I have a subclass called Test which extends ParseObject. I've been able to use most ParseObject methods so far, but I would like to save the whole list using the saveAll method, but it requires a List<ParseObject> and won't accept List<Test>. Any ideas?
Your ParseObject model may like this
class Person extends ParseObject
{
public static String NAME = “name”;
public static int AGE = “age”;
public void setName(String name)
{
put(NAME,name);
}
public void setAge(int age)
{
put(AGE,age);
}
public Stirng getName()
{
return get(NAME);
}
public int getAge()
{
return get(AGE);
}
}
now,Person is subclass of ParseObject. You can use ParseObject.saveAll(List personList)
Person person1 = new Person();
person1.setName("Mike");
person1.setAge(18);
Person person2 = new Person();
person2.setName("John");
person2.setAge(25);
List<Person> personList = new ArrayList<Person>();
personList.add(person1);
personList.add(person2);
ParseObject.saveAll(personList);
Found a solution here: https://parse.com/questions/how-to-use-parseobjectsaveall-on-subclass
Let's say you have your 3 Game object, game1, game2, game3, this should work:
List mygames = new ArrayList();
mygames.addAll(Arrays.asList(game1, game2, game3));
ParseObject.saveAllInBackground(mygames);
An alternative solution could be to write a custom save all method inside the subclass:
public static void saveAllInBackground(
final List<MySubclass> objects,
final SaveCallback savecallback) {
counter = 0;
for (MySubclass mySubclass : objects) {
mySubclass.saveEventually(new SaveCallback() {
#Override
public void done(ParseException e) {
if (e == null) {
counter++;
if (counter == objects.size()) {
savecallback.done(null);
}
} else {
savecallback.done(e);
}
}
});
}
}
Related
I have an Android app in which I'm getting data from an API. Now I need to save this data from the API into an ActiveAndroid table.
So I've got stuck on that part.
Here is my table Partners(Active Android):
#Table(name = "Partners")
public class Partners extends Model {
#Column(name = "Name")
public String name;
public Partners() {}
public Partners(String name) {
this.name = name;
}
}
This is my POJO model:
public class Partner {
#Expose
#Column(name = "name")
private List<String> name;
public List<String> getName() {
return name;
}
public void setName(List<String> name) {
this.name = name;
}
}
And here is part of code where I'm getting data and trying to save it into ActiveAndroid table:
public class DownloadMain extends Fragment implements Callback<Partner> {
private static final String TAG = DownloadMain.class.getSimpleName();
private Button dloadPartners;
private Call callPartners;
public DownloadMain() {}
public DownloadMain newInstance() { return new DownloadMain(); }
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.download_main, container, false);
dloadPartners = (Button) view.findViewById(R.id.downloadPartners);
dloadPartners.setOnClickListener(btnListener);
callPartners = APIHelper.getApiService().getPartners();
return view;
}
Button.OnClickListener btnListener = (new Button.OnClickListener() {
#Override
public void onClick(View v) {
callPartners.clone().enqueue(DownloadMain.this);
insertPartners();
}
});
#Override
public void onResponse(Call call, Response response) {
if(response.body() == null) {
try {
response.errorBody().string();
} catch (IOException e) {
e.printStackTrace();
}
Toast.makeText(getActivity(), "No Partners!", Toast.LENGTH_SHORT).show();
} else {
List<String> partners = (List<String>) response.body();
Log.d(TAG, "Number of partners received: " + partners.size());
Toast.makeText(getActivity(), "Partners downloaded!", Toast.LENGTH_SHORT).show();
}
}
#Override
public void onFailure(Call call, Throwable t) {
}
private void insertPartners() {
ActiveAndroid.beginTransaction();
try {
for (int i = 0; i < 100; i++) {
Partner partner = new Partner();
partner.getName();
//partner.save();
}
ActiveAndroid.setTransactionSuccessful();
} finally {
ActiveAndroid.endTransaction();
}
}
}
The problem is how to save data I get from the API into table, so I need few tips and advice how to properly do that.
Question: I need some tips how to save data I get from web with retrofit into ActiveAndroid table?
please check my old weather app project, where I'f already used ActiveAndroid.
Here's one of my saving to database methods:
public void saveCityDataToDatabase(Forecast forecast) {
ActiveAndroid.beginTransaction();
try {
if (WeatherApplication.getCityList().size() > 0) {
new Delete().from(City.class).execute();
}
forecast.getCity().getCoord().save();
forecast.getCity().save();
ActiveAndroid.setTransactionSuccessful();
} finally {
ActiveAndroid.endTransaction();
}
Log.d("DATABASE", "WeatherApplication: " + WeatherApplication.getCityList());
} }
From: https://github.com/piotrek1543/LocalWeather/blob/master/app/src/main/java/com/piotr/localweather/repositories/WeatherDatabaseRepository.java
With ActiveAndroid is really easy to save Objects like Weather or Wind, but for some purposes you would need to use TypeSerializer. In your example you would use it to deserialize and save List<String>.
As you may notice from its Github page: https://github.com/pardom/ActiveAndroid
this libary is not maintained more than two years, so I can say clearly that is deprecated and not good to use to fresh projects. It may have many bugs. For me, implementation of this lib was a pretty painful.
Instead of ActiveAndroid, I would recommend you to use Realm, greenDao or ORMLite library to store your data.
Hope it would help
First of all create a parameterless constructor and call super in it.
public Partners() {
super();
}
then a partern.save() should suffice.
To retreive all the parterns you could do something like
List<Partner> partners = new Select().from(Partner.class).execute());
if you get the Partner object fro web via retrofit, probably you are using Gson to put the json in partner object. so you can make that object extending model, put a paramterless constructor like above and put a #Table annotation.
I have data in my firebase DB, everything works fine until I try to De-serialize the data.
Error: argument 1 has type io.realm.RealmList, got java.util.ArrayList
Here's my code:
DatabaseReference root = FirebaseDatabase.getInstance().
getReferenceFromUrl("https://swing-8792d.firebaseio.com/playlist");
Query playlistQuery = root.orderByKey().equalTo(key);
playlistQuery.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot child : dataSnapshot.getChildren()) {
Log.d("Child", child + "");
Playlist receivedPlaylist = child.getValue(Playlist.class);
Playlist playlist = new Playlist();
playlist.setCreatedBy(receivedPlaylist.getCreatedBy());
playlist.setName(receivedPlaylist.getName());
playlist.setMyMap(receivedPlaylist.getMyMap());
playlist.setQrKey(receivedPlaylist.getQrKey());
playlist.setCount(receivedPlaylist.getCount());
playlist.setId(receivedPlaylist.getId());
playlist.setTracks(receivedPlaylist.getTracks());
mPlaylist.add(playlist);
}
This is my POJO class:
#RealmClass
public class Playlist extends RealmObject {
String name;
Long id;
RealmList<Track> tracks;
Integer count;
String createdBy;
RealmList<UserMap> myMap;
String qrKey;
public RealmList<UserMap> getMyMap() {
return myMap;
}
public void setMyMap(RealmList<UserMap> myMap) {
this.myMap = myMap;
}
public Playlist(){}
public String getQrKey() {
return qrKey;
}
public void setQrKey(String qrKey) {
this.qrKey = qrKey;
}
public String getCreatedBy() {
return createdBy;
}
public void setCreatedBy(String createdBy) {
this.createdBy = createdBy;
}
public RealmList<Track> getTracks() {
return tracks;
}
public void setTracks(RealmList<Track> tracks) {
this.tracks = tracks;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Integer getCount() {
return count;
}
public void setCount(Integer count) {
this.count = count;
}
}
If I try to de-serialize with Normal POJO class (i.e Removing Realm) it works fine.
Firebase won't work with classes that do not have default constructor or private variables i.e no public getter/setter.
A easier solution in your case would be to make a middleware class that is the same pojo just not extending RealmObject. Next initialise your RealmObject subclass using the values of the pojo.
Pseudo code
class SimplePojoPlaylist {
public String variable;
}
class Playlist extends RealmObject {
public String variable;
}
Then first cast into SimplePojoPlaylist
for (DataSnapshot child : dataSnapshot.getChildren()) {
SimplePojoPlaylist receivedPlaylist = child.getValue(SimplePojoPlaylist.class);
Playlist playList = new Playlist();
playList.variable = receivedPlaylist.variable;
}
RealmList is not a supported type for deserialization. Your database checks its structure and deduces that tracks should be an ArrayList. Then, when it tries to convert it, it finds that the types do not match.
Check this link from the docs:
Also, it is a good practice to make your objects immutable to avoid unwanted access and/or modifications.
Creating an empty object from scratch and then calling setter methods to define its state is not a very good pattern, because it can create a situation where an object is accessed before when its state is "broken".
If you need to create an object that is flexible, has a few mandatory fields and some optional, consider using the Builder pattern, although to do it you'd have to redesign your model.
wikipedia - Builder
If you don't need/want to use a builder, my advice is:
1) Make the empty constructor private and create another public one that requires all the fields.
2) Change your tracks field to be of type "List". Then, if you need the object to return a RealmList create another getter method such as tracksAsRealmList() that makes a RealmList out of the member list and returns it.
3) Make sure that the "Track" model has an empty private constructor, a public one with all of its parameters and that all of its fields are supported by firebase deserialization.
4) Unless strictly necessary, make your object fields private and set its value through a setter method.
I hope this helps you.
I have data in my firebase DB, everything works fine until I try to De-serialize the data.
Error: argument 1 has type io.realm.RealmList, got java.util.ArrayList
Here's my code:
DatabaseReference root = FirebaseDatabase.getInstance().
getReferenceFromUrl("https://swing-8792d.firebaseio.com/playlist");
Query playlistQuery = root.orderByKey().equalTo(key);
playlistQuery.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot child : dataSnapshot.getChildren()) {
Log.d("Child", child + "");
Playlist receivedPlaylist = child.getValue(Playlist.class);
Playlist playlist = new Playlist();
playlist.setCreatedBy(receivedPlaylist.getCreatedBy());
playlist.setName(receivedPlaylist.getName());
playlist.setMyMap(receivedPlaylist.getMyMap());
playlist.setQrKey(receivedPlaylist.getQrKey());
playlist.setCount(receivedPlaylist.getCount());
playlist.setId(receivedPlaylist.getId());
playlist.setTracks(receivedPlaylist.getTracks());
mPlaylist.add(playlist);
}
This is my POJO class:
#RealmClass
public class Playlist extends RealmObject {
String name;
Long id;
RealmList<Track> tracks;
Integer count;
String createdBy;
RealmList<UserMap> myMap;
String qrKey;
public RealmList<UserMap> getMyMap() {
return myMap;
}
public void setMyMap(RealmList<UserMap> myMap) {
this.myMap = myMap;
}
public Playlist(){}
public String getQrKey() {
return qrKey;
}
public void setQrKey(String qrKey) {
this.qrKey = qrKey;
}
public String getCreatedBy() {
return createdBy;
}
public void setCreatedBy(String createdBy) {
this.createdBy = createdBy;
}
public RealmList<Track> getTracks() {
return tracks;
}
public void setTracks(RealmList<Track> tracks) {
this.tracks = tracks;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Integer getCount() {
return count;
}
public void setCount(Integer count) {
this.count = count;
}
}
If I try to de-serialize with Normal POJO class (i.e Removing Realm) it works fine.
Firebase won't work with classes that do not have default constructor or private variables i.e no public getter/setter.
A easier solution in your case would be to make a middleware class that is the same pojo just not extending RealmObject. Next initialise your RealmObject subclass using the values of the pojo.
Pseudo code
class SimplePojoPlaylist {
public String variable;
}
class Playlist extends RealmObject {
public String variable;
}
Then first cast into SimplePojoPlaylist
for (DataSnapshot child : dataSnapshot.getChildren()) {
SimplePojoPlaylist receivedPlaylist = child.getValue(SimplePojoPlaylist.class);
Playlist playList = new Playlist();
playList.variable = receivedPlaylist.variable;
}
RealmList is not a supported type for deserialization. Your database checks its structure and deduces that tracks should be an ArrayList. Then, when it tries to convert it, it finds that the types do not match.
Check this link from the docs:
Also, it is a good practice to make your objects immutable to avoid unwanted access and/or modifications.
Creating an empty object from scratch and then calling setter methods to define its state is not a very good pattern, because it can create a situation where an object is accessed before when its state is "broken".
If you need to create an object that is flexible, has a few mandatory fields and some optional, consider using the Builder pattern, although to do it you'd have to redesign your model.
wikipedia - Builder
If you don't need/want to use a builder, my advice is:
1) Make the empty constructor private and create another public one that requires all the fields.
2) Change your tracks field to be of type "List". Then, if you need the object to return a RealmList create another getter method such as tracksAsRealmList() that makes a RealmList out of the member list and returns it.
3) Make sure that the "Track" model has an empty private constructor, a public one with all of its parameters and that all of its fields are supported by firebase deserialization.
4) Unless strictly necessary, make your object fields private and set its value through a setter method.
I hope this helps you.
I am having trouble retrieving a List from the Firebase. I have no trouble storing it, but as soon as I try to cast dataSnapshot.getValue() to ArrayList my app crashes, giving an exception:
HashMap cannot be casted to ArrayList
But when I tried to cast it to a HashMap, it also crashes, giving exception:
ArrayList can't be casted to hashmap
Need help please! Here is the code that is creating the problem:
Fire.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
List<TaskDes> td = (ArrayList<TaskDes>) dataSnapshot.getValue()
notifyDataSetChanged();
}
#Override
public void onCancelled(FirebaseError firebaseError) {
}
});
I want to retrieve all the data in the Firebase as one List. The class TaskDes contains three fields:
class TaskDes { // definition
boolean done
String taskDescription
String taskTitle
}
You need to create a GenericTypeIndicator object to pass as DataSnapshot.getValue() parameter.
Code:
GenericTypeIndicator<List<String>> t = new GenericTypeIndicator<List<String>>() {};
List<String> yourStringArray = dataSnapshot.getValue(t);
Your Model
public class TaskDes {
private boolean done;
private String taskDescription;
private String taskTitle;
public TaskDes() {
}
public boolean isDone() {
return done;
}
public void setDone(boolean done) {
this.done = done;
}
public String getTaskDescription() {
return taskDescription;
}
public void setTaskDescription(String taskDescription) {
this.taskDescription = taskDescription;
}
public String getTaskTitle() {
return taskTitle;
}
public void setTaskTitle(String taskTitle) {
this.taskTitle = taskTitle;
}
}
You need to create a GenericTypeIndicator object to pass as DataSnapshot.getValue() parameter.
In Activity
private static final String TAG=MainActivity.class.getSimpleName();
private FirebaseDatabase database;
private DatabaseReference myRef=null;
#Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
database=FirebaseDatabase.getInstance();
myRef=database.getReference("ADD_YOUR_REFERECE");
myRef.addValueEventListener(new ValueEventListener(){
#Override
public void onDataChange(DataSnapshot dataSnapshot){
/* This method is called once with the initial value and again whenever data at this location is updated.*/
long value=dataSnapshot.getChildrenCount();
Log.d(TAG,"no of children: "+value);
GenericTypeIndicator<List<TaskDes>> genericTypeIndicator =new GenericTypeIndicator<List<TaskDes>>(){};
List<TaskDes> taskDesList=dataSnapshot.getValue(genericTypeIndicator);
for(int i=0;i<taskDesList.size();i++){
Toast.makeText(MainActivity.this,"TaskTitle = "+taskDesList.get(i).getTaskTitle(),Toast.LENGTH_LONG).show();
}
}
#Override
public void onCancelled(DatabaseError error){
// Failed to read value
Log.w(TAG,"Failed to read value.",error.toException());
}
});
}
Make another item that contains a list for your item:
This is your item:
class TaskDes { // definition
boolean done
String taskDescription
String taskTitle
}
This is the list item
class TaskDesList { // definition
private ArreyList<TaskDes> yourlist
}
public TaskDesList(){
}
public ArrayList<TaskDes> getYourlist() {
return yourlist;
}
and when calling an EventListener
ref.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
yourlist.clear();
taskDesList=dataSnapshot.getValue(TaskDesList.class);
if (taskDesList!=null) {
yourlist= taskDesList.getYourlist();
}
}
and now "yourlist" is a list that contains all of your "TaskDes" items
A bit late, but in case any one else needs this.
IF the list is inside another object.
The object
public class Question {
public Date date;
public String questionNumber;
public String questionText;
public QuestionType questionType;
public String multipleSelection1;
public String multipleSelection2;
public String multipleSelection3;
public Question() {
// Default constructor required for calls to DataSnapshot.getValue(User.class)
}
}
Then to get your array of question objects
GenericTypeIndicator<List<Question>> t = new GenericTypeIndicator<List<Question>>() {};
List<Question> questionList = dataSnapshot.getValue(t);
Apparently, the GenericTypeIndicator doesn't work for all List objects particularly when the object contains none primitive types like maps. So, if it didn't work for your use case as it didn't for me, try this alternate solution:
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
List<TaskDes> tDlist = new ArrayList<>();
for (DataSnapshot d: dataSnapshot.getChildren()){
TaskDes tD = d.getValue(TaskDes.class);
tDlist.add(tD);
}
notifyDataSetChanged();
}
As mentioned in the previous answers make sure your class( like TaskDes in this case) has a public constructor which is empty so the getValue method can deserialize correctly to your java class.
I have used ignition in my app to cache my composite object,let say mStudentObject. I have cached my data successfully, the issue is , when i retrieve my object after killing app from recently running apps button(from currently running tasks button) ,i haven't fount any data against key(cached clear automatically).When i re-launch app (with out killing app from recent tasks) object retrieved properly.
i don't know what is wrong with code.I want to cache my object permanently for 2 days. when ever i launch my app,app should get data from cached object either i kill app from currently running tasks or not. Any idea,please share.Here is my complete code:
public class MainActivity extends Activity {
Button[] buttons = null;
// ObjectLRUCache objectLRUCache = null;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
buttons = new Button[2];
buttons[0] = (Button) findViewById(R.id.button1);// to save data
buttons[1] = (Button) findViewById(R.id.button2); // to get data
// final Student s = new Student("imran", 23, 16);
buttons[0].setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
if (IgnetionHelper.getInstance()!= null) {
Log.d("test", "key contains, updating");
Student s = new Student("imran", 23, 16);
IgnetionHelper.getInstance().putData(s);
} else{
Log.d(""test),"instance is null..");
}
});
buttons[1].setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
IgnetionHelper ddd = IgnetionHelper.getInstance();
if (IgnetionHelper.getInstance().getData()!= null) {
Student s = (Student) IgnetionHelper.getInstance().getData();
Log.d("test", "key contains, age is: " + s.age);
} else {
Log.d("test", "data is null...");
}
}
});
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.activity_main, menu);
return true;
}
}
and My Person class is as:
public abstract class Person extends CachedModel implements Serializable{
public String name = "";
public int age = 0;
public Person(){};
public Person (String name,int age) {
this.name=name;
this.age=age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
Student class is as:
public class Student extends Person{
public String name = "";
public int age = 0;
public int rollNo = 0;
public Student(){
}
public Student(String name, int age, int rollno) {
this.rollNo = rollno;
this.name=name;
this.age=age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public int getRollNo() {
return rollNo;
}
public void setRollNo(int rollNo) {
this.rollNo = rollNo;
}
#Override
public boolean reloadFromCachedModel(ModelCache modelCache,
CachedModel cachedModel) {
Student student = (Student) cachedModel;
name = student.name;
age = student.age;
rollNo = student.rollNo;
return false;
}
#Override
public String createKey(String id) {
// TODO Auto-generated method stub
return id;
}
}
And finally, ignition helper class is as:
public class IgnetionHelper {
private static final String KEY_FOR_MYOBJECT = "MY_TEST_KEY";
private static ModelCache cache;
private final static int initialCapacity = 1000;
private final static int maxConcurrentThreads = 3;
private final static long expirationInMinutes = 60 * 24 * 2;
private static IgnetionHelper mIgnetionHelper = null;
public static IgnetionHelper getInstance() {
if (cache == null)
cache = new ModelCache(initialCapacity, expirationInMinutes,
maxConcurrentThreads);
if (mIgnetionHelper == null)
mIgnetionHelper = new IgnetionHelper();
return mIgnetionHelper;
}
public boolean putData(CachedModel model) {
model.setId(KEY_FOR_MYOBJECT);
if (model.save(cache)) {
Log.d("IgnetionHelper", "saved.....");
return true;
} else {
Log.d("IgnetionHelper", "saved.....");
return false;
}
// CachedModel model = Feed.find(cache, key, Feed.class);
// if (model != null) {
// Log.d("test", "key contains, updating");
// Feed s = (Feed) model;
// return s.save(cache);
// }
}
public CachedModel getData() {
return Student.find(cache, KEY_FOR_MYOBJECT, Student.class);
}
}
i have found solution of my problem.
Let say you have student object
Student s = new Student("imran",16,23);
and then implement these methods in your ignetionhelper calss:
public static boolean putData(Object object, Context context,String key) {
return GenericStore.saveObject(GenericStore.TYPE_MEMDISKCACHE,key, (Serializable) object, context.getApplicationContext());
}
public static Object getData(Context context,String key) {
return GenericStore.getObject(GenericStore.TYPE_MEMDISKCACHE,key, context.getApplicationContext());
}
https://github.com/wareninja/generic-store-for-android
import library given hare and then use above methods as:
IgnetionHelper.putData(s, context, IgnetionHelper.YOUR_KAY);
Student s=(Student)IgnetionHelper.getData(context,IgnetionHelper.YOUR_KAY);
You will need to use a cache that is stored to disk, when the app is killed the cache you are using appears to be cleared.
There is some information from Google about cache storage here http://developer.android.com/guide/topics/data/data-storage.html and check out this existing SO answer on some options for data caching within your app Best Way to Cache Data in Android