Database onUpgrade - Android Software Development

Due to client request on app to not require WiFi or 3G, I have my database copied in from the assets folder in the app. Works great.
However, when I change the version number, I don't get a call to onUpgrade().
Here is my constructor that gets called on database instantiate:
Code:
/** Constructor */
public DataBaseHelper(Context context) {
super(context, DB_NAME, null, DB_VERSION);
this.myContext = context;
}
I change the constant DB_VERSION, run the program and no onUpgrade called. Any ideas?
Thanks,
Roots

Related

[Q][SOLVED] PreferenceActivity as AppWidget Config

I have been using a hand built ListActivity as my AppWidget config Activity but to be honest it looks ****ty and doesnt fit in with the rest of the app. So i wanted to transition over to a PreferenceActivity. i made a stub of a PreferenceActivity that launches the layout just fine when it is the main activity. but when i try to change from my ListActivity to my PreferenceAcitivity i get no launching of PreferenceActivity when i launch my widget. all i get is my widget.
i did a refactoring of my xml files to change the instances of my ListActivity (GITextConfig) to my PreferenceActivity (GITextPreferences).
how can i use a PreferenceActivity as my config?
do i need to have a dummy Activity be the config with a button to launch the PreferenceActivity? cause that works just fine. its lame and shouldnt be that way... nvm that does not work... i just cant get a prefs activity to run from an appwidget
anyone? this is quite annoying... i know it can be done as other widgets like gmail unread count does this. at least it appears to have a preferenceactivity as the configuration
got it to work. i dont know what i was doing before but i think i had a little too much of a stub for it to work. after i implemented the appwidget id verification and created my PreferenceManger and overode the onBackPressed() method it seems to work.... happy and confused.
Code:
public class GITextPreferences extends PreferenceActivity {
private int mAppWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
PreferenceManager localPrefs = getPreferenceManager();
localPrefs.setSharedPreferencesName("GITC_Prefs");
addPreferencesFromResource(R.xml.gitc_preferences);
// Find the widget id from the intent.
Intent intent = getIntent();
Bundle extras = intent.getExtras();
if (extras != null) {
mAppWidgetId = extras.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID);
}
// If they gave us an intent without the widget id, just bail.
if (mAppWidgetId == AppWidgetManager.INVALID_APPWIDGET_ID) {
finish();
}
}
@Override
public void onBackPressed() {
// Make sure we pass back the original appWidgetId
Intent resultValue = new Intent();
resultValue.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, mAppWidgetId);
setResult(RESULT_OK, resultValue);
finish();
}
}

[Q] Parsing XML from web into ListView

Hey guys,
I've been making an app for my ROM (SkyDragon) and I want to include a news section, which will retrieve info from the web using a XML file.
But, I've tried many things and they won't work. So could anyone post a quick working parsing code here that will put the items in a listview, so I can experiment a bit with it? It'd be widely appreciated
I might reccommend using a library like Jackson 2.0+. I have not had the experience to use it with XML, but rather JSON, but it does appear to be just as easy to do so (at least since 2.0).
You would set up a POJO (Plain Old Java Object) class to represent the structure of the xml data, for instance:
Code:
public class Simple
{
private int x, y;
public int getX(){ return x; }
public int getY(){ return y; }
public void setX(int x){ this.x = x; }
public void setY(int y){ this.y = y; }
}
would represent xml like:
Code:
<Simple>
<x>1</x>
<y>2</y>
</Simple>
and to build the object you would use the library as such:
Code:
ObjectMapper xmlMapper = new XmlMapper();
Simple value = xmlMapper.readValue("<Simple><x>1</x><y>2</y></Simple>", Simple.class);
Thanks, will try it. But it can't be that simple, right? I mean, every tutorial is pretty big, and uses multiple activities.
Sent from my awesome fridge
Well like I said, I haven't actually used it for XML but rather JSON, but it really was that simple for me. What I listed is of course a very simple example, but scaling it up really just requires mapping your xml source to a POJO. The hardest part about your use will be that you don't control the XML.
Here is an example right out of a project of mine that worked great. "request.result" was basically a String object that contained the JSON response from a restful web service that I did not control but knew the structure of (by examination). Truly it is just these 2 lines of code to parse the response and after that you have an object that is easy to use.
Code:
ObjectMapper mapper = new ObjectMapper();
inventory = mapper.readValue(request.result, PlayerInventory.class);
Unfortunately this service no longer exists so I cannot get you an example response, but below is the POJO that I used to map it.
Code:
package com.mcdermotsoft;
import java.util.Map;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
@JsonIgnoreProperties(ignoreUnknown = true)
public class PlayerInventory
{
private int ok;
private Map<String,Slot> contents;
public PlayerInventory(){}
public int getOk() {
return ok;
}
public Map<String,Slot> getContents() {
return contents;
}
public void setOk(int ok) {
this.ok = ok;
}
public void setContents(Map<String,Slot> contents) {
this.contents = contents;
}
}
"@JsonIgnoreProperties(ignoreUnknown = true)" is important because I really didn't care to map everything from the response so this annotation tells the Jackson parser to ignore anything it can't map instead of throwing an exception (don't remember what the exception is but you might run into it yourself).

Android/Java Newbie

Hi all, im having a go at developing a simple app. i have little experience with Java and Android development. i have a little test app at the moment and have created a new class, im trying to create a new instance of this class on a button click. it fails to do so, i cant for the life of me see why so.. can someone shed any light on this?
Thanks
Debuging this shows it hitting the "LocationFactory locationf = new LocationFactory();" line and throwing an exception-
"java.lang.NullPointerException"
Main
Code:
package com.example.testapp;
import android.os.Bundle;
import android.app.Activity;
import android.content.Context;
import android.view.Menu;
import android.view.View;
import android.widget.Toast;
import java.io.IOException;
public class MainActivity extends Activity {
private static final Context Context = null;
protected static final String TAG = null;
[user=439709]@override[/user]
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
[user=439709]@override[/user]
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
public void mainButton(View view) throws IOException {
try {
LocationFactory locationf = new LocationFactory();
Toast.makeText(this, locationf.getAddress(),Toast.LENGTH_LONG).show();
} catch (Exception e)
{
Toast.makeText(this, e.toString(), Toast.LENGTH_LONG).show();
}
}
}
Class
Code:
package com.example.testapp;
import android.content.Context;
import android.location.Address;
import android.location.Geocoder;
import android.location.Location;
import android.location.LocationManager;
import java.io.IOException;
import java.util.Locale;
import java.util.List;
public class LocationFactory
{
private static final Context Context = null;
Geocoder geocoder = new Geocoder(Context, Locale.getDefault());
LocationManager manager = (LocationManager) Context.getSystemService(android.content.Context.LOCATION_SERVICE);
public double Latitude = 0.0;
public double Longitude = 0.0;
public LocationFactory()
{
}
public String getAddress() throws IOException
{
String ReturnAddress = "";
String Address = "", City = "", Country = "";
List<Address> addresses = null;
if(manager.isProviderEnabled(LocationManager.GPS_PROVIDER))
{
// Use GPS Radio Location
Location GPSlocation = manager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
Latitude = GPSlocation.getLatitude();
Longitude = GPSlocation.getLongitude();
}
else
{
// Use Cell Tower Location
Location NETlocation = manager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
Latitude = NETlocation.getLatitude();
Longitude = NETlocation.getLongitude();
}
if(Latitude > 0 && Longitude > 0)
{
addresses = geocoder.getFromLocation(Latitude, Longitude, 1);
if(!addresses.isEmpty())
{
Address = addresses.get(0).getAddressLine(0);
City = addresses.get(0).getAddressLine(1);
Country = addresses.get(0).getAddressLine(2);
}
}
ReturnAddress = Address + " " + City + " " + Country;
return ReturnAddress;
}
}
I don't see anywhere in your code where you are calling the mainButton(View view) method. In the Android lifecycle, the onCreate method is the equivalent of a normal Java program's main() method, which means that code execution begins with the first line of onCreate(). Not knowing what you're trying to do, a good start would be to call your mainButton() method AFTER setContentView() in onCreate().
Side note: your mainButton() method has a View parameter that is never used. Is there a reason for that?
Android activity lifecycle: http://developer.android.com/reference/android/app/Activity.html#ActivityLifecycle
You have to use an intent on that button click, use the method onClickListener and define the intent in the androidmanifest.xml
e.g
Code:
Button button = (Button) findViewById(R.id.[B]button[/B]) // replace latter button with actual id defined in main xml.
button.setOnClickListener(new View.OnClickListener() {
[user=439709]@override[/user]
public void onClick(View arg0) {
// TODO Auto-generated method stub
startActivity(new Intent("[B]com.example.packagename.CLASSNAME[/B]")); // this should be your own package name.
}
});
Also define this in android manifest under the <application> and </application>
Code:
<activity
android:name=".[B]CLASSNAME[/B]"
android:label="@string/app_name"
>
<intent-filter>
<action android:name="[B]com.example.packagename.CLASSNAME[/B]" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
Change the values of BOLD text according to your own values.
I tried to help you as far as I understood your question. Please let me know if you face any problem I would be more than happy to help you. Rest I am also in the learning phase so you can always PM me if you face any problem.
Hit thanks if I have helped you in any way.
coolbud012 said:
You have to use an intent on that button click, use the method onClickListener and define the intent in the androidmanifest.xml
Click to expand...
Click to collapse
Nope! He didn't say that he wanted to launch a new Activity when the button is clicked. He wants to create a new instance of his LocationFactory Class.
jpepin said:
Nope! He didn't say that he wanted to launch a new Activity when the button is clicked. He wants to create a new instance of his LocationFactory Class.
Click to expand...
Click to collapse
Oops yeah right read that now...I thought he want to start an activity... Anyways tried to delete my reply but not getting an option to delete.
There are many flaws in his code. And the other thing is if its his first app and if he has low level of programming experience then according to me it would be a next to impossible app for him, as per his code and what he is trying to implement.
I think he should rather start up with small apps, understand things and then move on to complex apps.
P.S - its just my opinion
Click to expand...
Click to collapse
Agreed that he should start small...which is exactly why your suggestion for creating and handling Intents makes no sense. Before that, he should first understand the activity lifecycle. Until then, he can just stick to trivial single-activity apps to gain experience.
OP: This code should be placed in the onCreate method:
Code:
Button button = (Button) findViewById(R.id.your_button_ID_here)
button.setOnClickListener(new View.OnClickListener() {
[user=439709]@override[/user]
public void onClick(View arg0) {
mainButton(); // get rid of the View parameter in this method...it's not needed
}
});
This will cause a new instance of your LocationFactory to be created, and will also cause your Toast message to be displayed.
thanks for the replies. yes you are right in that i am inexperienced, but this is just a test app for me to play around with and learn on. i tend to learn better by doing rather than constantly reading. thanks for your suggestions ill look into them
osmorgan said:
thanks for the replies. yes you are right in that i am inexperienced, but this is just a test app for me to play around with and learn on. i tend to learn better by doing rather than constantly reading. thanks for your suggestions ill look into them
Click to expand...
Click to collapse
I also believe in the same, I also keep on doing experiments and testing things out.
What I would suggest is that start with a small app and understand the insights on how android works and all...
Thanks
Potential Solution
Alright, I think I've found your problem. Have a look at where you define your variables in your LocationManager class:
Code:
private static final Context Context = null;
Geocoder geocoder = new Geocoder(Context, Locale.getDefault());
LocationManager manager = (LocationManager) Context.getSystemService(android.content.Context.LOCATION_SERVICE);
This is your problem:
Code:
Context Context = null;
If your context is null, and you use it to create a geocoder and call Context.getSystemService, you'll hit a null pointer. You're trying to access an object (the Context) that doesn't even exist
I'd recommend you pass the context in the LocationManager constructor and then instantiate your objects there. That's standard java procedure.
Code:
private Context mContext = null;
Geocoder geocoder = null;
LocationManager manager = null;
public double Latitude = 0.0;
public double Longitude = 0.0;
public LocationFactory(Context context)
{
this.mContext = context;
this.geocoder = new Geocoder(context, Locale.getDefault());
this.manager = (LocationManager) Context.getSystemService(android.content.Context.LOCATION_SERVICE);
}
I also renamed Context to mContext - it's generally a good idea to keep the instance's name separate from the class name.
Try that - it should work. Please feel free to ask any more questions - this is how I learned, and I think it's the best way!

Python API, Google App Engine and AsyncTask

I am not sure if I have correctly created an AsyncTask and a Method associated with it to make calls to my Google App Engine project.
Below is some code that I am currently implementing to handle creating an Event entity to be stored in the Datastore.
The sendResultToServer method uses the Python Response/Request messages that I created in my Python API. These are the only classes that offer the methods to 'set' the associated entity variables.
Anyone know whether or not I should be using the Request/Response message classes? - I also have a method implemented called insert() but it is in the Imhotep.java class which implements the Event class.
__________________________________________________________
Code:
private void sendResultToServer(String eventDesc, String eventName,
String eventTime) {
ImhotepApiMessagesEventRequest newEvent = new ImhotepApiMessagesEventRequest();
newEvent.setEventDesc(eventDesc);
newEvent.setEventTitle(eventName);
newEvent.setEventTime(eventTime);
new SendResultToServerTask().execute(newEvent, null, null);
}
/**
* Handles the request to the Event Endpoint, to save a score, without
* blocking the UI.
*/
private class SendResultToServerTask extends
AsyncTask<ImhotepApiMessagesEventRequest, Void, Void> {
@Override
protected Void doInBackground(ImhotepApiMessagesEventRequest... params) {
// TODO Auto-generated method stub
service.events();
return null;
}
}

[Tutorial] Learn to save data with SQLite on Android

Hello,
I create that thread to present you a tutorial learning you to save data with SQLite on Android. This tutorial is also available in video on Youtube :
Learn to save data with SQLite on Android
On Android, there are several solutions to persist data between users’ sessions. One solution is to use a relational database to persist data and then to be able to query easily these data. In standard, Android SDK comes with a SQLite implementation. Biggest advantage of SQLite integration to Android OS is the fact that there is no need to to setup the database. So, no administration of this database. SQLite is embedded in standard and each application can have its SQLite database.
The only job that developers must make is to define SQL tables and statements for creating and updating data. Access to an SQLite database involves accessing the file system. So, it can be a slow operation. To avoid ANR (Application Not Responding) errors, it’s recommended to perform database operations asynchronously.
When an application creates and uses a SQLite database, it will be saved by default in the directory : DATA/data/APP_PACKAGE/databases/FILENAME .
1. Architecture
All classes needed to manage databases in Android SDK are contained in the package android.database . The package android.database.sqlite contains the SQLite specific classes.
SQLite API is centered around 2 main classes :
SQLiteOpenHelper that is an helper class to extend to manage database operations.
SQLiteDatabase that is the base class for working with a SQLite database in Android.
2. SQLiteOpenHelper
When you want to work with a SQLite database in Android, you must extend SQLiteOpenHelper class. In the constructor of your subclass you call the super() method of SQLiteOpenHelper, specifying the database name and the current database version.
You need also to override the following methods :
onCreate() that is called when database is accessed but not yet created.
onUpgrade() called when you choose to increment the version number of the database. In this method you can manage the migration process between two databases versions.
Both methods get and SQLiteDatabase instance in parameter which is the way to communicate with the database.
Furthermore, SQLiteOpenHelper provides 2 methods to get access to an SQLiteDatabase instance object respectively in read and in write modes :
getReadableDatabase() for read mode.
getWriteableDatabase() for write mode.
3. SQLiteDatabase
SQLiteDatabase is the class used to communicate with a SQLite database. It exposes several methods to interact with database like insert(), update() or delete().
In addition, it lets you to make queries via rawQuery() to queries made directly in SQL or via query() method. This last method provides a structured interface for specifying a SQL query.
4. Practice
Now, you know theory about SQLite in Android context. We can put in practice all the concepts. To achieve that, we’re going to make a database with a players table letting us to store NBA players.
To start, we create a simple Player Java POJO :
Code:
public class Player {
private int id;
private String name;
private String position;
private int height;
public Player() {
}
public Player(int id, String name, String position, int height) {
this.id = id;
this.name = name;
this.position = position;
this.height = height;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPosition() {
return position;
}
public void setPosition(String position) {
this.position = position;
}
public int getHeight() {
return height;
}
public void setHeight(int height) {
this.height = height;
}
@Override
public String toString() {
return name + " - " + position + " - " + height + " cm";
}
}
Then, we must create the SQLiteOpenHelper extended class to manage our application database. Code is here :
Code:
package com.ssaurel.samples.sqlite;
import java.util.LinkedList;
import java.util.List;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
public class SQLiteDatabaseHandler extends SQLiteOpenHelper {
private static final int DATABASE_VERSION = 1;
private static final String DATABASE_NAME = "PlayersDB";
private static final String TABLE_NAME = "Players";
private static final String KEY_ID = "id";
private static final String KEY_NAME = "name";
private static final String KEY_POSITION = "position";
private static final String KEY_HEIGHT = "height";
private static final String[] COLUMNS = { KEY_ID, KEY_NAME, KEY_POSITION,
KEY_HEIGHT };
public SQLiteDatabaseHandler(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
@Override
public void onCreate(SQLiteDatabase db) {
String CREATION_TABLE = "CREATE TABLE Players ( "
+ "id INTEGER PRIMARY KEY AUTOINCREMENT, " + "name TEXT, "
+ "position TEXT, " + "height INTEGER )";
db.execSQL(CREATION_TABLE);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
// you can implement here migration process
db.execSQL("DROP TABLE IF EXISTS " + TABLE_NAME);
this.onCreate(db);
}
public void deleteOne(Player player) {
// Get reference to writable DB
SQLiteDatabase db = this.getWritableDatabase();
db.delete(TABLE_NAME, "id = ?", new String[] { String.valueOf(player.getId()) });
db.close();
}
public Player getPlayer(int id) {
SQLiteDatabase db = this.getReadableDatabase();
Cursor cursor = db.query(TABLE_NAME, // a. table
COLUMNS, // b. column names
" id = ?", // c. selections
new String[] { String.valueOf(id) }, // d. selections args
null, // e. group by
null, // f. having
null, // g. order by
null); // h. limit
if (cursor != null)
cursor.moveToFirst();
Player player = new Player();
player.setId(Integer.parseInt(cursor.getString(0)));
player.setName(cursor.getString(1));
player.setPosition(cursor.getString(2));
player.setHeight(Integer.parseInt(cursor.getString(3)));
return player;
}
public List<Player> allPlayers() {
List<Player> players = new LinkedList<Player>();
String query = "SELECT * FROM " + TABLE_NAME;
SQLiteDatabase db = this.getWritableDatabase();
Cursor cursor = db.rawQuery(query, null);
Player player = null;
if (cursor.moveToFirst()) {
do {
player = new Player();
player.setId(Integer.parseInt(cursor.getString(0)));
player.setName(cursor.getString(1));
player.setPosition(cursor.getString(2));
player.setHeight(Integer.parseInt(cursor.getString(3)));
players.add(player);
} while (cursor.moveToNext());
}
return players;
}
public void addPlayer(Player player) {
SQLiteDatabase db = this.getWritableDatabase();
ContentValues values = new ContentValues();
values.put(KEY_NAME, player.getName());
values.put(KEY_POSITION, player.getPosition());
values.put(KEY_HEIGHT, player.getHeight());
// insert
db.insert(TABLE_NAME,null, values);
db.close();
}
public int updatePlayer(Player player) {
SQLiteDatabase db = this.getWritableDatabase();
ContentValues values = new ContentValues();
values.put(KEY_NAME, player.getName());
values.put(KEY_POSITION, player.getPosition());
values.put(KEY_HEIGHT, player.getHeight());
int i = db.update(TABLE_NAME, // table
values, // column/value
"id = ?", // selections
new String[] { String.valueOf(player.getId()) });
db.close();
return i;
}
}
Database is created in the constructor of the extended class. Players table is created in the onCreate() method thanks to a SQL statement.
In our class, we add methods to add a new player, to delete an existing one, to update and then a method to get all the players in the table. In this last method, we use a Cursor object to iterate on rows and then build equivalent Player instances.
To use our class to create some players then display on a simple ListView, we can use the following code :
Code:
public class MainActivity extends Activity {
private SQLiteDatabaseHandler db;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// create our sqlite helper class
db = new SQLiteDatabaseHandler(this);
// create some players
Player player1 = new Player(1, "Lebron James", "F", 203);
Player player2 = new Player(2, "Kevin Durant", "F", 208);
Player player3 = new Player(3, "Rudy Gobert", "C", 214);
// add them
db.addPlayer(player1);
db.addPlayer(player2);
db.addPlayer(player3);
// list all players
List<Player> players = db.allPlayers();
if (players != null) {
String[] itemsNames = new String[players.size()];
for (int i = 0; i < players.size(); i++) {
itemsNames[i] = players.get(i).toString();
}
// display like string instances
ListView list = (ListView) findViewById(R.id.list);
list.setAdapter(new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_1, android.R.id.text1, itemsNames));
}
}
}
Execution result can be seen here :
{
"lightbox_close": "Close",
"lightbox_next": "Next",
"lightbox_previous": "Previous",
"lightbox_error": "The requested content cannot be loaded. Please try again later.",
"lightbox_start_slideshow": "Start slideshow",
"lightbox_stop_slideshow": "Stop slideshow",
"lightbox_full_screen": "Full screen",
"lightbox_thumbnails": "Thumbnails",
"lightbox_download": "Download",
"lightbox_share": "Share",
"lightbox_zoom": "Zoom",
"lightbox_new_window": "New window",
"lightbox_toggle_sidebar": "Toggle sidebar"
}
SQLite implementation in Android is simple and really powerful. You can now use it in your Android application to persist data.
Don't hesitate to give it a try and give me your feedbacks about this tutorial.
Thanks.
Sylvain
Hey, I have made a preview for SQLite database earlier this month for my friend.
If anyone's interested then it's there at https://www.GitHub.com/Fifa2151/SQLiteTest
Thanks,
Raj.
Sent from my Pixel using Tapatalk
sylsau said:
Hello,
I create that thread to present you a tutorial learning you to save data with SQLite on Android. This tutorial is also available in video on Youtube :
Learn to save data with SQLite on Android
On Android, there are several solutions to persist data between users’ sessions. One solution is to use a relational database to persist data and then to be able to query easily these data. In standard, Android SDK comes with a SQLite implementation. Biggest advantage of SQLite integration to Android OS is the fact that there is no need to to setup the database. So, no administration of this database. SQLite is embedded in standard and each application can have its SQLite database.
The only job that developers must make is to define SQL tables and statements for creating and updating data. Access to an SQLite database involves accessing the file system. So, it can be a slow operation. To avoid ANR (Application Not Responding) errors, it’s recommended to perform database operations asynchronously.
When an application creates and uses a SQLite database, it will be saved by default in the directory : DATA/data/APP_PACKAGE/databases/FILENAME .
1. Architecture
All classes needed to manage databases in Android SDK are contained in the package android.database . The package android.database.sqlite contains the SQLite specific classes.
SQLite API is centered around 2 main classes :
SQLiteOpenHelper that is an helper class to extend to manage database operations.
SQLiteDatabase that is the base class for working with a SQLite database in Android.
2. SQLiteOpenHelper
When you want to work with a SQLite database in Android, you must extend SQLiteOpenHelper class. In the constructor of your subclass you call the super() method of SQLiteOpenHelper, specifying the database name and the current database version.
You need also to override the following methods :
onCreate() that is called when database is accessed but not yet created.
onUpgrade() called when you choose to increment the version number of the database. In this method you can manage the migration process between two databases versions.
Both methods get and SQLiteDatabase instance in parameter which is the way to communicate with the database.
Furthermore, SQLiteOpenHelper provides 2 methods to get access to an SQLiteDatabase instance object respectively in read and in write modes :
getReadableDatabase() for read mode.
getWriteableDatabase() for write mode.
3. SQLiteDatabase
SQLiteDatabase is the class used to communicate with a SQLite database. It exposes several methods to interact with database like insert(), update() or delete().
In addition, it lets you to make queries via rawQuery() to queries made directly in SQL or via query() method. This last method provides a structured interface for specifying a SQL query.
4. Practice
Now, you know theory about SQLite in Android context. We can put in practice all the concepts. To achieve that, we’re going to make a database with a players table letting us to store NBA players.
To start, we create a simple Player Java POJO :
Code:
public class Player {
private int id;
private String name;
private String position;
private int height;
public Player() {
}
public Player(int id, String name, String position, int height) {
this.id = id;
this.name = name;
this.position = position;
this.height = height;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPosition() {
return position;
}
public void setPosition(String position) {
this.position = position;
}
public int getHeight() {
return height;
}
public void setHeight(int height) {
this.height = height;
}
@Override
public String toString() {
return name + " - " + position + " - " + height + " cm";
}
}
Then, we must create the SQLiteOpenHelper extended class to manage our application database. Code is here :
Code:
package com.ssaurel.samples.sqlite;
import java.util.LinkedList;
import java.util.List;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
public class SQLiteDatabaseHandler extends SQLiteOpenHelper {
private static final int DATABASE_VERSION = 1;
private static final String DATABASE_NAME = "PlayersDB";
private static final String TABLE_NAME = "Players";
private static final String KEY_ID = "id";
private static final String KEY_NAME = "name";
private static final String KEY_POSITION = "position";
private static final String KEY_HEIGHT = "height";
private static final String[] COLUMNS = { KEY_ID, KEY_NAME, KEY_POSITION,
KEY_HEIGHT };
public SQLiteDatabaseHandler(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
@Override
public void onCreate(SQLiteDatabase db) {
String CREATION_TABLE = "CREATE TABLE Players ( "
+ "id INTEGER PRIMARY KEY AUTOINCREMENT, " + "name TEXT, "
+ "position TEXT, " + "height INTEGER )";
db.execSQL(CREATION_TABLE);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
// you can implement here migration process
db.execSQL("DROP TABLE IF EXISTS " + TABLE_NAME);
this.onCreate(db);
}
public void deleteOne(Player player) {
// Get reference to writable DB
SQLiteDatabase db = this.getWritableDatabase();
db.delete(TABLE_NAME, "id = ?", new String[] { String.valueOf(player.getId()) });
db.close();
}
public Player getPlayer(int id) {
SQLiteDatabase db = this.getReadableDatabase();
Cursor cursor = db.query(TABLE_NAME, // a. table
COLUMNS, // b. column names
" id = ?", // c. selections
new String[] { String.valueOf(id) }, // d. selections args
null, // e. group by
null, // f. having
null, // g. order by
null); // h. limit
if (cursor != null)
cursor.moveToFirst();
Player player = new Player();
player.setId(Integer.parseInt(cursor.getString(0)));
player.setName(cursor.getString(1));
player.setPosition(cursor.getString(2));
player.setHeight(Integer.parseInt(cursor.getString(3)));
return player;
}
public List<Player> allPlayers() {
List<Player> players = new LinkedList<Player>();
String query = "SELECT * FROM " + TABLE_NAME;
SQLiteDatabase db = this.getWritableDatabase();
Cursor cursor = db.rawQuery(query, null);
Player player = null;
if (cursor.moveToFirst()) {
do {
player = new Player();
player.setId(Integer.parseInt(cursor.getString(0)));
player.setName(cursor.getString(1));
player.setPosition(cursor.getString(2));
player.setHeight(Integer.parseInt(cursor.getString(3)));
players.add(player);
} while (cursor.moveToNext());
}
return players;
}
public void addPlayer(Player player) {
SQLiteDatabase db = this.getWritableDatabase();
ContentValues values = new ContentValues();
values.put(KEY_NAME, player.getName());
values.put(KEY_POSITION, player.getPosition());
values.put(KEY_HEIGHT, player.getHeight());
// insert
db.insert(TABLE_NAME,null, values);
db.close();
}
public int updatePlayer(Player player) {
SQLiteDatabase db = this.getWritableDatabase();
ContentValues values = new ContentValues();
values.put(KEY_NAME, player.getName());
values.put(KEY_POSITION, player.getPosition());
values.put(KEY_HEIGHT, player.getHeight());
int i = db.update(TABLE_NAME, // table
values, // column/value
"id = ?", // selections
new String[] { String.valueOf(player.getId()) });
db.close();
return i;
}
}
Database is created in the constructor of the extended class. Players table is created in the onCreate() method thanks to a SQL statement.
In our class, we add methods to add a new player, to delete an existing one, to update and then a method to get all the players in the table. In this last method, we use a Cursor object to iterate on rows and then build equivalent Player instances.
To use our class to create some players then display on a simple ListView, we can use the following code :
Code:
public class MainActivity extends Activity {
private SQLiteDatabaseHandler db;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// create our sqlite helper class
db = new SQLiteDatabaseHandler(this);
// create some players
Player player1 = new Player(1, "Lebron James", "F", 203);
Player player2 = new Player(2, "Kevin Durant", "F", 208);
Player player3 = new Player(3, "Rudy Gobert", "C", 214);
// add them
db.addPlayer(player1);
db.addPlayer(player2);
db.addPlayer(player3);
// list all players
List<Player> players = db.allPlayers();
if (players != null) {
String[] itemsNames = new String[players.size()];
for (int i = 0; i < players.size(); i++) {
itemsNames[i] = players.get(i).toString();
}
// display like string instances
ListView list = (ListView) findViewById(R.id.list);
list.setAdapter(new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_1, android.R.id.text1, itemsNames));
}
}
}
Execution result can be seen here :
SQLite implementation in Android is simple and really powerful. You can now use it in your Android application to persist data.
Don't hesitate to give it a try and give me your feedbacks about this tutorial.
Thanks.
Sylvain
Click to expand...
Click to collapse
Awesome guide @sylsau...
Also, do you know how to make a flashify type app but only for a specific zip?
When you want to work with a SQLite database in Android, you must extend SQLiteOpenHelper class. In the constructor of your subclass you call the super() method of SQLiteOpenHelper, specifying the database name and the current database version.
Click to expand...
Click to collapse
You don't actually need to use a subclass of SQLiteOpenHelper you can use the SQliteDatabase's open????? methods.
Furthermore, SQLiteOpenHelper provides 2 methods to get access to an SQLiteDatabase instance object respectively in read and in write modes :
Click to expand...
Click to collapse
Actually, in either case, except if the database cannot be opened, for write, both getReadableDatabase and getWritableDatabase will open a database that can be written to. As per :-
Create and/or open a database. This will be the same object returned by getWritableDatabase() unless some problem, such as a full disk, requires the database to be opened read-only. In that case, a read-only database object will be returned. If the problem is fixed, a future call to getWritableDatabase() may succeed, in which case the read-only database object will be closed and the read/write object will be returned in the future.
Click to expand...
Click to collapse
as per developer.android.com/reference/android/database/sqlite/SQLiteOpenHelper#getReadableDatabase()​
On occasions people new to SQLite sometimes wonder why no database exists after they have instantiated the subclass of SQLiteOpenHelper (aka the DatabaseHelper). This is because the database is only created when either getWritableDatabase or getReadableDatabase is called. With a single line added to the constructor, the constructor will create the database (and thus invoke the onCreate method) e.g.
Code:
public SQLiteDatabaseHandler(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
this.getWritableDatabse();
}
AUTOINCREMENT is perhaps the most commonly misused keyword (perhaps wrongly named). It does not make the column automatically generate a unique ID. It is INTEGER PRIMARY KEY that does this, as it make the column an alias of the **rowid**.
Rather AUTOINCREMENT compliments INTEGER PRIMARY KEY adding a constraint that the generated ID must be larger that any ID that exists or have existed. However, this is a moot point as it's only when the largest possible ID has been assigned (9223372036854775807) that it comes into play (other than without AUTOINCREMENT a deleted highest ID will be resused). At this point a table with AUTOINCREMENT will then fail with an SQLITE_FULL exception (without AUTOINCREMENT will attempt to assign a free lower ID rather than fail). However, AUTOINCREMENT has overheads (using a limited test I came up with an 8-12% degradation in performance when inserting). This is due to a changed algorithm being used that utilises another table sqlite_sequence that stores the highest allocated ID.
The SQLite documentation states :-
The AUTOINCREMENT keyword imposes extra CPU, memory, disk space, and disk I/O overhead and should be avoided if not strictly needed. It is usually not needed.
Click to expand...
Click to collapse
sqlite.org/autoinc.html
There are a few issues with the code, such as :-
You should always close Cursors when finished with them (not doing so may result in too many databases /database objects open exception ).
Checking a Cursor for null after a Cursor is returned from a call to an SQLiteDatabase method that returns a Cursor serves no purpose. A valid Cursor will always be returned. If there is no data then using a Cursor moveTo????? method will return false is the move cannot be made, alternately the getCount() method will return the number of rows in the Cursor.
If there were now rows in the Players table, the the code would fail with an error when an attempt is made to retrieve data at
Code:
player.setId(Integer.parseInt(cursor.getString(0)));
Issues regarding mis-calculated column offsets can be reduced by taking advantage of the Cursor's **getColumnIndex** method.
As such, as an example, the getPlayer method would be improved if changed to :-
Code:
public Player getPlayer(int id) {
SQLiteDatabase db = this.getReadableDatabase();
Cursor cursor = db.query(TABLE_NAME, // a. table
COLUMNS, // b. column names
" id = ?", // c. selections
new String[] { String.valueOf(id) }, // d. selections args
null, // e. group by
null, // f. having
null, // g. order by
null); // h. limit
Player player = new Player(); //<<<<<<<<<< Always have a Player to return (should check for default player to indicated )
if (cursor.moveToFirst()) {
player.setId(Integer.parseInt(cursor.getString(cursor.getColumnIndex(KEY_ID))));
player.setName(cursor.getString(cursor.getColumnIndex(KEY_NAME)));
player.setPosition(cursor.getString(cursor.getColumnIndex(KEY_POSITION)));
player.setHeight(Integer.parseInt(cursor.getString(cursor.getColumnIndex(KEY_HEIGHT))));
}
cursor.close(); //<<<<<<<<<< Important to close a Cursor
return player;
}

Categories

Resources