Handler的使用
1.Handler類是android.os下的一個類,handler.post(Runnable r)可以將一個線程添加到訊息佇列中;handler.postDelay(Runnable r, long delayTime)在延遲delayTime毫秒後,將線程添加到訊息佇列中;handler.removeCalbacks(Runnable r)將隊列中掛起的Runnable移出。
2.Handler.obtainMessage()可以獲得一條訊息,這個訊息有兩個整型的參數arg1和arg2,利用它可以傳遞訊息。在建立Handler的時候,如果用
Handler handler = new Handler(){
@Override
public void handleMessage(Message msg){
……
}
}
來建立的話,該handler可以從訊息佇列(MessageQueue)中取出訊息並在handleMessage方法中處理。而在另一個地方,也可以使用handler.sendMessage(Message msg)來向訊息佇列中發送訊息。
Handler對於線程的處理並不是另外開啟一個線程,而是在原有線程的基礎上調用另一個Runnable的run函數。HanlderThread類實現了Looper來處理訊息佇列的功能,這個類由Android作業系統提供。利用該類,可以使用getLooper()(在使用getLooper()方法之前,必須調用該類的start()方法,否則這個Looper是null)方法來擷取這個Looper,之後,將這個Looper以參數的形式傳遞給Handler的建構函式,此時這個Handler的handleMessage()方法就可以由另一個線程來處理了,就不會阻塞Activity。
可以把Bundle看作一個特殊的Map,只是它的鍵固定為String類型,值也只有幾種基本的資料類型。
在使用Message傳遞資料的時候,發送之前可以使用Message.obj來傳遞一個資料,這個資料是一個Object即可。處理訊息的時候,也可以使用Message.obj來擷取,此時需要向下轉型。如果需要傳遞大量資料,可以使用Message.setData(Bundle data)。
Message.sendToTarget();方法可以講這個message發送給建立這個Message的Handler,在這個Handler裡面可以接收該Message。
SQLite的使用
1. SQLiteOpenHelper類的使用
public abstract class SQLiteOpenHelper類中有幾個函數:
onCreate(SQLiteDatabase db);當資料庫第一次建立的時候調用這個方法
onOpen(SQLiteDatabase db);當資料庫被開啟的時候調用這個方法
onUpgrade(SQLiteDatabase db);當資料庫需要升級的時候調用這個方法
getReadableDatabase();獲得可以讀的資料庫
getWritbaleDatabase();獲得可以寫的資料庫
我們一般繼承這個類,然後調用建構函式(父類沒有預設建構函式)。資料庫的版本為整數,從1開始,每次升級資料庫版本的時候,這個值依次遞增。當發現這個值變化的時候,就意味著資料庫已經進行了版本升級。
使用SQLiteDatabase.execSQL(String sql)來執行SQL語句。
2.adb工具的使用
可以使用adb工具(在cmd中輸入adb即可,在這之前需要為它配置環境變數,在sdk/platform-tools下面,另一個就是要保證模擬器AVD是開啟的,否則會報錯)來查看資料庫中的變化:
adb shell:進入Linux命令列(android作業系統是以Linux為核心的)
ls –l:以完整的形式顯示檔案和檔案夾
cd data:進入data
cd data:再進入data
這裡面有很多檔案夾(以應用程式的包名命名),每一個應用程式都有一個檔案夾
cd com.example.sqlite3:進入我們當前的應用程式
建立資料庫後,這裡面會多一個叫databases的檔案夾
cd databases:進入這個檔案夾,這裡面可以看到剛剛建立的資料庫
sqlite3 mydb:使用SQLite開啟資料庫mydb
然後就可以像Mysql一樣使用資料庫了:
select * from table_name;……
3.插入資料
使用ContentValues類來協助插入資料:
ContentValues values = new ContentValues();
values.put(“id”,1);//第一個參數為列名,第二個參數為列的值
values.put(“name”,”alvis”);
//DatabaseHelper類繼承於SQLiteOpenHelper類
DatabaseHelper dbHelper = new DatabaseHelper(MainActivity.this,”mydb”);
//得到一個資料庫物件
SQLiteDatabase db = dbHelper.getWritableDatabase();
db.insert(“user”,null,values);//調用insert方法插入資料。
insert方法的第一個參數為表名,第二個直接填null即可。第三個為帶有資料的ContentValues對象。
4.更新資料
DatabaseHelper dbHelper = new DatabaseHelper(MainActivity.this,”mydb”);
//得到一個資料庫物件
SQLiteDatabase db = dbHelper.getWritableDatabase();
ContentValues values = new ContentValues();
values.put(“name”,”alvis”);
db.update(“user”,values,”id=?”,new String[]{“1”});//這裡使用預留位置來設定參數
整個這幾句其實就組成了一句話:
update user set name=’alvis’ where id=1;
update方法第一個參數是要更新的表名,第二個參數是帶有要更新值的ContentValues對象,第三個參數是where字句的條件(可以有多個),第四個參數為where字句的值,類型為String[]。
5.查詢資料
DatabaseHelper dbHelper = new DatabaseHelper(MainActivity.this,”mydb”);
SQLiteDatabase db = dbHelper.getWritableDatabase();
Cursor cursor = db.query(“user”, new String[]{“id”,”name”}, ”id=?”, new String[]{“1”},null,null,”id” );
while(cursor.moveToNext()){
//這裡處理獲得的資料
String result = cursor.getString(cursor.getColumnIndex(“name”));
System.out.println(result);
}
cursor.moveToNext()方法有兩個作用: 將遊標下移看是否有下一條記錄,有就返回true,否則返回false,就是說把指標移到下一個位置的同時還判斷是否還有值。
query方法的參數依次為(後面三個參數均為字串):
表名,查詢的欄位,查詢條件,條件的參數,groupBy,having,orderBy
其實就是把一條select語句分解成了很多部分。
使用cursor擷取資料的時候,參數一定要是要查詢所在列的索引,這個索引可以通過cursor.getColumn(String columnName)來獲得,於是就有了上面的寫法。
建議不要太多的依賴於資料庫,也不要在SQLite資料庫中存入太多的資料,因為在開發的時候可能會出現很多奇怪的問題。
Android程式調試
可以使用Log類來輸出調試資訊:
Log.i(String tag,String message);//Info層級的
Log.v(String tag,String message);//致命的
Log.w(String tag,String message);//警告
Log.e(String tag,String message);//錯誤
Log.d(String tag,String message);//調試
檔案下載
1.下載檔案的步驟:
1).建立一個URL對象
URL url = new URL(String urlStr);
2).建立一個HttpURLConnection
HttpURLConnection urlConn = (HttpURLConnection)url.openConnection();
3).獲得一個InputStream對象
InputStream inputStream = urlConn.getInputStream();
然後就可以使用流操作讀取這個inputStream了
4).訪問網路的許可權:在Manifest.xml中聲明:
<uses-permission android:name="android.permission.INTERNET"/>
原始碼:
class DownloadMP3Listener implements OnClickListener{
@Override
public void onClick(View v) {
HttpDownloader httpDownloader = new HttpDownloader();
int status = httpDownloader.downFile("http://192.168.2.104:8080/source/ yiwangeshebude.mp3", "Download", "一萬個捨不得.mp3");
}
}
錯誤:android.os.NetworkOnMainThreadException
這個異常大概意思是在主線程訪問網路時出的異常。 Android在4.0之前的版本 支援在主線程中訪問網路,但是在4.0以後對這部分程式進行了最佳化,也就是說訪問網路的代碼不能寫在主線程中了。
解決辦法:重新開啟一個線程去跑網路相關的代碼。
class DownloadMP3Listener implements OnClickListener{
@Override
public void onClick(View v) {
new Thread(){ //重新開啟一個線程去訪問網路
@Override
public void run(){
HttpDownloader httpDownloader = new HttpDownloader();
int status = httpDownloader.downFile("http://192.168.2.104:8080/source/ yiwangeshebude.mp3", "Download", "一萬個捨不得.mp3");
}
}.start();
}
}
2.訪問SD卡
1).得到當前裝置SD卡的目錄:一般就是 /SDCARD
String path = Environment.getExternalStorageDirectory();
2).在Manifest.xml檔案中設定訪問SD卡的許可權(和application標籤同級)
<uses-permission android:name="android.permission.INTERNET"/>
ContentProvider初步
1.每一個ContentProvider都有一個公用的URI,這個URI表示這個ContentProvider所提供的資料。Android提供的ContentProvider都在android.provider包中。
2.ContentProvider所提供的函數:
query():查詢 insert():插入 update():更新
delete():刪除 getType():得到資料類型 onCreate():建立時的回呼函數
3.實現ContentProvider的過程:
1).定義一個CONTENT_URI常量
2).定義一個類,繼承ContentProvider類
3).實現query,insert,update,delete,getType和onCreate方法
4).在AndroidManifest.xml中進行聲明
XML檔案解析
ContentHandler介面
ContentHandler是Java類包中一個特殊的SAX介面,位於org.xml.sax包中,該介面封裝了一些對事件處理的方法,當XML解析器開始解析XML輸入文檔時,它會遇到某些特殊的事件,比如文檔的開頭和結束、元素的開頭和結束、以及元素中的字元資料等事件。當遇到這些事件時,XML解析器會調用ContentHandler介面中相應的方法來響應該事件。
ContentHandler介面的方法有以下幾種:
void startDocument()
void endDocument()
void startElement(String uri,String localName,String qName,Attributes atts)
void endElement(String uri,String localName,String qName)
void characters(char[] ch,int start,int length)讀取到中間的字元的時候調用
通常的處理流程如下:
1).建立事件處理常式
2).建立SAX解析器
3).將事件處理常式分配給解析器
4).對文檔進行解析,將每個時間發送給處理常式
如下面的例子:
//1.建立一個SAXParserFactory
SAXParserFactory factory = SAXParserFactory.newInstance();
//2.通過這個factory獲得一個XMLReader
XMLReader reader = factory.newSAXParser().getXMLReader();
//3.為XMLReader設定內容處理器
//注意這個方法的參數是一個ContentHander,但是由於ContentHandler裡面的
//方法太多,因此這裡使用適配器模式,MyContentHandler是繼承於DefaultHandler
//的,而DefaultHandler實現了ContentHanlder介面。
reader.setContentHandler(new MyContentHandler());
//4.開始解析檔案
reader.parse(new InputSource(new StringReader(xml)));
廣播機制
如果要監聽某一類事件,則需要在Manifest.xml檔案中聲明:
<receiver android:name=”.TestReceiver”>
<inteng-filter>
<action androi:name=”andriod.intent.action.EDIT”/>
</intent-filter>
</receiver>
同時接收方需要繼承BroadcastReceiver類,並複寫onReceiver方法:
class TestReceiver extends BroadcastReceiver{
@Override
public void onReceiver(Context context, Intent intent){
//這裡寫處理流程
}
}
注意藍色部分的匹配。
而在發送方,可以使用:
Intent intent = new Intent();
intent.setAction(Intent.ACTION_EDIT);
TestActivity.this.sendBrodcast(intent);
注意紅色的部分需要匹配,否則接收不到這個訊息。
這個程式的大體流程是:TestActivity廣播了一個action為ACTION_EDIT的 intent,TestReceiver因為繼承了BroadcastReceiver,因此是一個廣播的接收器,但是至於接不接收由TestActivity廣播的intent,就要看在Manifest.xml檔案中對TestReceiver的配置了。
在Manifest.xml檔案中對於TestReceiver的配置裡,<intent-filter>的<action>標籤指明了TestReceiver監聽的哪種action,只有當TestActivity廣播的intent中的action和這裡的action相同的時候,才會接收到,此時會產生一個TestReceiver,並調用該類的onReceiver方法。
注意:TestReceiver只做一次處理,如果處理過了,那麼這個對象就沒用了,如果再有同樣的廣播發送出來,那麼作業系統會再產生這樣一個對象來處理。