Source Code can be downloaded below. Also, the syntaxhighlighter for the XML code, has some problems. For some reason, the JS and CSS I used modifies the XML I place. Just check with the code downloadable below for the correct xml files.
1. Create new Android Project. -Activity Name: AccountList
2. Create View Classes and XML
2.1 Create account_list.xml
account_row.xml
2.2. Create ListActivity class AccountList
public class AccountList extends ListActivity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.account_list); initComponents(); } private void initComponents() { } }
2.3 Create account_detail.xml Below is an example of combining two or more layouts.
2.4. Create Activity class AccountDetail
public class AccountDetail extends Activity { public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.account_detail); initComponents(); } private void initComponents() { } }
3. Create Model Classes 3.1 Create Account class
public class Account { public static final String COL_ROW_ID = "_id"; public static final String COL_SERVER_NAME = "server_name"; public static final String COL_USERNAME = "username"; public static final String COL_PASSWORD = "password"; public static final String SQL_TABLE_NAME = "account_db"; public static final String SQL_CREATE_TABLE = "CREATE TABLE " + SQL_TABLE_NAME + " " + " (_id integer primary key autoincrement, " + "server_name text not null, username text not null, " + "password text not null); ";
public int getId() { return id; }
public void setId(int id) { this.id = id; }
public String getUsername() { return username; }
public void setUsername(String username) { this.username = username; }
public String getPassword() { return password; }
public void setPassword(String password) { this.password = password; }
public String getServerName() { return serverName; }
public void setServerName(String serverName) { this.serverName = serverName; }
private String username;
private String password;
private String serverName;
private int id; }
3.2 Create ActiveRecord interface This is the interface that will be extend by POJO to make it a sort-of Active Domain. I'm not really experienced with the Active Domain pattern but this is my understanding of it. So just correct me if I am wrong and I'll change the code.
public interface ActiveRecord { public long save(); public boolean delete(); public void load(Activity activity); public Cursor retrieveAll(); public void setSQLiteDatabase(SQLiteDatabase sqliteDb); }
3.3 Extend SQLiteOpenHelper I derived MyDatabaseAdapter class from Tutorial: A Notepad Application, However I made the MyDatabaseAdapter as a utility class instead of placing CRUD functions inside it. I made the Controller a sort-of Active Domain pattern so that the MyDatabaseAdapter can be re-used for future applications.
public class MyDatabaseAdapter extends SQLiteOpenHelper { private static SQLiteDatabase sqliteDb; private static MyDatabaseAdapter instance;
private static final String DATABASE_NAME = "simple_sqlite_db"; private static final int DATABASE_VERSION = 1;
@Override public void onCreate(SQLiteDatabase db) { db.execSQL(Account.SQL_CREATE_TABLE); }
@Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { Log.w(getClass().getSimpleName(), "Upgrading database from version " + oldVersion + " to " + newVersion + ", which will destroy all old data"); db.execSQL("DROP TABLE IF EXISTS " + Account.SQL_TABLE_NAME ); onCreate(db); }
3.4 Create implementation of ActiveRecord on Account class Here's the code that implements the CRUD methods of the ActiveRecord interface. I also learned that from the Notepad Tutorial, since the Android Docs, does not really explain how to use SQLiteDB, or maybe I just do not know where to look.
public class Account implements ActiveRecord {
public static final String COL_ROW_ID = "_id"; public static final String COL_SERVER_NAME = "server_name"; public static final String COL_USERNAME = "username"; public static final String COL_PASSWORD = "password";
public static final String SQL_TABLE_NAME = "account_db"; public static final String SQL_CREATE_TABLE = "CREATE TABLE " + SQL_TABLE_NAME + " " + " (_id integer primary key autoincrement, " + "server_name text not null, username text not null, " + "password text not null); ";
private SQLiteDatabase sqliteDatabase;
public int getId() { return id; }
public void setId(int id) { this.id = id; }
public String getUsername() { return username; }
public void setUsername(String username) { this.username = username; }
public String getPassword() { return password; }
public void setPassword(String password) { this.password = password; }
public String getServerName() { return serverName; }
public void setServerName(String serverName) { this.serverName = serverName; }
4. Create Controllers 4.1 AccountList Controllers For the AccountList I used the OptionsMenu.
public class AccountList extends ListActivity { /** Called when the activity is first created. */ private MyDatabaseAdapter myDatabaseAdapter;
private static final int INTENT_NEXT_SCREEN = 0; public static final String INTENT_EXTRA_SELECTED_ROW = "SELECTED_ROW";
private static final int INSERT_ID = Menu.FIRST; private static final int DELETE_ID = Menu.FIRST + 1; private static final int EXIT_ID = DELETE_ID + 1; private Account account = new Account(); private Intent intent;
@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.account_list); myDatabaseAdapter = MyDatabaseAdapter.getInstance(this); intent = new Intent(this, AccountDetail.class); initComponents(); }
private void initComponents() { account.setSQLiteDatabase(myDatabaseAdapter.getDatabase()); Cursor recordsCursor = account.retrieveAll(); startManagingCursor(recordsCursor); String[] from = new String[] { Account.COL_SERVER_NAME }; int[] to = new int[] { R.id.tfServerName }; SimpleCursorAdapter records = new SimpleCursorAdapter(this, R.layout.account_row, recordsCursor, from, to); setListAdapter(records); }
@Override public boolean onMenuItemSelected(int featureId, MenuItem item) { switch (item.getItemId()) { case INSERT_ID: createRecord(); return true; case DELETE_ID: account.setId((int) getListView().getSelectedItemId()); account.delete(); initComponents(); return true; case EXIT_ID: finish(); } return super.onMenuItemSelected(featureId, item); }
This tutorial is an android version of good old J2ME tutorial about Networking, User Experience and Threads; thus, I won't make my own J2ME tutorial for that.
Source code can be downloaded below.
For this Simple Http Connection application, it uses the following classes:
Unlike, the hello world tutorial, where only an alert screen shows, this tutorial will have two screens or two activities. So, I'll get started.
First, create two activity classes for the first screen and the next screen.
SimpleHttpConnection.java is the MAIN activity, NextScreen.java will display the network response.
Here's what the SimpleHttpConnection (main.xml) looks like. The white space on top of the buttons is supposed to be the progress bar, for some reason the android eclipse plug-in does not render it properly.
@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); initComponents(); }
Above is the code, for the user interface. Notice that the btnCancel and the progressBar is set to invisible. It will be visible to the user once btnConnect is clicked. Here's what the user-interface will look like.
When btnConnect is clicked, it initializes the NetworkConnection class and sends the request to the server. The btnConnect button is then set to invisible then the cancel button is set to visible. When the btnCancel is clicked, it will then interrupt the connection, and enables the btnConnect again, disabling the btnCancel and resets the progress bar. The NetworkConnection class implements Runnable since it will run as another thread.
public class NetworkConnection implements Runnable
Network Connection uses the following parameters:
progressBar - passes the screen's progress bar to be update the progress. serverUrl - the server's url. activity - the previous activity, this will be used to call startActivityForResult(intent, intentId); nextIntent - the next activity to be run after the network connection is done. intentId - the requestCode used by the Main Activity's onActivityResult method show below.
The transfer method, is just a basic HTTP connection, its just opens a connections from the url then opens an input stream. The important part of this method is
This code, puts the server response in the intent.putExra, then starts the next activity, which was defined on the first screen.
Also, the NetworkConnection has close method, that when the user clicks, it cancels the operation. The method I created is a crude one without any graceful handling. But for this app, it does not need to. If you're app parses data and saves them somewhere, be careful in using this since it will corrupt your data.
public void initComponents() { message = getIntent().getStringExtra(NetworkConnection.NC_RESPONSE); tvMessage = (TextView) findViewById(R.id.tvMessage); if (message != null) { tvMessage.setText(message); } else { tvMessage.setText("Message is null"); } btnBack = (Button) findViewById(R.id.btnBack); btnBack.setOnClickListener(this); }
@Override public void onClick(View v) { if (v == btnBack) { finish(); } } }
On the initComponent method, the Intent Extra is that was set in the NetworkConnection class was retrieved then set on the TextView.
Here's what it looks like.
When the Back button is clicked, the finish() method is called, signifying that the Activity is done. Thus, it goes back to the main screen, and calling the onActivityResult method. For this, application, I just reset the progress bar, and the buttons.
Also, do not forget to add permission, or you might get a Socket Exception.
Modify the Android Manifest and add uses-permission name="android.permission.INTERNET"
See the AndroidManifest.xml in the source code for more details.
I just found out how to write Java and XML code with syntax highlights in blogger. You can find the project here. So on the next post, i'll use it instead of screen captures of the source code.
public class HelloWorld { private String message = "Hello World";
public static void main(String[] args) { System.out.println(message); } }