Android Development 101 – Part 5:DroidDraw & Information Tracker Completed



In this tutorial we are going to cover completing the Information Tracker using DroidDraw to design the layout of this project. This will give you insight into an alternative to the stock layout manager in the eclipse environment and how DroidDraw functions. DroidDraw can be your best friend when designing Android applications or your worse enemy if you don’t know the layout of the application and how it works. This will show you the basics to this program and how to incorporate it into your development process.  This is significantly easier than the previous post but will teach skills on other programs to help development such as DroidDraw.

We will start out by downloading DroidDraw and starting it up using the downloaded .exe after extracting the files. After the program is up the interface is pretty straight forward. The left side of the program is the device screen and what it will look like when we run the application. The right hand side of the application gives you the objects you can place on the screen on the top half as well as displaying the generated code for you on the bottom half. This is a very unique program because you can not only choose to generate code into the bottom half of the right screen but also paste code and generate a layout of what your program already looks like to enhance it further.  The pictures below will give you an idea of the layout so the paragraph below is a bit easier:

First we are going to change the absolute layout on the screen to a ScrollView. To do this we navigate to the top left of the program to the drop down menu that says RootLayout and change it to ScrollView. Then we are going to add a LinearLayout to the screen by navigating to the top right of the program where the tabs are and click Layouts. Drag the one titled LinearLayout to the screen on the left and drop it there. Now while it is still selcted, go to the tab on the right called Properties and click it. We are changing the width and height of the LinearLayout to fill_parent and then clicking Apply to make the change. Going back to the Layouts screen we are going to select TableLayout and drop it into the LinearLayout then go to the Properties and change it to fill_parent on both height and width.

Now that we have the layouts sorted out, we are going to start dropping widgets onto the screen to make the interface more interactive. To start out with we need a label that will ask for a number. Drag and drop a TextView from the widget tab to the screen then go to properties and change the width to fill_parent and the text to Number:. Now we need to add a TextBox (a.k.a. EditText) under the label so we drag it from the widgets to the screen and change the properties for width to fill_parent, the text to a blank field and the id to @+id/NumRewards. Then we are adding another Label, using fill_parent for width and changing the text to Date: and applying the changes. Now we add a DatePicker right under the label and change the id to @+id/Date and apply the changes. Now we need a button to be able to pull information out of our form when it is pressed, so drag a button over and change the id to @+id/Add and the text to Add then click Apply. At this point we have to add 2 more labels and 2 more textboxes so I will let you complete this and give you the information to change on them. The first label’s text will need to change to say Numbers For This Month: and the first TextBox variables that need to change is the id goes to @+id/RewardsMonthly. The second label will need to say Numbers To Date: and the ID of the second textbox will need to change to @+id/RewardsTD. The code will be given below if something goes wrong but playing around with the interface of DroidDraw is the best way to learn the fastest way to produce an interface with it.

Now that our interface has been laid out we need to generate it using the button at the top of the program entitled Generate. This will fill the bottom right of the screen that you can copy and paste into the main.xml file. When pasting code into the xml file you will notice in the screenshot above that my textboxes below the button are greyed out. This is accomplished by adding android:enabled=”false” befor the closing > in the EditText nodes. This will allow you to display info and not let anyone change it. Here is the code generated from DroidDraw without the enabled feature added in:

<?xml version="1.0" encoding="utf-8"?>
<ScrollView
android:id="@+id/widget33"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
xmlns:android="http://schemas.android.com/apk/res/android"
>
<LinearLayout
android:id="@+id/widget29"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
>
<TableLayout
android:id="@+id/widget34"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
>
<TextView
android:id="@+id/widget35"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Number:"
>
<!--<span class="hiddenSpellError" pre=""-->TextView>
<EditText
android:id="@+id/NumRewards"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textSize="18sp"
android:phoneNumber="true"
>
<!--<span class="hiddenSpellError" pre=""-->EditText>
<TextView
android:id="@+id/widget37"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Date:"
>
<!--<span class="hiddenSpellError" pre=""-->TextView>
<DatePicker
android:id="@+id/Date"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
>
<!--<span class="hiddenSpellError" pre=""-->DatePicker>
<Button
android:id="@+id/Add"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Add"
>
</Button>
<TextView
android:id="@+id/widget41"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Numbers For This Month:"
>
</TextView>
<EditText
android:id="@+id/RewardsMonthly"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="18sp"
android:enabled="false"
>
<!--<span class="hiddenSpellError" pre=""-->EditText>
<TextView
android:id="@+id/widget43"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Numbers To Date:"
>
</TextView>
<EditText
android:id="@+id/RewardsTD"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="18sp"
android:enabled="false"
>
<!--<span class="hiddenSpellError" pre=""-->EditText>
</TableLayout>
</LinearLayout>
</ScrollView>

Here is the screenshots with the enabled=”false” implemented in the layout file:

Now that our layout is complete we can start by making the project.  We have walked through how to make a project from previous posts so this should be familiar.  This time I will leaving making the project completely up to you.  After the project is made we can start coding the adapter for the database that we will heavily utilize. Most of this will be standard by now, except for the select functions where we want to grab data using specific criteria. Here is the code for DBAdapter.java:

package com.gregjacobs.infotracker;
/**
 * @author Greg
 *
 */
import java.util.Calendar;
import java.util.Date;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;

public class DBAdapter
{
	public static final String KEY_ROWID = "_id";
    public static final String KEY_YEAROFREWARDS = "YearOfRewards";
    public static final String KEY_MONTHOFREWARDS = "MonthOfRewards";
    public static final String KEY_DAYOFREWARDS = "DayOfRewards";
    public static final String KEY_NUMOFREWARDS = "NumOfRewards";
    private static final String TAG = "DBAdapter";

    private static final String DATABASE_NAME = "BlockbusterRewards";
    private static final String DATABASE_TABLE = "tblRewards";
    private static final int DATABASE_VERSION = 1;

    private static final String DATABASE_CREATE =
        "create table tblRewards (_id integer primary key autoincrement, "
        + "YearOfRewards text not null, MonthOfRewards text not null," +
        		"DayOfRewards text not null," +
        		" NumOfRewards int not null );";

    private static final Date date = new Date();
    private final Context context;

    private DatabaseHelper DBHelper;
    private SQLiteDatabase db;

The code above is pretty standard from what we have seen so far. The only thing that I want to point out is the fact that i have a column for the day, month and year each instead of combining them into one row. I did it this way so that when referencing month and day i could do it quickly without too much code in the SQL statement added. The rest should look pretty familiar.

    public DBAdapter(Context ctx)
    {
        this.context = ctx;
        DBHelper = new DatabaseHelper(context);
    }

	private static class DatabaseHelper extends SQLiteOpenHelper
    {
        DatabaseHelper(Context context)
        {
            super(context, DATABASE_NAME, null, DATABASE_VERSION);
        }

        @Override
        public void onCreate(SQLiteDatabase db)
        {
            db.execSQL(DATABASE_CREATE);
        }

        @Override
        public void onUpgrade(SQLiteDatabase db, int oldVersion,
                              int newVersion)
        {
            Log.w(TAG, "Upgrading database from version " + oldVersion
                  + " to "
                  + newVersion + ", which will destroy all old data");
            db.execSQL("DROP TABLE IF EXISTS titles");
            onCreate(db);
        }
    }

    //---opens the database---
    public DBAdapter open() throws SQLException
    {
        db = DBHelper.getWritableDatabase();
        return this;
    }

    //---closes the database---
    public void close()
    {
        DBHelper.close();
    }

    //---insert a title into the database---
    public long insertRewards(String yearRewards, String monthRewards, String dayRewards, String numRewards)
    {
        ContentValues initialValues = new ContentValues();
        initialValues.put(KEY_YEAROFREWARDS, yearRewards);
        initialValues.put(KEY_MONTHOFREWARDS, monthRewards);
        initialValues.put(KEY_DAYOFREWARDS, dayRewards);
        initialValues.put(KEY_NUMOFREWARDS, Integer.parseInt(numRewards));
        return db.insert(DATABASE_TABLE, null, initialValues);
    }

    public int getAllRewards()
    {
        Cursor cursor = db.rawQuery(
                    "SELECT SUM(NumOfRewards) FROM tblRewards", null);
                if(cursor.moveToFirst()) {
                    return cursor.getInt(0);
                }
                return cursor.getInt(0);

    }

    public int getMonthlyRewards()
    {

        Cursor cursor = getMonthRewards();/*db.rawQuery(
                    "SELECT SUM(NumOfRewards) FROM tblRewards WHERE MonthOfRewards = " +
                    Calendar.MONTH + " AND YearOfRewards = " + Calendar.YEAR, null);*/
                if(cursor.moveToFirst()) {
                    return cursor.getInt(0);
                }
                return cursor.getInt(0);

    }

  //---retrieves all the titles---
    public Cursor getMonthRewards()
    {
    	Calendar cal = Calendar.getInstance();
    	int year = cal.get(Calendar.YEAR);
    	String WHERE = "MonthOfRewards = " + date.getMonth() + " AND YearOfRewards = " + year;
        return db.query(DATABASE_TABLE, new String[] {
        		"SUM(" + KEY_NUMOFREWARDS + ")"},
                WHERE,
                null,
                null,
                null,
                null);
    }
}

getMonthlyRewards gets all of the items in the getMonthRewards() method that pertain to a particular month and shows them in one of the textboxes under the button we are going to utilize in the layout. The getAllRewards() method will be called to show the accumulation of the items we have gotten to date.

We now move onto the .java file that we labeled InfoTracker.java. This file will utilize code that attaches an event listener to the button in our layout and when pressed it will update our textboxes below it. The code in this .java file has not been optimized for efficiency, it was designed to just work. My challenge to you is to understand this code, if you don’t like they way it looks, then make it better. Here is the code for InfoTracker.java:

package com.gregjacobs.infotracker;

import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.DatePicker;
import android.widget.EditText;
import android.widget.Toast;

public class InfoTracker extends Activity {
    /** Called when the activity is first created. */
	DBAdapter db = new DBAdapter(this);
	EditText rewards;
	EditText rewardsMonthly;
	EditText rewardsTD;
	DatePicker dateRewards;

    @Override
    public void onCreate(Bundle savedInstanceState) {
    	try
    	{
	        super.onCreate(savedInstanceState);
	        setContentView(R.layout.main);
	        rewardsTD = (EditText)findViewById(R.id.RewardsTD);
	        rewardsMonthly = (EditText)findViewById(R.id.RewardsMonthly);
	        db.open();
	        rewardsTD.setText(String.valueOf(db.getAllRewards()));
	        rewardsMonthly.setText(String.valueOf(db.getMonthlyRewards()));
	        db.close();
	        // Capture our button from layout
	        Button button = (Button)findViewById(R.id.Add);
	        // Register the onClick listener with the implementation above
	        button.setOnClickListener(mAddListener);

    	}
        catch (Exception ex)
        {
      	  Context context = getApplicationContext();
      	  CharSequence text = ex.toString();
      	  int duration = Toast.LENGTH_LONG;

      	  Toast toast = Toast.makeText(context, text, duration);
      	  toast.show();
      	  //System.out.println(ex.getMessage());
        }
    }

    // Create an anonymous implementation of OnClickListener
    private OnClickListener mAddListener = new OnClickListener() {
        public void onClick(View v) {
        long id = 0;
          // do something when the button is clicked
    	db.open();
    	try{
    		//setContentView(R.layout.main);
			rewards = (EditText)findViewById(R.id.NumRewards);
		    dateRewards = (DatePicker)findViewById(R.id.Date);
		    rewardsMonthly = (EditText)findViewById(R.id.RewardsMonthly);
		    rewardsTD = (EditText)findViewById(R.id.RewardsTD);
		    id = db.insertRewards(String.valueOf(dateRewards.getYear()),
		    		String.valueOf(dateRewards.getMonth()),
		    		String.valueOf(dateRewards.getDayOfMonth()),
		    		rewards.getText().toString());
		    rewardsTD.setText(String.valueOf(db.getAllRewards()));
            rewardsMonthly.setText(String.valueOf(db.getMonthlyRewards()));
          }
          catch (Exception ex)
          {
        	  Context context = getApplicationContext();
        	  CharSequence text = ex.toString() + "ID = " + id;
        	  int duration = Toast.LENGTH_LONG;

        	  Toast toast = Toast.makeText(context, text, duration);
        	  toast.show();
        	  //System.out.println(ex.getMessage());
          }

          db.close();

        }
    };
}

The code in this example was all covered in other tutorials with the only exceptions being that when we start this application we make a call to the database and see if anything is new and we make a call after we press the button to constantly update the numbers in the textboxes below. Also, the fact that we close the database after making a call differs from other applications we have made as this will possibly cut down on the battery usage instead of keeping it open the whole time. The last part we will have to do is the strings.xml file, so here is the code:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="app_name">Information Tracker</string>
</resources>

Here are the files from my project so you may use them in comparison:

DBAdapter.java | InfoTracker.java | Main.xml

Now we have completed the Information Tracker and have a basic understanding of how DroidDraw works. This is the second to last tutorial in our series so Android Development 101 is almost over with only one last stop to make. The next tutorial will cover packaging up and signing your application into an .apk file that you can easily deploy onto your own device or market it the world using the Android Market. Until the next tutorial, Happy Hacking!

Continue on to Part 6: Getting Ready For Market!

Comments

  1. dext0rb says:

    thanks for these android tuts. looking forward to the apk packaging one. keep up the good work.

  2. Colecago says:

    Yeah, I really like these tutorials. You should do a Bluetooth one, I’m sure lots of people would like that.

  3. mowcius says:

    Agreed but please shorten the RSS feed link…

    It’s like torture when I am already reading through a few hundred posts.

  4. Doug says:

    [quote]The only thing that I want to point out is the fact that i have a row for the day, month and year each instead of combining them into one row.[/quote]

    Don’t you mean “column”?

  5. @Doug – Thank you for catching that, It is fixed now :)

    Before:
    The only thing that I want to point out is the fact that i have a row for the day, month and year each instead of combining them into one row.

    After:
    The only thing that I want to point out is the fact that i have a column for the day, month and year each instead of combining them into one row.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

Join 96,467 other followers