I was reading this tutorial: http://developer.android.com/training/basics/data-storage/databases.html and it raised a lot of questions.
This is my code I made while following the tutorial:
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.provider.BaseColumns;
public final class SongDbHelper extends SQLiteOpenHelper {
// If you change the database schema, you must increment the database version.
public static final int DATABASE_VERSION = 1;
public static final String DATABASE_NAME = "Song.db";
private static final String TEXT_TYPE = " TEXT";
private static final String PRIMARY_KEY_TYPE = " INTEGER PRIMARY KEY";
private static final String COMMA_SEP = ",";
private static final String SQL_CREATE_ENTRIES =
"CREATE TABLE " + SongEntry.TABLE_NAME + " (" +
SongEntry._ID + PRIMARY_KEY_TYPE + COMMA_SEP +
SongEntry.COLUMN_NAME_SONG_TITLE + TEXT_TYPE + COMMA_SEP +
SongEntry.COLUMN_NAME_ENGLISH_LYRICS + TEXT_TYPE + COMMA_SEP +
SongEntry.COLUMN_NAME_ROMAJI_LYRICS + TEXT_TYPE + COMMA_SEP +
SongEntry.COLUMN_NAME_KANJI_LYRICS + TEXT_TYPE + COMMA_SEP +
SongEntry.COLUMN_NAME_INFO + TEXT_TYPE +
" )";
private static final String SQL_DELETE_ENTRIES =
"DROP TABLE IF EXISTS " + SongEntry.TABLE_NAME;
public SongDbHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
public void onCreate(SQLiteDatabase db) {
db.execSQL(SQL_CREATE_ENTRIES);
}
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
// This database is only a cache for online data, so its upgrade policy is
// to simply to discard the data and start over
db.execSQL(SQL_DELETE_ENTRIES);
onCreate(db);
}
public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {
onUpgrade(db, oldVersion, newVersion);
}
public static abstract class SongEntry implements BaseColumns {
public static final String TABLE_NAME = "Song";
public static final String COLUMN_NAME_SONG_TITLE = "song_title";
public static final String COLUMN_NAME_ENGLISH_LYRICS = "english_lyrics";
public static final String COLUMN_NAME_ROMAJI_LYRICS = "romaji_lyrics";
public static final String COLUMN_NAME_KANJI_LYRICS = "kanji_lyrics";
public static final String COLUMN_NAME_INFO = "info";
}
}
Are we supposed to call SongDbHelper.onCreate() every time the app opens up? (I'm imagining putting it in my main activity's onCreate() method.
If you call SongDbHelper.onCreate() more than once, will it recreate the table, or will SongDbHelper.onCreate() just fail silently and gracefully?
Why does the app need to call SongDbHelper.onCreate() anyways? If I put my app on the app store, won't I just let people download the database that I already filled with data?
When/where in my app do I call SongDbHelper.onUpgrade()? I assume this happens when the user notices that "There is an update available for this app. Click here to download it" or something like that. I'm just confused, because I'd imagine the user simply downloads a .db file with the database intact; and therefore won't need to call SongDbHelper.onCreate().
If the app has to call SongDbHelper.onCreate(), how does it fill the database with values? I think it would defeat the purpose of a database if I also have code that fills in the values, because then the values would be duplicated (in the code and the database).
What is the best way to fill a database with values? With the terminal, or programmatically in a separate program from the app, or only in the Android app?
Answer for :
Point 1,2,3 : As simply mentioned in tutorial you are following at this link, we are not supposed to call SongDbHelper.onCreate(). Instead of it, when we want to have reference of database from Helper class, we use the CONSTUCTOR like :
SongDbHelper mDbHelper = new SongDbHelper(getContext());
// this will call super method internally and
// this will create table in database
Point 4 : onUpgrade() is also not responsibility of ours to call explicitely. When we change database schema, we update DATABASE_VERSION and android framework will internally call onUpgrade() for us
Point 5 : You can store song lyrics one by one from your xml to database. This is right way as far as i know
Update :
The best way would be to store your database on a web server which is made prior, download it from the web server and have the app then read/write into database. This will not defeat purpose of database, in addition it will not duplicate database entries and code entries (xml). In addition to that, your app size will also be smaller because application will download database in runtime, rather than storing in device memory initially
Your SongDbHelper class should be implemented as Singleton instance.
It could be a good practice instantiate it in your Application class and exposing the SongDbHelper object for all your App
public class YourApp extends Application {
public SongDbHelper songDBHelper;
#Override
public void onCreate() {
super.onCreate();
songDBHelper = new SongDbHelper(.....);
}
public SongDBHelper getSongDB() {
return songDBHelper;
}
}
Firstly, I would recommend you to read the tutorial again to understand it. Now moving on to your questions,
1) You are not going to call onCreate() ever. As you can see, it comes from the super class SQLiteOpenHelper and it is called by the system and not the you when the app installs for the first time.
2) So from the previous question you can understand that there is not question of calling the onCreate() more than once. It will be called by the system only once to create the database when the user installs the app for the first time.
3) It doesn't work in this way as you are saying. When the app installs the onCreate() will be called to create the database. After that you can use your logic to fill data into it. No pre-defined data will be downloaded from anywhere as you said.
4) No, its also not like that "whenever the users get an update". onUpgrade() is only called when the database version changes. Like if you want to change the schema of the database on an app already existing in the Play Store, you can change the version number and perform the upgrade appropriately in the onUpgrade().
5) Your question is not clear.
I hope your conception will be changed after reading this answer. Do read the tutorials again to get a proper concept or post a new question if you have further questions.
UPDATE
5) You are thinking to create a database with song lyrics from before and put it inside your app. This is why you are having a misconception with onCreate().
See, when the user installs the app for the first time, the onCreate() will be called and a database with the given schema will be created. There would be no content inside it.
To put something inside it, you need to insert rows into that table programmatically. Hope it doesn't defeats the purpose now.
6) Now as for your use-case.
According to me, the best solution would be to put all your song lyrics in your web server and fetch those lyrics inside your app and put it in the database.
When the user install the app and runs for the first time, you should query the web server to check for the available lyrics and then fetch them one by one and put them inside your database using insert() method.
NOTE - the onCreate() just creates a blank table and doesn't put any values into it. But you are programmatically putting content inside your database, like the song lyrics using the insert() method.
Now when ever some new songs come up, just put the lyrics in your server and the app will automatically query the server to check if any new song lyrics is available and download it and insert in into the database accordingly.
Hope it is now clear to you.
Related
I am currently working on a diet app in android. So, I have planned to have a food database which could store information like calories, protein, fats, carbohydrates of food items. I don't know how to use SQL databases, that's why please tell me how can i use that data....for ex - if user searches for a food, say apple, in a search bar then how could the nutritional information of apple could be displayed.
Please provide me the source code for doing that...if you still feel confused about my question see the "myFitnessPal" android app and how the entries are made in that.
If you know any kind of references i could use kindly suggest.
Thanks in advance.
Here is a link that provides the details you need: http://developer.android.com/training/basics/data-storage/databases.html
I can't provide any code for you, as you have to think of what features your app should have and according to that you have to build up a database structure. But basically in your code you open a database which is then represented as a SQLiteDatabase object in your code. You can then run sql queries on the database with the execSQL function.
That's a lot of code to show to get something basic working. I would suggest following Vogella's SQLite Tutorial to get you started.
One thing in this tutorial that stumped me was he seemed to suggest that you need a SQLiteOpenHelper for each table. In fact what he meant was the SQLiteOpenHelper is for a single database and you would have a separate static class for each table where you would do something like:
public class MyDatabaseHelper extends SQLiteOpenHelper {
...
#Override
public void onCreate(SQLiteDatabase database) {
MyTable.onCreate(database);
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
MyTable.onUpdate(db, oldVersion, newVersion)
}
}
The MyTable class contains the methods to create and update the database for that specific table.
public class MyTable {
private static final String TABLE_NAME = "example";
private static final String COLUMN_ID = "id";
private static String DATABASE_CREATE = "CREATE TABLE " + TABLE_NAME + "("
+ COLUMN_ID + " INTEGER PRIMARY KEY)";
public static void onCreate(SQLiteDatabase database) {
database.execSQL(DATABASE_CREATE);
}
...
}
I have used SQLiteCipher to add security to my application database, the problem is, it is way too slow than the default android SQLite API. So I switched back to the default SQLite API, but I really need the security provided by SQLCipher, so What I did is:
Upon opening my app
Open the encrypted database file
Create a normal database file
Transfer records from encrypted to normal database
Delete the encrypted database file
Use the normal database file
When my app is closed,
Open the normal database file
Create a encrypted database file
Transfer records from normal to encrypted database
Delete the normal database file
This works without any problems, but transferring records takes some time and will consume more(I am assuming that my database file will contain thousands of records during its real-life usage). So is there any other way of what I have done?
Are there any more efficient ways of doing this? TIA!
EDIT : Here are some code using the SQLCipher
Main Activity
private final static String phrase = "passW0rd3r";
private EditText StudNum, StudName, StudCrse;
private DBHelper dbIns;
SQLiteDatabase DBFile;
private MainDBHelper DBHelp;
private MenuItem msg_app;
final Context con = this;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
StudNum = (EditText)findViewById(R.id.txtsNum);
StudName = (EditText)findViewById(R.id.txtsName);
StudCrse = (EditText)findViewById(R.id.txtCourse);
StudNum.requestFocus();
SQLiteDatabase.loadLibs(this);
dbIns = new DBHelper(this, DB_NAME);
DBFile = dbIns.getWritableDatabase(phrase);
DBHelp = new MainDBHelper(this);
//Takes too much time to load, loads around 3 seconds, compared to
//the default SQLite API, which is half a second only
}
MainDBHelper class
public class MainDBHelper {
private static final String DB_NAME = "StudentInfo.db";
private static final String TABLE_NAME = "StudentInfo";
private final static String phrase = "passW0rd3r";
private DBHelper openHelper;
private SQLiteDatabase database;
public MainDBHelper(Context context) {
openHelper = new DBHelper(context, DB_NAME);
database = openHelper.getWritableDatabase(phrase);
}
}
DBHelper class
public class DBHelper extends SQLiteOpenHelper{
private String DBName;
public DBHelper(Context context, String DBname) {
super(context, DBname, null, 5);
this.DBName = DBname.substring(0,DBname.length()-3);
// TODO Auto-generated constructor stub
}
#Override
public void onCreate(SQLiteDatabase arg0) {
// TODO Auto-generated method stub
arg0.execSQL("CREATE TABLE " + DBName + " (_id INTEGER PRIMARY KEY, " +
"Stud_Num TEXT, Stud_Name TEXT, Stud_Crse TEXT)");
}
#Override
public void onUpgrade(SQLiteDatabase arg0, int arg1, int arg2) {
// TODO Auto-generated method stub
arg0.execSQL("DROP TABLE IF EXISTS " + DBName);
onCreate(arg0);
}
}
Extra class that uses the same Database Connection
DisplayMessageActivity class - this one loads around 2 seconds just to show 3 records in the list view. If I use the default SQLite API, it can load up to 10 records in just a second
public class DisplayMessageActivity extends Activity {
private ListAdapter listAdapt;
private MainDBHelper DBHelp;
private EditText edtName, edtSnum, edtCrse;
private TextView dName, dSnum, dCrse, ssn;
private ListView lst_snum;
private SearchView sView;
private MenuItem sItem;
private View lView, diagView;
private AlertDialog.Builder DBuilder;
private AlertDialog ADiag;
private String StudentNumber, edSname, edSnum, edCrse;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_display_message);
DBHelp = new MainDBHelper(this);
lst_snum = (ListView)findViewById(R.id.lv_test);
refreshList();
createADiag(this);
lst_snum.setOnItemLongClickListener(new OnItemLongClickListener(){
#Override
public boolean onItemLongClick(AdapterView<?> parent, View view,
int position, long id) {
// TODO Auto-generated method stub
lView = view;
ssn = (TextView)view.findViewById(R.id.studNum);
ADiag.show();
return false;
}
});
}
private void refreshList(){
listAdapt = null;
listAdapt = new ListAdapter(this, DBHelp.getTimeRecordList());
lst_snum.setAdapter(listAdapt);
}
}
Update: I've read some questions related to mine and I really see that some are also facing performance issues by using SQLCipher, one answer said that to "Cache the database" for one time connection only that can be used on multiple activities on the same app, problem is, I don't have any idea to do that
There are a few very important guidelines for optimal SQLCipher performance:
Do not repeatedly open and close connections, as key derivation is very expensive, by design
Use transactions to wrap insert / update / delete operations. Unless executed in a transaction scope, every operation will occur within it's own transaction which slows things down by several orders of magnitude
Ensure your data is normalized (i.e., using good practices for separation of data into multiple tables to eliminate redundancy). Unnecessary duplication of data leads to database bloat, which means more pages for SQLCipher to operate on
Ensure that any columns that are used for searches or join conditions are indexed. If you don't, SQLCipher will need to execute full database scans across large numbers of pages
Vacuum periodically to ensure databases are compact if you do large deletes, updates etc.
Finally, to diagnose further the performance of your specific query statements, there are a couple of options. First, I would recommend running PRAGMA cipher_profile as CommonsWare mentioned above, you can read more about the usage here. This will give you a log of the queries performed on the database and their respective execution times in milliseconds. Next, you run an explain query plan command against some of your queries that may be performing poorly? The output of the explain query command is described here.
I am learning to use Sqlite on Android by using this tutorial. I am having trouble understanding some of the code.
public DatabaseHandler(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
// Creating Tables
#Override
public void onCreate(SQLiteDatabase db) {
String CREATE_CONTACTS_TABLE = "CREATE TABLE " + TABLE_CONTACTS + "("
+ KEY_ID + " INTEGER PRIMARY KEY," + KEY_NAME + " TEXT,"
+ KEY_PH_NO + " TEXT" + ")";
db.execSQL(CREATE_CONTACTS_TABLE);
}
I make a new object of DatabaseHandler in my activity. The super in the constructor is SQLiteOpenHelper constructor. The code works great, it creates a new database, if there is none and it uses the old one if it exists. I would like to make some changes to this code(I want to add different tables to one db), but I dont understand how exactly does this work, how does the constructor know if it should create a new db or use the existing one?
The trick is that your class extends SQLiteOpenHelper, the call to super in your constructor triggers a lot of behind-the-scenes code.
If you read through the SQLiteOpenHelper source code you'll see that getWritableDatabase() and getReadableDatabase() call the same method: SQLiteOpenHelper#getDatabaseLocked(). This method does most of the work. It is the one that determines whether a database needs to be created, opened, upgraded, or anything else, from the information that you supplied in one simple command: super(context, DATABASE_NAME, null, DATABASE_VERSION);.
When you want to open your db, you call SQLiteOpenHelper.getReadableDatabase() or SQLiteOpenHelper.getWriteableDatabase(). If the database exists, these return a handle to it. If it doesn't exist, the system calls onCreate(), where you do the db.execSQL.
It would be better to call the class DatabaseOpenHelper instead of DatabaseHandler. What it does is defer creating the database until its needed, instead of creating it at the beginning of some other class. This is particularly useful for content providers backed by an SQLite database. You should use ContentProvider.onCreate() to do very quick initialization, and then implement SQLiteOpenHelper.onCreate() to create the database. That way, the system can load your ContentProvider when your app starts, but it doesn't have to do anything with your database until something tries to access it.
I am writing an app that displays fun-facts (and the source they are from). The user can browse through the facts one by one.
Here is the design I thought of :
Create a table in SQLiteDatabase with a text column that stores the fun-fact and a second column that stores it's source. (not sure if this is the best way to go about doing it, but I want the app available even without the network)
My question is, when database is initially created on the device, should I manually populate the database from within the code, something like this pseodo-code:-
#Override
public void onCreate(SQLiteDatabase db) {
//Create the table
//Populate the table
//Insert statement 1
//Insert statement 2
//Insert statement 3
...
//Insert statement 500
}
Surely there must be a better method to create the initial database when the app is installed?
Are you certain that you really need a databse? Doesn't it just add unnecessary overhead to something so trivial?
Can't you just declare the array in your code, or am I missing something? Whether it's in the db or your code, it is taking up space. The db will add some overhead to that and vious?will take some time to load, plus your code has to handle errors, etc.
Woudl you not be better off with a simple array declared in your code? Or am I misisng something obvious? (maybe users can d/l a new db? But is that so much more overhead than d/ling a new program?)
If I'm way off, please explain (rather than downvoting). I am trying to help
Edit: presumably you already have your facts soemwhere? Maybe in a text file? You could just write code to parse that and initialze and array (or populate a db). It should bascially be a short for loop.
use a class derived from SQLiteOpenHelper
i already wrote sth obout this on my blog www.xenonite.net
public class myDatabase extends SQLiteOpenHelper
{
private static final String DB_NAME = "database.db";
private static final int DB_VERSION = 1;
public MyDatabase(Context context)
{
super(context, DB_NAME, null, DB_VERSION);
}
#Override
public void onCreate(SQLiteDatabase db)
{
db.execSQL("CREATE TABLE tbl_test ( id INTEGER PRIMARY KEY AUTOINCREMENT, test TEXT NOT NULL )");
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)
{
db.execSQL("DROP TABLE IF EXISTS tbl_test");
onCreate(db);
}
}
you can use this like
myDatabase db = new myDatabase(getApplicationContext());
sql = "INSERT INTO tbl_test (test) VALUES ('xyz')";
db.getWritableDatabase().execSQL(sql);
String sql = "SELECT id FROM tbl_test";
Cursor result = db.getWritableDatabase().rawQuery(sql, null);
int value;
while(result.moveToNext())
{
value = result.getInt(0);
}
on every call to db, myDatabase.onCreate() is called, so your database will be created on the first run. when changing the table structure, implement onUpgrade() and increment DB_VERSION
I'm still very new to Object Oriented programming and am having problems with the class inheritance and the scope of variables from one instantiated class to another.
I'm trying to build an android application that can read multiple XML feeds and save them to the phone's SQLite database. Each feed has a different name ("news", "audio_mixes" etc.) and I want to use these names to save each feed's data into separate database tables - each one named after the feed title.
In diagrammatic terms this is what my classes look like:
(source: baroquedub.co.uk)
The Main activity displays two buttons each of which starts an activity - both of which are instances of the TitlesBrowser class. Extras are used to pass different values of the_url and the_feed_type variables.
#Override
public void onCreate(final Bundle icicle) {
super.onCreate(icicle);
this.setContentView(R.layout.main);
this.getNewsButton = (Button) findViewById(R.id.get_news_button);
this.getNewsButton.setOnClickListener(new OnClickListener() {
public void onClick(final View v) {
Intent doGetNews = new Intent(Main.this, TitlesBrowser.class);
doGetNews.putExtra("the_url", Main.this.getString(R.string.titles_url));
doGetNews.putExtra("the_feed_type", Main.this.getString(R.string.news_type_var));
startActivity(doGetNews);
}
});
this.getMixtapesButton = (Button) findViewById(R.id.get_mixtapes_button);
this.getMixtapesButton.setOnClickListener(new OnClickListener() {
public void onClick(final View v) {
Intent doGetMixtapes = new Intent(Main.this, TitlesBrowser.class);
doGetMixtapes.putExtra("the_url", Main.this.getString(R.string.titles_url));
doGetMixtapes.putExtra("the_feed_type", Main.this.getString(R.string.mixtapes_type_var));
startActivity(doGetMixtapes);
}
});
}
The TitlesBrowser class, in its onCreate method, gets the Extras and saves them to private local variables.
Intent i = getIntent();
private String theUrl = (String) i.getStringExtra("the_url");
private String theFeedType = (String) i.getStringExtra("the_feed_type");</pre>
This class does two things,
1/ it creates an instance of the DatabaseHelper class, and uses a public set method in that class to pass on the value of the locally help theFeedType variable. Having done that it queries the database for any existing data (the theFeedType is the name of each table)
db=new DatabaseHelper(this);
db.setTableName(theFeedType);
dbCursor=db.getReadableDatabase().rawQuery("SELECT _ID, id, title FROM "+theFeedType+" ORDER BY id", null);
2/ then it loads new data from the feed URL by instantiating another class HTTPRequestHelper :
HTTPRequestHelper helper = new HTTPRequestHelper(responseHandler);
helper.performPost(theUrl, theFeedType);
The HTTP requests work fine, and depending on which of the two buttons is clicked, each of the two different activities display the appropriate XML (i.e. retrieve the correct data)
- therefore I know that theUrl and theFeedType variables are local to each instance of the TitlesBrowser class.
One calls:
http://baroquedub.co.uk/get-feed.php?feed=news
and the other one:
http://baroquedub.co.uk/get-feed.php?feed=audio_mixes
The problem is with the DatabaseHelper class:
public class DatabaseHelper extends SQLiteOpenHelper {
private static final String DATABASE_NAME="baroquedub.db";
private String table_name;
public DatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, 1);
}
#Override
public void onCreate(SQLiteDatabase db) {
db.execSQL("CREATE TABLE "+ table_name + "(_id INTEGER PRIMARY KEY AUTOINCREMENT, " +
"id INTEGER, " +
"title TEXT, " +
"details TEXT, " +
"picture TEXT, " +
"viewed BOOLEAN DEFAULT '0' NOT NULL);");
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
android.util.Log.w("Baroquedub", "Upgrading database, which will destroy all old data");
db.execSQL("DROP TABLE IF EXISTS mixtapes");
onCreate(db);
}
public void setTableName(String theName){
this.table_name = theName;
}
}
I would expect it to create a new table each time it is instantiated (whether "news" or "audio_mixes" was passed from its parent TitlesBrowser class.
But it only works once - if I start the application and click on "news" a table called news is created and each time I return to that activity it successfully retrieves data from that same database.
But if I then start the other activity by clicking on the other button (i.e access the other feed) I get an SQL error telling me that a database of that name doesn't exist. In other words the onCreate db.execSQL("CREATE TABLE... method doesn't appear to get called again.
It's as if multiple copies of the DatabaseHelper class aren't being created, although there are two instances of TitlesBrowser.
--
Here's a demonstration of the problem:
http://screencast.com/t/NDFkZDFmMz
This has been really tricky to explain (especially for a newbie!!!) and I hope it makes some sense. I'd be very grateful for any help, advice or guidance.
When you instanciate a SQLiteOpenHelper class you actually access a singleton in the Activity's context. The helper decides when to call the OnCreate / onUpgrade methods - specifically, if the DB doesn't exist or is stale.
Either way, the onCreate method is not called each time you create a new instance of the class - that would really make no sense. You should put the two CREATE TABLE commands in the onCreate method.
(PS I assume the error you're getting is that a table is missing and not the entire database).
A big thank you to adamk for providing the guidance necessary to solve this, in the answer he provided.
He suggested that I add two CREATE TABLE commands in the DatabaseHelper's onCreate method (on for each of my feeds). However, I needed to abstract things a little more so that I could still use multiple instantiations of the TitlesBrowser activity and so that I wouldn't have to rewrite the helper class every time a new feed came on board.
For those interested, here's the solution I came up with.
First of all, I removed the CREATE TABLE commands in the DatabaseHelper's onCreate method. I also removed the private table_name variable (and its associated set method) and I replaced this with a public method called makeTable():
public class DatabaseHelper extends SQLiteOpenHelper {
private static final String DATABASE_NAME="baroquedub.db";
public DatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, 1);
}
#Override
public void onCreate(SQLiteDatabase db) {
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
android.util.Log.w("Baroquedub", "Upgrading database, which will destroy all old data");
db.execSQL("DROP TABLE IF EXISTS mixtapes");
onCreate(db);
}
public void makeTable(String theTableName){
SQLiteDatabase thisDB = DatabaseHelper.this.getWritableDatabase();
thisDB.execSQL("CREATE TABLE IF NOT EXISTS "+ theTableName + "(_id INTEGER PRIMARY KEY AUTOINCREMENT, " +
"id INTEGER, " +
"title TEXT, " +
"details TEXT, " +
"picture TEXT, " +
"viewed BOOLEAN DEFAULT '0' NOT NULL);");
}
}
In TitlesBrowser, rather than instantiating the DatabaseHelper, setting the table name and then reading in the data:
db=new DatabaseHelper(this);
db.setTableName(theFeedType);
dbCursor=db.getReadableDatabase().rawQuery("SELECT _ID, id, title FROM "+theFeedType+" ORDER BY id", null);
Instead, I reworked all this so that it would more elegantly handle the creation and loading of the database data from each table:
The database Helper is created as before,
then the new databaseLoad() method tries to read from the required table
and if it can't, it calls the DatabaseHelper's public makeTable() method,
before finally trying to load the data again:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Intent i = getIntent();
theUrl = (String) i.getStringExtra("the_url");
theFeedType = (String) i.getStringExtra("the_feed_type");
// show saved in DB
db=new DatabaseHelper(this);
databaseLoad();
}
private void databaseLoad(){
try { // table exists
dbCursor=db.getReadableDatabase()
.rawQuery("SELECT _ID, id, title FROM "+theFeedType+" ORDER BY id", null);
displayContent();
} catch (Exception e) { // table doesn't exist
db.makeTable(theFeedType);
databaseLoad(); // try again
}
}