Android - XML or SQLite for static data - android

I am making Android app for practicing driving licence theory tests. I will have about 3000 questions. Question object would have several atributes (text, category, subcategory, answers, group). I will create them and put in app, so data won't ever change. When user chooses category, app would go througt data, look which question meets requirements (that user selected) and put it in list for displaying. What should I use to store data/questions, XML or SQLite? Thanks in advance.
Edit:
I forgot to mentiont that app won't use internet connection. Also, I planned to make simple java app for entering data. I would copy text from government's website (I don't have access to their database and I have to create mine), so I thought to just put question's image url to java program and it would download it and name it automaticaly. Also, when entering new question's text it would tell me if that question already exist before I enter other data. That would save me time, I wouldn't have to save every picture and name it my self. That is what I thought if using XML. Can I do this for JSON or SQLite?

If you do not have to perform complex queries, I would recommend to store your datas in json since very well integrated in android apps using a lib such as GSON or Jackson.
If you don't want to rebuild your app / redeploy on every question changes. You can imagine to have a small webserver (apache, nginx, tomcat) that serves the json file that you will request on loading of the app. So that you will download the questions when your app is online or use the cached one.
XML is a verbose format for such an usage, and does not bring much functions....
To respond to your last question, you can organise your code like that :
/**
* SOF POST http://stackoverflow.com/posts/37078005
* #author Jean-Emmanuel
* #company RIZZE
*/
public class SOF_37078005 {
#Test
public void test() {
QuestionsBean questions = new QuestionsBean();
//fill you questions
QuestionBean b=buildQuestionExemple();
questions.add(b); // success
questions.add(b); //skipped
System.out.println(questions.toJson()); //toJson
}
private QuestionBean buildQuestionExemple() {
QuestionBean b= new QuestionBean();
b.title="What is the size of your boat?";
b.pictures.add("/res/images/boatSize.jpg");
b.order= 1;
return b;
}
public class QuestionsBean{
private List<QuestionBean> list = new ArrayList<QuestionBean>();
public QuestionsBean add(QuestionBean b ){
if(b!=null && b.title!=null){
for(QuestionBean i : list){
if(i.title.compareToIgnoreCase(b.title)==0){
System.out.println("Question "+b.title+" already exists - skipped & not added");
return this;
}
}
System.out.println("Question "+b.title+" added");
list.add(b);
}
else{
System.out.println("Question was null / not added");
}
return this;
}
public String toJson() {
ObjectMapper m = new ObjectMapper();
m.configure(Feature.ALLOW_SINGLE_QUOTES, true);
String j = null;
try {
j= m.writeValueAsString(list);
} catch (JsonProcessingException e) {
e.printStackTrace();
System.out.println("JSON Format error:"+ e.getMessage());
}
return j;
}
}
public class QuestionBean{
private int order;
private String title;
private List<String> pictures= new ArrayList<String>(); //path to picture
private List<String> responseChoice = new ArrayList<String>(); //list of possible choices
public int getOrder() {
return order;
}
public void setOrder(int order) {
this.order = order;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public List<String> getPictures() {
return pictures;
}
public void setPictures(List<String> pictures) {
this.pictures = pictures;
}
public List<String> getResponseChoice() {
return responseChoice;
}
public void setResponseChoice(List<String> responseChoice) {
this.responseChoice = responseChoice;
}
}
}
CONSOLE OUTPUT
Question What is the size of your boat? added
Question What is the size of your boat? already exists - skipped & not added
[{"order":1,"title":"What is the size of your boat?","pictures":["/res/images/boatSize.jpg"],"responseChoice":[]}]
GIST :
provides you the complete working code I've made for you
https://gist.github.com/jeorfevre/5d8cbf352784042c7a7b4975fc321466
To conclude, what is a good practice to work with JSON is :
1) create a bean in order to build your json (see my example here)
2) build your json and store it in a file for example
3) Using android load your json from the file to the bean (you have it in andrdoid)
4) use the bean to build your form...etc (and not the json text file) :D

I would recommend a database (SQLite) as it provides superior filtering functionality over xml.

Create the db using DB Browser for SQLite
And then use the library SQLiteAssetHelper in the link-
https://github.com/jgilfelt/android-sqlite-asset-helper
Tutorial on how to use -
http://www.javahelps.com/2015/04/import-and-use-external-database-in.html

You can use Paper https://github.com/pilgr/Paper its a fast NoSQL data storage for Android.

SQLite is the best for your system. because you will have to maintain (text, category, subcategory, answers, group) etc. So if you create db and create table for them. That will be easy to manage and you can relationship with each other which is not possible to XML.

Related

DC2type on greenDao

I am using GreenDao for Android application, with some specification, for example, I have a Contact Model with some information like name, avatar, phone number, etc...
Right now the need is to change from only one phone number to a multiphone number.
Instead of creating two tables (table for numbers, and table for contacts), I really need just one information is the number so in my backend the contact numbers is stocked on a DC2type, (a json array saved as a string).
Do we have a possibility to do that using GreenDao?
i search for a solution or a DC2type implementation , etc ... and nothing is found
so i decide to created by my self , and this is what i did :
using the #Convert annotation presented of GreenDao 3 :
#Property(nameInDb = "phoneNumbers")
#Convert(converter = PhoneNumbersConverter.class, columnType = String.class)
private List<String> phoneNumbers;
static class PhoneNumbersConverter implements PropertyConverter<List<String>, String> {
#Override
public List<String> convertToEntityProperty(String databaseValue) {
List<String> listOfStrings = new Gson().fromJson(databaseValue,List.class);
return listOfStrings;
}
#Override
public String convertToDatabaseValue(List<String> entityProperty) {
String json = new Gson().toJson(entityProperty);
return json;
}
}
short story long , i create a json to array parser
thanks to myself to helped me :D

JSoup web-scraping: How to select each value

I'm currently trying to get some values from a website with Jsoup for my android application.
Basically, I wanted to extract these values:
so that in the code, the model name should go to gpuModel variable, prices goes to gpuPrice and so on for every single Graphic card. and then I would store them in firebase using this code:
public void addToDatabase(String model, int price, int rating, double value,
double bench) {
Map<String, Object> docData = new HashMap<>();
docData.put("model", model);
docData.put("rating", rating);
docData.put("bench", bench);
docData.put("value", value);
docData.put("price", price);
db.collection("gpu").document(model).set(docData);
}
This is the HTML code for each GPU:
i am currently trying to extract only the gpu model name to keep it simple (in the end i want to extract all the other values too), this is my current web scraping code:
public void webScrape(){
new Thread(new Runnable() {
#Override
public void run() {
final StringBuilder builder = new StringBuilder();
try {
Document doc = Jsoup.connect("https://www.videocardbenchmark.net/GPU_mega_page.html").get();
Elements gpus = doc.select("[id^=gpu]");
for (Element i : gpus) {
Elements gpuModel = i.select("tr td:nth-child(2)");
String gpuName = gpuModel.text().replace("/", "");
addToDatabase(gpuName, 12,12,12,12);
}
} catch (IOException e){
e.printStackTrace();
}
runOnUiThread(new Runnable() {
#Override
public void run() {
}
});
}
}).start();
going by my logic, this should select all the GPU, and then in the for loop, it would extract only the card's name. set the gpuName to whatever was extracted and push it to the database.
But instead, I got this in my database:
It extracted the GPU name, but also all the other unwanted fields (including the prices, value, test date, etc).
so my question is, how do i select each value separately? all the examples i found on the internet was done with a very simple website where each value has their own ID so I can't really learn from them.
If there's anything i should provide, please do tell me.
simple code representation of what i want:
Document doc = Jsoup.connect(the url).get();
Elements gpus = doc.select(all gpu);
for (each gpu in all gpus) {
gpuName = gpu.select(name);
gpuPrice = gpu.select(price);
gpuValue = gpu.select(value);
gpuPower = gpu.select(power);
addToDatabase(gpuName, gpuPrice, gpuPower, gpuValue);
}
You should use a:nth-child(2) as the model name selector inside your run method:
Elements gpuModel = i.select("a:nth-child(2)");

GreenDAO does not persist data across application restart

I want to use GreenDAO for persistence, but I cannot get it to persist my data.
The data is saved and loaded correctly as long as the application is not restarted.
Once i swipe the app away and reopen it from scratch, GreenDAO does not see the previous data (both on the emulator and real device).
This is my entity:
#Entity
public class TestSingleEntity {
#Id(autoincrement = true)
Long id;
int someNumber;
public TestSingleEntity(int someNumber) {
this.someNumber = someNumber;
}
#Generated(hash = 787203968)
public TestSingleEntity(Long id, int someNumber) {
this.id = id;
this.someNumber = someNumber;
}
#Generated(hash = 1371368161)
public TestSingleEntity() {
}
// ... some more stuff
}
This is how I insert entities to database:
Random rnd = new Random();
TestSingleEntity singleEntity = new TestSingleEntity();
singleEntity.setSomeNumber(rnd.nextInt());
DaoSession session = ((MyApp)getApplication()).getDaoSession();
TestSingleEntityDao dao = session.getTestSingleEntityDao();
dao.insert(singleEntity);
Log.d("tgd", "Inserted an entity with id " + singleEntity.getId());
And this is how I read them:
Query query = dao.queryBuilder().orderAsc(TestSingleEntityDao.Properties.SomeNumber).build();
StringBuilder builder = new StringBuilder();
List<TestSingleEntity> result = query.list();
Log.d("size", result.size());
for (TestSingleEntity testSingleEntity : result) {
Log.d("entity", testSingleEntity.toString());
}
As I have said, as long as I stay in the app (moving around in different activities is okay), everytime the insert is called, a new entity with a new ID is created. As soon as I relaunch the app, it goes back to square one.
The setup was taken directly from the GitHub page. What am I doing wrong? Thanks
Disclaimer: GreenDAO has gone through major changes since I last used it so this is purely based on reading their code on the github.
Apparently GreenDAO's poorly documented DevOpenHelper drops all tables on upgrade, so the real question is why is onUpgrade being called when clearly there hasn't been a change to the schema version. Try to look for the log line that mentions dropping the tables as described in the template for DevOpenHelper.
Regardless, using OpenHelper instead should fix the issue.

Sugar ORM is not saving data into the database

I am currently using Sugar ORM and Android Async Http Client for my Android application.
I read through the documentation of Sugar ORM and did exactly what is written there.
My HttpClient is using the singleton pattern and provides methods for calling some APIs.
Now comes the bad part about it. I am not able to save the data persistently into my database which is created by Sugar ORM.
Here is the method, that is calling an API:
public void getAvailableMarkets(final Context context, final MarketAdapter adapter) {
String url = BASE_URL.concat("/markets.json");
client.addHeader("Content-Type", "application/json");
client.addHeader("Accept", "application/json");
client.get(context, url, null, new JsonHttpResponseHandler() {
#Override
public void onSuccess(int statusCode, Header[] headers, JSONArray response) {
Log.i(TAG, "Fetched available markets from server: " + response.toString());
Result<Markets> productResult = new Result<Markets>();
productResult.setResults(new Gson().<ArrayList<Markets>>fromJson(response.toString(),
new TypeToken<ArrayList<Markets>>() {
}.getType()));
ArrayList<Markets> marketsArrayList = productResult.getResults();
// This lines tells me that there are no entries in the database
List<Markets> marketsInDb = Markets.listAll(Markets.class);
if(marketsInDb.size() < marketsArrayList.size() ||
marketsInDb.size() > marketsArrayList.size()) {
Markets.deleteAll(Markets.class);
for(Markets m : marketsArrayList) {
Markets market = new Markets(m.getId(), m.getName(), m.getChainId(), m.getLat(),
m.getLng(), m.getBusinessHourId(), m.getCountry(), m.getZip(), m.getCity(),
m.getStreet(), m.getPhoto(), m.getIcon(), m.getUrl());
market.save();
adapter.add(market);
}
adapter.notifyDataSetChanged();
}
List<Markets> market = Markets.listAll(Markets.class);
// This lines proves that Sugar ORM is not saving the entries
Log.i(TAG, "The market database list has the size of:" + market.size());
}
});
}
This is what Logcat is printing:
D/Sugar: Fetching properties
I/Sugar: Markets saved : 3
I/Sugar: Markets saved : 5
I/RestClient: The market database list has the size of:0
Also I took a look at the Sugar ORM tag here at stackoverflow, but no answers or questions could give me a hint on how to solve that problem.
I am a newbie to the android ecosystem and would love any help of you guys to solve this problem.
Thanks in advance
I just solve it the same problem as you have.
It was a pain in the neck but after few hours I find out what caused this problem.
Using Sugar ORM you must not set id property as it's belongs to SugarRecord class,
otherwise ORM will try to update objects instead of insert them.
As I need to have field with my object id, I used json annotation to assign it to another field.
Last step was configure GSON to exclude fields without Expose annotation.
So my class looks like one below now:
public class MyClass
{
#Expose
#SerializedName("id")
private long myId;
#Expose
private String field1;
#Expose
private String field2;
#Expose
private byte[] field3;
#Expose
private double field4;
public MyClass() { }
// parametrized constructor and more logic
}
Cheers!

Alphabet Indexed ListView Without a cursor

I receive data from a server using JSON and I want to order them alphabetically with alphabet indexed section and store them in a ListView.
Maybe something that will happen in :
for(int i=0;i<jArray.length();i++){
// here
}
I read that you can order elements like that only using a cursor. In my case would be very inefficient to store the elements from the server in the database and read them again. Waste of time and memory.
So, I am asking you if there could be any solution for my problem : order alphabetically with alphabet indexed section string received from JSON .
EDIT: I want my listview to look like this http://eshyu.wordpress.com/2010/08/15/cursoradapter-with-alphabet-indexed-section-headers/ . I mean with those sections . All tutorials I found said that you need to fetch information with a cursor. My question was if I could't do this wihout a cursor, because it would be a waste of memory to store them in the local database too.
You may need to parse the JSON Array :
List<Project> list = new ArrayList<Project>();
for (int i = 0; i < jArray.length(); i++) {
JSONObject obj = (JSONObject) jArray.get(i);
project = new Project();
project.setId( Long.parseLong(obj.get("id").toString()));
project.setKey(obj.get("key").toString());
project.setName(obj.get("name").toString());
list.add(project);
}
You can use the comparator class like this to sort them :
Collections.sort(list), new Comparator<Project>() {
public int compare(Project p1, Project p2) {
return p1.getKey().compareToIgnoreCase(p2.getKey());
}
});
You can also have Project class and implements Comparable:
public class Project implements Comparable<Project> {
private long id;
private String key;
private String name;
public int compareTo(Project p) {
if (this.key > p.key)
return -1;
else if (this.key < p.key)
return 1;
return 0;
}
}
And then sort the list by Collections.sort(list);
My suggestion is try to sort the data in the Server-side, because the memory of the phone is limited and it may make you application time consuming to show the data, but you do not have memory limitation problem in the Server-side.
use a comparator to sort the arraylist as described here . And then use an ArrayAdapter to show the items in Listview

Categories

Resources