Bài tập 33: Sử dụng ContentProvider trong Android

[polldaddy poll=9764234]

– Bài tập này Tôi sẽ hướng dẫn các bạn cách sử dụng ContentProvider. Cụ thể là cách đọc danh bạ, cách đọc lịch sử cuộc gọi, cách đọc Media và bookmark.

– Phần này rất nhiều và phong phú, bạn cần khám phá nó trên mạng nhiều hơn.

– Thời gian không cho phép do đó Tôi chỉ hướng dẫn những tính năng mà ta thường xuyên sử dụng nhất.

– Tôi có giao diện chính sau:

33_contentprovider_0

– Ta có cú pháp tổng quát:

 <standard_prefix>://<authority>/<data_path>/<id>

– Ví dụ để lấy tất cả các bookmark trong trình duyệt ta dùng cú pháp:

content://browser/bookmarks

– Để lấy toàn bộ danh bạ trong điện thoại ta dùng cú pháp:

content://contacts/people

– Để lấy 1 contact theo 1 định danh nào đó:

content://contacts/people/3

– Để lấy các kết quả trả về ta cũng dùng Cursor để quản lý.

– Có 2 cách sử dụng hàm lấy kết quả ở đây:

Cách 1:

CursorLoader loader=new  CursorLoader(context, uri, null, null, null, null);

Cursor c=loader.loadInBackground();

cách 2:

Cursor c = getContentResolver() .query(uri, null, null, null, null);

– Ta sẽ làm cụ thể từng chức năng trong ví dụ trên

– Bạn xem cấu trúc của bài tập này:

33_contentprovider_1

– Bạn xem XML Resource của màn hình chính (activity_main.xml):

[code language=”xml”]

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/LinearLayout1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity" >

<Button
android:id="@+id/btnshowallcontact"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Show All Contact" />

<Button
android:id="@+id/btnaccesscalllog"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Access The Call Log" />

<Button
android:id="@+id/btnmediastore"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Access Media Store" />

<Button
android:id="@+id/btnaccessbookmarks"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Access Bookmarks" />

</LinearLayout>

[/code]

– Source code xử lý MainActivity.java:

[code language=”java”]

package tranduythanh.com;

import android.os.Bundle;
import android.provider.Browser;
import android.provider.CallLog;
import android.provider.CallLog.Calls;
import android.provider.MediaStore;
import android.provider.MediaStore.Audio.Media;
import android.app.Activity;
import android.content.CursorLoader;
import android.content.Intent;
import android.database.Cursor;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.Toast;

public class MainActivity extends Activity implements OnClickListener{

Button btnshowallcontact;
Button btnaccesscalllog;
Button btnaccessmediastore;
Button btnaccessbookmarks;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btnshowallcontact=(Button) findViewById(R.id.btnshowallcontact);
btnshowallcontact.setOnClickListener(this);
btnaccesscalllog=(Button) findViewById(R.id.btnaccesscalllog);
btnaccesscalllog.setOnClickListener(this);
btnaccessmediastore=(Button) findViewById(R.id.btnmediastore);
btnaccessmediastore.setOnClickListener(this);
btnaccessbookmarks=(Button) findViewById(R.id.btnaccessbookmarks);
btnaccessbookmarks.setOnClickListener(this);
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.activity_main, menu);
return true;
}

@Override
public void onClick(View v) {
Intent intent=null;
if(v==btnshowallcontact)
{
intent=new Intent(this, ShowAllContactActivity.class);
startActivity(intent);
}
else if(v==btnaccesscalllog)
{
accessTheCallLog();
}
else if(v==btnaccessmediastore)
{
accessMediaStore();
}
else if(v==btnaccessbookmarks)
{
accessBookmarks();
}
}
/**
* hàm lấy danh sách lịch sử cuộc gọi
* với thời gian nhỏ hơn 30 giây và sắp xếp theo ngày gọi
*/
public void accessTheCallLog()
{
String [] projection=new String[]{
Calls.DATE,
Calls.NUMBER,
Calls.DURATION
};
Cursor c=getContentResolver().query(
CallLog.Calls.CONTENT_URI,
projection,
Calls.DURATION+"<?",new String[]{"30"},
Calls.DATE +" Asc");
c.moveToFirst();
String s="";
while(c.isAfterLast()==false){
for(int i=0;i<c.getColumnCount();i++){
s+=c.getString(i)+" – ";
}
s+="\n";
c.moveToNext();
}
c.close();
Toast.makeText(this, s, Toast.LENGTH_LONG).show();
}
/**
* hàm đọc danh sách các Media trong SD CARD
*/
public void accessMediaStore()
{
String []projection={
MediaStore.MediaColumns.DISPLAY_NAME,
MediaStore.MediaColumns.DATE_ADDED,
MediaStore.MediaColumns.MIME_TYPE
};
CursorLoader loader=new CursorLoader
(this, Media.EXTERNAL_CONTENT_URI,
projection, null, null, null);
Cursor c=loader.loadInBackground();
c.moveToFirst();
String s="";
while(!c.isAfterLast()){
for(int i=0;i<c.getColumnCount();i++){
s+=c.getString(i)+" – ";
}
s+="\n";
c.moveToNext();
}
Toast.makeText(this, s, Toast.LENGTH_LONG).show();
c.close();
}
/**
* hàm đọc danh sách Bookmark trong trình duyệt
*/
public void accessBookmarks()
{
String []projection={
Browser.BookmarkColumns.TITLE,
Browser.BookmarkColumns.URL,
};
Cursor c=getContentResolver()
.query(Browser.BOOKMARKS_URI, projection,
null, null, null);
c.moveToFirst();
String s="";
int titleIndex=c.getColumnIndex
(Browser.BookmarkColumns.TITLE);
int urlIndex=c.getColumnIndex
(Browser.BookmarkColumns.URL);
while(!c.isAfterLast())
{
s+=c.getString(titleIndex)+" – "+
c.getString(urlIndex);
c.moveToNext();
}
c.close();
Toast.makeText(this, s, Toast.LENGTH_LONG).show();
}
}

[/code]

– Source XML xử lý xem danh bạn (activity_show_all_contact.xml):

[code language=”xml”]

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/LinearLayout1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".ShowAllContactActivity" >

<ListView
android:id="@+id/listView1"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
</ListView>

<Button
android:id="@+id/btnback"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Back" />

</LinearLayout>

[/code]

– Source code xử lý xem danh bạ ( ShowAllContactActivity.java):

– Tôi viết theo 2 cách : Dùng CursorLoader và getContentResolver

[code language=”java”]

package tranduythanh.com;
import java.util.ArrayList;

import android.net.Uri;
import android.os.Bundle;
import android.provider.ContactsContract;
import android.app.Activity;
import android.content.CursorLoader;
import android.database.Cursor;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ListView;

public class ShowAllContactActivity extends Activity {
Button btnback;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_show_all_contact);
btnback=(Button) findViewById(R.id.btnback);
btnback.setOnClickListener(new OnClickListener() {

@Override
public void onClick(View v) {
// TODO Auto-generated method stub
finish();
}
});
showAllContacts1();
}
/**
* hàm danh toàn bộ danh bạ
* dùng CursorLoader
*/
public void showAllContacts1()
{
Uri uri=Uri.parse("content://contacts/people");
ArrayList<String> list=new ArrayList<String>();
CursorLoader loader=new
CursorLoader(this, uri, null, null, null, null);
Cursor c1=loader.loadInBackground();
c1.moveToFirst();
while(c1.isAfterLast()==false){
String s="";
String idColumnName=ContactsContract.Contacts._ID;
int idIndex=c1.getColumnIndex(idColumnName);
s=c1.getString(idIndex)+" – ";
String nameColumnName=ContactsContract.Contacts.DISPLAY_NAME;
int nameIndex=c1.getColumnIndex(nameColumnName);
s+=c1.getString(nameIndex);
c1.moveToNext();
list.add(s);
}
c1.close();
ListView lv=(ListView) findViewById(R.id.listView1);
ArrayAdapter<String>adapter=new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_1, list);
lv.setAdapter(adapter);
}
/**
* hàm danh toàn bộ danh bạ
* dùng getContentResolver
*/
public void showAllContacts2()
{
Uri uri=Uri.parse("content://contacts/people");
ArrayList<String> list=new ArrayList<String>();
Cursor c1=getContentResolver()
.query(uri, null, null, null, null);
c1.moveToFirst();
while(c1.isAfterLast()==false)
{
String s="";
String idColumnName=ContactsContract.Contacts._ID;
int idIndex=c1.getColumnIndex(idColumnName);
s=c1.getString(idIndex)+" – ";
String nameColumnName=ContactsContract.Contacts.DISPLAY_NAME;
int nameIndex=c1.getColumnIndex(nameColumnName);
s+=c1.getString(nameIndex);
c1.moveToNext();
list.add(s);
}
c1.close();
ListView lv=(ListView) findViewById(R.id.listView1);
ArrayAdapter<String>adapter=new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_1, list);
lv.setAdapter(adapter);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.activity_show_all_contact, menu);
return true;
}

}

[/code]

– Lưu ý cấp quyền cho ứng dụng:

AndroidManifest.xml:

[code language=”xml”]

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="tranduythanh.com"
android:versionCode="1"
android:versionName="1.0" >

<uses-sdk
android:minSdkVersion="14"
android:targetSdkVersion="17" />

<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.READ_CALL_LOG" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="com.android.browser.permission.READ_HISTORY_BOOKMARKS" />

<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name="tranduythanh.com.MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name="tranduythanh.com.ShowAllContactActivity"
android:label="@string/title_activity_show_all_contact" >
</activity>
</application>

</manifest>

[/code]

– Dòng 11, 12, 13, 14 là cấp quyền cho ứng dụng có thể truy suất các chức năng mong muốn.

– Bây giờ bạn thực hiện ứng dụng và quan sát, giờ Tôi chạy lên và dùng chức năng xem toàn bộ danh bạ:

33_contentprovider_2– Tương tự như vậy bản thử các chức năng còn lại trong ứng dụng.

– Bạn có thể tải coding mẫu đầy đủ ở đây: http://www.mediafire.com/download/kaac7d36ocvr8ba/LearnContentProvider.rar

– Bài tập kế tiếp các bạn sẽ được học về một kỹ thuật hoàn toàn mới trong Android và rất khó và rất hữu dụng, đó là kỹ thuật xử lý Đa Tiến Trình trong Android. Các bạn phải chú ý theo dõi vì nó vô cùng quan trọng, nó cũng giống như Intent là huyết mạch trong các ứng dụng của Android.

– Chúc các bạn thành công.

Bài tập 32: Tiếp tục củng cố kiến thức SQLite, ví dụ tổng hợp quản lý sách

Để làm được bài tập 32 này thì bắt buộc bạn phải đạt Đai Đen bài tập 31 , đồng thời bạn phải rành custom layout, intent … Trong bài tập này Tôi chủ ý không giải thích coding nhiều là để các bạn tự suy luận logic, tự tổng hợp lại các kiến thức đã học được từ các bài tập trước để hoàn thành bài này. Vì thực ra bài tập này là kết hợp của tất cả các kiến thức trước đó.

–          Viết chương trình quản lý sách được mô tả như sau:

  • Một tác giả sẽ có nhiều cuốn sách, thông tin tác giả gồm: mã , tên
  • Mỗi cuốn sách thuộc về một nhà tác giả nào đó, thông tin mỗi cuốn sách gồm: mã sách, tên sách, ngày xuất bản
  • Hãy chọn kiểu dữ liệu hợp lý để tạo cơ sở dữ liệu (sử dụng SQLite) cho đúng với mô tả trên

–          Thiết kế giao diện như hình bên dưới:

32_qls_0

–          Phải tạo Tác giả  trước khi vào chức năng quản lý Sách

–          Khi chọn chức năng thêm Tác giả, chương trình sẽ xuất hiện màn hình dưới đây (chú ý mở dưới dạng Dialog):

32_qls_1

  • Chọn “Lưu tác giả” để lưu,  chọn xóa trắng để xóa dữ liệu vừa nhập, focus tới mã.

–          Khi chọn “xem danh sách Tác giả”, chương trình sẽ mở một màn hình mới để hiển thị danh sách Tác giả đã tạo – chú ý dùng CustomLayout cho ListView:

32_qls_2

–          Khi chọn từng tác giả trong danh sách, sẽ hiển thị màn hình cho phép chỉnh sửa tác giả:

32_qls_3

  • Chọn Update để cập nhật lại Tác giả

–          Khi nhấn Thật Lâu (Long time) vào từng tác giả trong danh sách, chương trình sẽ hiển thị Alert Dialog hỏi xem có muốn xóa Tác giả này hay không?

32_qls_4

  • Chọn Có để xóa tác giả hiện tại,
  • Chọn Không để trở về màn hình xem danh sách

–          Khi chọn chức năng “quản lý sách” ở màn hình chính chương trình sẽ hiển thị:

32_qls_5

  • Load danh sách Tác giả vào Spinner
  • Sử dụng DatePickerDialog để chọ ngày xuất bản
  • Chọn “Thêm sách” lưu vào CSDL đúng với tác giả chọn trong Spinner, đồng thời cập nhập vào ListView bên dưới.

————————————————————————————————–

Bạn xem cấu trúc thư mục của ứng dụng:

32_qls_6

 

– Bài này rất phức tạp nên các bạn phải tập trung 12 thành công lực để nghiên cứu + ngồi thiền để tĩnh tâm làm bài nếu không sẽ bị Tẩu Hỏa Nhập Ma.

– Bạn xem activity_main.xml layout – Giao diện chính của chương trình:

[code language=”xml”]

[/code]

và Source code xử lý MainActivity.java:

[code language=”java”]

package tranduythanh.com;

import java.util.Locale;

import android.os.Bundle;
import android.app.Activity;
import android.content.ContentValues;
import android.content.Intent;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.Toast;
/**
* hàm hình chính cho phép chọn các thao tác
* @author drthanh
*
*/
public class MainActivity extends Activity {

Button btnCreateDatabase=null;
Button btnInsertAuthor=null;
Button btnShowAuthorList=null;
Button btnShowAuthorList2=null;
Button btnTransaction=null;
Button btnShowDetail=null;
Button btnInsertBook=null;
public static final int OPEN_AUTHOR_DIALOG=1;
public static final int SEND_DATA_FROM_AUTHOR_ACTIVITY=2;
SQLiteDatabase database=null;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btnInsertAuthor=(Button) findViewById(R.id.btnInsertAuthor);
btnInsertAuthor.setOnClickListener(new MyEvent());
btnShowAuthorList=(Button) findViewById(R.id.buttonShowAuthorList);
btnShowAuthorList.setOnClickListener(new MyEvent());
btnInsertBook=(Button) findViewById(R.id.buttonInsertBook);
btnInsertBook.setOnClickListener(new MyEvent());
getDatabase();
}
/**
* hàm kiểm tra xem bảng có tồn tại trong CSDL hay chưa
* @param database – cơ sở dữ liệu
* @param tableName – tên bảng cần kiểm tra
* @return trả về true nếu tồn tại
*/
public boolean isTableExists(SQLiteDatabase database, String tableName) {
Cursor cursor = database.rawQuery(“select DISTINCT tbl_name from sqlite_master where tbl_name = ‘”+tableName+”‘”, null);
if(cursor!=null) {
if(cursor.getCount()>0) {
cursor.close();
return true;
}
cursor.close();
}
return false;
}
/**
* hàm tạo CSDL và các bảng liên quan
* @return
*/
public SQLiteDatabase getDatabase()
{
try
{
database=openOrCreateDatabase(“mydata.db”, SQLiteDatabase.CREATE_IF_NECESSARY, null);
if(database!=null)
{
if(isTableExists(database,”tblAuthors”))
return database;
database.setLocale(Locale.getDefault());
database.setVersion(1);
String sqlAuthor=”create table tblAuthors (”
+”id integer primary key autoincrement,”
+”firstname text, ”
+”lastname text)”;
database.execSQL(sqlAuthor);
String sqlBook=”create table tblBooks (”
+”id integer primary key autoincrement,”
+”title text, ”
+”dateadded date,”
+”authorid integer not null constraint authorid references tblAuthors(id) on delete cascade)”;
database.execSQL(sqlBook);
//Cách tạo trigger khi nhập dữ liệu sai ràng buộc quan hệ
String sqlTrigger=”create trigger fk_insert_book before insert on tblBooks ”
+” for each row ”
+” begin ”
+” select raise(rollback,’them du lieu tren bang tblBooks bi sai’) ”
+” where (select id from tblAuthors where id=new.authorid) is null ;”
+” end;”;
database.execSQL(sqlTrigger);
Toast.makeText(MainActivity.this, “OK OK”, Toast.LENGTH_LONG).show();
}
}
catch(Exception e)
{
Toast.makeText(this, e.toString(), Toast.LENGTH_LONG).show();
}
return database;
}
public void createDatabaseAndTrigger()
{
if(database==null)
{
getDatabase();
Toast.makeText(MainActivity.this, “OK OK”, Toast.LENGTH_LONG).show();
}
}
/**
* hàm mở màn hình nhập Tác giả
*/
public void showInsertAuthorDialog()
{
Intent intent=new Intent(MainActivity.this, CreateAuthorActivity.class);
startActivityForResult(intent, OPEN_AUTHOR_DIALOG);
}
/**
* hàm xem danh sách tác giả dùng Activity
* Tôi làm 2 cách để các bạn ôn tập lại ListView
* bạn gọi hàm nào thì gọi 1 thôi showAuthorList1 hoặc showAuthorList2
*/
public void showAuthorList1()
{
Intent intent=new Intent(MainActivity.this, ShowListAuthorActivity.class);
startActivity(intent);
}
/**
* hàm xem danh sách tác giả dùng ListActivity
* Tôi làm 2 cách để các bạn ôn tập lại ListView
* bạn gọi hàm nào thì gọi 1 thôi showAuthorList1 hoặc showAuthorList2
*/
public void showAuthorList2()
{
Intent intent=new Intent(MainActivity.this, ShowListAuthorActivity2.class);
startActivity(intent);
}
/**
* Tôi cung cấp thêm hàm này để các bạn nghiên cứu thêm về transaction
*/
public void interactDBWithTransaction()
{
if(database!=null)
{
database.beginTransaction();
try
{
//làm cái gì đó tùm lum ở đây,
//chỉ cần có lỗi sảy ra thì sẽ kết thúc transaction
ContentValues values=new ContentValues();
values.put(“firstname”, “xx”);
values.put(“lastname”, “yyy”);
database.insert(“tblAuthors”, null, values);
database.delete(“tblAuthors”, “ma=?”, new String[]{“x”});
//Khi nào hàm này được gọi thì các thao tác bên trên mới thực hiện được
//Nếu nó không được gọi thì mọi thao tác bên trên đều bị hủy
database.setTransactionSuccessful();
}
catch(Exception ex)
{
Toast.makeText(MainActivity.this, ex.getMessage(), Toast.LENGTH_LONG).show();
}
finally
{
database.endTransaction();
}
}
}
/**
* hàm xử lý kết quả trả về
*/
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
// TODO Auto-generated method stub
super.onActivityResult(requestCode, resultCode, data);
if(resultCode==SEND_DATA_FROM_AUTHOR_ACTIVITY)
{
Bundle bundle= data.getBundleExtra(“DATA_AUTHOR”);
String firstname=bundle.getString(“firstname”);
String lastname=bundle.getString(“lastname”);
ContentValues content=new ContentValues();
content.put(“firstname”, firstname);
content.put(“lastname”, lastname);
if(database!=null)
{
long authorid=database.insert(“tblAuthors”, null, content);
if(authorid==-1)
{
Toast.makeText(MainActivity.this,authorid+” – “+ firstname +” – “+lastname +” ==> insert error!”, Toast.LENGTH_LONG).show();
}
else
{
Toast.makeText(MainActivity.this, authorid+” – “+firstname +” – “+lastname +” ==>insert OK!”, Toast.LENGTH_LONG).show();
}
}

}
}
/**
* class xử lý sự kiện
* @author drthanh
*
*/
private class MyEvent implements OnClickListener
{

@Override
public void onClick(View v) {
// TODO Auto-generated method stub
if(v.getId()==R.id.btnInsertAuthor)
{
showInsertAuthorDialog();
}
else if(v.getId()==R.id.buttonShowAuthorList)
{
showAuthorList1();
}

else if(v.getId()==R.id.buttonInsertBook)
{
Intent intent=new Intent(MainActivity.this, InsertBookActivity.class);
startActivity(intent);
}
}

}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.activity_simple_database_main, menu);
return true;
}
}

[/code]

– XML source thêm tác giả activity_create_author.xml:

[code language=”xml”]

[/code]

– Source code xử lý thêm tác giả – CreateAuthorActivity.java:

[code language=”java”]

package tranduythanh.com;

import android.os.Bundle;
import android.app.Activity;
import android.content.Intent;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
/**
* class nhập thông tin tác giả
* Mọi thay đổi đều gửi thông tin về MainActivity để xử lý
* @author drthanh
*
*/
public class CreateAuthorActivity extends Activity {

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_create_author);
final Button btnInsert =(Button) findViewById(R.id.buttonInsert);
final EditText txtFirstname=(EditText) findViewById(R.id.editTextFirstName);
final EditText txtLastname=(EditText) findViewById(R.id.editTextLastName);
final Intent intent= getIntent();
btnInsert.setOnClickListener(new OnClickListener() {

@Override
public void onClick(View v) {
// TODO Auto-generated method stub
Intent intent=new Intent();
Bundle bundle=new Bundle();
bundle.putString(“firstname”, txtFirstname.getText().toString());
bundle.putString(“lastname”, txtLastname.getText().toString());
intent.putExtra(“DATA_AUTHOR”, bundle);
setResult(MainActivity.SEND_DATA_FROM_AUTHOR_ACTIVITY, intent);
CreateAuthorActivity.this.finish();
}
});
final Button btnClear=(Button) findViewById(R.id.buttonClear);
btnClear.setOnClickListener(new OnClickListener() {

@Override
public void onClick(View v) {
// TODO Auto-generated method stub
txtFirstname.setText(“”);
txtLastname.setText(“”);
txtFirstname.requestFocus();
}
});

Bundle bundle= intent.getBundleExtra(“DATA”);
if(bundle!=null && bundle.getInt(“KEY”)==1)
{
String f2=bundle.getString(“getField2”);
String f3=bundle.getString(“getField3”);
txtFirstname.setText(f2);
txtLastname.setText(f3);
btnInsert.setText(“Update”);
this.setTitle(“View Detail”);
/*TableRow row=(TableRow) findViewById(R.id.tableRow3);
row.removeViewAt(0);
row.setGravity(Gravity.RIGHT);*/
}
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.activity_create_author, menu);
return true;
}
}

[/code]

– XML source thêm Sách – activity_insert_book.xml:

[code language=”xml”]

[/code]

– Source code xử lý thêm sách – InsertBookActivity.java:

[code language=”java”]

package tranduythanh.com;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import android.os.Bundle;
import android.app.Activity;
import android.app.DatePickerDialog;
import android.app.DatePickerDialog.OnDateSetListener;
import android.app.Dialog;
import android.content.ContentValues;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.AdapterView;
import android.widget.Button;
import android.widget.DatePicker;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.Spinner;
import android.widget.Toast;
/**
* class hiển thị thông tin Tác giả và Spinner
* và hiển thị thông tin sách vào ListView
* đồng thời cho phép thao tác với sách
* Class này là khó hiểu nhất, nhưng chỉ là tổng hợp của
* các kiến thức đã học trước đó
* @author drthanh
*
*/
public class InsertBookActivity extends Activity {

SQLiteDatabase database=null;
ListlistBook=null;
ListlistAuthor=null;
InforData authorData=null;
MySimpleArrayAdapter adapter=null;
int day,month,year;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_insert_book);
Spinner pinner=(Spinner) findViewById(R.id.spinner1);
listAuthor=new ArrayList();
InforData d1=new InforData();
d1.setField1(“_”);
d1.setField2(“Show All”);
d1.setField3(“_”);
listAuthor.add(d1);
//Lệnh xử lý đưa dữ liệu là Tác giả và Spinner
database=openOrCreateDatabase(“mydata.db”, SQLiteDatabase.CREATE_IF_NECESSARY, null);
if(database!=null)
{

Cursor cursor=database.query(“tblAuthors”, null, null, null, null, null, null);
cursor.moveToFirst();
while(cursor.isAfterLast()==false)
{
InforData d=new InforData();
d.setField1(cursor.getInt(0));
d.setField2(cursor.getString(1));
d.setField3(cursor.getString(2));
listAuthor.add(d);
cursor.moveToNext();
}
cursor.close();
}
adapter=new MySimpleArrayAdapter(InsertBookActivity.this, R.layout.my_layout_for_show_list_data,listAuthor);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
pinner.setAdapter(adapter);
//Xử lý sự kiện chọn trong Spinner
//chọn tác giả nào thì hiển thị toàn bộ sách của tác giả đó mà thôi
//Nếu chọn All thì hiển thị toàn bộ không phân hiệt tác giả
pinner.setOnItemSelectedListener(new OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView arg0, View arg1,
int arg2, long arg3) {
// TODO Auto-generated method stub
if(arg2==0)
{
//Hiển thị mọi sách trong CSDL
authorData=null;
loadAllListBook();
}
else
{
//Hiển thị sách theo tác giả chọn trong Spinner
authorData=listAuthor.get(arg2);
loadListBookByAuthor(authorData.getField1().toString());
}
}
@Override
public void onNothingSelected(AdapterView arg0) {
// TODO Auto-generated method stub
authorData=null;
}
});

setCurrentDateOnView();
//lệnh xử lý DatePickerDialog
Button bChangeDate=(Button) findViewById(R.id.buttonDate);
bChangeDate.setOnClickListener(new OnClickListener() {

@Override
public void onClick(View v) {
// TODO Auto-generated method stub
showDialog(113);
}
});
//Lệnh xử lý thêm mới một sản phẩm theo tác giả đang chọn
Button btnInsertBook =(Button) findViewById(R.id.buttonInsertBook);
btnInsertBook.setOnClickListener(new OnClickListener() {

@Override
public void onClick(View v) {
// TODO Auto-generated method stub
if(authorData==null)
{
Toast.makeText(InsertBookActivity.this, “Please choose an author to insert”, Toast.LENGTH_LONG).show();
return;
}
EditText txtTitle=(EditText) findViewById(R.id.editTextTitle);
ContentValues values=new ContentValues();
values.put(“title”, txtTitle.getText().toString());
Calendar c=Calendar.getInstance();
c.set(year, month, day);
SimpleDateFormat dfmt=new SimpleDateFormat(“dd-MM-yyyy”);
values.put(“dateadded”,dfmt.format(c.getTime()));
values.put(“authorid”, authorData.getField1().toString());
long bId=database.insert(“tblBooks”, null, values);
if(bId>0)
{
Toast.makeText(InsertBookActivity.this, “Insert Book OK”, Toast.LENGTH_LONG).show();
loadListBookByAuthor(authorData.getField1().toString());
}
else
{
Toast.makeText(InsertBookActivity.this, “Insert Book Failed”, Toast.LENGTH_LONG).show();
}
}
});
}
/*
* Hàm hiển thị mọi sách trong CSDL
*/
public void loadAllListBook()
{
Cursor cur=database.query(“tblBooks”, null, null, null, null, null, null);
cur.moveToFirst();
listBook=new ArrayList();
while(cur.isAfterLast()==false)
{
InforData d=new InforData();
d.setField1(cur.getInt(0));
d.setField2(cur.getString(1));
d.setField3(cur.getString(2));
listBook.add(d);
cur.moveToNext();
}
cur.close();
adapter=new MySimpleArrayAdapter(InsertBookActivity.this, R.layout.my_layout_for_show_list_data, listBook);
ListView lv=(ListView) findViewById(R.id.listViewBook);
lv.setAdapter(adapter);
}
/**
* hàm hiển thị sách theo tác giả
* @param authorid
*/
public void loadListBookByAuthor(String authorid)
{
Cursor cur=database.query(“tblBooks”, null, “authorid=?”, new String[]{authorid}, null, null, null);
cur.moveToFirst();
listBook=new ArrayList();
while(cur.isAfterLast()==false)
{
InforData d=new InforData();
d.setField1(cur.getInt(0));
d.setField2(cur.getString(1));
d.setField3(cur.getString(2));
listBook.add(d);
cur.moveToNext();
}
cur.close();
adapter=new MySimpleArrayAdapter(InsertBookActivity.this, R.layout.my_layout_for_show_list_data, listBook);
ListView lv=(ListView) findViewById(R.id.listViewBook);
lv.setAdapter(adapter);
}
@Override
protected Dialog onCreateDialog(int id) {
// TODO Auto-generated method stub
if(id==113)
{
return new DatePickerDialog(this, dateChange, year, month, day);
}
return null;
}
/**
* xử lý DatePickerDialog
*/
private DatePickerDialog.OnDateSetListener dateChange= new OnDateSetListener() {

@Override
public void onDateSet(DatePicker view, int year1, int monthOfYear,
int dayOfMonth) {
// TODO Auto-generated method stub
year=year1;
month=monthOfYear;
day=dayOfMonth;
EditText eDate=(EditText) findViewById(R.id.editTextDate);
eDate.setText(day+”-“+(month+1)+”-“+year);
}
};
/**
* thiết lập ngày tháng năm hiện tại
*/
public void setCurrentDateOnView()
{
EditText eDate=(EditText) findViewById(R.id.editTextDate);
Calendar cal=Calendar.getInstance();
day=cal.get(Calendar.DAY_OF_MONTH);
month=cal.get(Calendar.MONTH);
year=cal.get(Calendar.YEAR);
eDate.setText(day+”-“+(month+1)+”-“+year);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.activity_insert_book, menu);
return true;
}
}

[/code]

– XML Source cho custom layout:

[code language=”xml”]

 

[/code]

– Source code xử lý Custom layout – InforData.java:

[code language=”java”]

package tranduythanh.com;
/**
* class dùng chung để đọc dữ liệu hiển thị lên ListView Sách và tác giả
* bạn có thể bỏ class này viết class khác
* Ở đây Tôi hơi làm biếng 1 chút là Tôi muốn viết 1 Class có các kiểu Object
* để nó tự hiểu mọi kiểu dữ liệu đỡ phải viết lại nên bạn đọc có vẻ khó hiểu
* Nhưng thôi —> ráng lên
* @author drthanh
*
*/
public class InforData {
private Object field1;
private Object field2;
private Object field3;
public Object getField1() {
return field1;
}
public void setField1(Object field1) {
this.field1 = field1;
}
public Object getField2() {
return field2;
}
public void setField2(Object field2) {
this.field2 = field2;
}
public Object getField3() {
return field3;
}
public void setField3(Object field3) {
this.field3 = field3;
}
@Override
public String toString() {
// TODO Auto-generated method stub
return this.field1 +” – ” +this.field2 +” – “+this.field3;
}
}

[/code]

– Source code xử lý Custom layout – MySimpleArrayAdapter.java:

[code language=”java”]

package tranduythanh.com;

import java.util.List;

import android.app.Activity;
import android.content.Context;
import android.graphics.Color;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.TextView;
/**
* class dùng để custom layout
* dùng chung cho hiển thị Sách và Tác giả
* @author drthanh
*
*/
public class MySimpleArrayAdapter extends ArrayAdapter {

private Activity context;
private int layout;
private Listlist;
public MySimpleArrayAdapter(Context context, int textViewResourceId,
List objects) {
super(context, textViewResourceId, objects);
// TODO Auto-generated constructor stub
this.context=(Activity) context;
this.layout=textViewResourceId;
this.list=objects;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
LayoutInflater flater=context.getLayoutInflater();
View row=flater.inflate(layout, parent,false);
TextView txt1=(TextView) row.findViewById(R.id.textView1);
TextView txt2=(TextView) row.findViewById(R.id.textView2);
TextView txt3=(TextView) row.findViewById(R.id.textView3);
/*txt1.setTextAlignment(Gravity.LEFT);
txt2.setTextAlignment(Gravity.LEFT);
txt3.setTextAlignment(Gravity.LEFT);*/
InforData data=list.get(position);
txt1.setText(data.getField1()==null?””:data.getField1().toString());
txt2.setText(data.getField2()==null?””:data.getField2().toString());
txt3.setText(data.getField3()==null?””:data.getField3().toString());
if(position==0)
{
row.setBackgroundColor(Color.RED);
}
return row;
}
}

[/code]

– XML source xem danh sách tác giả – layout_show_data.xml:

[code language=”xml”]

[/code]

– Source code xử lý xem danh sách tác giả:

[code language=”java”]

package tranduythanh.com;

import java.util.ArrayList;
import java.util.List;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.AlertDialog.Builder;
import android.content.ContentValues;
import android.content.DialogInterface;
import android.content.Intent;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemLongClickListener;
import android.widget.Button;
import android.widget.ListView;
import android.widget.Toast;
/**
* class xem danh sách tác giả
* @author drthanh
*
*/
public class ShowListAuthorActivity extends Activity{
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.layout_show_data);
updateUI();
Button btn=(Button) findViewById(R.id.buttonBack);
btn.setOnClickListener(new OnClickListener() {

@Override
public void onClick(View v) {
// TODO Auto-generated method stub
ShowListAuthorActivity.this.finish();
}
});
}
Listlist=new ArrayList();
InforData dataClick=null;
SQLiteDatabase database=null;
MySimpleArrayAdapter adapter=null;
public void updateUI()
{
database=openOrCreateDatabase(“mydata.db”, SQLiteDatabase.CREATE_IF_NECESSARY, null);
if(database!=null)
{

Cursor cursor=database.query(“tblAuthors”, null, null, null, null, null, null);
startManagingCursor(cursor);
InforData header=new InforData();
header.setField1(“STT”);
header.setField2(“Mã tác giả”);
header.setField3(“Tên tác giả”);
list.add(header);
cursor.moveToFirst();
while(!cursor.isAfterLast())
{
InforData data=new InforData();
data.setField1(cursor.getInt(0));
data.setField2(cursor.getString(1));
data.setField3(cursor.getString(2));
list.add(data);
cursor.moveToNext();
}
cursor.close();
adapter=new MySimpleArrayAdapter(ShowListAuthorActivity.this, R.layout.my_layout_for_show_list_data, list);
final ListView lv= (ListView) findViewById(R.id.listViewShowData);
lv.setAdapter(adapter);
lv.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView arg0, View arg1,
int arg2, long arg3) {
// TODO Auto-generated method stub
Toast.makeText(ShowListAuthorActivity.this,”View –>”+ list.get(arg2).toString(), Toast.LENGTH_LONG).show();
Intent intent=new Intent(ShowListAuthorActivity.this, CreateAuthorActivity.class);
Bundle bundle=new Bundle();
bundle.putInt(“KEY”, 1);
bundle.putString(“getField1”, list.get(arg2).getField1().toString());
bundle.putString(“getField2”, list.get(arg2).getField2().toString());
bundle.putString(“getField3”, list.get(arg2).getField3().toString());
intent.putExtra(“DATA”, bundle);
dataClick=list.get(arg2);
startActivityForResult(intent, MainActivity.OPEN_AUTHOR_DIALOG);
}
});
lv.setOnItemLongClickListener(new OnItemLongClickListener() {
@Override
public boolean onItemLongClick(AdapterView arg0, View arg1,
int arg2, long arg3) {
// TODO Auto-generated method stub
final InforData data=list.get(arg2);
final int pos=arg2;
Toast.makeText(ShowListAuthorActivity.this, “Edit–>”+data.toString(), Toast.LENGTH_LONG).show();
AlertDialog.Builder b=new Builder(ShowListAuthorActivity.this);
b.setTitle(“Remove”);
b.setMessage(“Xóa [“+data.getField2() +” – “+data.getField3() +”] hả?”);
b.setPositiveButton(“Có”, new DialogInterface.OnClickListener() {

@Override
public void onClick(DialogInterface dialog, int which) {
// TODO Auto-generated method stub
int n=database.delete(“tblAuthors”, “id=?”, new String[]{data.getField1().toString()});
if(n>0)
{
Toast.makeText(ShowListAuthorActivity.this, “Remove ok”, Toast.LENGTH_LONG).show();
list.remove(pos);
adapter.notifyDataSetChanged();
}
else
{
Toast.makeText(ShowListAuthorActivity.this, “Remove not ok”, Toast.LENGTH_LONG).show();
}
}
});
b.setNegativeButton(“Không”, new DialogInterface.OnClickListener() {

@Override
public void onClick(DialogInterface dialog, int which) {
// TODO Auto-generated method stub
dialog.cancel();
}
});
b.show();
return false;
}
});
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
// TODO Auto-generated method stub
super.onActivityResult(requestCode, resultCode, data);
if(resultCode==MainActivity.SEND_DATA_FROM_AUTHOR_ACTIVITY)
{
Bundle bundle=data.getBundleExtra(“DATA_AUTHOR”);
String f2=bundle.getString(“firstname”);
String f3=bundle.getString(“lastname”);
String f1=dataClick.getField1().toString();
ContentValues values=new ContentValues();
values.put(“firstname”, f2);
values.put(“lastname”, f3);
if(database!=null)
{
int n=database.update(“tblAuthors”, values, “id=?”, new String[]{f1});
if(n>0)
{
Toast.makeText(ShowListAuthorActivity.this, “update ok ok ok “, Toast.LENGTH_LONG).show();
dataClick.setField2(f2);
dataClick.setField3(f3);
if(adapter!=null)
adapter.notifyDataSetChanged();
}
}
}
}
}

[/code]

– Bạn có thể tải source code đầy đủ ở đây: http://www.mediafire.com/download/nf4ghdbr44igpa6/Ex_Module3_Bai6.rar

– Bài tập kế tiếp Tôi sẽ hướng dẫn các bạn cách sử dụng Content Provider để đọc danh bạ trong điện thoại, cách đọc lịch sử cuộc gọi, cách đọc Media trong điện thoại cũng như bookmark. Bạn chú ý theo dõi

– Chúc các bạn thành công.

Bài tập 31: Cách sử dụng SQLite trong Android

Nếu bạn nào muốn rèn luyện thêm lập trình Java, lập trình Android, lập trình Webservice với tổng thời lượng học >80 giờ thì có thể đăng ký học theo các link sau:

1) Lập trình java trong 4 tuần – 19 giờ(chỉ dành cho những ai CHƯA BIẾT GÌ VỀ LẬP TRÌNH hoặc đã biết lơ mơ về Java, lý thuyết và các bài tập phong phú tạo nền tảng lập trình Android và các hướng khác liên quan tới Java):
https://kyna.vn/lap-trinh-java-trong-4-tuan/325931
2) Lập trình Android cơ bản (>24 giờ học) – toàn bộ kiến thức về Android cơ bản:
https://kyna.vn/lap-trinh-android-co-ban/325931
3) Lập trình Android nâng cao (23 giờ học) – toàn bộ kiến thức về Android nâng cao:
https://kyna.vn/lap-trinh-android-nang-cao/325931
4) Lập trình Webservice cho Di Động – 14 giờ (dành cho những ai ĐÃ BIẾT ANDROID), những ai chưa biết Android tuyệt đối không đăng ký, khóa học hướng dẫn tỉ mỉ từ A->Z để có thể xây dựng được một phần mềm hoàn chỉnh tương tác client-server:
https://kyna.vn/lap-trinh-webservice-cho-di-dong/325931

[polldaddy poll=9764234]

Bài tập này Tôi sẽ hướng dẫn các bạn cách sử dụng SQLite trong Android.

Thay vì lưu trữ bằng text file, XML hay SharePreference thì bạn cũng có thể lưu trữ thông tin bằng SQLite. SQLite đã được tích hợp sẵn trong Android SDK.

Trong bài này các bạn sẽ học các phần sau:

1) Cách tạo / xóa một cơ sở dữ liệu SQLite trong Android

2) Cách tạo / xóa bảng trong SQLite

3) Cách thêm/ sửa/ xóa dữ liệu trong bảng

4) Cách truy vấn dữ liệu trong bảng.

– Tất nhiên còn rất nhiều chức năng khác, nhưng theo Tôi các bạn chỉ cần làm tốt 4 phần này thì có thể viết ứng dụng Android có SQLite một cách chuyên nghiệp rồi.

– Theo Tôi thì các bạn nên sử dụng công cụ SQLite Administrator: http://download.orbmu2k.de/files/sqliteadmin.zip để tạo hoàn chỉnh 1 CSDL sau đó kéo thả tập tin đó vào DDMS cho lẹ (cái này bạn tải về và tự tạo, rồi kéo thả vào DDMS). Còn các hướng dẫn dưới này Tôi muốn giúp các bạn hiểu được sâu xa bên trong (hướng programmer) CSDL SQLite.

– Giả sử các bạn cần tạo CSDL như mô tả dưới đây (qlquanlysinhvien.db):

– Bảng Lớp học (tbllop):

tbllop 
Tên cột Kiểu dữ liệu Mô tả
malop TEXT Khóa chính
tenlop TEXT
siso INTEGER

– Bảng sinh viên (tblsinhvien):

tblsinhvien
Tên cột Kiểu dữ liệu Mô tả
masv TEXT Khóa chính
tensv TEXT
malop TEXT khóa ngoại

– Để sử dụng SQLite, bạn import thư viện sau:

import android.database.sqlite.SQLiteDatabase;

———————————————————————————————————————-

1) Cách tạo / xóa một cơ sở dữ liệu SQLite trong Android:

– Tạo mới 1 CSDL:

31_sqlite_0

Khi lưu thành công, nó sẽ lưu CSDL vào:

/data/data/app/databases/

cụ thể:

31_sqlite_1

– Nếu bạn muốn lưu trữ trên SD Card thì bắt buộc bạn phải cấp quyền giống như đã đề cập tới ở những bài trước:

<uses-permission android:name=”android.permission.WRITE_EXTERNAL_STORAGE” />

– Bạn chỉ việc lấy đường dẫn của SD Card ra rồi lưu tên CSDL vào đúng đường dẫn SD Card là ok. (Bạn tự xem lại các bài tập trước mà Tôi đã hướng dẫn cách làm).

– Xóa 1 CSDL:

31_sqlite_2

– Như trên thì ta chỉ cần gọi lệnh deleteDatabase(tên CSDL). Nếu xóa thành công thì trả về true, xóa thất bại trả về false;

2) Cách tạo / xóa bảng trong SQLite:

– Ở đây các bạn sẽ tạo 2 bảng tbllop tblsinhvien. Chú ý là chúng có mối ràng buộc toàn vẹn.

– Bạn xem cách tạo bảng lớp:

31_sqlite_3

– Bạn chú ý là tên đối tượng database (chỗ database.execSQL(sql)) là đối tượng SQLiteDatabase được tạo ra ở bước tạo CSDL. Bạn phải khai báo cho  phù hợp để ở trong hàm này cũng có thể truy suất.

– Tạo bảng sinh viên:

31_sqlite_4

– Vì bảng sinh viên có chứa khóa ngoại để tham chiếu tới bảng lớp, nên bạn phải chú ý dòng lệnh tham chiếu ở trên.

3) Cách thêm/ sửa/ xóa dữ liệu trong bảng:

– Cách thêm một dòng dữ liệu vào trong bảng:

+ Dùng đối tượng ContentValues để đưa dữ liệu vào bảng. Đối tượng này có các phương thức put (tên cột , dữ liệu)

+ Sau đó gọi phương thức insert để đưa đối tượng (dòng này) vào bảng.

+ Bạn chú ý là phương thức insert có rất nhiều loại đối số khác nhau, nhưng ở đây Tôi chỉ nói 1 loại đơn giản nhất (các kiểu khác bạn tự tìm hiểu thêm). Loại mà Tôi muốn đề cập tới đó là không liên quan gì tới kiểm tra các điều kiện, chỉ cần đưa đối tượng ContentValues vào insert là bạn sẽ có được 1 dòng mới:

31_sqlite_5

– Nhìn vào đoạn code ở trên, bạn thấy đó Tôi sử dụng cả 3 cột maloptenlopsiso của bảng lớp học:

values.put(“malop“,”DHTH7C”) ; tức là đưa giá trị “DHTH7C” vào cột malop.

– dòng lệnh database.insert(“tbllop“,null,values); Đối số 1 là tên bảng, đối số 2 bạn truyền null, đối số 3 bạn truyền đối tượng values

– Nếu thêm thành công thì sẽ trả về giá trị khác -1. Nếu bằng -1 là thất bại.

– Cách cập nhật dữ liệu:

– Ta dùng hàm update để cập nhật dữ liệu theo một điều kiện bất kỳ nào đó.

public int update (String table, ContentValues values,    String whereClause, String[] whereArgs)

– Đối số 1 là tên bảng

– Đối số 2 là đối tượng muốn chính sửa (với giá trị mới)

– Đối số 3 là tập các điều kiện lọc (dùng dấu chấm hỏi ? để tạo điều kiện lọc)

– Đối số 4 là tập các giá trị của điều kiện lọc (lấy theo đúng thứ tự)

– Hàm này trả về số dòng bị ảnh hưởng. Ví dụ nếu có 3 dòng bị thay đổi thì nó trả về 3. nếu không có dòng nào bị ảnh hưởng thì nó trả về 0.

Ví dụ: Tôi viết hàm chỉnh  sửa (bạn cũng nên tách thành từng hàm giống vậy):

31_sqlite_6

– Hàm trên : Đối số 1 là mã nào muốn được chỉnh sửa . Đối số 2 là giá trị mới. Cụ thể bảng lớp của chúng ta có 3 cột: mã lớp, tên lớp và sĩ số, nhưng mà Tôi chỉ muốn chỉnh sửa Tên lớp mà thôi. Do đó bạn thấy như vậy (ở đây Tôi chủ ý viết khuyết như vậy để các bạn hiểu rằng không nhất thiết phải sử dụng hết các cột).

– Xóa dữ liệu:

– Ta dùng hàm delete để xóa:

public int delete (String table,       String whereClause,       String[] whereArgs) 

– Đối số 1 là tên bảng

– Đối số 2 là tập điều kiện lọc (dùng ? để tạo)

– Đối số 3 là tập các giá trị của điều kiện lọc

– Hàm trả về số dòng bị ảnh hưởng.

– Muốn xóa toàn bộ dữ liệu trong bảng thì ta truyền null vào 2 đối số cuối:

31_sqlite_7

– Muốn xóa theo 1 mã nào đó:

31_sqlite_8

4) Cách truy vấn dữ liệu trong bảng.

– Là thao tác phức tạp nhất trong truy suất SQLite

– Ta dùng Cursor để lưu trữ giá trị trả về của hàm dưới đây:

public Cursor query (String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy) 

Xem bảng mô tả chi tiết:

table The table name to compile the query against.
columns A list of which columns to return. Passing null will return all columns, which is discouraged to prevent reading data from storage that isn’t going to be used.
selection A filter declaring which rows to return, formatted as an SQL WHERE clause (excluding the WHERE itself). Passing null will return all rows for the given table.
selectionArgs You may include ?s in selection, which will be replaced by the values from selectionArgs, in order that they appear in the selection. The values will be bound as Strings.
groupBy A filter declaring how to group rows, formatted as an SQL GROUP BY clause (excluding the GROUP BY itself). Passing null will cause the rows to not be grouped.
having A filter declare which row groups to include in the cursor, if row grouping is being used, formatted as an SQL HAVING clause (excluding the HAVING itself). Passing null will cause all row groups to be included, and is required when row grouping is not being used.
orderBy How to order the rows, formatted as an SQL ORDER BY clause (excluding the ORDER BY itself). Passing null will use the default sort order, which may be unordered.

– Ở đây Tôi làm ví dụ đơn giản nhất là truy vấn không phải lọc theo điều kiện nào cả:

– Ví dụ đọc tất cả danh sách lớp học trong bảng tbllop:

31_sqlite_9

-database.query sẽ trả về một Cursor, Lúc này Cursor đầu đọc chưa trỏ tới dòng dữ liệu nào cả. Do đó ta phải gọi lệnh .moveToFirst để Cursor trỏ đầu đọc tới dòng đầu tiên. Sau đó ta dùng vòng lặp while để duyệt từng dòng dữ liệu. Chú ý là Cursor này giống như Pointer nó cho phép truy suất ngẫu nhiên.

– Bạn có thể tải coding mẫu đầy đủ của phần hướng dẫn này ở đây: http://www.mediafire.com/download/leuuld4a225tw5c/LearnSQLite.rar

– Bài tập tiếp theo Tôi sẽ yêu cầu các bạn viết chương trình quản lý sách sử dụng SQLite để bạn củng cố thêm kiến thức về nó.

– Chúc các bạn thành công.

Bài tập 30: Thực hành về Shared Preferences

[polldaddy poll=9764234]

Trong bài tập này Tôi sẽ trình bày về cách lưu trạng thái của ứng dụng (liên quan tới Shared Preferences) và cách tạo các màn hình cấu hình (liên quan tới Shared Preference Change Listeners)

————————————————————————————————————————–

-A- Cách lưu trạng thái của ứng dụng:

Bước 1:

– Gọi hàm getSharedPreferences, hàm này trả về SharedPreferences và nó có 2 đối. Đối số 1 là tên tập tin để lưu trạng thái, đối số 2 là kiểu lưu. Chú ý là đối số 1 ta chỉ ghi tên tập tin (không cần ghi phần mở rộng, vì phần mở rộng mặc nhiên của nó là .xml khi ta lưu thành công), đối số 2 thường ta để là MODE_PRIVATE:

SharedPreferences pre=getSharedPreferences(“my_data“, MODE_PRIVATE);

Bước 2:

– Tạo đổi tượng Editor để cho phép chỉnh sửa dữ liệu:

SharedPreferences.Editor edit=pre.edit();

Bước 3:

– Đưa dữ liệu muốn lưu trữ vào edit bằng các phương thức edit.putXXX(“key”,”value”);

Tùy vào kiểu dữ liệu ta muốn lưu trữ mà XXX được thay thế bởi các kiểu dữ liệu phù hợp:

editor.putString(“user”, “drthanh”);

editor.putString(“pwd”, “hoilamgi”);

editor.putBoolean(“checked”, true);

Bước 4:

– Lưu trạng thái bằng cách gọi dòng lệnh:

editor.commit();

————————————————————————————————————————–

Sau khi bạn làm đúng 4 bước trên thì chương trình sẽ lưu được trạng thái, như trên đã nói mặc định phần mở rộng là .xml (tức là trạng thái được lưu dưới định dạng tập tin XML). Bên trên ta đặt tên là my_data có nghĩa là chương trình sẽ tạo ra tập tin my_data.xml (bạn mở DDMS lên để xem) – tự động nó sẽ lưu vào thư mục shared_prefs như hình bên dưới:

30_SharedPreferences_5

————————————————————————————————————————–

-B- Cách đọc trạng thái đã lưu:

Rất đơn giản

Bước 1:

– Gọi hàm getSharedPreferences để trả về đối tượng SharedPreferences (giống như phần lưu trạng thái mà Tôi nói ở trên)

SharedPreferences pre=getSharedPreferences (my_data,MODE_PRIVATE);

Bước 2:

– Gọi các phương thức getXXX(“key”,giá trị mặc định) để lấy các giá trị lúc trước được lưu

boolean bchk=pre.getBoolean(“checked”, false); //đối số 2 Tôi để false là giá trị mặc định khi nó tìm không thấy key =checked
String user=pre.getString(“user”, “”);//lấy giá trị được lưu trong key=user, nếu không thấy thì gán giá trị mặc định là chuỗi rỗng
String pwd=pre.getString(“pwd”, “”);//giống trên

————————————————————————————————————————–

******** Gợi ý *******

– Lưu và đọc trạng thái bạn nên viết thành các hàm riêng biệt cho dễ sử dụng

– Hàm lưu bạn gọi trong sự kiện onPause

– Hàm đọc bạn gọi trong sự kiện onResume.

– Đừng hỏi tại vì sao???? sẽ bị 0 điểm lý do là Tôi đã giải thích rõ ở bài tập 5bài tập 6 rồi. Bạn tự xem lại.

******** END *******

Tôi sẽ làm ví dụ cụ thể dưới đây để bạn hiểu rõ hơn về lý thuyết:

Ví dụ 1: bạn muốn tạo một màn hình đăng nhập có checkbox cho phép lưu lại thông tin đăng nhập, lần sau khởi đội lại thì nó sẽ lấy lại thông tin nhập lúc trước để người sử dụng đỡ phải mất công nhập lại (biết về Shared Preferences), xem hình mình họa:

30_SharedPreferences_0

– Khi chọn nút đăng nhập, chương trình sẽ đóng Activity hiện tại và hiển thị Activity dưới đây:

30_SharedPreferences_2

– Chọn nút Thoát, chương trình tiếp tục đóng Activity này giúp tắt hẳn các Activity trong ứng dụng.

– Khởi động lại chương trình sẽ phải tự động load lại thông tin đăng nhập trước đó (Nếu khi đăng nhập có chọn “Lưu thông tin“).

– Bạn xem cấu trúc của Project:

30_SharedPreferences_4

– Layout XML của màn hình chính (activity_main.xml):

[code language=”xml”]

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/LinearLayout1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity" >

<TextView
android:id="@+id/textView1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#80FFFF"
android:gravity="center"
android:text="Đăng nhập hệ thống" />

<TableLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:stretchColumns="*"
>

<TableRow
android:id="@+id/tableRow1"
android:layout_width="wrap_content"
android:layout_height="wrap_content" >

<TextView
android:id="@+id/textView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="User:" />

<EditText
android:id="@+id/editUser"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:inputType="text"
android:ems="10" >

<requestFocus />
</EditText>
</TableRow>

<TableRow
android:id="@+id/tableRow2"
android:layout_width="wrap_content"
android:layout_height="wrap_content" >
</TableRow>

<TableRow
android:id="@+id/tableRow3"
android:layout_width="wrap_content"
android:layout_height="wrap_content" >

<TextView
android:id="@+id/textView3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Pasword:" />

<EditText
android:id="@+id/editPassword"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ems="10"
android:inputType="textPassword" />
</TableRow>

<TableRow
android:id="@+id/tableRow4"
android:layout_width="wrap_content"
android:layout_height="wrap_content" >

<CheckBox
android:id="@+id/chksaveacount"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_column="1"
android:text="Lưu thông tin" />
</TableRow>

<TableRow
android:id="@+id/tableRow5"
android:layout_width="wrap_content"
android:layout_height="wrap_content" >

<Button
android:id="@+id/btnlogin"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_column="1"
android:text="Đăng nhập" />
</TableRow>
</TableLayout>

</LinearLayout>

[/code]

– Layout XML của activity_dang_nhap_thanh_cong.xml:

[code language=”xml”]

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/LinearLayout1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".DangNhapThanhCongActivity" >

<TextView
android:id="@+id/txtmsg"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="TextView"
android:textSize="20sp" />

<Button
android:id="@+id/btnThoat"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="Thoát" />

</LinearLayout>

[/code]

– Bạn xem Source code MainActivity.java:

[code language=”java”]

package tranduythanh.com;

import android.os.Bundle;
import android.app.Activity;
import android.content.Intent;
import android.content.SharedPreferences;
import android.view.Menu;
import android.view.View;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.EditText;

public class MainActivity extends Activity {
Button btnlogin;
EditText edituser,editpassword;
CheckBox chksaveaccount;
//đặt tên cho tập tin lưu trạng thái
String prefname="my_data";
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btnlogin=(Button) findViewById(R.id.btnlogin);
edituser =(EditText)
findViewById(R.id.editUser);
editpassword=(EditText)
findViewById(R.id.editPassword);
chksaveaccount=(CheckBox)
findViewById(R.id.chksaveacount);
btnlogin.setOnClickListener(
new View.OnClickListener() {
public void onClick(View arg0) {
doLogin();
}
});
}
/**
* hàm đăng nhập hệ thống
*/
public void doLogin()
{
finish();//đóng màn hình hiện tại
Intent i=new Intent(this, DangNhapThanhCongActivity.class);
//truyền dữ liệu qua màn hình mới
i.putExtra("user", edituser.getText().toString());
startActivity(i);//mở màn hình mới
}
@Override
protected void onPause() {
// TODO Auto-generated method stub
super.onPause();
//gọi hàm lưu trạng thái ở đây
savingPreferences();
}
@Override
protected void onResume() {
// TODO Auto-generated method stub
super.onResume();
//gọi hàm đọc trạng thái ở đây
restoringPreferences();
}
/**
* hàm lưu trạng thái
*/
public void savingPreferences()
{
//tạo đối tượng getSharedPreferences
SharedPreferences pre=getSharedPreferences
(prefname, MODE_PRIVATE);
//tạo đối tượng Editor để lưu thay đổi
SharedPreferences.Editor editor=pre.edit();
String user=edituser.getText().toString();
String pwd=editpassword.getText().toString();
boolean bchk=chksaveaccount.isChecked();
if(!bchk)
{
//xóa mọi lưu trữ trước đó
editor.clear();
}
else
{
//lưu vào editor
editor.putString("user", user);
editor.putString("pwd", pwd);
editor.putBoolean("checked", bchk);
}
//chấp nhận lưu xuống file
editor.commit();
}
/**
* hàm đọc trạng thái đã lưu trước đó
*/
public void restoringPreferences()
{
SharedPreferences pre=getSharedPreferences
(prefname,MODE_PRIVATE);
//lấy giá trị checked ra, nếu không thấy thì giá trị mặc định là false
boolean bchk=pre.getBoolean("checked", false);
if(bchk)
{
//lấy user, pwd, nếu không thấy giá trị mặc định là rỗng
String user=pre.getString("user", "");
String pwd=pre.getString("pwd", "");
edituser.setText(user);
editpassword.setText(pwd);
}
chksaveaccount.setChecked(bchk);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.activity_main, menu);
return true;
}
}

[/code]

– Bạn xem source code DangNhapThanhCongActivity.java:

[code language=”java”]

package tranduythanh.com;

import android.os.Bundle;
import android.app.Activity;
import android.content.Intent;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;

public class DangNhapThanhCongActivity extends Activity {

TextView txtMsg;
Button btnThoat;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_dang_nhap_thanh_cong);
txtMsg=(TextView) findViewById(R.id.txtmsg);
btnThoat=(Button) findViewById(R.id.btnThoat);
btnThoat.setOnClickListener(new OnClickListener() {

@Override
public void onClick(View arg0) {
// TODO Auto-generated method stub
finish();
}
});

Intent i=getIntent();
txtMsg.setText("Hello : "+i.getStringExtra("user"));
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.activity_dang_nhap_thanh_cong, menu);
return true;
}

}

[/code]

– Như vậy là đã xong, bạn đã biết được cách lưu trạng thái. Chú ý là lưu trạng thái chỉ lưu Primitive Data, không cho phép lưu Object Serialize.

– Bạn click vào đây để tải coding mẫu: http://www.mediafire.com/download/4e4lyykdukgof82/LearnSharedPreferences.rar

————————————————————————————————————————–

-B- cách tạo Shared Preference Change Listeners để tạo giao diện cấu hình:

Bước 1:

– Tạo một Project Android bất kỳ, sau đó tạo thêm một layout PreferenceScreen:

30_SharedPreferences_6

– đặt tên tùy ý (ở đây Tôi đặt tên mypreferencelayout)

– Không giống như layout bình thường, preference screen sẽ nằm trong thư mục xml như hình bên dưới:

30_SharedPreferences_7

– Tiến hành tạo Checkbox giống như trên. (nó có nhiều control khác, tùy vào nhu cầu)

Bước 2:

– Tạo Activity cho Prefence layout trên (Kế thừa từ PreferenceActivity):

30_SharedPreferences_8

Bước 3:

– Cấu hình Manifest XML cho Preference Activity ở trên:

30_SharedPreferences_9

Bước 4:

– Tiến hành sửa MainActivity để sử dụng Preference Activity (Đăng ký OnSharePreferenceChangeListener):

30_SharedPreferences_10

– Bạn có thể xem kết quả như bên dưới:

30_SharedPreferences_11

————————————————————————————————————————–

Ví dụ 2:

– Bạn cố gắng tự xem lại lý thuyết và đọc coding để hiểu. Ví dụ này Tôi không giải thích coding.

– Hay bạn cần tạo ra các màn hình để cấu hình (giống như màn hình Setting của thiết bị chẳng hạn – cần biết Shared Preference Change Listeners):

30_SharedPreferences_1

– Bạn tải source code ở đây: http://www.mediafire.com/download/lg8881lz8jrp1np/Ex_Module3_Bai5.rar

– Chúc các bạn thành công.

Bài tập 29: XML Parser trong Android

[polldaddy poll=9764234]

– Tiếp tục chuỗi xử lý tập tin trong Android, bài tập này Tôi mong muốn các bạn sẽ làm được những công việc sau:

1) Biết cách tạo XML (tất nhiên rất nhiều bạn đã biết nó từ lâu)

2) Biết cách sử dụng XML

3) Biết cách duyệt XML bằng kỹ thuật DOM

4) Biết cách duyệt XML bằng kỹ thuật SAX.

– Dĩ nhiên  bạn phải thực hiện được 2 bài ví dụ bên dưới thì mới có thể nói là hiểu về XML trong Android.

Extensible Markup Language (XML): Các bạn xem chi tiết tại http://www.w3schools.com/xml/default.asp

———————————————————————————————————–

A)Kỹ thuật dùng DOM:

– DOM (Document Object Model ): Cache all – cơ chế của nó là đọc toàn bộ nội dung tập tin XML vào bộ nhớ (do đó nếu XML lớn thì làm chậm chương trình và có thể phung phí bộ nhớ vì không phải lúc nào ta cũng muốn đọc hết nội dung XML).

– DOM cho phép lấy: NodeLists, .getElementsByTagName() , .item(i), .getName() , .getValue() , .getFirstChild() , .getAttributes(),…

Ta lướt qua ví dụ này (cần dùng DOM để đọc XML bên dưới lên EditText):

29_xml_0

– Ta đi vào các bước cụ thể để đọc được tập tin XML bằng DOM như sau:

——————————————————————————————————————–

Bước 1: 

Để có thể sử dụng được kỹ thuật DOM trong Android, chúng ta import các thư viện sau (kể cả những thư viện để bắt lỗi):

[code language=”java”]

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;

[/code]

– Các bạn chú ý là trong quá trình viết code trong Eclipse, nó sẽ tự import tất cả các thư viện trên giùm ta (Bạn không phải gõ import dòng nào cả).

Bước 2:

Tạo đối tượng DocumentBuilder (builder ) bằng lệnh dưới đây:

[code language=”java”]

DocumentBuilderFactory fac=DocumentBuilderFactory.newInstance();
DocumentBuilder builder=fac.newDocumentBuilder();

[/code]

Bước 3:

Tạo FileInputStream từ tập tin XML nguồn (ở đây Tôi để XML nguồn trong SD Card):

[code language=”java”]

String sdcard=Environment.getExternalStorageDirectory().getAbsolutePath();
String xmlfile=sdcard+"/employee.xml";
FileInputStream fIn=new FileInputStream(xmlfile);

[/code]

Bước 4:

Dùng phương thức parse của đối tượng builder ở bước 2 để tạo Document

[code language=”java”]

Document doc=builder.parse(fIn);

[/code]

Bước 5:

Ta dựa vào đối tược doc được tạo ra ở bước 4 để duyệt từng node trong XML:

[code language=”java”]

Element root= doc.getDocumentElement(); //lấy tag Root ra
NodeList list= root.getChildNodes();// lấy toàn bộ node con của Root
String datashow="";//biến để lưu thông tin
for(int i=0;i <list.getLength();i++) // duyệt từ node đầu tiên cho tới node cuối cùng
{
Node node=list.item(i);// mỗi lần duyệt thì lấy ra 1 node
if(node instanceof Element) // kiểm tra xem node đó có phải là Element hay không, vì ta dựa vào element để lấy dữ liệu bên trong
{
Element employee=(Element) node;// lấy được tag Employee ra
String id=employee.getAttribute("id");//id là thuộc tính của tag Employee
String title=employee.getAttribute("title");//title là thuộc tính của tag employee
NodeList listChild= employee.getElementsByTagName("name");// lấy tag name bên trong của tag Employee
String name=listChild.item(0).getTextContent();//lấy nội dung của tag name
listChild=employee.getElementsByTagName("phone");// lấy tag phone bên trong của tag Employee
String phone=listChild.item(0).getTextContent();// lấy nội dung của tag phone</span>
datashow+=id+"-"+title+"-"+name+"-"+phone+"\n———\n";//lưu vào biến lưu thông tin
}
}
//ta dựa vào datashow để hiển thị lên giao diện
[/code]

– Bạn có thể tải code mẫu ở đây: http://www.mediafire.com/download/04q4rlg33nmrina/LearnXMLParser_DOM.rar (Tôi có đính kèm employee.xml trong project này, bạn chỉ việc kéo thả nó vào SD Card trong máy của bạn là ok).

——————————————————————————————————————–

B) kỹ thuật dùng SAX:

  Cũng với ví dụ ở mục A, nhưng Ta sẽ viết theo kỹ thuật SAX.

– Simple API for XML , scan the document , Đỡ tốn bộ nhớ , Chạy nhanh , viết phức tạp hơn DOM

– Các tag là element trong SAX có thể dùng các hàm:

.getAttributeCount()

.getAttributeName()

.getAttributeValue()

29_xml_2-Sử dụng XmlPullParser  để scan tài liệu:

29_xml_3

– Bước 1:

– Ta cần import các thư viện sau:

[code language=”java”]

import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlPullParserFactory;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;

[/code]

– Ta cũng không phải gõ từng dòng import mà eclipse tự động import giùm.

– Bước 2:

Tạo đối tượng parser từ class XmlPullParser

[code language=”java”]

XmlPullParserFactory fc=XmlPullParserFactory.newInstance();
XmlPullParser parser= fc.newPullParser();

[/code]

– Bước 3:

– Tạo FileInputStream từ xml source (XML để trong SD Card)

[code language=”java”]

String sdcard=Environment.
getExternalStorageDirectory().getAbsolutePath();
String xmlfile=sdcard+"/employee.xml";
FileInputStream fIn=new FileInputStream(xmlfile);

[/code]

– Bước 4:

– Tiến hành duyệt

[code language=”java”]

parser.setInput(fIn, "UTF-8");

int eventType=-1;
String nodeName;
String datashow="";
while(eventType!=XmlPullParser.END_DOCUMENT)//chưa kết thúc tài liệu
{
eventType=parser.next();// bắt đầu duyệt để
switch(eventType)
{
case XmlPullParser.START_DOCUMENT:
break;
case XmlPullParser.END_DOCUMENT:
break;
case XmlPullParser.START_TAG://là tag mở
nodeName=parser.getName();
if(nodeName.equals("employee")){// kiểm tra đúng tag mình muốn hay không
datashow+=parser.getAttributeValue(0)+"-";//lấy giá trị của thuộc tính
datashow+=parser.getAttributeValue(1)+"-";
}
else if(nodeName.equals("name")){
datashow+=parser.nextText()+"-";//lấy nội dung tag element
}
else if(nodeName.equals("phone")){
datashow+=parser.nextText()+"-";
}
break;
case XmlPullParser.END_TAG://là tag đóng
nodeName=parser.getName();
if(nodeName.equals("employee")){
datashow+="\n—————-\n";
}
break;
}
}

//dựa vào datashow để hiển thị lên giao diện

[/code]

– Bạn có thể tải code mẫu ở đây : http://www.mediafire.com/download/fh22pkib490n7lf/LearnXMLParser_SAX.rar

———————————————————————————————————————-

-Bài tập dành cho độc giả:

– Duyệt XML bằng DOM và SAX

– Title của các tag XML ta đưa vào Spinner (chú ý không đưa trùng lắp)

– Các thông tin khác đưa vào ListView

– Mỗi lần chọn Title trong Spinner thì chỉ hiển thị những employee theo Title này trong XML mà thôi

29_xml_1

– Chúc các bạn thành công.

Bài tập 28: Xử lý tập tin trong Android

[polldaddy poll=9764234]

– Bài tập này Tôi sẽ hướng dẫn các bạn cách xử lý tập tin trong Android, bao gồm:

+ Internal Storage

+ External Storage

+ Saving Cache Files

– Các bạn chú ý là Android sử dụng cấu trúc tập tin giống như trong ứng dụng Java thuần túy.

– Tập tin trong Android có thể được lưu trữ trong Main Memory (thường là lưu trữ tập tin có dung lượng nhỏ) hoặc SD Card (thường là lưu trữ tập tin có dung lượng lớn).

– Các tập tin được lưu trữ cùng với các tài nguyên khác trong bộ nhớ trong (chẳng hạn như Icons, hình ảnh, nhạc,…) thì người ta gọi chung là Resource Files.

– Trên mạng có đầy rẫy website hướng dẫn về thao tác với tập tin trong Android, nhưng ở đây Tôi muốn trình bày theo cách của Tôi.

1) Internal Storage

– Ở đây có 2 trường hợp:

– Thứ nhất: đọc Resource File (Read only)

– Thứ nhì : đọc và ghi tập tin (Read & Write).

* Đọc Resource File:

– Bạn xem giao diện bên dưới: Tôi tạo 1 tập tin và nhập đại vào một số dữ liệu rồi kéo thả tập tin đó vào thư mục drawable. Nếu như ứng dụng của bạn không có thư mục này thì bạn tự tạo nó nhớ là viết y xì “drawable“, tên file cũng đừng để khoảng trắng, đừng để chữ số đằng trước.

28_file_0– Khi nhấn chọn “Read Data“, chương trình sẽ đọc nội dung từ myfile.txt và hiển thị lên EditText.

– Ở đây Tôi muốn hỏi các bạn là : “Tại sao các resource được đóng gói trong APK lại là Read Only?“. Tôi nghĩ câu trả lời đơn giản nhất đó là sử dụng tối ưu bộ nhớ. Vì điện thoại không giống như máy tính, bộ nhớ trong của nó không có bao la bát ngát như PC, mỗi phần mềm (.APK) được cài đặt vào thì nó sẽ không muốn “Co Giãn” dung lượng vì nó cần quản lý phần mềm để tối ưu nhất (sử dụng bộ nhớ ít nhất).

– Bạn xem cấu trúc XML của giao diện (activity_main.xml):

[code language=”xml”]
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/LinearLayout1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity" >

<Button
android:id="@+id/btnreaddata"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Read Data" />

<EditText
android:id="@+id/editdata"
android:layout_width="match_parent"
android:layout_height="0dip"
android:layout_weight="2"
android:ems="10"
android:gravity="top|left"
android:inputType="textMultiLine" >

<requestFocus />
</EditText>
[/code]

– Đây là source code để đọc Resource File:

– Bạn chỉ cần copy đoạn code này vào sự kiện của nút đọc là xong:

[code language=”java”]
public void readData()
{
String data;
InputStream in= getResources().openRawResource(R.drawable.myfile);
InputStreamReader inreader=new InputStreamReader(in);
BufferedReader bufreader=new BufferedReader(inreader);
StringBuilder builder=new StringBuilder();
if(in!=null)
{
try
{
while((data=bufreader.readLine())!=null)
{
builder.append(data);
builder.append("\n");
}
in.close();
editdata.setText(builder.toString());
}
catch(IOException ex){
Log.e("ERROR", ex.getMessage());
}
}
}

[/code]

– Ở đây Tôi không cung cấp source nguồn, vì nó chỉ có 1 hàm xí xi đó. Các bạn chỉ cần thiết kế giao diện cho giống như XML Layout rồi copy code vào sự kiện của nút nhấn là xong.

– Cách đọc tập tin trong Android y chang như trong Java thuần túy, ở đây bạn chỉ để ý dòng lệnh số 4:

InputStream in= getResources().openRawResource(R.drawable.myfile);

Dòng lệnh này để đọc Resource File và trả về InputStream. Khi có InputStream rồi thì mọi xử lý sẽ giống như Java.

* Đọc và ghi tập tin:

– Trường hợp này bạn kéo thả tập tin vào cấu trúc thư mục như hình bên dưới (dùng DDMS):

– Nhìn vào những vệt Tôi tô màu vàng, các bạn kéo thả vào đúng vị trí ứng dụng của bạn.

28_file_1

– XML Resource cho bài tập này:

[code language=”xml”]

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/LinearLayout1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity" >

<Button
android:id="@+id/btnreaddata"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Read Data" />

<EditText
android:id="@+id/editdata"
android:layout_width="match_parent"
android:layout_height="0dip"
android:layout_weight="2"
android:ems="10"
android:gravity="top|left"
android:inputType="textMultiLine" >

<requestFocus />
</EditText>

<Button
android:id="@+id/btnwritedata"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Write Data" />

</LinearLayout>

[/code]

– XML resource trên sẽ tạo giao diện như hình bên dưới:

28_file_2

– Source Activity

[code language=”java”]

package tranduythanh.com;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;

import android.os.Bundle;
import android.app.Activity;
import android.util.Log;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;

public class MainActivity extends Activity implements OnClickListener{

Button btnread,btnwrite;
EditText editdata;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btnread=(Button) findViewById(R.id.btnreaddata);
btnwrite=(Button) findViewById(R.id.btnwritedata);
editdata=(EditText) findViewById(R.id.editdata);
btnread.setOnClickListener(this);
btnwrite.setOnClickListener(this);
}
public void onClick(View v) {
if(v.getId()==R.id.btnreaddata)
{
readData();
}
else if(v.getId()==R.id.btnwritedata)
{
writeData();
}
}
/**
* Hàm đọc tập tin trong Android
* Dùng openFileInput trong Android để đọc
* ra FileInputStream
*/
public void readData()
{
try {
FileInputStream in= openFileInput("myfile.txt");
BufferedReader reader=new
BufferedReader(new InputStreamReader(in));
String data="";
StringBuilder builder=new StringBuilder();
while((data=reader.readLine())!=null)
{
builder.append(data);
builder.append("\n");
}
in.close();
editdata.setText(builder.toString());
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* Hàm ghi tập tin trong Android
* dùng openFileOutput để ghi
* openFileOutput tạo ra FileOutputStream
*/
public void writeData()
{
try {
FileOutputStream out=
openFileOutput("myfile.txt",0);
OutputStreamWriter writer=
new OutputStreamWriter(out);
writer.write(editdata.getText().toString());
writer.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
/*
* hàm này là đọc Resource File, Tôi gom chung vào đây
*/
public void readData2()
{
String data;
InputStream in= getResources()
.openRawResource(R.drawable.myfile);
InputStreamReader inreader=new InputStreamReader(in);
BufferedReader bufreader=new BufferedReader(inreader);
StringBuilder builder=new StringBuilder();
if(in!=null)
{
try{
while((data=bufreader.readLine())!=null)
{
builder.append(data);
builder.append("\n");
}
in.close();
editdata.setText(builder.toString());
}
catch(IOException ex){
Log.e("ERROR", ex.getMessage());
}
}
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.activity_main, menu);
return true;
}
}

[/code]

– Bạn nhìn vào dòng lệnh 52: FileInputStream in= openFileInput(“myfile.txt”);

Lệnh ở dòng này mở tập tin lên để đọc, nó trả về FileInputStream nên mọi thứ sẽ giống như Java thuần túy.

– Tiếp tục nhìn vào dòng lệnh 78: FileOutputStream out=openFileOutput(“myfile.txt”,0);

Lệnh ở dòng này mở tập tin lên để ghi. đối số thứ 2 Tôi để là số 0 (MODE_PRIVATE) là mặc định. Bạn có thể dùng MODE_APPEND, MODE_WORLD_READABLE, MODE_WORLD_WRITEABLE. Ý nghĩa của mỗi mode bạn có thể lên mạng tìm. Hoặc chỉ cần di chuyển chuột vào hàm trên là eclipse tự giải thích cho các bạn (nếu eclipse bạn đã cài Javadoc).

– Bạn tải source code mẫu phần này ở đây:

http://www.mediafire.com/download/toi0ht8ht0t5gd3/LearnFileInternalStorage.rar

2. External Storage:

– Phần này Tôi muốn hướng dẫn các bạn cách tương tác với tập tin được lữu trữ trên SD Card.

– Để thao tác được trên SD Card, bạn phải cấp quyền cho ứng dụng (uses – permission)

– Để vừa ghi vừa đọc trên SD Card thì ta phải sử dụng 2 permission bên dưới trong AndroidManifest:

<uses-permission android:name=”android.permission.WRITE_EXTERNAL_STORAGE” />
<uses-permission android:name=”android.permission.READ_EXTERNAL_STORAGE” />

– Để lấy được đường dẫn của SD Card ta dùng lệnh:

String sdcard=Environment.getExternalStorageDirectory().getAbsolutePath();

– Sau đó mọi thứ tương tác với tập tin thì y xì như Java thuần túy, ở đây Tôi dùng Scanner để đọc và OutputStreamWriter để ghi.

– Vì vậy giao diện Tôi làm y chang như Internal Storage:

– Bạn tạo Project và kéo thả tập tin vào SD card (dĩ nhiên khi tạo AVD thì bạn phải checked vào using SD card thì mới có). Bạn xem hình để biết cách kéo thả vào SD Card:

28_file_3

– Ở hình trên bạn vào DDMS, tới thư mục mnt/ chọn sdcard. Phải chọn cho đúng vì nó có nhiều thư mục cùng tên sdcard, nhưng bạn chọn sdcard ở trong thư mục mnt thôi. Sau đó kéo thả tập tin vào đây là xong.

– XML Resource y xì như phần internal Storage nên Tôi không đưa vào đây, bạn xem Source code Activity:

[code language=”java”]

package tranduythanh.com;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.util.Scanner;

import android.os.Bundle;
import android.os.Environment;
import android.app.Activity;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;

public class MainActivity extends Activity implements OnClickListener{

Button btnread,btnwrite;
EditText editdata;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btnread=(Button) findViewById(R.id.btnreaddata);
btnwrite=(Button) findViewById(R.id.btnwritedata);
editdata=(EditText) findViewById(R.id.editdata);
btnread.setOnClickListener(this);
btnwrite.setOnClickListener(this);
}
public void onClick(View v) {
if(v.getId()==R.id.btnreaddata)
{
readData();
}
else if(v.getId()==R.id.btnwritedata)
{
writeData();
}
}
/*
* đọc từ SD Card
* Environment.getExternalStorageDirectory().getAbsolutePath()
* để lấy đường dẫn trên SD Card
*/
public void readData()
{
String sdcard=Environment
.getExternalStorageDirectory()
.getAbsolutePath()+"/myfile.txt";
try {
Scanner scan=new Scanner(new File(sdcard));
String data="";
while(scan.hasNext())
{
data+=scan.nextLine()+"\n";
}
scan.close();
editdata.setText(data+"");
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
/**
* ghi tập tin trên SD Card
*/
public void writeData()
{
String sdcard=Environment
.getExternalStorageDirectory()
.getAbsolutePath()+"/myfile.txt";
try {
OutputStreamWriter writer=
new OutputStreamWriter(
new FileOutputStream(sdcard));
writer.write(editdata.getText()+"");
writer.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.activity_main, menu);
return true;
}

}

[/code]

– Vì có sử dụng Permission nên bạn xem AndroidManifest:

[code language=”xml”]

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="tranduythanh.com"
android:versionCode="1"
android:versionName="1.0" >

<uses-sdk
android:minSdkVersion="14"
android:targetSdkVersion="17" />

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

<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name="tranduythanh.com.MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>

</manifest>

[/code]

– Khi thực thi ứng dụng, bạn sẽ có giao diện như trình bày ở trên, với kết quả như mong muốn.

– Bạn có thể tải coding mẫu ở đây:

http://www.mediafire.com/download/1ydvjc8wvizzjcm/LearnFileExternalStorage.rar

3) Saving cache files:

Lợi ích của cache files là gì? Để tăng tốc độ xử lý của ứng dụng khi bạn thường xuyên truy cập internet thì bạn nên lưu cache.

– Khi lưu cache thì nó sẽ để ở đâu trong điện thoại? bạn xem hình:

28_file_4

– Khi lưu cache thì mặc định nó sẽ lưu vào thư mục cache như hình bên trên. Hình trên Tôi có tập tin tên là myCachefile.Cache.

– Lưu như thế nào? và xóa như thế nào? 

Khi bạn lưu cache, Android thường chỉ cho tối đa file cache là 1MB, khi bạn gỡ bỏ phần mềm thì nó cũng tự động xóa cache của phần mềm này đi.

– Để lấy được đường dẫn của thư mục Cache trong ứng dụng, ta dùng lệnh : getCacheDir() . Sau đó cách lưu cache tương tự như Java thuần túy.

– Dưới đây là phần mềm minh họa Cache, giao diện tương tự như trên:

XML resource:

[code language=”xml”]

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/LinearLayout1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity" >

<Button
android:id="@+id/btncreatecache"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Create Cache" />

<EditText
android:id="@+id/editdata"
android:layout_width="match_parent"
android:layout_height="0dip"
android:layout_weight="2"
android:ems="10"
android:gravity="top|left"
android:inputType="textMultiLine" >

<requestFocus />
</EditText>

<Button
android:id="@+id/btnreadcache"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Read Cache" />

</LinearLayout>

[/code]

– Xử lý code Activity:

[code language=”java”]

package tranduythanh.com;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Scanner;

import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;

public class MainActivity extends Activity implements OnClickListener{

Button btncreatecache,btnreadcache;
EditText editdata;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btncreatecache=(Button) findViewById(R.id.btncreatecache);
btnreadcache=(Button) findViewById(R.id.btnreadcache);
editdata =(EditText) findViewById(R.id.editdata);
btncreatecache.setOnClickListener(this);
btnreadcache.setOnClickListener(this);
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.activity_main, menu);
return true;
}

@Override
public void onClick(View v) {
// TODO Auto-generated method stub
if(v.getId()==R.id.btncreatecache)
{
createCache();
}
else if(v.getId()==R.id.btnreadcache)
{
readCache();
}
}
/**
* Lấy toàn bộ file cache
*/
public void loadAllCache()
{
File pathCacheDir = getCacheDir();
File []listCache= pathCacheDir.listFiles();
for(File f :listCache)
{
//process f here
f.delete();
}
}
/**
* đọc cache file
* getCacheDir() trả về đúng thư mục cache
*/
public void readCache() {
try {
File pathCacheDir = getCacheDir();
String strCacheFileName = "myCacheFile.cache";
File newCacheFile = new
File(pathCacheDir, strCacheFileName);
Scanner sc=new Scanner(newCacheFile);
String data="";
while(sc.hasNext())
{
data+=sc.nextLine()+"\n";
}
editdata.setText(data);
sc.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
/**
* Lưu cache file
*/
public void createCache()
{
try {
File pathCacheDir = getCacheDir();
String strCacheFileName = "myCacheFile.cache";
String strFileContents = editdata.getText()+"";
File newCacheFile = new
File(pathCacheDir, strCacheFileName);
newCacheFile.createNewFile();
FileOutputStream foCache =
new FileOutputStream(
newCacheFile.getAbsolutePath());
foCache.write(strFileContents.getBytes());
foCache.close();
} catch (IOException e) {
e.printStackTrace();
}
}

}

[/code]

– Vì giao diện và cách chạy tương tự như ví dụ trước nên Tôi không chụp hình minh họa,

– Bạn có thể tải coding mẫu ở đây: http://www.mediafire.com/download/u0smn6v68xf6uc5/LearnCacheFile.rar

– Như vậy tôi đã giới thiệu xong tương tác tập tin trong Android: internal Storage, external storage, caching file

– Trong bài tập kế tiếp Tôi sẽ hướng dẫn các bạn cách tương tác với XML file trong Android, trong bài tập này Tôi muốn trình bày về 2 kỹ thuật duyệt tập tin XML đó là : DOMSAX. Tôi thấy nó rất hay, các bạn nên chú ý theo dõi.