Android應用開發-數據存儲和界面展示(二)

 

SQLite數據庫

 

// 自定義類MyOpenHelper繼承自SQLiteOpenHelper
MyOpenHelper oh = new MyOpenHelper(getContext(), "school.db", null, 1);
// 獲取數據庫對象,若是數據庫不存在,會自動建立數據庫,數據庫文件名爲school.db,數據庫版本爲1
SQLiteDatabase db = oh.getWritableDatabase();

 

  getWritableDatabase():以讀寫的方式打開數據庫對應的SQLiteDatabase對象,磁盤空間不足時會報錯java

  getReadableDatabase():該函數首先調用getWritableDatabase(),若是磁盤空間不足,會返回打開失敗,而後以只讀的方式打開數據庫對應的SQLiteDatabase對象sql

 

  MyOpenHelper的代碼以下:數據庫

public class MyOpenHelper extends SQLiteOpenHelper
{

    public MyOpenHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version)
    {
        super(context, name, factory, version);
    }
    
    @Override
    public void onCreate(SQLiteDatabase db)     // 數據庫建立時,此方法會調用
    {
        db.execSQL("create table teacher(_id integer primary key autoincrement, name char(10), salary char(20), phone integer(20))"); // 通常以_id做爲主鍵
    }
    
    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)    // 數據庫升級時,此方法會調用
    {
        System.out.println("數據庫升級了");
    }
}

 

 

數據庫的增刪改查

 

SQL語句

  insert into teacher (name, phone, money) values ('張三', '159874611', 2000);

  delete from teacher where name = '李四' and _id = 4;

  update teacher set money = 6000 where name = '李四';

  select name, phone from teacher where name = '張三';

 

 

執行SQL語句實現增刪改查

db.execSQL("insert into teacher (name, phone, money) values (?, ?, ?);", new Object[]{"張三", 15987461, 75000});// 插入
Cursor cs = db.rawQuery("select _id, name, money from teacher where name = ?;", new String[]{"張三"});        // 查找

 

 

使用API實現增刪改查

  插入數組

// 把要插入的數據以鍵值對的形式封裝至ContentValues對象
ContentValues cv = new ContentValues();
cv.put("name", "劉能");
cv.put("phone", 1651646);
cv.put("money", 3500);
long i = db.insert("teacher", null, cv);  // 返回值是所插入行的主鍵,若是出錯返回-1

 

  刪除緩存

int i = db.delete("teacher", "_id = ? and name = ?", new String[]{"1", "張三"});    // 返回值是刪除的行數

 

  修改架構

ContentValues cv = new ContentValues();
cv.put("money", 25000);
int i = db.update("teacher", cv, "name = ?", new String[]{"趙四"});    // 返回值是所修改行的主鍵,若是出錯返回-1

 

  查找app

// arg2:要查詢的字段
// arg3:查詢條件
// arg4:填充查詢條件的佔位符
Cursor cs = db.query("teacher", new String[]{"name", "money"}, "name = ?", new String[]{"張三"}, null, null, null);
while(cs.moveToNext()){
    // 獲取指定列的索引值
    String name = cs.getString(cs.getColumnIndex("name"));
    String money = cs.getString(cs.getColumnIndex("money"));
    System.out.println(name + ";" + money);
}

 

 

事務

  保證多條SQL語句要麼同時成功,要麼同時失敗異步

  最多見案例:銀行轉帳ide

  事務API函數

try {
    // 開啓事務
    db.beginTransaction();
    ...........
    // 設置事務執行成功
    db.setTransactionSuccessful();
} finally{
    // 關閉事務
    // 若是此時已經設置事務執行成功,則sql語句生效,不然不生效
    db.endTransaction();
}

 

 

把數據庫的數據顯示至屏幕

 

  1. 任意插入一些數據

  2. 定義業務bean:Teacher.java

  3. 讀取數據庫的全部數據

Cursor cs = db.query("teacher", null, null, null, null, null, null);
while(cs.moveToNext()){
    String name = cs.getString(cs.getColumnIndex("name"));
    String phone = cs.getString(cs.getColumnIndex("phone"));
    String money = cs.getString(cs.getColumnIndex("money"));
    Teacher t = new Teacher(name, phone, money);// 把讀到的數據封裝至Teacher對象
    list.add(t);    // 把Teacher對象保存至集合中
}

 

 

  4. 把集合中的數據顯示至屏幕

LinearLayout ll = (LinearLayout) findViewById(R.id.ll);
 for(Teacher t : list){
     TextView tv = new TextView(this); // 建立TextView,每條數據用一個文本框顯示
     tv.setText(t.toString());
     ll.addView(tv);    // 把文本框設置爲ll的子節點
 }

 

  分頁查詢

Cursor cs = db.query("teacher", null, null, null, null, null, null, "0, 10");

 

 

ListView的使用及優化

 

  LsitView用來顯示一行一行的條目,每個條目都是一個View對象,能夠由佈局文件填充(inflate)而來

  MVC架構

    M:model模型層,提供要展現的數據 ———— List集合

    V:view視圖層,用戶看到的界面 ———— ListView

    C:control控制層,操做數據如何顯示 ———— Adapter

 

 

擴展BaseAdapter

  擴展BaseAdapter實現咱們本身的Adapter能夠對列表項進行最大限度的定製,它須要實現四個方法,其中最主要的是下面這兩個方法:

    第一個

// 系統調用此方法,用來獲知模型層有多少條數據
public int getCount() {
    return list.size();
}

 

    第二個

// 由系統調用,獲取一個View對象,做爲ListView的條目
// position:本次getView方法調用所返回的View對象,在ListView中位於第幾個條目,那麼position的值就是多少
@Override
public View getView(int position, View convertView, ViewGroup parent){
    
    View v = View.inflate(MainActivity.this, R.layout.item_listview, null);    // 則把佈局文件填充成一個View對象
    // 經過資源id查找控件,注意調用的是View對象的findViewById 
    TextView tv_name = (TextView) v.findViewById(R.id.tv_name);
    TextView tv_phone = (TextView) v.findViewById(R.id.tv_phone);
    TextView tv_salary = (TextView) v.findViewById(R.id.tv_salary);
Teacher t
= list.get(position); tv_name.setText(t.getName()); tv_phone.setText(t.getPhone()); tv_salary.setText(t.getSalary()); return v; }

 

  一旦給ListView設置了Adapter,即 listView.setAdapter(new MyAdapter()); ,上面的方法就開始調用,屏幕上顯示多少個條目,getView方法就會被調用多少次,當向下滑動屏幕時,getView會繼續被調用,得到更多的View對象顯示至ListView

 

 

使用條目的緩存convertView

    當ListView中的某條目(View)完全劃出屏幕時,系統會把該條目緩存至內存(內存充足時),這時內存中就有了條目緩存。若是此時用戶繼續滑動到新的條目,系統在調用getView時會把內存中已緩存的條目取出並做爲convertView參數傳入,可是傳入的條目不必定是咱們須要的那個條目,即系統有可能正在調用getView方法獲取第10個條目,convertView傳入的倒是第1個條目的緩存,因此即便在條目緩存存在( convertView != null )時,咱們仍須要對條目中的內容從新賦值,以達到複用緩存條目(即複用View,避免了沒必要要的inflate操做。另外,由於inflate操做耗時較長,因此Android系統使用異步操做來實現它)的目的,避免產生OOM(Out Of Memory)。

    對上面的getView()進行改造,使用convertView複用緩存條目的代碼以下:

@Override
public View getView(int position, View convertView, ViewGroup parent) {

    if (convertView == null) {    // 沒有緩存,則把佈局文件填充成一個View對象
        convertView = View.inflate(MainActivity.this, R.layout.item_listview, null);
    }
    TextView tv_name = (TextView) convertView.findViewById(R.id.tv_name);
    TextView tv_phone = (TextView) convertView.findViewById(R.id.tv_phone);
    TextView tv_salary = (TextView) convertView.findViewById(R.id.tv_salary);

    Teacher t = list.get(position);
    tv_name.setText(t.getName());
    tv_phone.setText(t.getPhone());
    tv_salary.setText(t.getSalary());
    return convertView;
}

 

 

使用ViewHolder模式提升效率

  findViewById()是經過在控件樹中以深度優先遍從來查找與指定資源id匹配的控件的,上面代碼儘管複用了緩存條目convertView,可是在用戶反覆滑動ListView的過程當中仍會大量的調用findViewById(),從而耗費大量的內存資源,咱們可使用ViewHolder模式對上面的代碼進行進一步的優化。使用ViewHolder模式來優化ListView很是簡單,只須要在自定義Adapter中定義一個內部類ViewHolder,並將佈局中的控件做爲ViewHolder的成員變量

final class ViewHolder {  // ViewHolder優化:防止大量的findViewById操做耗費資源
    // 條目的佈局文件中有哪些控件,這裏就定義什麼成員變量
    TextView tv_name;
    TextView tv_phone;
    TextView tv_salary;
}

 

   接下來,只要在getView()方法中將ViewHolder封裝至條目緩存convertView,當緩存存在時直接複用convertView並從中取出所封裝的ViewHolder,便可避免沒必要要的findViewById()

@Override
public View getView(int position, View convertView, ViewGroup parent) {

    ViewHolder holder;
    if (convertView == null) {
        convertView = View.inflate(MainActivity.this, R.layout.item_listview, null);
        holder = new ViewHolder();
        // 把佈局文件中全部控件封裝至ViewHolder中
        holder.tv_name = (TextView) convertView.findViewById(R.id.tv_name);
        holder.tv_phone = (TextView) convertView.findViewById(R.id.tv_phone);
        holder.tv_salary = (TextView) convertView.findViewById(R.id.tv_salary);
        convertView.setTag(holder); // 把ViewHolder封裝至View對象,最後會封裝至條目緩存convertView
    } else {
        holder = (ViewHolder) convertView.getTag();// 緩存的View對象中攜帶着ViewHolder,能夠避免頻繁的findViewById操做
    }
    Teacher t = list.get(position);
    holder.tv_name.setText(t.getName());
    holder.tv_phone.setText(t.getPhone());
    holder.tv_salary.setText(t.getSalary());
    return convertView;
}

 

 

 

對話框

 

肯定取消對話框

  建立對話框構建器對象,相似工廠模式

AlertDialog.Builder builder = new Builder(this);

 

  設置標題和正文

builder.setTitle("警告");
builder.setMessage("若練此功,必先自宮");

 

  設置肯定和取消按鈕

builder.setPositiveButton("如今自宮", new OnClickListener() {

    @Override
    public void onClick(DialogInterface dialog, int which) {
        // TODO Auto-generated method stub
        Toast.makeText(MainActivity.this, "恭喜你自宮成功,如今程序退出", 0).show();
    }
});

builder.setNegativeButton("下次再說", new OnClickListener() {

    @Override
    public void onClick(DialogInterface dialog, int which) {
        // TODO Auto-generated method stub
        Toast.makeText(MainActivity.this, "若不自宮,必定不成功", 0).show();
    }
});

 

  使用構建器建立出對話框對象

AlertDialog ad = builder.create();
ad.show();

 

 

單選對話框

 

AlertDialog.Builder builder = new Builder(this);
builder.setTitle("選擇你的性別");

 

  定義單選選項

final String[] items = new String[]{
        "男", 
        "女"
};
//-1表示默認誰也不選中
//點擊偵聽的導包要注意別導錯
builder.setSingleChoiceItems(items, -1, new OnClickListener() {

    //dialog:觸發這個方法的對話框
    //which:用戶所選的條目的下標
    @Override
    public void onClick(DialogInterface dialog, int which) {
        Toast.makeText(MainActivity.this, "您選擇了" + items[which], 0).show();
        //關閉對話框
        dialog.dismiss();
    }
});
//能夠直接用構建器顯示對話框
builder.show();

 

 

多選對話框

 

AlertDialog.Builder builder = new Builder(this);
builder.setTitle("請選擇你以爲帥的人");

 

  定義多選的選項,由於能夠多選,因此須要一個boolean數組來記錄哪些選項被選了

final String[] items = new String[]{
        "吳彥祖",
        "吳亦凡",
        "劉德華",
        "古天樂"
};
//默認只選中第一個條目
final boolean[] checkedItems = new boolean[]{
        true,
        false,
        false,
        false,
};
builder.setMultiChoiceItems(items, checkedItems, new OnMultiChoiceClickListener() {

    //which:用戶點擊條目的下標
    //isChecked:用於判斷用戶點擊該條目是選中仍是取消
    @Override
    public void onClick(DialogInterface dialog, int which, boolean isChecked) {
        checkedItems[which] = isChecked;
    }
});
//設置一個肯定按鈕
builder.setPositiveButton("肯定", new OnClickListener() {

    @Override
    public void onClick(DialogInterface dialog, int which) {
        StringBuffer sb = new StringBuffer();
        for(int i = 0;i < items.length; i++){
            sb.append(checkedItems[i] ? items[i] + " " : "");
        }
        Toast.makeText(MainActivity.this, sb.toString(), 0).show();
    }
});
builder.show();
相關文章
相關標籤/搜索