編輯:關於Android編程
本節引言:
Android入門系列已經寫了大半了,學習了這麼多理論知識,不練下手怎麼行呢?
在實際的開發中我們會遇到更多的問題,同時也能加固我們的基礎知識!鑒於
筆者的水平有限,該項目,面對的是初學者,各位大牛路過不喜勿噴!好吧說下第一個
練手項目吧,前幾天中秋節今天又是教師節,各種祝福短信滿天飛,手打再群發,條條
短信一個樣,沒意思!直接用別人弄好的短信群發,別人又不知道你是誰,起碼加個:
親愛的XXX.我是隔壁老王,.....別人起碼知道你是誰把!好了,廢話不多說,開始app
的開發吧!
ps:目前app的基本功能已經實現,效果圖如下,如果有需要可以進行下載
到後面會逐步完善相關功能:
效果圖:

參考代碼下載:
源碼下載
正文:

創建數據庫文件:有兩個表,分別為存儲聯系人的表contacts和存儲節日祝福語的表festival
可以直接使用SQLite Expert或者其他SQLite的可視化工具創建表,可以代碼創建或者手動創建
代碼創建的話執行以下語句生成數據庫表:
CREATE TABLE festival(sentence_id INTEGER PRIMARY KEY AUTOINCREMENT,detail)
CREATE TABLE contacts(_id INTEGER PRIMARY KEY,pname,pnumber,pstate)
接著對節日表進行數據的錄入,結束的表結構如下:
festival表:

contacts表:

在完成上述創建數據庫的步驟後,接著我們需要把數據庫文件復制到assert目錄下
這裡我們要做什麼呢?
在應用啟動的時候我們需要判斷data/data/<包名>/database下有沒有我們的數據庫文件
如果不存在的話,我們需要通過代碼將數據庫文件導入到指定目錄下!
①先定義我們的數據庫名稱以及包名常量:
public static String dbName=my.db;//數據庫的名字 private static String DATABASE_PATH=/data/data/com.jay.example.festivalsmshelper/databases/;
②接著定義判斷是數據庫文件是否存在的方法:
public boolean checkDataBase(){
SQLiteDatabase checkDB = null;
try{
String databaseFilename = DATABASE_PATH+dbName;
checkDB =SQLiteDatabase.openDatabase(databaseFilename, null,
SQLiteDatabase.OPEN_READONLY);
}catch(SQLiteException e){
}
if(checkDB!=null){
checkDB.close();
}
return checkDB !=null?true:false;
}
public void copyDataBase() throws IOException{
String databaseFilenames =DATABASE_PATH+dbName;
File dir = new File(DATABASE_PATH);
if(!dir.exists())//判斷文件夾是否存在,不存在就新建一個
dir.mkdir();
FileOutputStream os = null;
try{
os = new FileOutputStream(databaseFilenames);//得到數據庫文件的寫入流
}catch(FileNotFoundException e){
e.printStackTrace();
}
InputStream is = MainActivity.this.getAssets().open(my.db);
byte[] buffer = new byte[4096];
int count = 0;
try{
while((count=is.read(buffer))>0){
os.write(buffer, 0, count);
os.flush();
}
}catch(IOException e){e.printStackTrace();}
is.close();
os.close();
}
boolean dbExist = checkDataBase();
if(dbExist){}
else{//不存在就把assert裡的數據庫寫入手機
try{
copyDataBase();
}catch(IOException e){throw new Error(復制數據庫出錯);}
}

如圖就說明數據庫文件復制完畢,是僅僅有一個my.db文件而已!後面那個my.do-journal是因為執行了
其他的操作生成的!
這裡的話我們讀取的僅僅是聯系人的目錄,並不包括sim卡中的聯系人哦!
這塊就涉及到了我們前面所學的使用系統提供的ContentProvider了!
我們先把系統提供的聯系人的數據庫文件找出來瞅瞅吧!
打開文件浏覽器:data/data/com.android.providers.contacts/databases
下面的contacts2.db文件就是存儲系統聯系人的數據庫文件了:

導出以後查看幾個重要的基本表,以及相關字段:
contacts表

data表

phone_look_up表

raw_contact表

以上四個就是我們要留意的四個表了
好了,說下我們要獲取的數據:聯系人id,姓名,一個電話號碼
於是我們定義一個類GetPhone類並定義一個讀取聯系人的方法,將讀到數據存儲到list集合中:
代碼如下:
public static ListgetPerson(Context context) { List persons = new ArrayList (); ContentResolver cr = context.getContentResolver(); Cursor cursor = cr.query(ContactsContract.Contacts.CONTENT_URI,null, null, null, null); while(cursor.moveToNext()){ Person person = new Person(); //獲取聯系人id String contatId = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts._ID)); person.setId(Integer.parseInt(contatId)); //獲取聯系人姓名 String name = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME)); person.setName(name); //因為一個聯系人的電話號碼可能有幾個,但我們這裡僅僅是獲取一個就夠了,所以就不循環遍歷了 Cursor phones = context.getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, ContactsContract.CommonDataKinds.Phone.CONTACT_ID+=+contatId, null, null); phones.moveToFirst(); String num = phones.getString(phones.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER)); person.setNumber(num); person.setState(-1); persons.add(person); phones.close(); } cursor.close(); return persons; }
該方法的參數是一個Person的對象,我們使用ContentValues來存儲從person取出的不同數據!
再調用db.insert(contacts,null,contentValue)將記錄插入到contacts表中
代碼:
public void insert(Person person){
SQLiteDatabase db = dbOpenHelper.getWritableDatabase();
ContentValues values = new ContentValues();
values.put(_id, person.getId());
values.put(pname, person.getName());
values.put(pnumber, person.getNumber());
values.put(pstate, person.getState());
db.insert(contacts, null, values);
}
怕數據太多,出現卡住的情況,加個進度條,用戶看著沒那麼不爽!
再new一個線程,一秒鐘後讓進度條消失,第一個界面消失,通過intent跳轉
到第二個界面中!
代碼:
//加個進度條,數據太多可能卡住不好,用戶看著不爽 final ProgressDialog dialog = ProgressDialog.show(this, 提示, 讀取聯系人中, false, true); GetContactsService getContacts = new GetContactsService(getApplicationContext()); Listpersons = GetPerson.getPerson(MainActivity.this); Cursor cursor = getContacts.query(select count(*) from contacts, null); cursor.moveToFirst(); //判斷聯系人數目是否發生變更,沒變更的話就不用調用下面的for循環了 if(persons.size() != cursor.getInt(0)) { for(Person p : persons) { System.out.println(p.toString()); getContacts.insert(p); } } //設置讓圓形進度條過一秒後消失,以及第一個界面消失,跳轉到第二個界面 new Thread() { public void run() { try { sleep(1000); } catch (InterruptedException e) {e.printStackTrace();} dialog.dismiss(); Intent it = new Intent(getApplicationContext(), ChooseActivity.class); startActivity(it); finish(); }; }.start();

將my.db文件導出後可以看到contacts表的data已經有數據了,就完成了
另外記得還有個Person類別漏了,定義四個屬性:id,name,number,state(記錄是否已經發送)
這裡就不給出了,另外要創建出第二個Activity完成Intent的跳轉哦!不然可是會報錯的!
1.判斷app中的數據庫文件是否存在?不存在的話如何使用輸入流將文件寫入到相應目錄下
2.如何獲得assert裡的文件,從而獲得輸入流對象;
3.哪裡可以找到系統保存聯系人的數據庫;相關表以及字段的了解!
讀取表中我們需要的聯系人信息!
4.調用database的insert()方法插入ContentValues類型的數據
5.獲得數據庫表有多少條記錄的方法:
Cursor cursor = getContacts.query(select count(*) from contacts, null);
cursor.moveToFirst();
cursor.getInt(0);
6.獲取List集合中的數據元素:list.size();
好了這一節就暫且到這裡吧,如果對本文有什麼建議,批評的,歡迎指出!
不慎感激!
項目的代碼會隨著後面深入慢慢完善的!
RecyclerView詳解之基礎使用
android.support.v7.widget.RecyclerViewandroid.support.v7.widget.LinearLayoutManageran
Android性能優化與內存洩漏分析
性能問題一般歸結為3類:1.UI卡頓和穩定性,這類問題用戶可直接感知,最為重要。2.內存問題,內存問題主要表現為內存洩漏。如果存在內存洩漏,應用會不斷消耗內存,容易導致頻
Android中實現用命令行同步網絡時間
一、簡介Android基於Linux平台的開源手機操作系統。二、原理既然是Linux,那就應該支持linux的各種命令行,高度的可配置,但實驗發現Android是Goog
Android帶圓形數字進度的自定義進度條示例
開發設計搞了一個帶圓形進度的進度條,在GitHub上逛了一圈,發現沒有,自己撸吧。先看界面效果:主要思路是寫一個繼承ProgressBar的自定義View,不廢話,直接上