Is there a better way to pre-load items into a database? - android

In my Android app I have a
SQLiteHelper class that extends SQLIteOpenHelper, and takes care of things like table-creation and upgrades.
SQLiteDatasource class that performs CRUD operations on the SQLiteHelper object.
I want to pre-load one of the tables with certain items so there is something present when the user first uses the app. These items may change so I want to make them modular.
Right now I am doing it this way:
public class MyDefaults {
public static final ArrayList<HashMap<String, String>> MY_DEFAULTS;
static {
MY_DEFAULTS = new ArrayList<HashMap<String, String>>();
HashMap<String, String> map = new HashMap<String, String>();
//All the values below you change to whatever defaults you want
map.clear();
map.put(SQLiteHelper.KEY_1, "Value 1A");
map.put(SQLiteHelper.KEY_2, "Value 2A");
map.put(SQLiteHelper.KEY_3, "Value 3A");
MY_DEFAULTS.add(new HashMap<String, String>(map));
map.clear();
map.put(SQLiteHelper.KEY_1, "Value 1B");
map.put(SQLiteHelper.KEY_2, "Value 2B");
map.put(SQLiteHelper.KEY_3, "Value 3B");
MY_DEFAULTS.add(new HashMap<String, String>(map));
map.clear();
map.put(SQLiteHelper.KEY_1, "Value 1C");
map.put(SQLiteHelper.KEY_2, "Value 2C");
map.put(SQLiteHelper.KEY_3, "Value 3C");
MY_DEFAULTS.add(new HashMap<String, String>(map));
//and so on
}
}
And then in my SQLiteDatasource class I have a method that performs the insert of these default values:
public void preloadDefaults() {
mDatabase.beginTransaction();
try {
for (HashMap<String, String> map : MyDefaults.MY_DEFAULTS) {
ContentValues values = new ContentValues();
values.put(SQLiteHelper.KEY_1, map.get(SQLiteHelper.KEY_1));
values.put(SQLiteHelper.KEY_2, map.get(SQLiteHelper.KEY_2));
values.put(SQLiteHelper.KEY_3, map.get(SQLiteHelper.KEY_3));
mDatabase.insert(SQLiteHelper.SOME_TABLE, null, values);
}
}
finally {
mDatabase.endTransaction();
}
}
Is my way of doing this considered bad practice? Is there a better way to define the "defaults" that get inserted into a table after it gets created? Possibly through XML instead of a static class?
Note: I can't just copy an external DB because I'm actually inserting these fields with some other values created at runtime (the code above is a simplification of what my real code is).

As it is in this answer also
The SQLiteAssetHelper library makes this task really simple.
It's easy to add as a gradle dependency (but a Jar is also available for Ant/Eclipse), and together with the documentation it can be found at:
https://github.com/jgilfelt/android-sqlite-asset-helper
As explained in documentation:
Add the dependency to your module's gradle build file:
dependencies {
compile 'com.readystatesoftware.sqliteasset:sqliteassethelper:+'
}
Copy the database into the assets directory, in a subdirectory called assets/databases. For instance:
assets/databases/my_database.db
(Optionally, you may compress the database in a zip file such as assets/databases/my_database.zip. This isn't needed, since the APK is compressed as a whole already.)
Create a class, for example:
public class MyDatabase extends SQLiteAssetHelper {
private static final String DATABASE_NAME = "my_database.db";
private static final int DATABASE_VERSION = 1;
public MyDatabase(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
}

You can memorize your data, with Serialize Objects. Read here:
How do I serialize an object and save it to a file in Android?

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

Annotation Processor : initialize a field

I am writing an annotation processor in android which generates a java file. I am using JavaPoet library for that.
The purpose of generated file:
It should have a list of names of the classes with a particular annotation that my processor supports and provide a public method to get that list.
Now, I've generated the file:
private final List<String> names;
GeneratedFile(ArrayList<String> names) {
this.names = names;
}
public List<String> getNames() {
return names;
}
Now, the problem is: How do I initialize the names field from the processor? The Javapoet api provides an initializer for the field but that only takes a string.
In my processor, I've the list of classes that have my supported annotation. I want to populate this field with that list.
As you already know, JavaPoet offers only a string to specify field initialization. To accomplish your task you have to (I will show you some code that is not specific to your problem, but it can be a good example to show you how to do it):
Get from your annotation processor the list of classes with your annotation (the code is copied from a my library):
#Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
model = new PrefsModel();
parseBindType(roundEnv);
// Put all #BindSharedPreferences elements in beanElements
for (Element item : roundEnv.getElementsAnnotatedWith(BindSharedPreferences.class)) {
AssertKripton.assertTrueOrInvalidKindForAnnotationException(item.getKind() == ElementKind.CLASS, item, BindSharedPreferences.class);
// store type name somewhere
}
return true;
}
Use this set of TypeName to generate the initial value for you field:
...
Builder sp = FieldSpec.builder(ArrayTypeName.of(String.class), "COLUMNS", Modifier.STATIC, Modifier.PRIVATE,
Modifier.FINAL);
String s = "";
StringBuilder buffer = new StringBuilder();
for (SQLProperty property : entity.getCollection()) {
buffer.append(s + "COLUMN_" +
columnNameToUpperCaseConverter.convert(property.getName()));
s = ", ";
}
classBuilder.addField(sp.addJavadoc("Columns array\n").initializer("{" +
buffer.toString() + "}").build());
...
You will find my library on github. In particular, you have to read the class com.abubusoft.kripton.processor.sqlite.BindTableGenerator.
Hope this information can be still useful.

Android - XML or SQLite for static data

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.

android sqllite cannot be accessed from outside package

I am making an Android app to learn sqllite. Because I use 7 tables, I decided to create 7 class files in a folder "DBHelper", and want to make 7 files in a folder "DBadapter". Here what the structure looks like:
root
DBHelper: 7 helper files (ex: PersonHelper.java)
DBadapter: 7 adapter files (ex: PersonDAO.java)
But I get an error message with PersonDAO.java: "cannot be accessed from outside package", when I declared the object: "PersonHelper personHelper = new PersonHelper(context);" in the constructor.
Anyone has an idea how to fix that without putting all files in one folder? What is the standard in the industry when creating multiple large tables?
PS: The error is gone once I place all files in one directory.
public class PersonDAO {
private Context context;
//Database info
private static final String DATABASE_NAME = "MyDB";
private static final int DATABASE_VERSION = 1;
//Table helper info
public PersonHelper databaseHelper;
private SQLiteDatabase db = null;
//Constructors
PersonDAO(Context context) {
this.context = context;
databaseHelper = new PersonHelper(context); //Error: "cannot be accessed from outside package"
}
Your constructor of your PersonHelper is probably default like it is in your PersonDAO class. So it can only be accessed from the same package. You have to change it to public to access it from PersonDAO:
public PersonHelper(Context context){
...
}

What is the fastest way to parse a JSON string into an SQLite table?

I'm writing an Android application which will occasionally need to download a json string of around 1MB and containing around 1000 elements, and parse each of these into an SQLite database, which I use to populate a ListActivity.
Even though the downloading and parsing isn't something that needs to be done on every interaction with the app (only on first run or when the user chooses to refresh the data), I'm still concerned that the parsing part is taking too long, at around two to three minutes - it seems like an eternity in phone app terms!
I'm currently using Gson to parse each json object into a custom object that I've defined, and then using an SQLiteOpenHelper to enter it into the database.
My question is - is there a faster way of implementing this? Would it be noticeably faster to interact with the json directly, without using Gson? Or am I doing something stupid in the code below that's slowing things down?
Here's the method I'm using in my AsyncTask to parse the json to SQLite:
protected Boolean doInBackground(Integer... bType) {
InputStream source = getJsonInputStream(bTypeString);
VegDataHandler db = new VegDataHandler(mainActivity, bTypeString);
Gson gson = new Gson();
Reader reader = new InputStreamReader(source);
JsonParser jParser = new JsonParser();
JsonArray jArray = jParser.parse(reader).getAsJsonArray();
aLength = jArray.size();
mCurrProgress = 1;
publishProgress(mCurrProgress, 0, aLength);
/* Each array element is of the form { company: {...} } */
int i = 0;
mCurrProgress = 2;
for (JsonElement obj : jArray) {
Company c = gson.fromJson(obj.getAsJsonObject().getAsJsonObject("company"), Company.class);
db.addCompany(c);
i++;
publishProgress(mCurrProgress, i);
}
}
This is the addCompany method from my VegDataHandler class, which extends SQLiteOpenHelper:
public void addCompany(Company c) {
SQLiteDatabase db = this.getWritableDatabase();
ContentValues values = new ContentValues();
values.put(KEY_ID, c.getCompanyId());
values.put(KEY_NAME, c.getCompanyName());
values.put(KEY_RYG, c.getCompanyRedYellowGreen());
values.put(KEY_COUNTRY, c.getCompanyCountry());
values.put(KEY_URL, c.getCompanyUrl());
values.put(KEY_NOTES, c.getCompanyNotes());
values.put(KEY_EMAIL, c.getCompanyEmail());
db.insertWithOnConflict(TABLE_COMPANY, null, values, SQLiteDatabase.CONFLICT_REPLACE);
db.close();
}
This is the class that holds each json element before adding to the SQLite (I've omitted the getters and setters for brevity).
public class Company {
public Company() {
}
#SerializedName("id")
public int companyId;
#SerializedName("company_name")
public String companyName;
#SerializedName("red_yellow_green")
public String companyRedYellowGreen;
#SerializedName("country")
public String companyCountry;
#SerializedName("url")
public String companyUrl;
#SerializedName("notes")
public String companyNotes;
#SerializedName("email")
public String companyEmail;
}
Thanks in advance for any replies.
First you need to determine the portion(s) of the process that are eating up the most time. From your comment above it sounds like the JSON parsing is the culprit.
If JSON parsing is the issue:
Research and consider a faster JSON parser. Perhaps something like json-smart.
If SQLite/DB bulk inserts are the issue:
See my answer here
General tips:
Recycle objects as much as possible (keep new to a minimum)
Always use transactions in DB bulk inserts at the very least
Don't open/close the database. Do this once at the start/finish of your processing
Use pre-compiled statements!

Categories

Resources