Pages

Showing posts with label controls. Show all posts
Showing posts with label controls. Show all posts

Saturday, May 14, 2016

Android Text Controls

Text controls include:

1. TextView.

2. EditText

3. AutoCompleteEditText

4. MultiCompleteTextView

TextView
The TextView represent an un-editable text. It resembles the Label control in C# or ASP.NET but it has an interesting feature which is the ability to highlight the text if its is an URL, an e-mail or a phone number so that when the user clicks on the textview the default intent whether it is the web browser or the dialer launches
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
android_orientation="vertical"
android_layout_width="fill_parent"
android_layout_height="fill_parent"
>
<TextView
android_layout_width="fill_parent"
android_layout_height="wrap_content"
android_text="Visit Http://www.android-pro.blogspot.com"
android_autoLink="web"
android_id="@+id/txtURL"
/>

<TextView
android_layout_width="fill_parent"
android_layout_height="wrap_content"
android_text="Dial 1 650-253-0000"
android_autoLink="all"
/>
</LinearLayout>


you can see that the TextViews containing URLs or Phone numbers are highlighted, and when the user presses on them the default intent (the browser or the dialer launches)


this is done by using the property android:autoLink which can have the values:
web, email ,phone, map
or
All
this can be achieved from code by using the following code:
TextView txtURL=(TextView)findViewById(R.id.txtURL);
Linkify.addLinks(txtURL, Linkify.ALL);

EditText
The EditText is a subclass of the TextView it is like the TextBox in C#. it enables users to edit text.


We can use the autoText property to make the EditText to correct the common spelling mistakes.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
android_orientation="vertical"
android_layout_width="fill_parent"
android_layout_height="fill_parent"
>
<EditText
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:autoText="true"

/>
</LinearLayout>



We can use the capitalize property to make the text capitalized like this:
<LinearLayout 
android_orientation="vertical"
android_layout_width="fill_parent"
android_layout_height="fill_parent"
>

<EditText
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:capitalize="characters"

/>
<EditText
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:capitalize="none"
/>
<EditText
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:capitalize="words"
/>
</LinearLayout>



we can use the password property to make the control accepts phone numbers input:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
android_orientation="vertical"
android_layout_width="fill_parent"
android_layout_height="fill_parent"
>

<EditText
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:password="true"

/>

</LinearLayout>



We can enforce the Control to wrap all the text in a single line by setting android:singleLine property to true.

AutoCompleteTextView
The autoCompleteTextView is an EditText with auto complete functionality. The auto complete functionality can be achieved by attaching an Adapter with the auto complete values to the control like this:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
android_orientation="vertical"
android_layout_width="fill_parent"
android_layout_height="fill_parent"
>

<AutoCompleteTextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="@+id/act"

/>

</LinearLayout>



Then attach the adapter from the code like this:
AutoCompleteTextView act=(AutoCompleteTextView)findViewById(R.id.act);
ArrayAdapter arr=new ArrayAdapter(this,android.R.layout.simple_dropdown_item_1line,new String []{"Hello","Hi","Alloha"});
act.setAdapter(arr);

in a search program for example you can obtain the auto complete words from a web service and populate the adapter with these words.

MultiAutoCompleteTextView

The AutoCompleteTextView can suggest auto complete for the entire text in the control, meaning that if you type more than one word it would try to match the whole sentence not the single words.
The MultiAutoCompleteTextView works the same way as the AutoCompleteTextView except you can add a Tokenizer that parses the text and allows you to suggest where to start suggesting words like this:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
android_orientation="vertical"
android_layout_width="fill_parent"
android_layout_height="fill_parent"
>

<MultiAutoCompleteTextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="@+id/act"

/>

</LinearLayout>


then from code:
MultiAutoCompleteTextView mact=(MultiAutoCompleteTextView)findViewById(R.id.act);
ArrayAdapter arr=new ArrayAdapter(this,android.R.layout.simple_dropdown_item_1line,new String []{"Hello","Hi","Alloha"});
mact.setAdapter(arr);
mact.setTokenizer(new MultiAutoCompleteTextView.CommaTokenizer());

The tokenizer tells the control to start suggesting for words separated by a comma.
Read More..

Sunday, May 1, 2016

Android Date and Time Controls

The Date-Time Controls in Android enable the user to pick date and time values and store them anywhere.
The date and time controls include:
1. DatePicker
2. Time Picker.
3. DatePickerDialog.
4. TimePickerDialog.
5. AnalogClock.
6. DigitalClock.
7. chronometer

DatePicker:

The DatePicker control enables the user to select a value of date only.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
android_orientation="vertical"
android_layout_width="fill_parent"
android_layout_height="fill_parent"
>
<TextView
android_layout_width="fill_parent"
android_layout_height="wrap_content"
android_id="@+id/txt"
/>
<DatePicker
android_layout_width="fill_parent"
android_layout_height="wrap_content"
android_id="@+id/datePick"
/>
<Button
android_layout_width="wrap_content"
android_layout_height="wrap_content"
android_id="@+id/btn"
android_text="Select Date"
/>
</LinearLayout>


final DatePicker dp=(DatePicker)findViewById(R.id.datePick);
Button btn=(Button)findViewById(R.id.btn);
btn.setOnClickListener(new OnClickListener()
{

public void onClick(View arg0) {
// TODO Auto-generated method stub

TextView txt=(TextView)findViewById(R.id.txt);
txt.setText("You selected "+dp.getDayOfMonth()+"/"+(dp.getMonth()+1)+"/"+dp.getYear());
}

}

);

Notice that we add 1 to the value of DatePicker.getMonth() because the months range is from 0 to 11.

If you want to set an initial selected date for the DatePicker you can use:
DatePicker.init(year, monthOfYear, dayOfMonth, onDateChangedListener);

If you want to capture the date as the date changes in the control you can make the activity implements the OnDateChangedListener interface and implements the onDateChanged method
Calendar cal=Calendar.getInstance(Locale.ENGLISH);
dp.init(cal.getTime().getYear()+1900, cal.getTime().getMonth(), cal.getTime().getDay(), this);

then

public void onDateChanged(DatePicker view, int year, int monthOfYear,
int dayOfMonth) {
// TODO Auto-generated method stub
TextView txt=(TextView)findViewById(R.id.txt);
txt.setText("You selected "+view.getDayOfMonth()+"/"+(view.getMonth()+1)+"/"+view.getYear());
}


TimePicker:
TimePicker is like DatePicker but it displays time instead of date, here’s how it looks like:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
android_orientation="vertical"
android_layout_width="fill_parent"
android_layout_height="fill_parent"
>
<TextView
android_layout_width="fill_parent"
android_layout_height="wrap_content"
android_id="@+id/txt"
/>
<TimePicker
android_layout_width="fill_parent"
android_layout_height="wrap_content"
android_id="@+id/TimePick"
/>
<Button
android_layout_width="wrap_content"
android_layout_height="wrap_content"
android_id="@+id/btn"
android_text="Select Date"
/>
</LinearLayout>


final TimePicker tp=(TimePicker)findViewById(R.id.TimePick);
Button btn=(Button)findViewById(R.id.btn);
btn.setOnClickListener(new OnClickListener()
{

public void onClick(View arg0) {
// TODO Auto-generated method stub

TextView txt=(TextView)findViewById(R.id.txt);
txt.setText("You selected "+tp.getCurrentHour()+":"+tp.getCurrentMinute());

Notice that by default the time picker displays the time in AM/PM format. If you want it to display time in 24-hours format you can use
TimePicker.setIs24HourView(boolen is24HourView);
If you want to initialize the timepicker with a certain time you can use the methods:

TimePicker.setCurrentHour(int Hour);
TimePicker.setCurrentMinute(int Minute);

You can implement the OnTimeChangedListener so that you capture any change in the time picker:
final TimePicker tp=(TimePicker)findViewById(R.id.TimePick);
tp.setCurrentHour(10);
tp.setCurrentMinute(45);

tp.setOnTimeChangedListener(new OnTimeChangedListener()
{

public void onTimeChanged(TimePicker arg0, int arg1, int arg2) {
// TODO Auto-generated method stub
TextView txt=(TextView)findViewById(R.id.txt);
txt.setText("You selected "+arg0.getCurrentHour()+":"+arg0.getCurrentMinute());
}

}
);

We checked so far the DatePicker and TimePicker widgets, but they take big space on the screen so Android provides similar controls but with different look: the DatePickerDialog and TimePickerDialog.

These widgets act the same as DatePicker and TimePicker but the appear as dialogs or popups instead of occupying a space on the screen

DatePickerDialog
DatePickerDialog is not a View, that you can’t define it in the xml layout file.
Instead you declare it from code with the following two constructors:
DatePickerDialog(Context context, DatePickerDialog.OnDateSetListener callBack, int year, int monthOfYear, int dayOfMonth);
DatePickerDialog(Context context, int theme, DatePickerDialog.OnDateSetListener callBack, int year, int monthOfYear, int dayOfMonth);

You can use it like this:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Button btn=(Button)findViewById(R.id.btn);

final OnDateSetListener odsl=new OnDateSetListener()
{

public void onDateSet(DatePicker arg0, int year, int month, int dayOfMonth) {
// TODO Auto-generated method stub
TextView txt=(TextView)findViewById(R.id.txt);
txt.setText("The date is "+dayOfMonth+"/"+month+"/"+year);
}

};

btn.setOnClickListener(new OnClickListener()
{

public void onClick(View arg0) {
// TODO Auto-generated method stub


Calendar cal=Calendar.getInstance();
DatePickerDialog datePickDiag=new DatePickerDialog(DateTimeControls.this,odsl,cal.get(Calendar.YEAR),cal.get(Calendar.MONTH),cal.get(Calendar.DAY_OF_MONTH));
datePickDiag.show();
}

}

);

}

To take an action when the date is set you define an OnDateSelectedListner and implement the onDateSet method

TimePickerDialog

DatePickerDialog is similar to DatePickerDialog but used for setting time.
The constructors for TimePickerDialog are:
TimePickerDialog(Context context, TimePickerDialog.OnTimeSetListener callBack, int hourOfDay, int minute, boolean is24HourView);

TimePickerDialog(Context context, int theme, TimePickerDialog.OnTimeSetListener callBack, int hourOfDay, int minute, boolean is24HourView);


You can use it like this:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Button btn=(Button)findViewById(R.id.btn);
}

final OnTimeSetListener otsl=new OnTimeSetListener()
{

public void onTimeSet(TimePicker arg0, int hourOfDay, int minute) {
// TODO Auto-generated method stub
TextView txt=(TextView)findViewById(R.id.txt);
txt.setText("The time is "+hourOfDay+":"+minute);
}
};

btn.setOnClickListener(new OnClickListener()
{

public void onClick(View arg0) {
// TODO Auto-generated method stub


Calendar cal=Calendar.getInstance();
TimePickerDialog timePickDiag=new TimePickerDialog(DateTimeControls.this,otsl,cal.get(Calendar.HOUR_OF_DAY),cal.get(Calendar.MINUTE),true);
timePickDiag.show();
}

}

);




AnalogClock

If you want to display time as in a clock you can use the AnalogClock widget. It just displays the time with no ability to edit the time.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
android_orientation="vertical"
android_layout_width="fill_parent"
android_layout_height="fill_parent"
>
<TextView
android_layout_width="fill_parent"
android_layout_height="wrap_content"
android_id="@+id/txt"
/>

<AnalogClock
android_layout_width="wrap_content"
android_layout_height="wrap_content"
android_id="@+id/clock"
/>


</LinearLayout>






DigitalClock
Same as AnalogClock but displays a digital clock
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
android_orientation="vertical"
android_layout_width="fill_parent"
android_layout_height="fill_parent"
>
<TextView
android_layout_width="fill_parent"
android_layout_height="wrap_content"
android_id="@+id/txt"
/>

<DigitalClock
android_layout_width="wrap_content"
android_layout_height="wrap_content"
android_id="@+id/digitalClock"
/>


</LinearLayout>




ChronoMeter:

The ChronoMeter acts like a timer. It has a starting point and an endpoint and you can calculate the time elapsed between these two points.
Read More..

Friday, April 29, 2016

Android Selection Controls

Android offers selection Controls like


1. List View.

2. Spinner

3. Check box

4. Radio Button

The List View:


ListView represents a list of items that can be selected. It is similar to the ListBox in C#.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
android_orientation="vertical"
android_layout_width="fill_parent"
android_layout_height="fill_parent"
>
<TextView
android_layout_width="fill_parent"
android_layout_height="wrap_content"
android_id="@+id/txt"
/>
<ListView
android_layout_width="wrap_content"
android_layout_height="wrap_content"
android_id="@+id/List"
/>
</LinearLayout>



To populate the list and handle the ItemClick event we can do it like this :
final String [] items=new String[]{"Item1","Item2","Item3","Item4"};
ArrayAdapter ad=new ArrayAdapter(this,android.R.layout.simple_list_item_1,items);
list=(ListView)findViewById(R.id.List);
list.setAdapter(ad);
list.setOnItemClickListener(new OnItemClickListener()
{

public void onItemClick(AdapterView arg0, View arg1, int arg2,
long arg3) {
// TODO Auto-generated method stub
TextView txt=(TextView)findViewById(R.id.txt);
txt.setText(list.getItemAtPosition(arg2).toString());


}

}
);

The above code displays the selected item text in the textview:
The parameters of the OnItemClick method are:


Arg0:the listview, notice that it is of type AdapterView.

Arg1: the view that represents the selected item, in this example it will be a TextView

Arg2: the position of the selected item.

Arg3: the id of the selected item.

When creating the adapter you can specify the layout of the list by using simple_list_item_1 to display a simple list or by using


simple_list_item_single_choice to display radio buttons for single selection

Or by using simple_list_item_multiple_choice to display check boxes for multiple selection
You can set the choice mode of the list by using setchoicemode() method:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//setContentView(R.layout.main);
final String [] items=new String[]{"Item1","Item2","Item3","Item4"};
ArrayAdapter ad=new ArrayAdapter(this,android.R.layout.simple_list_item_multiple_choice,items);
setListAdapter(ad);
ListView list=getListView();
list.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);

}

Now suppose you want to change the text of the an item when it is clicked, you can do it like this:
list.setOnItemClickListener(new OnItemClickListener()
{

public void onItemClick(AdapterView arg0, View arg1, int arg2,
long arg3) {
// TODO Auto-generated method stub
TextView txt=(TextView)findViewById(R.id.txt);
items[arg2]="changed";
list.setAdapter(new ArrayAdapter(ListControls.this,android.R.layout.simple_list_item_1,items));

}

}
);

Or a more neat way:
list.setOnItemClickListener(new OnItemClickListener()
{

public void onItemClick(AdapterView arg0, View arg1, int arg2,
long arg3) {
// TODO Auto-generated method stub
TextView temp=(TextView)arg1;
temp.setText("changed 2");
}

}
);

See that you actually change the value of the string array item at the selected position then bind the listview with the adapter again. Or you capture the View object and do what you want.



If the activity will contain just one listview you can create an activity that extends list view. In this case you don’t have to specify a layout as a listview will fill the screen.
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
final String [] items=new String[]{"Item1","Item2","Item3","Item4"};
ArrayAdapter ad=new ArrayAdapter(this,android.R.layout.simple_list_item_1,items);
setListAdapter(ad);


If you want to reference or customize this listview then you can define it in the layouts xml fine by assigning it the id “android:id/list” so that the activity knows which listView is the main list for the activity .

This example shows a listview and a textview
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
android_orientation="vertical"
android_layout_width="fill_parent"
android_layout_height="fill_parent"
>
<TextView
android_layout_width="fill_parent"
android_layout_height="wrap_content"
android_id="@+id/txt"
android_text="List View Demo"
/>

<ListView
android_layout_width="fill_parent"
android_layout_height="wrap_content"
android_id="@android:id/list"
/>
</LinearLayout>



Now if you want to customize the ui of each row of the listview you define two layouts files: the first has the layout of the activity and the other has layout of each row in the listview
Read More..

Friday, March 25, 2016

Android Eclipse LogCat showing a singe Line only at a time

The LogCat shows different device events. In Eclipse sometimes you notice that only a single line is shown and you cant scroll to see previous events. This happens because the LogCat window gets full, so clearing it will give the window a new emty space to display the log events as usual.
Read More..

Thursday, February 25, 2016

Android Button Controls

Android offers three types of button controls


1. The Basic Button.

2. Image Button

3. Toggle Button.

The Basic Button:


The android standard button. It is a subclass of the TextView class so it inherits all of its properties.

<linearlayout 
android:layout_height="fill_parent"
android:layout_width="fill_parent"
android:orientation="vertical"
>
<Button
android:id="@+id/btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Click Me"
/>
</linearlayout>


If you want to implement the OnClick event handler for a button there are three ways to do it:
First
You can implement the OnClickListner Interface for each single button in the activity like this:

Button btn=(Button)findViewById(R.id.btn);

btn.setOnClickListener(new OnClickListener()
{
public void onClick(View v) {
Button btn=(Button)v;
btn.setText("You clicked on the button");
}
}
);

But this will lead to large code blocks with lots of redundancy cause you will do it for each button in your activity.

Second
You can use an activity that implements the OnClickListner Interface and use the onClick method by switching between the buttons IDs:
public class ButtonControls extends Activity implements OnClickListener {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);

}
public void onClick(View v) {
// TODO Auto-generated method stub
switch(v.getId())
{
case R.id.btn1:
//Do something
break;
case R.id.btn2:
// Do something
break;
}
}
}


Third
Since Android 1.6 there was a new cool feature which is the ability to define the on click handlers for the bttons from the XML layout definition. Which is similar to that in ASP.NET.

<button 
android:id="@+id/btn1"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:onClick="ClickHandler"
android:text="Click Me"
/>
<button
android:id="@+id/btn2"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:onclick="ClickHandler"
android:text="Click Me too"
/>
Then you define the event handler method in your class file in the same normal way

 public void ClickHandler(View v) { 
// TODO Auto-generated method stub
switch(v.getId())
{
case R.id.btn1:
//Do something
break;
case R.id.btn2:
// Do something
break;
}
}

The ImageButton
The ImageButton control is similar to the Button except it represents a button with an image instead of the text
<linearlayout android_layout_height="fill_parent" android_layout_width="fill_parent" android_orientation="vertical" 
/>
<imagebutton
android:id="@+id/btn1"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:src="@drawable/globe"
/>
</linearlayout>

You can set the image source property from the code like this:
ImageButton btn=(ImageButton)findViewById(R.id.btn1);
btn.setImageResource(R.drawable.globe);


TheToggleButton:
The toggle button is like a check box or radio button, it has two states: On or Off.
The default behavior of ToggleButton is Off state, it displays a gray bar and the text Off.
When in On state it displays a green bar and has the text On.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
android_orientation="vertical"
android_layout_width="fill_parent"
android_layout_height="fill_parent"
>
<ToggleButton
android:id="@+id/tb"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Switch On"
/>
</LinearLayout>


See that despite we specified the android:text property of the toggle button, it displays the default text “Off”.
This is because ToggleButton inherits from TextView. But practically the android:text property is useless.
Instead we define the android:textOn and android:textOff properties.

In code to check the state of the Toggle button programmatically you can define the click handler in the regular way:
<ToggleButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textOff="Switch On"
android:textOn="Switch Off"
android:id="@+id/btn"
android:onClick="ClickHandler"
/>

Then check the state of it like this:
public void ClickHandler(View v)
{
ToggleButton tg=(ToggleButton)v;
if(tg.isChecked())
//Do something
else
//Do something else
}

heres what its gonna look like:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
android_orientation="vertical"
android_layout_width="fill_parent"
android_layout_height="fill_parent"
>
<ToggleButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textOff="Switch On"
android:textOn="Switch Off"
/>
<ToggleButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textOff="Switch On"
android:textOn="Switch Off"
/>
</LinearLayout>


Read More..

Friday, February 19, 2016

Android 2 3 Gingerbread released

Yesterday Google fially released the long-anticipated Android 2.3 (Gingerbread).

here are some of the new features:
  1. API Level: 9.
  2. The Dalvik VM introduces a new concurrent garbage collector that produces a smoother and faster performance.
  3. Session Initiation Protocol (SIP) based VoIP API to build telephony applications.
  4. Near Field Communication (NFC) API.
  5. New Sensors: Gyroscope (for measuring orientation), barometer (for measuring atmospheric pressure), sensors for gravity and acceleration.
  6. Support for multiple cameras: the camera API can detect multiple cameras in the device and add new capabilites for shooting such as managing focus.
  7. Usage of third-party video drivers: improves the performance of OpenGL ES.
  8. Audio Effects: new audio effects such as bass boost, reverb and equalization.
  9. New Downlaod Manager: handles downloading files in the background.
  10. Strict Mode: helps developers to optimize their code by detecting disk or network usage that could degrade the performance of the application.
and heres the official release video:
Read More..

Monday, February 8, 2016

Building Android Content Providers

Content providers are the way that Android applications can share info between each other. an application can ask for info from another application using content providers.

In this post were going to create a content provider to access data from our previous Employees simple application from the SQLite post.

to remind you the database has two tables Employees and Dept

remember that any content provider must provide the following:
  1. A URi from which we can run queries.
  2. MIME type corresponding to the content.
  3. Insert() method.
  4. Update() methd.
  5. Delete() method.

Creating the content type:

first we will create a new class, I will call it EmployeesContentProvider and choose its super class to be ContentProvider. the class initially will be like this:
package mina.android.DatabaseDemo;

import android.content.ContentProvider;
import android.content.ContentValues;
import android.database.Cursor;
import android.net.Uri;

public class EmployeesContentProvider extends ContentProvider {
DatabaseHelper db;
public static final Uri CONTENT_URI=Uri.parse("content://employees");
@Override
public int delete(Uri arg0, String arg1, String[] arg2) {
// TODO Auto-generated method stub
return 0;
}

@Override
public String getType(Uri uri) {
// TODO Auto-generated method stub
return null;
}

@Override
public Uri insert(Uri uri, ContentValues values) {
// TODO Auto-generated method stub
return null;
}

@Override
public boolean onCreate() {
// TODO Auto-generated method stub
return false;
}

@Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
// TODO Auto-generated method stub
return null;
}

@Override
public int update(Uri uri, ContentValues values, String selection,
String[] selectionArgs) {
// TODO Auto-generated method stub
return 0;
}

}


we added a member of type DatabaseHelper db to hold a reference to our database.
also we added a static URi object that represents the URi of our content provider.
it has all the abstract methods implementations of the ContentProvider class. so lets check each method

onCreate() method:

the onCreate() method is the first method invoked when the content provider is created (similar to the Activitys onCreate() method). here you can load your database or check for files you may read/write to them.
the method return a Boolean. it should be true if everything is ok, otherwise it should be false.
in our case we will just reference our SQLite database:
@Override
public boolean onCreate() {
// TODO Auto-generated method stub
db=new DatabaseHelper(this.getContext());
if(db==null)
return false;
else
return true;
}

query() method:

the query() method is the method that gets invoked when a content provider data is requested by a URi.

but first lets talk a little about content providers URI.
the content provider URi has the following format:
content://Authority/[(n) path]/[instance indentifier]
explanation:
  • the URI starts with content:// scheme.
  • the authority is a unique identifier for the content provider.
  • the authority can be followed by one or more paths (optional) refer to data paths within the content.
  • there can be an instance identifier that refers to a specific data instance.
for example we can have a URi like this content://Employees/Marketing//11.
this URi has Employees as the authority, Marketing as a data path and 11 as an instance (employee) identifier.

back to our query method, we have the following parameters:
  1. Uri: the URi requested.
  2. String [] projection: representing the columns (projection) to be retrieved.
  3. String[] selection: the columns to be included in the WHERE clause.
  4. String[] selectionArgs: the values of the selection columns.
  5. String sortOrder: the ORDER BY statement.
the first step in our query method is to parse the client URi.
we expect the URi to be in one of the following forms:
  1. content://employees/: retrieves all employees.
  2. content://employees/id: retrieves a certain employee by ID.
  3. content://employess/IT: retreives employees of IT Dept.
  4. content://employess/HR: retrieves employees of HR Dept.
  5. content://employees/Sales: retreives employees of sales Dept.
so we will add some constatnt values to our class to refer to the above URis:
//authority and paths
public static final String AUTHORITY="employees";
public static final String ITPATH="IT";
public static final String HRPATH="HR";
public static final String SALESPATH="Sales";


//URiMatcher to match client URis
public static final int ALLEMPLOYEES=1;
public static final int SINGLEEMPLOYEE=2;
public static final int IT=3;
public static final int HR=4;
public static final int SALES=5;
then were going to define a URiMatcher object that matches the client URi
static final UriMatcher matcher=new UriMatcher(UriMatcher.NO_MATCH);
static{
matcher.addURI(AUTHORITY,null,ALLEMPLOYEES);
matcher.addURI(AUTHORITY, ITPATH, IT);
matcher.addURI(AUTHORITY, HRPATH, HR);
matcher.addURI(AUTHORITY, SALESPATH, SALES);
//you can use * as a wild card for any text
matcher.addURI(AUTHORITY, "#", SINGLEEMPLOYEE);
}
the static initializer block loads the URimatcher objects with the values to match when the class initializes.
so lets write our query method:
@Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
SQLiteQueryBuilder builder=new SQLiteQueryBuilder();

builder.setTables(DatabaseHelper.viewEmps);

String order=null;
Cursor result=null;
if(sortOrder!=null)
order=sortOrder;
int match=matcher.match(uri);
switch(match)
{
case ALLEMPLOYEES:
//content://employees//id
result=builder.query(db.getWritableDatabase(), projection, selection, selectionArgs, null, null, sortOrder);
break;
case SINGLEEMPLOYEE:
//content://employees//id
Listsegments=uri.getPathSegments();
String empID=segments.get(0);
result=db.getEmpByID(empID);

break;
case IT:
//content://employees//IT
result=db.getEmpByDept("IT");
result=builder.query(db.getReadableDatabase(), projection, db.colDeptName+"=?", new String[]{"IT"}, null, null, sortOrder);
break;
case HR:
//content://employees//HR
result=db.getEmpByDept("HR");
result=builder.query(db.getReadableDatabase(), projection, db.colDeptName+"=?", new String[]{"HR"}, null, null, sortOrder);
break;
case SALES:
//content://employees//Sales
result=db.getEmpByDept("Sales");
result=builder.query(db.getReadableDatabase(), projection, db.colDeptName+"=?", new String[]{"Sales"}, null, null, sortOrder);

break;

}

return result;
}

the function just parses the URi and returns the data in a cursor.

Insert() method:
the insert methods inserts a new record to the db;
the insert method has the following form:
public Uri insert(Uri uri, ContentValues values) {

return null;
}
the method has two parameters:
  1. URi uri: the URi of the content provider, we need to check its correct.
  2. ContentValues values: object holding the info of the new item to be inserted.
the method returns the URi of the newly inserted item to be used for further manipulations.
so heres the implentation:
@Override
public Uri insert(Uri uri, ContentValues values) {
int match=matcher.match(uri);
//not the Uri were expecting
long newID=0;
if(match!=1)
throw new IllegalArgumentException("Wrong URi "+uri.toString());
if(values!=null)
{
newID=db.getWritableDatabase().insert(DatabaseHelper.employeeTable, DatabaseHelper.colName, values);
return Uri.withAppendedPath(uri, String.valueOf(newID));

}
else
return null;
}
we first check the Uri if it is not correct, throw an exception.
then check the content values object, if null return null otherwise insert the new item and return the URi with the id of the new item.
the Update() method:
the update method updates existing record(s) and returns the number of updated rows.
a trick rises from the fact that you need to specify whether to update a collection of records or a single record, based on the URi.
the method has the following parameters:
  1. URi uri: the URi of the content provider, we need to check its correct.
  2. ContentValues values: object holding the info of the new item to be inserted.
  3. String Selection : the filter to match the rows to update
  4. String [] selectionArgs : the values of the filter parameters
heres the implementation of the update method:
@Override
public int update(Uri uri, ContentValues values, String selection,
String[] selectionArgs) {
int match=matcher.match(uri);
//not the Uri were expecting
int rows=0;
//update single instance
if(match==2)
{
if(values!=null)
{
Listsegments=uri.getPathSegments();
String empID=segments.get(0);
rows=db.getWritableDatabase().update(DatabaseHelper.employeeTable, values,DatabaseHelper.colID+"=?", new String []{empID});

}

}
//update all emps in a certain dept
else if(match==3 ||match==4||match==5)
{
Listsegments=uri.getPathSegments();
String deptName=segments.get(0);
int DeptID=db.GetDeptID(deptName);
rows=db.getWritableDatabase().update(db.employeeTable, values,db.colDept+"=?", new String []{String.valueOf(DeptID)});

}
return rows;
}
the Delete() method:
the delete method has the following parameters:
  1. Uri uri: the URi of the content provider.
  2. String Condition: the condition of the delete statement.
  3. String[] args: the delete condition arguments

so heres the implementation:
@Override
public int delete(Uri uri, String where, String[] args) {

int match=matcher.match(uri);
//expecting the URi to be in the form of
if(match==1)
{
SQLiteDatabase dataBase=db.getWritableDatabase();
return dataBase.delete(db.employeeTable, where, args);
}
else
return 0;
}
we just check for the URi and perform a delete command.
The getType() method:
the last mthod to implement is getType() method which returns the MIME type associated with the URi passed to it.
if the URi is of a group of employees, then the MIME type is a collection type, otherwise its of an instance type
@Override
public String getType(Uri uri) {
int match=matcher.match(uri);
// single employee
if(match==2)
{
return "mina.android.Employee";
}
//collection of employees
else
{
return "mina.android.Employees";
}
}
Modifying the Manifest.xml file:
the last thing we need to do is to add an entry in our applications manifest.xml file to register our class as a content provider class.
so add this entry just below the <application>
<provider android_name="mina.android.DatabaseDemo.EmployeesContentProvider" 
android_authorities="employees"/>

the
when an application requests data through our content provider, Android system will search all the manifest files of all aplications on the device and when it finds such an entry, it will process the request

Testing the content provider:
now suppose you are in another activity and you want to use our activity.
Testing queries:
to make a query to retrieve all employees:
Uri empsUri=Uri.parse("content://employees");
Cursor cursor=getContentResolver().query(empsUri, null, null, null, null);Cursor cursor=getContentResolver().query(empsUri, null, null, null, null);
the cursor should have all the records.
to retrieve a certain employee by ID or all employees in a certain department:
Uri empUri=Uri.parse("content://employees//5");
Uri empDeptUri=Uri.parse("content://employees//Sales");

Inserting:
Uri empsUri=Uri.parse("content://employees");
ContentValues cvs=new ContentValues();
cvs.put("EmployeeName", "Mark Anderson");
cvs.put("Age", 35);
cvs.put("Dept", 1);
// URi of the new inserted item
Uri newEmp=getContentResolver().insert(empsUri, cvs);

Updating:
to update a single employee:
//Uri with the id of the employee
Uri empsUri=Uri.parse("content://employees/8");

Cursor cursor=getContentResolver().query(empsUri, null, null, null, null);
txt.setText(String.valueOf(cursor.getCount()));

ContentValues cvs=new ContentValues();
cvs.put("EmployeeName", "Mina Samy mod");
cvs.put("Age", 35);
cvs.put("Dept", 1);
// number of rows modified
int rowsNumber=getContentResolver().update(empsUri, cvs, "EmployeeID=?", new String[]{"8"});
to update all employees in a certain department
Uri empsUri=Uri.parse("content://employees/Sales");

Cursor cursor=getContentResolver().query(empsUri, null, null, null, null);
txt.setText(String.valueOf(cursor.getCount()));

ContentValues cvs=new ContentValues();
cvs.put("EmployeeName", "mod");
cvs.put("Age", 35);
cvs.put("Dept", 1);
int rowsNumber=getContentResolver().update(empsUri, cvs, "colDept=?", new String[]{"1"});

as a matter of fact, in both cases we dont need to specify the wher clause and the where parameters as they are implicitly specified in the URi. so we just can replace the update statement to be like this:
int rowsNumber=getContentResolver().update(empsUri, cvs, null,null);

Deleting:
I left the delete operation open to any criteria, you can delete a single employee or employees of a certain department or even all employees
Uri empsUri=Uri.parse("content://employees");
// delete employee of id 8
int rowsNumber=getContentResolver().delete(empsUri,"EmployeeID=?",new String[]{"8"});

Final Word:
creating a content provider for a certain type of data can be done in many ways, this example can be implemented in several variations.

another thing is that you need to create a strongly typed class for you data model to be used by clients accessing your content. in this example when I tested the query i wrote the column names of the database as strings like this: "EmployeeID" and "EmployeeName".
this is not ideal in a production release of an application. I should created a class library that holds all the info about the database to be used by other client applications.

you can download the source code for this example from here.
Read More..