Android AutocompleteTextView with Custom Adapter Example

Before this Android AutocompleteTextView with custom adapter example, we made the code on Android AutocompleteTextView with suggestions from SQLite database, that’s really fine and useful, but here’s another problem:

What if you want to customize the appearance of the drop-down suggestions?

This is where the custom ArrayAdapter will come to the scene. Using this post, you will be able to customize the look and feel of your AutocompleteTextView drop down – according to your app design theme or visual needs.

We will cover the following content:

1.0 AutocompleteTextView with Custom Adapter Video Demo
2.0 Android AutoComplete EditText Program Files
3.0 Android AutocompleteTextView with Custom Adapter Example Codes
3.1 to 3.8 Main Files Description with Codes Explained via Comments

DOWNLOAD SOURCE CODE

1.0 AutocompleteTextView with Custom Adapter Video Demo

Here’s a video I shoot so you can see the final output of our code for today.

2.0 Android AutoComplete EditText Program Files

You may click on each of the files below to see the code and some insights or explanations. File # 1 and 2 were found in your res/layout/ folder, the rest is of course in the src/your.package.name

  1. activity_main.xml
  2. list_view_row.xml
  3. MainActivity.java
  4. AutocompleteCustomArrayAdapter.java
  5. CustomAutoCompleteView.java
  6. DatabaseHandler.java
  7. CustomAutoCompleteTextChangedListener.java
  8. MyObject.java

3.0 Android AutocompleteTextView with Custom Adapter Example Codes

Now here’s the exciting part. We’ll dig deeper with each main files of the program, see the codes and some explanation. Enjoy!

3.1 activity_main.xml – see how our custom AutoCompleteTextView were put in the XML layout.

The tag looks like com.example.autocompletetextviewdb.CustomAutoCompleteView because it was referenced to our CustomAutoComputeView.java file.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <TextView
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="" />

    <com.example.autocompletetextviewcustomadapter.CustomAutoCompleteView
        android:id="@+id/myautocomplete"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:completionThreshold="1" >
    </com.example.autocompletetextviewcustomadapter.CustomAutoCompleteView>

</LinearLayout>

3.2 list_view_row.xml – helps customize the appearance of AutoCompleteTextView suggestions, you can add an ImageView or something suits your app theme or design.

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:padding="10dp" >

    <TextView
        android:id="@+id/textViewItem"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:text="Item name here..."
        android:textSize="15dp" />

</RelativeLayout>

3.3 MainActivity.java – where the program will try to insert sample data, initialize some variables and will be shown when you the program runs.

package com.example.autocompletetextviewcustomadapter;

import android.os.Bundle;
import android.app.Activity;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ArrayAdapter;
import android.widget.RelativeLayout;
import android.widget.TextView;

public class MainActivity extends Activity {

    /*
     * Change to type CustomAutoCompleteView instead of AutoCompleteTextView 
     * since we are extending to customize the view and disable filter
     * The same with the XML view, type will be CustomAutoCompleteView
     */
    CustomAutoCompleteView myAutoComplete;
    
    // adapter for auto-complete
    ArrayAdapter<MyObject> myAdapter;
    
    // for database operations
    DatabaseHandler databaseH;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        try{
            
            // instantiate database handler
            databaseH = new DatabaseHandler(MainActivity.this);
            
            // put sample data to database
            insertSampleData();
            
            // autocompletetextview is in activity_main.xml
            myAutoComplete = (CustomAutoCompleteView) findViewById(R.id.myautocomplete);
            
            myAutoComplete.setOnItemClickListener(new OnItemClickListener() {

                @Override
                public void onItemClick(AdapterView<?> parent, View arg1, int pos, long id) {
                    
                    RelativeLayout rl = (RelativeLayout) arg1;
                    TextView tv = (TextView) rl.getChildAt(0);
                    myAutoComplete.setText(tv.getText().toString());
                    
                }

            });
            
            // add the listener so it will tries to suggest while the user types
            myAutoComplete.addTextChangedListener(new CustomAutoCompleteTextChangedListener(this));
            
            // ObjectItemData has no value at first
            MyObject[] ObjectItemData = new MyObject[0];
            
            // set the custom ArrayAdapter
            myAdapter = new AutocompleteCustomArrayAdapter(this, R.layout.list_view_row_item, ObjectItemData);
            myAutoComplete.setAdapter(myAdapter);
        
        } catch (NullPointerException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    public void insertSampleData(){
        
        // CREATE
        databaseH.create( new MyObject("January") );
        databaseH.create( new MyObject("February") ); 
        databaseH.create( new MyObject("March") );
        databaseH.create( new MyObject("April") );
        databaseH.create( new MyObject("May") );
        databaseH.create( new MyObject("June") );
        databaseH.create( new MyObject("July") );
        databaseH.create( new MyObject("August") );
        databaseH.create( new MyObject("September") );
        databaseH.create( new MyObject("October") );
        databaseH.create( new MyObject("November") );
        databaseH.create( new MyObject("December") );
        databaseH.create( new MyObject("New Caledonia this is just to make and see if the text will go down") ); 
        databaseH.create( new MyObject("New Zealand this is just to make and see if the text will go down") );
        databaseH.create( new MyObject("Papua New Guinea this is just to make and see if the text will go down") );
        databaseH.create( new MyObject("COFFEE-1K") );
        databaseH.create( new MyObject("coffee raw") );
        databaseH.create( new MyObject("authentic COFFEE") );
        databaseH.create( new MyObject("k12-coffee") );
        databaseH.create( new MyObject("view coffee") );
        databaseH.create( new MyObject("Indian-coffee-two") );
        
    }
}

3.4 AutocompleteCustomArrayAdapter.java – where you can customize the appearance of the suggestion drop-down. If your suggestions will contain a large list, I suggest using a ViewHolder pattern to make it smooth.

package com.example.autocompletetextviewcustomadapter;

import android.content.Context;
import android.graphics.Color;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.TextView;

public class AutocompleteCustomArrayAdapter extends ArrayAdapter<MyObject> {

    final String TAG = "AutocompleteCustomArrayAdapter.java";
        
    Context mContext;
    int layoutResourceId;
    MyObject data[] = null;

    public AutocompleteCustomArrayAdapter(Context mContext, int layoutResourceId, MyObject[] data) {

        super(mContext, layoutResourceId, data);
        
        this.layoutResourceId = layoutResourceId;
        this.mContext = mContext;
        this.data = data;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        
        try{
            
            /*
             * The convertView argument is essentially a "ScrapView" as described is Lucas post 
             * http://lucasr.org/2012/04/05/performance-tips-for-androids-listview/
             * It will have a non-null value when ListView is asking you recycle the row layout. 
             * So, when convertView is not null, you should simply update its contents instead of inflating a new row layout.
             */
            if(convertView==null){
                // inflate the layout
                LayoutInflater inflater = ((MainActivity) mContext).getLayoutInflater();
                convertView = inflater.inflate(layoutResourceId, parent, false);
            }
            
            // object item based on the position
            MyObject objectItem = data[position];

            // get the TextView and then set the text (item name) and tag (item ID) values
            TextView textViewItem = (TextView) convertView.findViewById(R.id.textViewItem);
            textViewItem.setText(objectItem.objectName);
            
            // in case you want to add some style, you can do something like:
            textViewItem.setBackgroundColor(Color.CYAN);
            
        } catch (NullPointerException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
        
        return convertView;
        
    }
}

3.5 CustomAutoCompleteView.java – since we have to display everything the database gets, we have to display the AutoCompleteTextView’s default filtering function. This is also what was called in the XML layout. See activity_main.xml code above.

package com.example.autocompletetextviewcustomadapter;

import android.content.Context;
import android.util.AttributeSet;
import android.widget.AutoCompleteTextView;

public class CustomAutoCompleteView extends AutoCompleteTextView {

    public CustomAutoCompleteView(Context context) {
        super(context);
        // TODO Auto-generated constructor stub
    }
    
    public CustomAutoCompleteView(Context context, AttributeSet attrs) {
        super(context, attrs);
        // TODO Auto-generated constructor stub
    }

    public CustomAutoCompleteView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        // TODO Auto-generated constructor stub
    }

    // this is how to disable AutoCompleteTextView filter
    @Override
    protected void performFiltering(final CharSequence text, final int keyCode) {
        String filterText = "";
        super.performFiltering(filterText, keyCode);
    }
}

3.6 DatabaseHandler.java – where we insert sample data and query the database for autocomplete suggestions.

package com.example.autocompletetextviewcustomadapter;

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;

public class DatabaseHandler extends SQLiteOpenHelper {

    // for our logs
    public static final String TAG = "DatabaseHandler.java";

    // database version
    private static final int DATABASE_VERSION = 5;

    // database name
    protected static final String DATABASE_NAME = "NinjaDatabase2";

    // table details
    public String tableName = "locations";
    public String fieldObjectId = "id";
    public String fieldObjectName = "name";

    // constructor
    public DatabaseHandler(Context context) {
        super(context, DATABASE_NAME, null, DATABASE_VERSION);
    }

    // creating table
    @Override
    public void onCreate(SQLiteDatabase db) {

        String sql = "";

        sql += "CREATE TABLE " + tableName;
        sql += " ( ";
        sql += fieldObjectId + " INTEGER PRIMARY KEY AUTOINCREMENT, ";
        sql += fieldObjectName + " TEXT ";
        sql += " ) ";

        db.execSQL(sql);

    }

    
    // When upgrading the database, it will drop the current table and recreate.
    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

        String sql = "DROP TABLE IF EXISTS " + tableName;
        db.execSQL(sql);

        onCreate(db);
    }

    
    // create new record
    // @param myObj contains details to be added as single row.
    public boolean create(MyObject myObj) {

        boolean createSuccessful = false;

        if(!checkIfExists(myObj.objectName)){
                    
            SQLiteDatabase db = this.getWritableDatabase();
            
            ContentValues values = new ContentValues();
            values.put(fieldObjectName, myObj.objectName);
            createSuccessful = db.insert(tableName, null, values) > 0;
            
            db.close();
            
            if(createSuccessful){ 
                Log.e(TAG, myObj.objectName + " created.");
            }
        }
        
        return createSuccessful;
    }
    
    // check if a record exists so it won't insert the next time you run this code
    public boolean checkIfExists(String objectName){
        
        boolean recordExists = false;
                
        SQLiteDatabase db = this.getWritableDatabase();
        Cursor cursor = db.rawQuery("SELECT " + fieldObjectId + " FROM " + tableName + " WHERE " + fieldObjectName + " = '" + objectName + "'", null);
        
        if(cursor!=null) {
            
            if(cursor.getCount()>0) {
                recordExists = true;
            }
        }

        cursor.close();
        db.close();
        
        return recordExists;
    }

    // Read records related to the search term
    public MyObject[] read(String searchTerm) {

        // select query
        String sql = "";
        sql += "SELECT * FROM " + tableName;
        sql += " WHERE " + fieldObjectName + " LIKE '%" + searchTerm + "%'";
        sql += " ORDER BY " + fieldObjectId + " DESC";
        sql += " LIMIT 0,5";

        SQLiteDatabase db = this.getWritableDatabase();

        // execute the query
        Cursor cursor = db.rawQuery(sql, null);

        int recCount = cursor.getCount();
        
        MyObject[] ObjectItemData = new MyObject[recCount];
        int x = 0;
        
        // looping through all rows and adding to list
        if (cursor.moveToFirst()) {
            do {

                String objectName = cursor.getString(cursor.getColumnIndex(fieldObjectName));
                Log.e(TAG, "objectName: " + objectName);
                
                MyObject myObject = new MyObject(objectName);

                ObjectItemData[x] = myObject;
                
                x++;
                
            } while (cursor.moveToNext());
        }

        cursor.close();
        db.close();

        return ObjectItemData;
        
    }

}

3.7 CustomAutoCompleteTextChangedListener.java – each time the user types a character, it queries the database and updates our customized ArrayAdapter.

package com.example.autocompletetextviewcustomadapter;

import android.content.Context;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.Log;

public class CustomAutoCompleteTextChangedListener implements TextWatcher{

    public static final String TAG = "CustomAutoCompleteTextChangedListener.java";
    Context context;
    
    public CustomAutoCompleteTextChangedListener(Context context){
        this.context = context;
    }
    
    @Override
    public void afterTextChanged(Editable s) {
        // TODO Auto-generated method stub
        
    }

    @Override
    public void beforeTextChanged(CharSequence s, int start, int count,
            int after) {
        // TODO Auto-generated method stub
        
    }

    @Override
    public void onTextChanged(CharSequence userInput, int start, int before, int count) {

        try{
            
            // if you want to see in the logcat what the user types
            Log.e(TAG, "User input: " + userInput);
    
            MainActivity mainActivity = ((MainActivity) context);
            
            // update the adapater
            mainActivity.myAdapter.notifyDataSetChanged();
            
            // get suggestions from the database
            MyObject[] myObjs = mainActivity.databaseH.read(userInput.toString());
            
            // update the adapter
            mainActivity.myAdapter = new AutocompleteCustomArrayAdapter(mainActivity, R.layout.list_view_row_item, myObjs);
            
            mainActivity.myAutoComplete.setAdapter(mainActivity.myAdapter);
            
        } catch (NullPointerException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
        
    }
    
    

}

3.8 MyObject.java – used for the sample data to appear in the auto-complete suggestion.

package com.example.autocompletetextviewcustomadapter;

public class MyObject {

    public String objectName;

    // constructor for adding sample data
    public MyObject(String objectName){
        
        this.objectName = objectName;
    }

}

I recommend reading more about Android AutocompleteTextView. Feel free to drop your questions or suggestions to improve this Android AutocompleteTextView with custom adapter example. Thanks!

Android AutocompleteTextView with Database Data as Suggestions

Our code example for today is about a very useful Android widget called AutocompleteTextView. Specifically, we’ll code an Android AutocompleteTextView with database data as drop-down suggestions.

If you’re not yet familiar with AutocompleteTextView, this widget looks like an EditText but shows completion suggestions automatically while the user is typing.

The list of suggestions is displayed in a drop down menu from which the user can choose an item to replace the content of the edit box with.

I recently played with this widget for my project, but it requires that the auto-complete suggestions must come from SQLite database. I know this could be helpful for your projects too.

In this post, we will cover the following content:

1.0 Android AutocompleteTextView with Database Video Demo
2.0 Android AutoComplete EditText Program Files
3.0 Android AutocompleteTextView with Database Example Codes
3.1 to 3.6 Main Files Description with Codes Explained via Comments

1.0 Android AutocompleteTextView with Database Video Demo

Visualizing our code output is important so here’s a video I shoot for you to show the code’s final output.

2.0 Android AutoComplete EditText Program Files

Our example project for today contains only 5 java files. Click the file names below to read its purpose and see the code inside.

  1. activity_main.xml
  2. MainActivity.java
  3. CustomAutoCompleteView.java
  4. DatabaseHandler.java
  5. CustomAutoCompleteTextChangedListener.java
  6. MyObject.java

3.0 Android AutocompleteTextView with Database Example Codes

3.1 activity_main.xml – see how the AutoCompleteTextView widget was put in the XML layout.

The tag looks like com.example.autocompletetextviewdb.CustomAutoCompleteView because it was referenced to our CustomAutoComputeView.java file.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <TextView
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="" />

    <com.example.autocompletetextviewdb.CustomAutoCompleteView
        android:id="@+id/myautocomplete"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:completionThreshold="1" >
    </com.example.autocompletetextviewdb.CustomAutoCompleteView>

</LinearLayout>

3.2 MainActivity.java – this is where we initialize everything and insert sample data to the database.

package com.example.autocompletetextviewdb;

import java.util.List;

import android.os.Bundle;
import android.app.Activity;
import android.widget.ArrayAdapter;

public class MainActivity extends Activity {

    /*
     * Change to type CustomAutoCompleteView instead of AutoCompleteTextView 
     * since we are extending to customize the view and disable filter
     * The same with the XML view, type will be CustomAutoCompleteView
     */
    CustomAutoCompleteView myAutoComplete;
    
    // adapter for auto-complete
    ArrayAdapter<String> myAdapter;
    
    // for database operations
    DatabaseHandler databaseH;
    
    // just to add some initial value
    String[] item = new String[] {"Please search..."};
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        try{
            
            // instantiate database handler
            databaseH = new DatabaseHandler(MainActivity.this);
            
            // put sample data to database
            insertSampleData();
            
            // autocompletetextview is in activity_main.xml
            myAutoComplete = (CustomAutoCompleteView) findViewById(R.id.myautocomplete);
            
            // add the listener so it will tries to suggest while the user types
            myAutoComplete.addTextChangedListener(new CustomAutoCompleteTextChangedListener(this));
            
            // set our adapter
            myAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_dropdown_item_1line, item);
            myAutoComplete.setAdapter(myAdapter);
        
        } catch (NullPointerException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    public void insertSampleData(){
        
        // CREATE
        databaseH.create( new MyObject("January") );
        databaseH.create( new MyObject("February") ); 
        databaseH.create( new MyObject("March") );
        databaseH.create( new MyObject("April") );
        databaseH.create( new MyObject("May") );
        databaseH.create( new MyObject("June") );
        databaseH.create( new MyObject("July") );
        databaseH.create( new MyObject("August") );
        databaseH.create( new MyObject("September") );
        databaseH.create( new MyObject("October") );
        databaseH.create( new MyObject("November") );
        databaseH.create( new MyObject("December") );
        databaseH.create( new MyObject("New Caledonia") ); 
        databaseH.create( new MyObject("New Zealand") );
        databaseH.create( new MyObject("Papua New Guinea") );
        databaseH.create( new MyObject("COFFEE-1K") );
        databaseH.create( new MyObject("coffee raw") );
        databaseH.create( new MyObject("authentic COFFEE") );
        databaseH.create( new MyObject("k12-coffee") );
        databaseH.create( new MyObject("view coffee") );
        databaseH.create( new MyObject("Indian-coffee-two") );
        
    }
    
    // this function is used in CustomAutoCompleteTextChangedListener.java
    public String[] getItemsFromDb(String searchTerm){
        
        // add items on the array dynamically
        List<MyObject> products = databaseH.read(searchTerm);
        int rowCount = products.size();
        
        String[] item = new String[rowCount];
        int x = 0;
        
        for (MyObject record : products) {
            
            item[x] = record.objectName;
            x++;
        }
        
        return item;
    }

}

3.3 CustomAutoCompleteView.java – since we want the AutocompleteTextView to work with a database, we must customize by extending it.

package com.example.autocompletetextviewdb;

import android.content.Context;
import android.util.AttributeSet;
import android.widget.AutoCompleteTextView;

public class CustomAutoCompleteView extends AutoCompleteTextView {

    public CustomAutoCompleteView(Context context) {
        super(context);
        // TODO Auto-generated constructor stub
    }
    
    public CustomAutoCompleteView(Context context, AttributeSet attrs) {
        super(context, attrs);
        // TODO Auto-generated constructor stub
    }

    public CustomAutoCompleteView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        // TODO Auto-generated constructor stub
    }

    // this is how to disable AutoCompleteTextView filter
    @Override
    protected void performFiltering(final CharSequence text, final int keyCode) {
        String filterText = "";
        super.performFiltering(filterText, keyCode);
    }

    /*
     * after a selection we have to capture the new value and append to the existing text
     */
    @Override
    protected void replaceText(final CharSequence text) {
        super.replaceText(text);
    }

}

3.4 DatabaseHandler.java – as the name suggests, this is where we can create the database, tables, manipulate and query the data.

package com.example.autocompletetextviewdb;

import java.util.ArrayList;
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;
import android.util.Log;

public class DatabaseHandler extends SQLiteOpenHelper {

    // for our logs
    public static final String TAG = "DatabaseHandler.java";

    // database version
    private static final int DATABASE_VERSION = 4;

    // database name
    protected static final String DATABASE_NAME = "NinjaDatabase2";

    // table details
    public String tableName = "locations";
    public String fieldObjectId = "id";
    public String fieldObjectName = "name";

    // constructor
    public DatabaseHandler(Context context) {
        super(context, DATABASE_NAME, null, DATABASE_VERSION);
    }

    // creating table
    @Override
    public void onCreate(SQLiteDatabase db) {

        String sql = "";

        sql += "CREATE TABLE " + tableName;
        sql += " ( ";
        sql += fieldObjectId + " INTEGER PRIMARY KEY AUTOINCREMENT, ";
        sql += fieldObjectName + " TEXT ";
        sql += " ) ";

        db.execSQL(sql);

    }

    // When upgrading the database, it will drop the current table and recreate.
    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

        String sql = "DROP TABLE IF EXISTS " + tableName;
        db.execSQL(sql);

        onCreate(db);
    }

    // create new record
    // @param myObj contains details to be added as single row.
    public boolean create(MyObject myObj) {

        boolean createSuccessful = false;

        if(!checkIfExists(myObj.objectName)){
                    
            SQLiteDatabase db = this.getWritableDatabase();
            
            ContentValues values = new ContentValues();
            values.put(fieldObjectName, myObj.objectName);
            createSuccessful = db.insert(tableName, null, values) > 0;
            
            db.close();
            
            if(createSuccessful){ 
                Log.e(TAG, myObj.objectName + " created.");
            }
        }
        
        return createSuccessful;
    }
    
    // check if a record exists so it won't insert the next time you run this code
    public boolean checkIfExists(String objectName){
        
        boolean recordExists = false;
                
        SQLiteDatabase db = this.getWritableDatabase();
        Cursor cursor = db.rawQuery("SELECT " + fieldObjectId + " FROM " + tableName + " WHERE " + fieldObjectName + " = '" + objectName + "'", null);
        
        if(cursor!=null) {
            
            if(cursor.getCount()>0) {
                recordExists = true;
            }
        }

        cursor.close();
        db.close();
        
        return recordExists;
    }

    // Read records related to the search term
    public List<MyObject> read(String searchTerm) {

        List<MyObject> recordsList = new ArrayList<MyObject>();

        // select query
        String sql = "";
        sql += "SELECT * FROM " + tableName;
        sql += " WHERE " + fieldObjectName + " LIKE '%" + searchTerm + "%'";
        sql += " ORDER BY " + fieldObjectId + " DESC";
        sql += " LIMIT 0,5";

        SQLiteDatabase db = this.getWritableDatabase();

        // execute the query
        Cursor cursor = db.rawQuery(sql, null);

        // looping through all rows and adding to list
        if (cursor.moveToFirst()) {
            do {

                // int productId = Integer.parseInt(cursor.getString(cursor.getColumnIndex(fieldProductId)));
                String objectName = cursor.getString(cursor.getColumnIndex(fieldObjectName));
                MyObject myObject = new MyObject(objectName);

                // add to list
                recordsList.add(myObject);

            } while (cursor.moveToNext());
        }

        cursor.close();
        db.close();

        // return the list of records
        return recordsList;
    }

}

3.5 CustomAutoCompleteTextChangedListener.java – this is where the program requeries the database each time a user types a character on the AutocompleteTextView.

package com.example.autocompletetextviewdb;

import android.content.Context;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.Log;
import android.widget.ArrayAdapter;

public class CustomAutoCompleteTextChangedListener implements TextWatcher{

    public static final String TAG = "CustomAutoCompleteTextChangedListener.java";
    Context context;
    
    public CustomAutoCompleteTextChangedListener(Context context){
        this.context = context;
    }
    
    @Override
    public void afterTextChanged(Editable s) {
        // TODO Auto-generated method stub
        
    }

    @Override
    public void beforeTextChanged(CharSequence s, int start, int count,
            int after) {
        // TODO Auto-generated method stub
        
    }

    @Override
    public void onTextChanged(CharSequence userInput, int start, int before, int count) {

        // if you want to see in the logcat what the user types
        Log.e(TAG, "User input: " + userInput);

        MainActivity mainActivity = ((MainActivity) context);
        
        // query the database based on the user input
        mainActivity.item = mainActivity.getItemsFromDb(userInput.toString());
        
        // update the adapater
        mainActivity.myAdapter.notifyDataSetChanged();
        mainActivity.myAdapter = new ArrayAdapter<String>(mainActivity, android.R.layout.simple_dropdown_item_1line, mainActivity.item);
        mainActivity.myAutoComplete.setAdapter(mainActivity.myAdapter);
        
    }

}

3.6 MyObject.java – this is used for inserting sample data and other operations related to the database.

package com.example.autocompletetextviewdb;

public class MyObject {

    public String objectName;

    // constructor for adding sample data
    public MyObject(String objectName){
        
        this.objectName = objectName;
    }

}

On the next post, we’ll have this code with a custom ArrayAdapter so you can style the drop down that appears, see you! Feel free to drop a comment on this Android AutocompleteTextView with database example.

Simple Android JSON Parser Example Code with URL and Logcat Output

android json parser example

Today I’m going to share an Android JSON Parser example code to parse a JSON string from a URL.

This code is really useful because nowadays, JSON string is being used by most APIs like Facebook graph API and Google Maps.

You should use JSON in your projects instead of XML because it is lightweight, so much easier to parse, and is supported by most programming language.

Recently, I wrote about how to generate JSON string with PHP which can be useful for you too.

But if you really have to use XML, you can also take a look at my older post: Parse XML in Android With Three Input Sources

DOWNLOAD SOURCE CODE

We will cover the following contents in this post:

1.0 Creating JSON String
2.0 Creating our JSON Parser Class
3.0 Using JSON Parser Class with JSON String
4.0 Logcat Output
5.0 Online Resources

1.0 Creating JSON String

Create a JSON string and make it accessible via URL. I created an example for this post, you can see it in this URL: http://demo.codeofaninja.com/tutorials/json-example-with-php/index.php

What it looks like in a JSON viewer:

android-json-parser-example-json-string

As for the code on how to create that JSON string, you can take a look at my older post: Generating JSON String with PHP

2.0 Create our JSON Parser Class

You can use this JSON parser class with any of your JSON string from URL. Here’s our JsonParser.java:

package com.example.androidjsonparsing;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.json.JSONException;
import org.json.JSONObject;

import android.util.Log;

public class JsonParser {

    final String TAG = "JsonParser.java";

    static InputStream is = null;
    static JSONObject jObj = null;
    static String json = "";

    public JSONObject getJSONFromUrl(String url) {

        // make HTTP request
        try {

            DefaultHttpClient httpClient = new DefaultHttpClient();
            HttpPost httpPost = new HttpPost(url);

            HttpResponse httpResponse = httpClient.execute(httpPost);
            HttpEntity httpEntity = httpResponse.getEntity();
            is = httpEntity.getContent();           

        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (ClientProtocolException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

        try {

            BufferedReader reader = new BufferedReader(new InputStreamReader(is, "iso-8859-1"), 8);
            StringBuilder sb = new StringBuilder();
            String line = null;
            while ((line = reader.readLine()) != null) {
                sb.append(line + "\n");
            }
            is.close();
            json = sb.toString();

        } catch (Exception e) {
            Log.e(TAG, "Error converting result " + e.toString());
        }

        // try parse the string to a JSON object
        try {
            jObj = new JSONObject(json);
        } catch (JSONException e) {
            Log.e(TAG, "Error parsing data " + e.toString());
        }

        // return JSON String
        return jObj;
    }
}

3.0 Using JSON Parser Class with JSON String

Now we want to make use of our JSON parser with the generated JSON string from URL. But before running our code, make sure you enable internet permission in your AndroidManifest.xml

<uses-permission android:name="android.permission.INTERNET"></uses-permission>

Now take a look at our MainActivity.java:

package com.example.androidjsonparsing;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import android.os.AsyncTask;
import android.os.Bundle;
import android.app.Activity;
import android.util.Log;

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // we will using AsyncTask during parsing 
        new AsyncTaskParseJson().execute();
    }

    // you can make this class as another java file so it will be separated from your main activity.
    public class AsyncTaskParseJson extends AsyncTask<String, String, String> {

        final String TAG = "AsyncTaskParseJson.java";

        // set your json string url here
        String yourJsonStringUrl = "http://demo.codeofaninja.com/tutorials/json-example-with-php/index.php";

        // contacts JSONArray
        JSONArray dataJsonArr = null;

        @Override
        protected void onPreExecute() {}

        @Override
        protected String doInBackground(String... arg0) {

            try {

                // instantiate our json parser
                JsonParser jParser = new JsonParser();

                // get json string from url
                JSONObject json = jParser.getJSONFromUrl(yourJsonStringUrl);

                // get the array of users
                dataJsonArr = json.getJSONArray("Users");

                // loop through all users
                for (int i = 0; i < dataJsonArr.length(); i++) {

                    JSONObject c = dataJsonArr.getJSONObject(i);

                    // Storing each json item in variable
                    String firstname = c.getString("firstname");
                    String lastname = c.getString("lastname");
                    String username = c.getString("username");

                    // show the values in our logcat
                    Log.e(TAG, "firstname: " + firstname 
                            + ", lastname: " + lastname
                            + ", username: " + username);

                }

            } catch (JSONException e) {
                e.printStackTrace();
            }

            return null;
        }

        @Override
        protected void onPostExecute(String strFromDoInBg) {}
    }
}

4.0 Android JSON Parser Example Logcat Output

It is important for us to see the extracted data from the JSON string or URL. So here’s the logcat output of our code for today.

android-json-parsing-tutoril

5.0 Online Resources

I think the following online resources can also help you in doing such tasks. Check them out!

How to parse JSON in Android?
Android JSON Reader

If you have any other solutions or comments to improve this Android JSON parser example code, please let us know in the comments section below. Thanks for reading our code tutorial!

Fixing Android EditText Lag

Lately I encountered this annoying android EditText lag, each time I try to type a character, it makes me wait for around 1 to 3 seconds before I can type the next character! Now that’s horrible. EditText is not useful. Keyboard looks broken.

Fixing Android EditText Lag

If you have the same issue, I have a good news for you, I found a fix! Now take a look at the code below.

Old Code

This is the XML layout I used for my customized search bar, and it is very laggy.

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content" >

    <TextView
        android:id="@+id/tvSearchBy"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_alignParentTop="true"
        android:padding="10dp"
        android:text="u25BC" />

    <TextView
        android:id="@+id/tvSearchButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
        android:layout_alignParentTop="true"
        android:layout_marginRight="1dp"
        android:layout_marginTop="1dp"
        android:background="#d1d1d1"
        android:padding="10dp"
        android:text="Search" />

    <EditText
        android:id="@+id/autoCompleteTv"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:layout_toLeftOf="@+id/tvSearchButton"
        android:layout_toRightOf="@+id/tvSearchBy"
        android:hint="Type..."
        android:padding="10dp"
        android:singleLine="true"
        android:text="" />

</RelativeLayout>

New Code

Now here’s a fix. The code below makes everything smooth and feel good.

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content" >

    <TextView
        android:id="@+id/tvSearchBy"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:padding="10dp"
        android:text="u25BC" />

    <EditText
        android:id="@+id/autoCompleteTv"
        android:layout_width="220dp"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:hint="Type..."
        android:padding="10dp"
        android:singleLine="true"
        android:text="" />

    <TextView
        android:id="@+id/tvSearchButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginRight="1dp"
        android:layout_marginTop="1dp"
        android:background="#d1d1d1"
        android:padding="10dp"
        android:text="Search" />

</LinearLayout>

The Solution

So what’s the actual solution? Avoid using EditText inside a RelativeLayout, use LinearLayout instead. According to James, If you look at the DDMS, a lot of redraws and recalculations occur while entering the text which is related to the RelativeLayout. So that gives us a clue the the problem is indeed the RelativeLayoutUpdate: I forgot to mention that setting a fixed with of an EditText will help a lot with the performance. It prevents re-calculation and re-drawing of layout. Thanks to Giorgos Kylafas for pointing it out in the comments section below! He also included links that can be useful for you when it comes to Android performance tips so I suggest reading his comment.

Did you have the same experience? If this solution did not work for you and you found your own solution, please share it in the comments section below, I’m willing to include your story and update this post!

Android ViewHolder Pattern Example

Now we are going to code the smooth scrolling of our Android ListView. In the previous post, we tried to understand how the ListView with adapter works. This time, it will be all about performance.
I did this a separate post because Android ListView is difficult to understand at times. What I have in mind is, “we have to do the basics first, and then apply the optimization.”

android-ViewHolder-pattern-example

What’s with the ViewHolder pattern?

The ViewHolder design pattern enables you to access each list item view without the need for the look up, saving valuable processor cycles. Specifically, it avoids frequent call of findViewById() during ListView scrolling, and that will make it smooth.

Without the ViewHolder Design Pattern

Okay, let’s dig it out and see how it works without the ViewHolder pattern.

Let’s take a look at our previous getView() method in ArrayAdapterItem.java

1. The first time it was loaded, convertView is null. We’ll have to inflate our list item layout and find the TextView via findViewById().

2. The second time it was loaded, convertView is not null, good! We don’t have to inflate it again. But we’ll use findViewById() again.

3. The following times it was loaded, convertView is definitely not null. But findViewById() is constantly called, it will work but, it slows down the performance especially if you have lots of items and Views in your ListView.

With the ViewHolder Design Pattern

Now let’s see how it works with the ViewHolder pattern.
1. The first time it was loaded, convertView is null. We’ll have to inflate our list item layout, instantiate the ViewHolder, find the TextView via findViewById() and assign it to the ViewHolder, and set the ViewHolder as tag of convertView.

2. The second time it was loaded, convertView is not null, good! We don’t have to inflate it again. And here’s the sweet thing, we won’t have to call findViewById() since we can now access the TextView via its ViewHolder.

3. The following time it was loaded, convertView is definitely not null. The findViewById() is never called again, and that makes our smooth ListView scrolling.

Let’s Code!

So here it is, we’ll make use of the Android ViewHolder pattern in our ListView (in just 3 steps!).
Step 1: Add the following static class on our ArrayAdapterItem.java file

// our ViewHolder.
// caches our TextView
static class ViewHolderItem {
    TextView textViewItem;
}

Step 2: Our getView() will now look like this:

@Override
public View getView(int position, View convertView, ViewGroup parent) {

    ViewHolderItem viewHolder;
    
    
      // The convertView argument is essentially a "ScrapView" as described is Lucas post 
      // http://lucasr.org/2012/04/05/performance-tips-for-androids-listview/
      // It will have a non-null value when ListView is asking you recycle the row layout. 
      // So, when convertView is not null, you should simply update its contents instead of inflating a new row    layout.
     
    if(convertView==null){
        
        // inflate the layout
        LayoutInflater inflater = ((Activity) mContext).getLayoutInflater();
        convertView = inflater.inflate(layoutResourceId, parent, false);
        
        // well set up the ViewHolder
        viewHolder = new ViewHolderItem();
        viewHolder.textViewItem = (TextView) convertView.findViewById(R.id.textViewItem);
        
        // store the holder with the view.
        convertView.setTag(viewHolder);
        
    }else{
        // we've just avoided calling findViewById() on resource everytime
        // just use the viewHolder
        viewHolder = (ViewHolderItem) convertView.getTag();
    }
    
    // object item based on the position
    ObjectItem objectItem = data[position];
    
    // assign values if the object is not null
    if(objectItem != null) {
        // get the TextView from the ViewHolder and then set the text (item name) and tag (item ID) values
        viewHolder.textViewItem.setText(objectItem.itemName);
        viewHolder.textViewItem.setTag(objectItem.itemId);
    }
    
    return convertView;
    
}

Step 3: For the sake of testing, we’re going to put thousands of items in our ListView. On our MainActivity.java, our showPopUp() will now look like this:

public void showPopUp(){
    
    // we'll specify the number of items we want our ListView to have.
    int numberOfItems = 1000;
    
    // add your items, this can be done programatically
    // your items can be from a database
    ObjectItem[] ObjectItemData = new ObjectItem[numberOfItems];
    
    // we'll use a for loop 
    // created objects = number of items specified above
    for(int x=0; x<numberOfItems; x++){
        
        int sampleId = 90 + x;
        ObjectItemData[x] = new ObjectItem(sampleId, "Store # " + (x+1));
        
    }
    
    // our adapter instance
    ArrayAdapterItem adapter = new ArrayAdapterItem(this, R.layout.list_view_row_item, ObjectItemData);
    
    // create a new ListView, set the adapter and item click listener
    ListView listViewItems = new ListView(this);
    listViewItems.setAdapter(adapter);
    listViewItems.setOnItemClickListener(new OnItemClickListenerListViewItem());
    
    // put the ListView in the pop up
    alertDialogStores = new AlertDialog.Builder(MainActivity.this)
        .setView(listViewItems)
        .setTitle("Stores")
        .show();
    
}

I tested this code with as much as 2,000 items, and the performance is still smooth and great.

What’s Next?

If you have other ideas regarding this topic, please drop it in the comment section below. I’m more than willing to update this post and improve the life of mankind.

In the next post, we’ll try to use the AsyncTask to load image into the ListView. Something like how the Google Play Store app does it.

Thanks for reading this Android ViewHolder Pattern Example!

Fixed: Android Dependencies – Missing facebooksdk.jar

Recently I was working with the Facebook SDK for Android and found the error:     Android     Dependencies     –     Missing     facebooksdk.jar. My project was unable to run and the eclipse console or logcat does not give a clear description of the error.

Home>Android Fixed: Android Dependencies – Missing facebooksdk.jar

But it can be seen when you try to view the properties > java build path > libraries tab > android dependencies of your project.
It looks like the project is looking for the facebooksdk.jar in the Facebook SDK bin folder. But it was missing. I wasn’t able to found a fix after around 30 minutes of googling the error. I don’t know, maybe my google skills are just failing me.
But the good thing is I was able to fixed this error myself. And here is the solution:

Right click on your project > properties > java compiler > compiler compliance level > select 1.7 on the dropdown.

Wait for a while while eclipse re-builds the workspace. Suddenly it was fixed!
Sorry I was too lazy to put up some screenshots, this is just a quick post that I thought can be useful to some devs. As always, thanks for reading!

Android ListView with Adapter Example

How android ListView with adapter works is not so clear to me until I read this awesome article with code examples of Lucas Rocha: Performance Tips for Android’s ListView.

In relation to that, I was inspired again to make a post about android ListView with Adapter, but this one is much more simple than the previous post: How To Customize Android ListView?

Today I’m going to show you the code I use whenever I wanted the user to select an “item” in an AlertDialog with ListView. If you are looking for an example AlertDialog with simple ListView (without an adapter), here’s a blog post I made: Android AlertDialog with ListView.

A ListView item here contains a text (item name) and an ID (item ID), so whenever the user selects an item in the pop up, you’ll be able to get the text and ID of that selected item.
This is very useful if the items are from a database – records with IDs and names. The tags (item IDs) were set using the TextView’s setTag() method.

Video Demo

Here’s the final output of our code for today. Name and ID were fetched and show via toast.

Video Demo Permalink

DOWNLOAD CODE

Let’s Code!

We only need 6 files to run this sample code successfully.
1. activity_main.xml – our main layout. Our trigger to show the ListView is a button.

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".MainActivity" >

    <Button
        android:id="@+id/buttonShowPopUp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:text="Show AlertDialog with ListView" />

</RelativeLayout>

2. MainActivity.java – will show the main layout, a button at the center of the screen. Clicking that button will show our awesome ListView.

package com.example.listviewpopupwithadapter;

import android.os.Bundle;
import android.view.View;
import android.widget.ListView;
import android.app.Activity;
import android.app.AlertDialog;

public class MainActivity extends Activity {

    AlertDialog alertDialogStores;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        // a button to show the pop up with a list view
        View.OnClickListener handler = new View.OnClickListener(){
            public void onClick(View v) {
                switch (v.getId()) {

                    case R.id.buttonShowPopUp:
                        showPopUp();
                        break;
                }
            }
        };
        
        findViewById(R.id.buttonShowPopUp).setOnClickListener(handler);
        
    }
    
    public void showPopUp(){
        
        // add your items, this can be done programatically
        // your items can be from a database
        ObjectItem[] ObjectItemData = new ObjectItem[20];
        
        ObjectItemData[0] = new ObjectItem(91, "Mercury");
        ObjectItemData[1] = new ObjectItem(92, "Watson");
        ObjectItemData[2] = new ObjectItem(93, "Nissan");
        ObjectItemData[3] = new ObjectItem(94, "Puregold");
        ObjectItemData[4] = new ObjectItem(95, "SM");
        ObjectItemData[5] = new ObjectItem(96, "7 Eleven");
        ObjectItemData[6] = new ObjectItem(97, "Ministop");
        ObjectItemData[7] = new ObjectItem(98, "Fat Chicken");
        ObjectItemData[8] = new ObjectItem(99, "Master Siomai");
        ObjectItemData[9] = new ObjectItem(100, "Mang Inasal");
        ObjectItemData[10] = new ObjectItem(101, "Mercury 2");
        ObjectItemData[11] = new ObjectItem(102, "Watson 2");
        ObjectItemData[12] = new ObjectItem(103, "Nissan 2");
        ObjectItemData[13] = new ObjectItem(104, "Puregold 2");
        ObjectItemData[14] = new ObjectItem(105, "SM 2");
        ObjectItemData[15] = new ObjectItem(106, "7 Eleven 2");
        ObjectItemData[16] = new ObjectItem(107, "Ministop 2");
        ObjectItemData[17] = new ObjectItem(108, "Fat Chicken 2");
        ObjectItemData[18] = new ObjectItem(109, "Master Siomai 2");
        ObjectItemData[19] = new ObjectItem(110, "Mang Inasal 2");
        
        // our adapter instance
        ArrayAdapterItem adapter = new ArrayAdapterItem(this, R.layout.list_view_row_item, ObjectItemData);
        
        // create a new ListView, set the adapter and item click listener
        ListView listViewItems = new ListView(this);
        listViewItems.setAdapter(adapter);
        listViewItems.setOnItemClickListener(new OnItemClickListenerListViewItem());
        
        // put the ListView in the pop up
        alertDialogStores = new AlertDialog.Builder(MainActivity.this)
            .setView(listViewItems)
            .setTitle("Stores")
            .show();
        
    }

    
}

3. ObjectItem.java – each item in the list is considered as an object with name and ID.

package com.example.listviewpopupwithadapter;

//another class to handle item's id and name
public class ObjectItem {
    
    public int itemId;
    public String itemName;
    
    // constructor
    public ObjectItem(int itemId, String itemName) {
        this.itemId = itemId;
        this.itemName = itemName;
    }

}

4. ArrayAdapterItem.java – where our ListView performance depends.

package com.example.listviewpopupwithadapter;

import android.app.Activity;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.TextView;

// here's our beautiful adapter
public class ArrayAdapterItem extends ArrayAdapter<ObjectItem> {

    Context mContext;
    int layoutResourceId;
    ObjectItem data[] = null;

    public ArrayAdapterItem(Context mContext, int layoutResourceId, ObjectItem[] data) {

        super(mContext, layoutResourceId, data);
        
        this.layoutResourceId = layoutResourceId;
        this.mContext = mContext;
        this.data = data;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {

        /*
         * The convertView argument is essentially a "ScrapView" as described is Lucas post 
         * http://lucasr.org/2012/04/05/performance-tips-for-androids-listview/
         * It will have a non-null value when ListView is asking you recycle the row layout. 
         * So, when convertView is not null, you should simply update its contents instead of inflating a new row layout.
         */
        if(convertView==null){
            // inflate the layout
            LayoutInflater inflater = ((Activity) mContext).getLayoutInflater();
            convertView = inflater.inflate(layoutResourceId, parent, false);
        }
        
        // object item based on the position
        ObjectItem objectItem = data[position];
        
        // get the TextView and then set the text (item name) and tag (item ID) values
        TextView textViewItem = (TextView) convertView.findViewById(R.id.textViewItem);
        textViewItem.setText(objectItem.itemName);
        textViewItem.setTag(objectItem.itemId);

        return convertView;
        
    }
    
}

5. OnItemClickListenerListViewItem.java – answers what will happen if the user clicks an item in the list?

package com.example.listviewpopupwithadapter;

import android.content.Context;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.TextView;
import android.widget.Toast;

/*
 * Here you can control what to do next when the user selects an item
 */
public class OnItemClickListenerListViewItem implements OnItemClickListener {

    @Override
    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {

        Context context = view.getContext();
        
        TextView textViewItem = ((TextView) view.findViewById(R.id.textViewItem));
        
        // get the clicked item name
        String listItemText = textViewItem.getText().toString();
        
        // get the clicked item ID
        String listItemId = textViewItem.getTag().toString();
        
        // just toast it
        Toast.makeText(context, "Item: " + listItemText + ", Item ID: " + listItemId, Toast.LENGTH_SHORT).show();

        ((MainActivity) context).alertDialogStores.cancel();
        
    }
    
}

6. list_view_row_item.xml – the layout of each item in the list. You can modify this if you want to have an image or subtitle for each item of your ListView.

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:padding="10dp" >

    <TextView
        android:id="@+id/textViewItem"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:text="Item name here..."
        android:textSize="15dp" />

</RelativeLayout>

This is just the first part, the second part will be about the Android ListView performance optimization with the help of Android ViewHolder Design Pattern.

Please share your thoughts about this Android ListView with Adapter Example!

How to Use Joda Time in Eclipse?

Joda Time is another very useful library for your Android application development. It provides a quality library of classes to replace the Java JDK Date and Time classes.

This post is generally about how to import a library in eclipse for Android development, we just choose Joda Time library as a good example. Every time I have a post instructing to install a library, I’ll probably link into this post.

Ok, back to our main topic.

Why use Joda Time? Well, there are plenty of reasons, some include:

  • Easy to use – straightforward field accessors such as getDayOfWeek()
  • Up-to-date time zone calculations – based on public tz database
  • Maturity – active development since 2002, and
  • Open source (Apache).

It can save you a lot of time for tasks such as:

Joda Time: Step by Step

Step 1: Download the latest version of Joda Time.

How to Use Joda Time in Eclipse?

Download joda time in source forge.

Step 2: Extract the ZIP and find the JAR file.

Files included in the zip.

Files included in the zip.

Step 3,: Copy to JAR file to your project’s libs folder.

> Ctrl+C the Jar file
> find your libs folder (My libs folder is located in my c:/workspace/MyProject/libs/),
> and then Ctrl+V (paste) it there.

Refreshing (Click+F5) your project would look like this:

joda-time-jar-in-eclipse-copy

Step 4: Add the JAR file to your build path.

> Right click your project
> java build path
> libraries tab
> add jars button
> browse the joda time jar file in the libs folder
> order and export tab
> check the joda time jar file

If you want some visuals for this step 4, see this one:

Video Demo Permalink

Step 5: Test. You can have the following code on your sample project to see if it works.

We’ll have this code on our MainActivity.java

package com.example.jodatimeexample;

import java.text.SimpleDateFormat;
import java.util.Date;

import org.joda.time.DateTime;
import org.joda.time.Days;

import android.os.Bundle;
import android.app.Activity;
import android.widget.TextView;

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        String textViewContents = "Joda Time Results:nn";
        
        TextView tv = (TextView) findViewById(R.id.tvDisplay);
        tv.setText(textViewContents);
        
        
        int daysBetween = getNumDaysBetween("2013-09-01", "2013-09-02");
        tv.setText("Days between 2013-09-01 and 2013-09-02: " + daysBetween);
        
    }

    public int getNumDaysBetween(String dateStart, String dateEnd){
        
        int numDays = 0;
        
        try{
            
            SimpleDateFormat formatYmd = new SimpleDateFormat("yyyy-MM-dd");
         
            Date d1 = formatYmd.parse(dateStart);
            Date d2 = formatYmd.parse(dateEnd);
    
            DateTime dt1 = new DateTime(d1);
            DateTime dt2 = new DateTime(d2);
            
            numDays = Days.daysBetween(dt1, dt2).getDays();
            
            // Days between 2013-09-01 and 2013-09-02: 1
            
        } catch (NullPointerException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
        
        return numDays;
    }
    
}

activity_main.xml (layout file) used:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".MainActivity" >

    <TextView
        android:id="@+id/tvDisplay"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Loading value..." />

</RelativeLayout>

The TextView will hold the output when you run the code above, and should look like this:

Days between 2013-09-01 and 2013-09-02: 1

Download Code

Just in case you want to download the code we used: JodaTimeExample.zip

Further Readings

As for some pros and cons of using Joda Time, see Jon’s answer here.

Since Joda Time is another API to learn, you’ll need more examples codes, here are some few hundred Joda Time code examples.