Showing posts with label sqllite. Show all posts

Getting Started - A Complete Android App walkthrough for Beginners (Part 2)

This is part 2 of a walkthrough of one of my first ever Android app, that happened to get a little bit of love in the android market, and for which the ENTIRE(!!) source code of the application is available to you good people to do whatever you want with.. see part 1 for more details of the app, what happened and the first steps in getting started!

So far, we have created a simple Activity class, designed a layout with several buttons and then implemented an onClickListener within our Activity class to handle the required actions for all of our buttons. The remaining Activities are all fairly straight forward, and work in a similar fashion: the RulesActivity is just a simple activity what has a block of text with a brief description of the game; the SettingsActivity is a simple activity that has three radio buttons which allows the user to select the difficulty; the QuestionsActivity just displays a question and then a selection of multiple choice answers.

If you are not familiar with Activities then you can open up those other classes and see exactly what is going on, they are all pretty similar but each have slight nuances or differences in their components and actions.

At the moment the application is pretty simple – there is a basic welcome screen with some buttons, and once you start the game you get taken through the QuestionsActivity several times, refreshing with different questions until you have answered all the questions, and then at the end it displays a simple graphic based on your accumulated score. Easy right?!

Really, the only big gap in what is going on is the DB – all the questions need to be stored in the DB on the client device, and then that data needs to be accessed, so we basically need a DAO type class.

In this app, we have a single DBHelper class – you may want to wrap this with a service class, to allow better separation of layers and decreased coupling etc, but for the sake of this app, lets just jump into the DBHelper. To access the DB on Android you need to have your class extend SQLLiteOpenHelper, now lets walk through the code required

private static String DB_PATH = "/data/data/com.tmm.android.chuck/databases/";
private static String DB_NAME = "questionsDb";
private SQLiteDatabase myDataBase; 
private final Context myContext;

First of all we define some simple class member variables. The DB_PATH will be used later to access our file that contains all our questions in it, the DB_NAME is just a name of choice to reference the DB.

public DBHelper(Context context) {
 super(context, DB_NAME, null, 1);
 this.myContext = context;
} 

You have to make sure you override the constructor, as this needs to initialise the context and DB before starting.

Next we have the createDatabase method – this one is quite straight forward:

public void createDataBase() throws IOException{

 boolean dbExist = checkDataBase();
 if(!dbExist)
 {
  this.getReadableDatabase();
  try {
   copyDataBase(); 
  } catch (IOException e) {
   throw new Error("Error copying database");
  }
 }
}


As you can see, it simply checks if the DB already exists, if it doesn’t (in which case its the first time that the app has been launched on this device) then it calls the copyDataBase() method:

private void copyDataBase() throws IOException{

 InputStream myInput = myContext.getAssets().open(DB_NAME);

 String outFileName = DB_PATH + DB_NAME;

 OutputStream myOutput = new FileOutputStream(outFileName);

 byte[] buffer = new byte[1024];
 int length;
 while ((length = myInput.read(buffer))>0){
  myOutput.write(buffer, 0, length);
 }

 //Close the streams
 myOutput.flush();
 myOutput.close();
 myInput.close();
}

Again, this is pretty straight forward – it just opens an Input stream to read the file (our questions file that we have saved in the /assets/ directory) and then writes it to the output stream which has been set up to be our DB Path/Name. Easy right?

So now we pretty much have our DBHelper class that checks for an existing DB, if its found then it opens a connection, if its not then it loads the data (our question set) in for the first time.

Now, the only remaining thing that our helper needs to do is to be able to access the data so we can select questions to show the user. So let’s look at how we add some DAO access methods. What I have done here is create a simple method to return a (random) question set:

public List getQuestionSet(int difficulty, int numQ){
 List questionSet = new ArrayList();

Cursor c = myDataBase.rawQuery("SELECT * FROM QUESTIONS WHERE DIFFICULTY=" + difficulty +
   " ORDER BY RANDOM() LIMIT " + numQ, null);
 
while (c.moveToNext()){
  Question q = new Question();
  q.setQuestion(c.getString(1));
  q.setAnswer(c.getString(2));
  q.setOption1(c.getString(3));
  q.setOption2(c.getString(4));
  q.setOption3(c.getString(5));
  q.setRating(difficulty);
  questionSet.add(q);
 }
 return questionSet;
}

Here, I am modelling the questions in a pre-created “Question” class – this just has the necessary member variables so I can handle the questions more easily than having to try and deal with DB cursors throughout the code. In the above method we just call a pure SQL statement, and then iterate through the cursor to populate my Question ArrayList.

And thats it! There are some other Activity classes and helper classes running doing small things throughout the app, but the core features are covered, so feel free to have a look around the code, edit it, change the design and just generally have fun.