Click here to Skip to main content
Click here to Skip to main content

CPForAndroid and an Android Project Template

By , 11 Feb 2011
Rate this:
Please Sign up or sign in to vote.

MyDroidTemplate

MyDroidTemplateIDE478x260.png

CPForAndroid

Introduction

This article will explore some of the interesting components I found while producing CPForAndroid which may be useful for those learning to develop Android applications. There is also a template application with some classes that are needed with most applications like database functions and menus which you will not find in the Eclipse New Project wizard.

I am guessing that there are many readers familiar with SQLite. I have not had a chance to work with light-weight embedded SQL database engine library and I am very glad that it is being used in Android development. I decided to make a small SQLite template made of two classes so they may be reused in future projects. After a very short time attempting this, I decided to just combined some of what I made with a Creative Commons licensed class SQLiteDatabaseAdapter by alessandrofranzi (that's what we like to do around here right? re-use code :smileSmile | :) . SQLite seemed to be an efficient solution to help remember the end user's previously read CPForAndroid RSS items.

The Android SDK and Eclipse Integrated Development Environment (IDE)

I believe there are more in-depth tutorials on Codeproject on how to get setup for Android development, but here is a quick reference guide that I have compiled for this article:

  1. Make sure you have the Eclipse IDE for Java.
  2. Download the Android SDK you may get an error while running the SDK setup OR Go to window->preferences. Then navigate to Install/update - available software sites. Then you can add http://dl-ssl.google.com/android/eclipse/site.xml to the list. Now if you need to download the android developer's tools, you go back to the main eclipse screen and navigate to help->Install New Software. In the space where it says to Work with paste in that same URL: http://dl-ssl.google.com/android/eclipse/site.xml. Then select all the developer tools available. Restart, and you now have the Android dev tools available. More help HERE.
  3. Follow the Quick Start for setting up Eclipse IDE.

MyDroidTemplate

template_files208x421.png When you are building an Android project from scratch using the New -> Android Project wizards, it builds the basics for an application but there are a few expected items that are missing. This template is an attempt to have a template that may be trimmed down and customized rather than hunting down code and adding it in. To use this template, extract the MyDroidTemplate.zip to a new location (for example in your Eclipse 'workspace' folder) and then rename the root folder to your new project name. Next, File -> Import -> Existing Projects into Workspace. You will then need to update the project class name and namespace to your new name.

Here are some things I have added to the Eclipse generated MyDroidTemplate.java file:

import android.util.Log; //Used for debug and error logging [Log.e(TAG, "e.getMessage()");]
public final String TAG = "MyDroidTemplate"; //Used in logging etc.

Menu

I have read somewhere that most Android users expect a menu to be present in the application, so let's add one in the project template. I created a subfolder 'menu' under '.\MyDroidTemplate\res' (If you are not familiar with Eclipse, remember that you will need to press F5 in your project when you add folders or files outside of the Eclipse IDE.). This will contain the details on how to draw the buttons in the menu. All we need are three buttons for the template: 'Options', 'Quit', and 'About'.

<?xml version="1.0" encoding="utf-8"?>
<menu
  xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:id="@+id/options" 
    android:title="Options" 
    android:icon="@android:drawable/ic_menu_preferences">
    </item>
    <item android:id="@+id/quit" 
    android:title="Quit" 
    android:icon="@android:drawable/ic_menu_close_clear_cancel">
    </item>
    <item android:id="@+id/about" 
    android:title="About" 
    android:icon="@android:drawable/ic_menu_info_details">
    </item>
</menu>

Next, we need some methods to trigger and draw the menus. Eclipse does a good job at auto adding import lines when it sees it needs a class library. Here are the ones needed for this OptionsMenu:

import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;

And in the MyDroidTemplate class, we have the following methods to make it work (NOTE: I have commented out the lines we are not ready for yet like AboutDialog, etc).

//*** ANDROID.VIEW.MENU START ***// 
public boolean onCreateOptionsMenu(Menu menu) 
{
     // Create the menu from the menu_xml
     MenuInflater inflater = getMenuInflater();
     inflater.inflate(R.menu.menu, menu);
     return true;
}
public boolean onOptionsItemSelected(MenuItem item) {
     // Handle item selection
     switch (item.getItemId()) {
     case R.id.options:
          //DO OPTIONS()
          return true;
     case R.id.quit:
          finish();
          return true;
     case R.id.about:
          //new AboutDialog(this).show();
          return true;
     default:
          return super.onOptionsItemSelected(item);
     }
}
//*** ANDROID.VIEW.MENU END ***// 

AlertDialog

Here is how the AboutDialog is added in the template. With all Android views, there must be a corresponding layout XML file. I created one in Eclipse by selecting the folder I want to add the XML to and selecting "New -> Android XML File"; make sure layout is checked and write 'about.xml' in the 'File' textbox and click Finish. Here is the about.xml and notice we are adding mostly TextViews so we can format and send text to it later (NOTE: I added some color values to the \values\strings.xml). [NOTE: PopUpDialog.java and popup.xml are now added to the template which enables you to create a popup message with one line of code.]

<?xml version="1.0" encoding="utf-8"?>
<ScrollView
xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:id="@+id/options" 
     android:layout_width="fill_parent"
     android:layout_height="wrap_content"
     android:orientation="vertical">

          <LinearLayout
          android:layout_width="fill_parent"
          android:layout_height="wrap_content"
          android:orientation="vertical">
          <TextView
          android:id="@+id/app_name"
          android:layout_height="wrap_content"
          android:layout_width="wrap_content"
          android:textStyle="bold"
          android:textSize="16sp"
          android:textColor="@color/white"
          android:layout_marginLeft="20dip"
          android:layout_marginRight="20dip"
          android:layout_marginTop="12dip"
          android:layout_marginBottom="4dip" />
          <TextView
          android:id="@+id/author"
          android:layout_height="wrap_content"
          android:layout_width="wrap_content"
          android:textStyle="bold"
          android:textSize="14sp"
          android:textColor="@color/white"
          android:layout_marginLeft="20dip"
          android:layout_marginRight="20dip"
          android:layout_marginTop="4dip"
          android:layout_marginBottom="4dip" />
          <TextView
          android:id="@+id/graphics_byline"
          android:layout_height="wrap_content"
          android:layout_width="wrap_content"
          android:textStyle="bold"
          android:textSize="14sp"
          android:textColor="@color/white"
          android:layout_marginLeft="20dip"
          android:layout_marginRight="20dip"
          android:layout_marginTop="4dip"
          android:layout_marginBottom="4dip" />
          <TextView
          android:id="@+id/license"
          android:layout_height="wrap_content"
          android:layout_width="wrap_content"
          android:textStyle="bold"
          android:textSize="14sp"
          android:layout_marginLeft="20dip"
          android:layout_marginRight="20dip"
          android:layout_marginTop="4dip"
          android:layout_marginBottom="8dip" />
          <TextView
          android:id="@+id/what_is_this"
          android:layout_height="wrap_content"
          android:layout_width="wrap_content"
          android:textStyle="bold"
          android:textSize="14sp"
          android:layout_marginLeft="20dip"
          android:layout_marginRight="20dip"
          android:layout_marginTop="8dip"
          android:layout_marginBottom="8dip" />
          <TextView
          android:id="@+id/website"
          android:autoLink="web"
          android:layout_height="wrap_content"
          android:layout_width="wrap_content"
          android:textStyle="bold"
          android:textSize="14sp"
          android:textColor="@color/white"
          android:layout_marginLeft="20dip"
          android:layout_marginRight="20dip"
          android:layout_marginTop="8dip"
          android:layout_marginBottom="4dip" />
          <TextView
          android:id="@+id/bugs"
          android:autoLink="web"
          android:layout_height="wrap_content"
          android:layout_width="wrap_content"
          android:textStyle="bold"
          android:textSize="14sp"
          android:textColor="@color/white"
          android:layout_marginLeft="20dip"
          android:layout_marginRight="20dip"
          android:layout_marginTop="4dip"
          android:layout_marginBottom="12dip" />
</LinearLayout>
</ScrollView>

Now we must have a Java class that will handle the AboutDialog box. We can create this in Eclipse by right-clicking the 'src' folder and 'New -> class'. For 'Package', I browsed to 'com.android.MyDroidTemplate' and the 'Name' field I placed 'AboutDialog' and clicked the Finish button. Below is the AboutDialog.java and Utils.java. I find AboutDialog a good class to copy for created new dialogs. The Utils class has some reusable code to get the ever changing application details. (NOTE: Once again, I have added to the \values\strings.xml to store the common text for an application.)

//AboutDialog.java
package com.android.MyDroidTemplate;

import android.app.AlertDialog;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.TextView;

public class AboutDialog {
@SuppressWarnings("unused")
private static final String TAG = "AboutDialog";
private final Context mCtx;

public AboutDialog(Context ctx) {
     super();
     this.mCtx = ctx;
     }

public void show() {
final LayoutInflater factory = LayoutInflater.from(mCtx);

View dialogView = factory.inflate(R.layout.about, null);
innerUpdate(dialogView);
AlertDialog.Builder adBuilder = new AlertDialog.Builder(mCtx).setTitle(
R.string.about).setIcon(android.R.drawable.ic_dialog_info)
.setView(dialogView);
adBuilder.show();
}
private void innerUpdate(View dialogView) {
TextView appName = (TextView) dialogView.findViewById(R.id.app_name);
TextView author = (TextView) dialogView.findViewById(R.id.author);
TextView graphics_byline = (TextView) dialogView.findViewById(R.id.graphics_byline);
TextView license = (TextView) dialogView.findViewById(R.id.license);
TextView whatIsThis = (TextView) dialogView.findViewById(R.id.what_is_this);
TextView website = (TextView) dialogView.findViewById(R.id.website);
TextView bugs = (TextView) dialogView.findViewById(R.id.bugs);

// app name & version
String appText = Utils.getAppName(mCtx, mCtx.getPackageName()) + " v"
+ Utils.getAppVersionName(mCtx, mCtx.getPackageName());
appName.setText(appText);

// author
author.setText(R.string.author);

// license
license.setText(R.string.license);

// text
whatIsThis.setText(R.string.about_text);
// website
website.setText(mCtx.getString(R.string.website) + ":\n\n"
+ mCtx.getString(R.string.website_url));

// email
bugs.setText("Suggestions or Bugs:\n\n"
+ mCtx.getString(R.string.issues));
     }
} 

And the Utils.java:

//Utils.java

import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;

public class Utils {
 public static boolean checkForInstalledApp(Context ctx, String pkgName) {
      try {
      PackageManager pm = ctx.getPackageManager();
      pm.getPackageInfo(pkgName, 0);
      // Log.d(TAG, pkgString + " is installed");
      return true;
      } catch (NameNotFoundException e) {
           // Log.d(TAG, pkgString + " is not installed");
      }
      return false;
}

public static String getAppName(Context ctx, String pkgName) {
     try {
           PackageManager pm = ctx.getPackageManager();
           ApplicationInfo appInfo = pm.getApplicationInfo(pkgName, 0);
          String label = pm.getApplicationLabel(appInfo).toString();
          return label;
           } catch (NameNotFoundException e) {
            return "";
           }
}

     public static String getAppVersionName(Context ctx, String pkgName) {
     try {
          PackageManager pm = ctx.getPackageManager();
          PackageInfo pkgInfo = pm.getPackageInfo(pkgName, 0);
          String ver = pkgInfo.versionName;
          return ver;
     } catch (NameNotFoundException e) {
     return "0";
          }
}

public static int getAppVersionCode(Context ctx, String pkgName) {
try {
PackageManager pm = ctx.getPackageManager();
PackageInfo pkgInfo = pm.getPackageInfo(pkgName, 0);
return pkgInfo.versionCode;
} catch (NameNotFoundException e) {
return 0;
}
}
}

The SQLite Database Classes

SQLiteDatabaseAdapter.java (Class that delivers methods to manage a SQLite database) and DbDataLayer.java (Partner class to manage database version management opening, creating, and upgrading) has been added for SQLite database support. Instead of posting the entire class, I will explain the important methods that create and get information in the database. For the most part, the only class you will need to customize is DbDataLayer (if you will need to perform upgrades later modify the OnUpgrade method in SQLiteDatabaseAdapter). DbDataLayer needs your name of the database and its tablename. It also needs your table data structure in the standard SQL 'create table' statement. Finially, you will need to modify the AddRecord method so it can properly add records to the table schema.

//DbDataLayer.java
private static final String DATABASE_NAME = "mydbname.db"; //CUSTOMIZE
private static final String TABLE_NAME = "mytablename";//CUSTOMIZE

Also, you will need to customize the table creation to fit your needs (see below). You will notice that the template is defaulted to create a table 'mytablename' and it has columns 'ID', 'Link', 'Title', and 'Pubdate' in the database 'mydbname.db'

//DbDataLayer.java
public DbDataLayer(Context c) 
{
     //CUSTOMIZE FOR YOUR TABLE
     String sql = "create table "+ TABLE_NAME + " " +
     "("+ BaseColumns._ID + " integer primary key autoincrement, " +
     "Link text not null, " +
     "Title text not null, " +
     "Pubdate text not null); "; 

     _dbHelper = new SQLiteDatabaseAdapter(c, DATABASE_NAME, null , 1, sql);
}

Now here is how to initialize the database before you can perform any reads or writes:

//MyDroidTemplate.java

public DbDataLayer d ;

public class MyDroidTemplate extends Activity {
public DbDataLayer db ;
...
...
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
     super.onCreate(savedInstanceState);
     setContentView(R.layout.main);

            try {
               //DO SOMETHING
               db = new DbDataLayer(getBaseContext());//Initialize the database
     } catch (Exception e) {
          Log.e(TAG, e.getMessage());
     }
} 

Call the following method to write to the database:

//DbDataLayer.java
//CUSTOMIZE FOR YOUR DATABASE ENTRIES
public void AddRecord(String title, String link, String pubdate) {
     SQLiteDatabase db = _dbHelper.getWritableDatabase();
     try {
          ContentValues values = new ContentValues();
          values.put("Link", link);
          values.put("Title", title);
          values.put("Pubdate", pubdate);

          db.insert(TABLE_NAME, "", values);
     }catch (Exception e)
     {
          Log.e(tag,"AddRecord Exception [" + e.getMessage() + "]");
     } finally {
          if (db != null)
          db.close();
     }
}

ProgressDialog Class

This, by far, was one of the challenging features to implement and I still am not happy with it. So any suggestions and feedback would be great. However, I needed a Progressbar feature in my template so this is what I have for version 1. Calling showDialog triggers the onCreateDialog which displays the requested ProgressDialog.

//MyDroidTemplate
import android.app.ProgressDialog;

public class MyDroidTemplate extends Activity {
...
static final int PROGRESS_DIALOG = 0; //Used for DownloadedThread PRogressBar handling
DownloaderThread progressThread; //Used for DownloadedThread PRogressBar handling
ProgressDialog progressDialog; //Used for DownloadedThread PRogressBar handling

//*** PROGRESSBAR THREAD START ***//
// Define the Handler that receives messages from the thread and update the progress
final Handler handler = new Handler() {
     public void handleMessage(Message msg) {
          dismissDialog(PROGRESS_DIALOG);
          progressThread.setState(DownloaderThread.STATE_DONE);
     }
};

protected Dialog onCreateDialog(int id) {
     switch(id) {
     case PROGRESS_DIALOG:
          progressDialog = new ProgressDialog(this);
          progressDialog.setMessage("Loading...");
          progressThread = new DownloaderThread(handler);
          progressThread.start();
          return progressDialog;
     default:
          return null;
     }
}

/** Nested class that performs progress */
private class DownloaderThread extends Thread {
     Handler mHandler;
     final static int STATE_DONE = 0;
     final static int STATE_RUNNING = 1;
     int mState;
     int total;

     DownloaderThread(Handler h) {
     mHandler = h;
     }

     public void run() {
     mState = STATE_RUNNING; 
     while (mState == STATE_RUNNING) 
     {
          Message msg = mHandler.obtainMessage();
     try {
     //Do The Work
     Thread.sleep(10000);
     } catch (Exception e) {
          Log.e("ERROR", "Thread Interrupted Exception [" + e.getMessage() + "]");
     }
     mHandler.sendMessage(msg);
     }}

/* sets the current state for the thread,
* used to stop the thread */
public void setState(int state) {
     mState = state;
     }
}

TabView Template (android.widget.TabHost)

A set of classes are included in the template if you need tabbed viewing support. MyTabView.java and mytabview.xml handle the main display of the 2 tabs (you may add more) which are created with MyTabActivity.java and MyTabActivity2.java. MyTabActivity.java populates the ListView with a simple String array and MyTabActivity2.java populates with a custom adapter (MyLVAdapter.java [My List View Adapter]).

Android Debug Bridge (adb.exe)

The Android Debug Bridge (adb.exe) allows you direct access to an emulator instance or Android-powered device for debugging. For example, for this template app I could use it to look at the database after making some entries (NOTE: adb.exe resides in the 'android-sdk-windows\tools' folder). Start the emulator, and then the Android application. Below are commands I have in a textfile so I can easily copy and paste (NOTE: Some of the commands will need modification to access the correct database and table names).

C:\android-sdk-windows\tools>adb shell

cd data

cd data

cd com.android.MyDroidTemplate

cd databases

sqlite3 mydbname.db

cd data

cd data

cd com.android.MyDroidTemplate

cd databases

#ls
ls
mydbname.db
# sqlite3 mydbname.db
sqlite3 mydbname.db
SQLite version 3.5.9
Enter ".help" for instructions
sqlite> select * from mytablename;
select * from mytablename;
1|http://msn.com|MSN|Mon Aug 30 08:00
2|http://codeproject.com|Codeproject|Mon Aug 30 09:00
3|http://cpforandroid.googlecode.com|CPForAndroid|Mon Aug 30 10:00
sqlite>

CPForAndroid: A Droid App for Interacting with CodeProject.com

Get CPForAndroid now on your Android Phone at the market. Please rate after you try it out!!

qrcode.png

CPForAndroid

App for Interacting with CodeProject.com! Follow the buzzing activity at your favorite programming community. Easy on your eyes and fun.
Current Features include:

  • View Latest Article RSS feed
  • View Lounge RSS feed
  • Removes read items
  • View details on each item with optional jump url
  • Facebook, Google, Twitter, Windows Live, CP Email link sharing

  

https://market.android.com/details?id=org.android.CPForAndroidPlusPlus

If you are interested in help to develop or provide feedback, visit the development and support site.

Publishing your app to the Market

  1. Be certain you have declared the 'android:minSdkVersion' attribute in your manifest (http://developer.android.com/guide/appendix/api-levels.html), then Export your app to .apk file [File -> Export]. This will also generate the Certificate that is needed for your .apk. (BACKUP YOUR KEYSTORE ASAP!!! You will thank me later.)
  2. $25.00 to publish your applications to the Android Market. http://market.android.com/publish
  3. Complete the registration process.
  4. Upload your files according to the publishing instructions.

Tips

These are just some items that I had to search for along the way. You may find them useful as you are typing along.

Conclusion

Browsing Codeproject.com on my mobile was motivation enough to learn how to develop using the Android SDK and its emulator. Documenting everything here will help 6 to 12 months from now when I have another idea for an Android app. Hopefully, others will find this article helpful and the MyDroidTemplate a useful starting point for an Android Project skeleton. Along with the template, I provided some useful links to help as you develop your app and a quick reference to uploading your application to the Android Market. I plan on posting a video shortly for readers who don't own an Android phone nor have the Eclipse IDE to see what this article is about.

This template was a by-product of CPForAndroid. CPForAndroid is an Android application to help keep up with Codeproject.com. It is an open source project and open to all. Just visit the development and support website for more info. Come help out; the more the merrier!

References

  • Developer.Android.com [^]
  • Eclipse Development [^]
  • CPForAndroid Open Source Project Support and Development website [^]
  • SQLite.org [^]

Updates

  • 8/30/2010
    • Uploaded MyDroidTemplate v1.0.0.0 (tested in Eclipse 3.4)
  • 9/1/2010
    • Tested in Eclipse 3.6 MyDroidTemplate v1.0.0.0 (So verified in 3.4 and 3.6)
  • 9/5/2010
    • Added PopUpDialog.java and popup.xml to MyDroidTemplate
    • Uploaded MyDroidTemplate.zip version 1.1
    • Updated template_files208x421.png
    • Updated cpforandroid_main.png
    • Updated MyDroidTemplateIDE478x260.png
    • CPForAndroid now at version 1.17 and available on the Android Market
  • 9/8/2010
    • Added cur.deactivate() in class DbDataLayer method DoesExist() to avoid any errors
    • Added sample Toast line
    • Uploaded MyDroidTemplate versionName="1.2" versionCode="3"
  • 9/13/2010
    • Uploaded MyDroidTemplate.zip version 1.3  
    • Added ToastMsg to Utils class
    • Added MyTabView.java and mytabview.xml
    • Added MyTabActivity.java and mytabact.xml
    • Added MyTabActivity2.java (Uses MyLVAdapter)
    • Added 'Show TabView' button in main.xml layout
    • Added listview_row.xml for MyLVView.java
    • Added MyLVView.java
    • Added MyLVAdapter.java
    • Added e.printStackTrace(); to exception catch statements for better debugging
  • 2/11/2011
    • CPForAndroid is now CPForAndroid++
    • Updated qcode and Market Publishing section

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

JoeSox
Engineer
United States United States
Born in Bristol PA, just north of Philadelphia. Joe has been programming since he was ten[now much older]. He is entirely self-taught programmer, and he is currently working as a Network Administrator (and a bunch of other crap) in Seattle WA. He was previously U.S. Navy Active Reservist for (SPAWAR)
In '98 was honorably discharged from the USN. He served onboard the USS Carl Vinson (94-98) He was lucky enough to drink President Clinton's leftover wine, promoted by his Captain, and flew in a plane off the flightdeck but not all at the same time. His interests, when time allows, are developing
misc apps and Artificial Intelligence proof-of-concept demos that specifically exhibits human behavior. He is a true sports-a-holic, needs plenty of caffeine, and a coding junkie. He also enjoys alternative music and a big Pearl Jam, Nirvana, and new alternative music fan.
 
Joe is an INTP[^] personality type. Joe "sees everything in terms of how it could be improved, or what it could be turned into. INTP's live primarily inside their own minds." INTPs also can have the "greatest precision in thought and language. Can readily discern contradictions and inconsistencies. The world exists primarily to be understood. 1% of the total population" [
Follow on   Twitter   Google+   LinkedIn

Comments and Discussions

 
GeneralMy vote of 5 PinmemberSRSHINDE7-Apr-13 21:08 
GeneralMy Vote PinmemberPeetHV15-May-12 3:40 
GeneralMy vote of 5 PinmemberTomislav Galic25-Apr-12 0:56 
GeneralMy vote of 5 PinmemberMember 830732513-Oct-11 0:24 
GeneralMy vote of 5 Pinmemberqingshanyin14-Sep-10 19:11 
Very good!
GeneralMy vote of 5 PinmemberSwelborn1-Sep-10 2:19 
GeneralMy vote of 3 Pinmembertouchyp31-Aug-10 22:53 
GeneralExcellent work! PinmemberMarcelo Ricardo de Oliveira31-Aug-10 11:12 
GeneralMy vote of 5 Pinmembersam.hill31-Aug-10 5:55 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web01 | 2.8.140415.2 | Last Updated 11 Feb 2011
Article Copyright 2010 by JoeSox
Everything else Copyright © CodeProject, 1999-2014
Terms of Use
Layout: fixed | fluid