I am working on an android app that loads in a list of students to display in a list based activity. There are two components to the app. There is a server which responds via xml with the list of current active students and a database on the app end which stores theses students with some details (name,age etc). I would like a way to sync these two data sources. When the app starts, I would like to check against the xml to see if students on the server were added/deleted and update the db accordingly.
I would be parsing the xml list into a student object at login. Is there any way to store/retrieve an entire object into an android supported db so I can do a direct comparison to see what to update/delete? It would end up being something like
if (serverStudent[0].name == dbStudent[0].name)
//overwrite dbStudent object with serverStudent fields
What is the most efficient/lightweight way to achieve object persistance and then comparison in Android?
Here's a method I have used in the past:
Anytime an object in the database is changed, use a timestamp column to store that time. When the app connects on startup, simply check each timestamp in the app db against the timestamp in the server db for each object. If the timestamps match, do nothing. If the timestamps don't match, retrieve the updated record from the server. Make sure you're using a detail enough timestamp (usually down to milli- or micro- seconds).
The nice thing about timestamps is that if you don't want the server data to override the app data, you could look at which is newer and keep that object if they've both been edited. Just adding some additional thoughts!
You can do something like this -
public class StudentRecord {
Vector<StudentData> studentDatas;
public StudentRecord()
{
studentDatas = new Vector<StudentData>();
}
public Vector<StudentData> getRecords() {
return studentDatas;
}
public void setRecords(Vector<StudentData> records) {
this.studentDatas = records;
}
public class StudentData
{
String name,Rollno;
public String getRollno() {
return Rollno;
}
public void setRollno(String rollno) {
Rollno = rollno;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
}
When you get the vector object studentDatas you can do something like this -
for(Object object : record.getRecords())
{
data = (StudentData)object;
data.getRollno();
data.getName();
}
Check out these libraries:
http://www.datadroidlib.com/
https://github.com/octo-online/robospice
I believe both offer solutions for your situation.
Or you can roll your own solution... Basically you will want to create a service or asynctask to do the syncing, in your student object you can create a constructor that you can pass an id to and have it pull the appropriate record from your local db then make a comparison method that will update if newer information is available.
I'm not sure i understood your question correctly.But as far as i understand i would do something like this.
In server side send send Json array which holds json student objects.
In android side create similer Student class and override equals
method as you want.
Then for each student check with equals method whether they are
equals or not and take action accordingly.
If you want to make faster search in students object array then apply
hash map instead of arrays.
Related
I'm using Firebase for data storage on an Android project, and using the Firebase Java API to deal with data. I'm not sure I'm doing it as efficiently as possible, though, and I'd like some advice on best practices for retrieving and formatting data. My Firebase repository looks something like this....
-POLLS
NUMPOLLS - 5
(pollskey) - NAME - Poll1
NUMELECTIONS - 2
ELECTIONS
(electionskey) - NAME - Election1
NUMNOMINATIONS - 2
NUMVOTERS - 2
NUMBERTOELECT - 1
VOTERS - (votesrkey) - NAME - Charles
NUMBER - (678) 333-4444
.
.
.
(voterskey) - ...
NOMINATIONS - (nominationskey) - NAME - Richard Nixon
NUMBEROFVOTES - 2
.
.
.
(nominationskey) - ...
.
.
.
(electionskey) - ...
.
.
.
(pollskey) - ...
So, for example here I'm trying to get all data out of a poll to list poll name, it's election names, and the candidate names and number of votes for each election. I get the POLLS level DataSnapshot during the OnCreate() function of my main activity like this...
private static final Firebase polls = pollsFirebase.child("Polls");
protected void onCreate(Bundle savedInstanceState) {
polls.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot snapshot) {
for (DataSnapshot child : snapshot.getChildren()) {
if (!child.getName().equals("NumPolls")) {
createPollTableAndHeaders(child);
}
}
}
});
}
Then I proceed to read out the individual pieces of data I need by successively calling getValue() on DataSnapshots, and checking the keys of the resulting HashMaps...
private void createPollTableAndHeaders(DataSnapshot poll) {
String pollName = "";
int numPolls;
Object p = poll.getValue();
if (p instanceof HashMap) {
HashMap pollHash = (HashMap) p;
if (pollHash.containsKey("Name")) {
pollName = (String) pollHash.get("Name");
}
if (pollHash.containsKey("Elections")) {
HashMap election = (HashMap) pollHash.get("Elections");
Iterator electionIterator = election.values().iterator();
while (electionIterator.hasNext()) {
Object electionObj = electionIterator.next();
if (electionObj instanceof HashMap) {
HashMap electionHash = (HashMap) electionObj;
if (electionHash.containsKey("Name")) {
String electionName = (String) electionHash.get("Name");
}
}
};
}
}
This seems like a pretty tedious way to drill down through the data structure, and I'm wondering if there's a better way.
I've seen the getValue(java.lang.Class<T> valueType) method in the documentation, but haven't been able to get it to work in my case, since I'm working with composed objects and not just containers for primitive types. How does the function know what Firebase data to assign to which member variables of a model object? Does it match Firebase key names with member variables, and therefore do these have to be exactly the same, with case sensitivity? How would that deal with Firebase generated key names like produced when pushing to a List? How to you construct model objects for composed objects?
The getValue(java.lang.Class valueType) method follows the same rules as the jackson object mapping library (it's what we use internally: http://wiki.fasterxml.com/JacksonInFiveMinutes). So, your Java classes must have default constructors (no arguments) and getters for the properties that you want assigned (https://www.firebase.com/docs/java-api/javadoc/com/firebase/client/DataSnapshot.html#getValue(java.lang.Class)).
In short, yes, the key names in Firebase must match the member variables.
For an example using composite objects, including a list, see AndroidDrawing. Specifically, the Segment class contains a list of Point instances. There is one catch using lists of data generated with the .push() method. Since the key names generated are Strings so that they can be unique across clients, they deserialize the Maps rather than Lists. However, if you iterate over dataSnapshot.getChildren() they will be returned in order.
In addition, if you don't want to deserialize into a HashMap, you can use the child() method on DataSnapshot. For instance:
String pollName = poll.child("Name").getValue(String.class);
DataSnapshot elections = poll.child("Elections");
for (DataSnapshot election : elections.getChildren()) {
String electionName = election.child("Name").getValue(String.class);
}
In this example, any values that don't exist will be returned as null.
Hope that helps!
public T getValue(Class valueType)
1.The class must have a default constructor that takes no arguments
2.The class must define public getters for the properties to be assigned. Properties without a public getter will be set to their default value when an instance is deserialized
Check it from:
this source It'll help you
detail
I'm trying to merge these three objects into a single complex object:
public class Person {
private String name;
private List<Event> events;
// getters and setters
}
public class Event {
private String name;
private List<Gift> gifts;
// getters and setters
}
public class Gift {
private String name;
private String recipient;// the name of the person
private String eventName;
// getters and setters
}
My goal is to save the Person object in MongoDB using Morphia and this how I want my document laid out. I've created a document builder, of sorts, that combines lists of each object. Each Person gets a list of all Events, but can only receive specific Gifts. While my document builder does create a document that Morphia can persist, only the Gifts of that last recipient (sort order) are inserted into the Events for all Persons. Though for the correct Events.
public void merge() {
for (Person person : listOfPersons) {
for (Event event : listOfEvents) {
// somePersonsGifts: a sublist of gifts based on Event and Person.
List<Gift> somePersonsGifts = new ArrayList<Gift>();
for (Gift gift : listOfGifts) {
if (person.getName().equals(gift.getRecipient()) && gift.getEventName().equals(event.getName())) {
somePersonsGifts.add(gift);
}
}
event.setGifts(somePersonsGifts);
}
person.setEvents(listOfEvents)
}
}
If I modify the code slightly to process one person at a time by removing the outer loop and having the method take an argument for specific index of the Persons list:
public void merge(int p) {
Person person = listOfPersons.get(p);
//...and so on
I get one complete Person object with the correct gifts. If try to feed the this modified version into a loop, the problem comes back. I've tried using regular for-loops and synchronized collections. I've tried using Google Guava's ImmutableArrayList and still no luck. I know the problem is that I'm changing the lists while accessing them but I can't find anyway around it. I wrote a DAO that uses the MongoDB driver directly and it works properly, but it's a lot more code and quite ugly. I really want this approach to work, the answer is in front of me but I just can't see it. Any help would be greatly appreciated.
Here is your problem:
List<Gift> somePersonsGifts = new ArrayList<Gift>();
....
event.setGifts(somePersonsGifts);
You add the gifts only for one person; if you want to aggregate all the gifts into the event, re-use the existing list.
I don't know anything about MongoDB or Morphia but I suspect the problem is your use of the setters event.setGifts(somePersonsGifts) and person.setEvents(events). Your code does not seem to merge the existing gift and event lists with the ones you are calculating further in the loop, which is how you would want it to behave (if I understand the question correctly).
You should retrieve the allready existing gift list (and event list too) instead of overwriting them with empty new ones.
I don't know if the method merge() is inside the list but I assume that since you are using the list events here
person.setEvents(events);
Maybe you meant
person.setEvents(listOfEvents)
Notice that you are adding all the events to each person. If all the persons went to all the events, it is unnecessary to have the events inside the person.
I want to build in a select with the possibility of marking more elements. So multiple="true". I use mysql and the Dao Technology of spring. I get the values for the select from database successfully. But now I have a problem when inserting the selected values to my database.
The important tables for that are:
The table demo.instrumente is filled with data like guitar, piano, etc. and an id. These values (i.e. guitar, piano) are displayed in the multiple select.
A user is able to select maybe 2 or 3 instruments. So I need to add the following instruments to the students. I do this with the table schueler_instrumente. Every student and instrument has an id. So i need to create data like this:
student_id 1 and instrument_id 2
student_id 1 and instrument_id 5
Here is my code for the instrument model class:
public class Instrumente {
private Integer instrumentid;
private String instrumentname;
//...getters and setters
}
This code is part of my controller:
#RequestMapping(method = RequestMethod.GET)
public String showUserForm(ModelMap model) {
model.put("instrumentListe", schuelerManager.getinstrumente());
return "usercenter";
}
And here's the relevant part of my schuelerManager
public Map<String, String> getinstrumente() {
Map<String,String> result = new LinkedHashMap<String,String>();
for (Instrumente instrument : instrumentDao.getInstrumente()) {
result.put(instrument.getInstrumentid().toString(),
instrument.getInstrumentname());
}
return result;
}
And here's how I get the data from my database:
public List<Instrumente> getInstrumente() {
return getJdbcTemplate().query("SELECT * FROM instrumente",
new RowMapper<Instrumente>() {
public Instrumente mapRow(ResultSet rs,
int rowNum)
throws SQLException {
Instrumente instrument = new Instrumente();
instrument.setInstrumentid
(rs.getInt("Instrument_ID"));
instrument.setInstrumentname
(rs.getString("Instrumentenbezeichnung"));
return instrument;
}
});
}
I do now know what I need to do in order to get the selected values from the select list. What do I have to write to the path="?" in the jsp.
I think that I can get a list of values back but how can I insert this list to my table schueler_instrument. Did I need to make a while or for repeat and make an insert everytime?
I can't find any nice example on the Internet. I hope someone can show me how to do this maybe with some code snippets.
In your controller's showUserForm() you are adding correctly your date to the ModelMap (or you could use its Java-5 counterpart Model). Now you'll need to use Spring's form tags in your view to represent the options in a dropdown/list way and receive onSubmit back in your controller the results that you will further persist in your db.
Have a look for a full example here.
Something that is not showcased in this example and I suggest you take a look is the #ModelAttribute annotation which is a nice way to communicate objects and values between your controller and your jsp view. For an example have a look in this tutorial.
Im using ORMLite in my Android app. I need to persist this class, which has a HashMap. What is a good way of persisting it? Its my first time trying to persist a HashMap, also first time with ORMLite so any advice would be greatly appreciated!
*Edit*
If that makes any difference, the Exercise class is simply a String (that also works as id in the database), and the Set class has an int id (which is also id in database), int weight and int reps.
#DatabaseTable
public class Workout {
#DatabaseField(generatedId = true)
int id;
#DatabaseField(canBeNull = false)
Date created;
/*
* The hashmap needs to be persisted somehow
*/
HashMap<Exercise, ArrayList<Set>> workoutMap;
public Workout() {
}
public Workout(HashMap<Exercise, ArrayList<Set>> workoutMap, Date created){
this.workoutMap = workoutMap;
this.created = created;
}
public void addExercise(Exercise e, ArrayList<Set> setList) {
workoutMap.put(e, setList);
}
...
}
Wow. Persisting a HashMap whose value is a List of Sets. Impressive.
So in ORMLite you can persist any Serializable field. Here's the documentation about the type and how you have to configure it:
http://ormlite.com/docs/serializable
So your field would look something like:
#DatabaseField(dataType = DataType.SERIALIZABLE)
Map<Exercise, List<Set>> workoutMap;
Please note that if the map is at all large then this will most likely not be very performant. Also, your Exercise class (and the List and Set classes) need to implement Serializable.
If you need to search this map, you might consider storing the values in the Set in another table in which case you might want to take a look at how ORMLite persists "foreign objects".
Main Goal : Select a school listed in the first datagrid, and display all the student records /details of that school in the next datagrid. But, since datagrid is editable and requirement mentions : "Use a Wrapper class around the object to get the data, set the same and save. Ensure wrapper is bindable to take into consideration the updates being made to datagrid text fields."
I have an object which is a type of a Data Access Objects i.e. DO.
mySchool:mySchoolDO.
The mySchoolDO is an actionScript class of following code :
public class mySchoolDO
{
public var schoolName:String;
public var schoolLocation:String;
public var schoolStudents:ArrayCollection;
// Array of myStudentDO instances
}
The above has an array collection of students called schoolStudents which accesses the myStudentDO.as class as described below.
myStudent:myStudentDO.
The myStudentDO.as is an actionScript class of following code :
public class myStudentDO implements IExternalizable
{
[Bindable] public var studentID: String;
[Bindable] public var studentCourses: Array
[Bindable] public var studentPhone:Number;
[Bindable] public var studentGender:Boolean;
public function readExternal(input:IDataInput):void {
studentID = SerializationUtils.readNullableString(input);
studentCourses = SerializationUtils.readNullableString(input);
studentPhone = SerializationUtils.readStringList(input);
studentGender = SerializationUtils.readNullableString(input);
}
In my main mxml application. I do the following :
1> Get all schools array. Instantiate a school object and get school data.
2> Using school object access all studentsDO data and store as an ARRAY OF OBJECTS.
private function availableSchools(schools:Array): void
{
mySchools=schools;
loadSchools();
}
private function loadSchools():void
{
for(var z:int =0; z
Once a school is clicked, an ItemClick Event is fired which takes the school and then displays all the school students data.
private function itemClickEvent(event:ListEvent):void
{
_school = event.currentTarget.selectedItem;
showSchoolStudents(_school);
}
private function showSchoolStudents(school:mySchoolDO)
{
for(var b:int=0; b<(school.schoolStudents).length;b++)
{
schoolDatagridProvider.push(school.schoolStudents[b]);
}
dgOfSchool.dataProvider = schoolDatagridProvider;
dgOfSchool.invalidateList();
}
The showSchoolStudents will display all the details of students on to the datagrid. But,
my datagrid is editable. And, I want to use WRAPPER CLASS around this object such that
a> I can retrieve individual values as present in studentsDO i.e. studentID, studentCourses, studentGender, studentPhone.
b> I shouldbe able to set the values as they are updated in the visual datagrid.
c> Finally save all the data and submit on submit click.
Please help with code. It will be highly appreciated.
Thanks.
Looks like you're really just starting out with Flex.
Suggestion: read the documentation. There's plenty of examples of the basic thing you're trying to do here which is to have an editable Grid that displays data coming from the server.
Some key concepts:
Make sure you're using an ArrayCollection as the dataProvider to the Grid, not an Array. ArrayCollections provide the change-notification machinery you'll invariably want with this use case.
Make sure your DO model classes are all Bindable. Looks like you're only making the Student properties bindable at the moment. Make the School bindable as well.
Make the reference from School to the collection of Students an ArrayCollection, not an Array.
Follow convention and use initial caps in Class names. i.e. MyStudentDO, MySchoolDO
Tell the DataGrid that you want to allow item editing.
But, in all seriousness, read the docs. There's plenty of examples available.