緊接着上一篇博客,接着複習Android的知識點。一個暑假的時間自己在學車,即使每天都看了一點點知識,但是效率不高,現在需要在圖書館裏給他補起來!
第五個知識點:如何利用Handle處理
在默認情況下,Android所有的操作都在主線程中進行,對一些耗時的操作,必須開啓一個子線程來處理。這就需要用到Handle,通俗點來說,就是在子線程中獲取數據,數據獲取完之後,handle發送“數據已經獲得的消息”,然後在主線程中把這些數據在組件中展示出來。
下面是具體的用法(類似與一種框架):
首先開啓一個子線程,像是從數據庫中取數據,進行網絡需求下載數據等等都需要進行開啓子線程,
子線程中存在多種消息(多種情況)
new Thread(){
@Override
public void run() {
msg = Message.obtain();
msg.what = "0101"
handler.sendMessage(msg);
}
}.start();
private Handler handler = new Handler(){
public void handleMessage(Message msg){
switch (msg.what){
case 0101:
//執行相應的操作
break;
case 0102:
//執行相應的操作
break;
default:
}
}
}
子線程中只存在一種消息:
new Thread(){
@Override
public void run() {
handler.sendEmptyMessage(0);
}
}.start();
private Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
lv_contact_items.setAdapter(new ContactAdapter());
}
};
Handle的使用框架就是上面的兩種方式。
第六個知識點:SQLlite的使用
使用這個知識點的時候,我是真正的感覺到了書上的知識畢竟是書上的,自己寫的代碼是自己的寫的,這還得從實踐中得到真知啊!
三步走使用sqlite
第一步首先建立DBHelper,建造數據庫:
public class BlackNumberDBHelper extends SQLiteOpenHelper {
public BlackNumberDBHelper(Context context) {
super(context,"blacknumber.db",null,1);
}
/**
* 創建一個數據庫表
* @param db
* 包含三個字段 id phonenumber model
* model 0 全部攔截 1 電話攔截 2 短信攔截
*/
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL("create table number1 (id Integer primary key AUTOINCREMENT,phonenumber varchar(20),model varchar(2) )");
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
}
構建這個類,首先要繼承SQLiteOpenHelper類,然後最重要的就是構造方法,使用父類的構造方法,傳入一個上下文參數,第二個是數據庫名稱,其他兩個不重要,照着寫就行。
第二個方法是構建一張表,這就能用到之前學的數據庫的知識了,注意點就是上面的表名就是number1,在編寫第二步類的時候,要與這個表名保持一致纔行!!!
然後就可以執行第二步了;
第二步:寫BDDao
我覺得這個類中最主要就是構造方法,忽然覺得有一種豁然開朗的感覺,非常的舒服!
public class BlackNumberDao {
private BlackNumberDBHelper db;
private String tablename = "number1";
//寫在構造器中 只要對象new 出來 數據庫就會自動創建
public BlackNumberDao(Context context) {
db = new BlackNumberDBHelper(context);
}
public List<BlackNumberInfo> QueryAll(){
SQLiteDatabase readableDatabase = db.getReadableDatabase();
Cursor query = readableDatabase.query(tablename, null, null, null, null, null, null);
while (query.moveToNext()){
String phone = query.getString(1);
blackNumberInfo.setPhonenumber(phone);
String model = query.getString(2);
}
query.close();
readableDatabase.close();
return list;
}
/**
* 往數據庫中添加數據
*
* @param phone 電話
* @param model 攔截模式
*/
public Boolean Add(String phone, String model) {
SQLiteDatabase writableDatabase = db.getWritableDatabase();
ContentValues contentValues = new ContentValues();
contentValues.put("phonenumber", phone);
Log.d("測試", "Add: "+phone);
contentValues.put("model", model);
//如果insert的值位-1 則說明插入失敗
long insert = writableDatabase.insert(tablename, null, contentValues);
writableDatabase.close();
//如果插入進數據庫 則返回true
if (insert != -1) {
return true;
} else {
return false;
}
}
/**
* 刪除數據庫中的數據
*
* @param phone
* @return
*/
public Boolean Delete(String phone) {
SQLiteDatabase writableDatabase = db.getWritableDatabase();
//返回值爲0 說明沒有刪除數據
int delete = writableDatabase.delete(tablename, "phonenumber=?", new String[]{phone});
writableDatabase.close();
if (delete != 0) {
return true;
} else {
return false;
}
}
/**
* 更改攔截模式
*
* @param phone
* @param model
* @return
*/
public Boolean Update(String phone, String model) {
SQLiteDatabase writableDatabase = db.getWritableDatabase();
ContentValues contentValues = new ContentValues();
contentValues.put("model", model);
int update = writableDatabase.update(tablename, contentValues, "phonenumber=?",new String[]{phone});
writableDatabase.close();
if (update==0){
return false;
}else {
return true;
}
}
/**
* 查找數據的操作 主要是查找phone的model
* @param phone
* @return
*/
public String Query(String phone){
String model = null;
SQLiteDatabase readableDatabase = db.getReadableDatabase();
Cursor query = readableDatabase.query(tablename, new String[]{"model"}, "phonenumber=?", new String[]{phone}, null, null, null);
while (query.moveToNext()){
model = query.getString(0);
}
return model;
}
}
這個類中有個DBHelper的實例變量,恰好在構造方法中有初始化了這個實例變量,這個就能使用這個數據庫了,記住這個上下文參數也要傳進入,這樣就可以利用這些db進行增刪改查了。具體的使用方法基本就是上面這幾種了。更新,刪除,插入如果失敗返回的是-1,因此只要判斷返回的是不是-1即可。查詢函數是比較難寫的一個方法,因爲他的參數特別多,需要加以記憶!還有就是這個SQL語句很簡單,並沒有涉及到很難得查詢,因此那更難得查詢應該怎樣寫,這還是一個自己沒有嘗試得地方。
第三步:在Activity中掉用這個DBdao即可使用:
BlackNumberDao blackNumberDao = new BlackNumberDao(getApplicationContext());
Boolean add = blackNumberDao.Add(phone, model);
這樣就完成了數據庫的使用,現在回想起來,使用這個數據庫也挺簡單的,每次看一遍代碼,自己都會有新的體會!
第七個知識點:Fragment的使用
這個知識點的內容也是非常中要的,具體的重要原理咱不講,咱只說如何使用。
用一個小小的Demo來說明如何使用Fragment:像微信的主頁面那樣,按下面的一張圖片就跳轉到一個界面,可以來回的跳轉。
在做這個Demo的時候,我認爲Fragment還不容易嗎!!不就是利用replace和add等方法加上去不就行了,結果是,我居然搞了2個多小時,把我的激情都給搞沒有了,再一次被編程打擊了!!但是最終的結果還好,自己完成了這個小小的需求,自己遇到了三個錯誤,搞了半天。
錯誤一:自己把自己的Activity頁面搞混了
這是一個小錯誤,我覺得是因爲自己好多天沒有學習Android所導致的,最近在寫JavaWeb的東西,這個問題不大,自己看界面的錯誤就解決了
錯誤二:對於import android.app.Fragment和android.support.v4.app.Fragment的問題
我在Fragment中使用android.support.v4.app.Fragment,結果在Activity中使用import android.app.Fragment,結果是一致報錯,我心想,我自己不會這麼白癡吧,這點知識還能打錯了,自己找了半天,才解決了這個問題,具體他們兩個的區別點擊這篇博客看看吧,一定要保持一致的包,這樣纔不會出錯。
錯誤三:java.lang.IllegalStateException: commit already called報這個錯誤
到了最後了,我心想該沒有錯了吧,結果又給我提個錯,結果百度一搜,答案就出來了,原因如下:
是因爲你的ft事務是全局的變量,只能commit一次。所以用兩個局部ft事務去做commit即可。
所以說,一個ft只能執行一次commit操作,而且,一定要保證ft爲局部變量,否則可能會拋出這個錯誤,
還有一個最最最最最重要的錯誤,如下:下面兩段代碼中,這三句的
FragmentManager fm = getFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
Fragment fragment = null;
的作用範圍是一樣的嗎????
private void initEvent() {
View.OnClickListener pagechange = new View.OnClickListener() {
@Override
public void onClick(View v) {
FragmentManager fm = getFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
Fragment fragment = null;
switch (v.getId()) {
case R.id.ib_home_home:
fragment = new HomeFragment();
break;
case R.id.ib_home_check:
fragment = new CheckFragment();
break;
case R.id.ib_home_myinfo:
fragment = new MyinfoFragment();
break;
default:
break;
}
ft.replace(R.id.home_content_fragment, fragment);
ft.commit();
}
};
private void initEvent() {
View.OnClickListener pagechange = new View.OnClickListener() {
FragmentManager fm = getFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
Fragment fragment = null;
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.ib_home_home:
fragment = new HomeFragment();
break;
case R.id.ib_home_check:
fragment = new CheckFragment();
break;
case R.id.ib_home_myinfo:
fragment = new MyinfoFragment();
break;
default:
break;
}
ft.replace(R.id.home_content_fragment, fragment);
ft.commit();
}
};
答案是不一樣的,第二種代碼就會報上面那種錯。(我認爲第二種方式ft已經是局部變量了,但是他不是,必須是onClick種的變量纔是局部變量)具體的代碼我就不展示了,畢竟是一個小小的Demo,不難,但是易錯點多,我輩尚需努力啊!
第八個知識點,也是我認爲最難理解的知識點:ListView的使用
ListView用到是會用,但是對於一些具體的細節問題,需要進步的去理解,去慢慢的琢磨
下面就先利用簡單的list做個簡單的demo,再利用很多的數據做一個進階版的Demo,就是一個用系統的,一個用自定義的item
剛寫好代碼就遇到一個錯誤,這個錯誤是這樣的Error running HomeActivity: The activity must be exported or contain an intent-filte
怎麼都運行不了了,然後到網上一搜,發現我在運行一個activity界面,並不是一個app程序:如下所示:
listview的使用也分三個步驟:
第一:首先在佈局裏聲明ListView組件:
<ListView
android:id="@+id/lv_listview_demo1"
android:divider="#000"
android:dividerHeight="5dp"
android:layout_width="match_parent"
android:layout_height="match_parent">
</ListView>
divider屬性是指兩個item之間的邊框線的顏色 ,dividerHeight是指邊框線的高度
第二步:初始化對象
這一步很簡單,就是find viewbyid之類的步驟
第三步:直接利用SetAdapter就行了:
private String [] data = new String[]{"aaa","aaa","aaa","aaa","aaa","aaa","aaa","aaa",
"aaa","aaa","aaa","aaa","aaa","aaa","aaa","aaa","aaa"
};
private ListView lv_listview_demo1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
initView();
initData();
initAnimation();
initEvent();
}
private void initView() {
setContentView(R.layout.activity_listview1);
lv_listview_demo1 = findViewById(R.id.lv_listview_demo1);
}
private void initData() {
lv_listview_demo1.setAdapter(new ArrayAdapter<String>( Listview1Activity.this,android.R.layout.simple_list_item_1,data) );
}
private void initAnimation() {
}
private void initEvent() {
lv_listview_demo1.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
String res = parent.getItemAtPosition(position).toString();
Toast.makeText(Listview1Activity.this,res,Toast.LENGTH_SHORT).show();
}
});
}
這種方式的ListView是最簡單的,不過也是沒有進行優化的。具體的優化方式就是我不太理解的地方(開發者爲什麼都知道這個bug了,爲什麼還是不在最基本的源碼部分修改這個bug呢?)
接下來就是自定義一個listview了,開始自己寫吧!
在這就只給一部分代碼:
private ListView lv_listview_demo2;
private String [] data = new String[]{"aaa","aaa","aaa","aaa","aaa","aaa","aaa","aaa",
"aaa","aaa","aaa","aaa","aaa","aaa","aaa","aaa","aaa"
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
initView();
initData();
initAnimation();
initEvent();
}
private void initView() {
setContentView(R.layout.activity_listview2);
lv_listview_demo2 = findViewById(R.id.lv_listview_demo2);
}
private void initData() {
lv_listview_demo2.setAdapter(new DemoAdapter());
}
private void initAnimation() {
}
private void initEvent() {
}
public class DemoAdapter extends BaseAdapter{
@Override
public int getCount() {
return data.length;
}
@Override
public Object getItem(int position) {
return null;
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View inflate = View.inflate(getApplicationContext(), R.layout.listview_item, null);
TextView title = inflate.findViewById(R.id.title);
TextView content = inflate.findViewById(R.id.content);
title.setText(data[position]);
content.setText(data[position]);
return inflate;
}
}
像這種級別的代碼,一看就會,不過對於listview,這些都不行,還得學會他的優化方式,但是這篇博客,不說關於優化的方式,因爲自己還沒有學的很透徹,等我理解了具體的操作方式,我準備專門寫一篇博客講述爲什麼要優化listview。
這篇博客就到這吧,寫了一下午的博客和代碼,有點累了,不過很充實,我喜歡這種感覺!