Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> 開發隨筆:自定義ListView、數據庫操作和Activity交互

開發隨筆:自定義ListView、數據庫操作和Activity交互

編輯:關於Android編程

在項目中做了列表頁面和詳情頁面,用到了以下幾個知識點,在這裡和大家分享一下:

1.數據庫模塊的完善:

1.1升級數據庫,抽出版本字段;

如果xxx.db 數據庫已經存在了,之後不管我們怎樣Create database ,MyDatabaseHelper 中的onCreate()方法都不會再次執行。

解決這個問題的辦法也相當簡單,只需要先將程序卸載掉,然後重新運行,這時xxx.db 數據庫已經不存在了,如果再點擊Create database,MyDatabaseHelper 中的onCreate()方法就會執行,這時就可以成功了。

不過通過卸載程序的方式毫無疑問是很極端的做法,其實我們只需要巧妙地運用SQLiteOpenHelper 的升級功能就可以很輕松地解決這個問題。

還記得onUpgrade()方法嗎?他就是升級數據庫的關鍵,還記得SQLiteOpenHelper 的構造方法裡接收的第四個參數嗎?它表示當前數據庫的版本號,之前我們傳入的是1,現在只

要傳入一個比1 大的數,就可以讓onUpgrade()方法得到執行了。

如果多處讀寫數據庫,一個個去改版本號常數就會很麻煩,這時抽出版本字段,一改全改就是必然。

 

public  static final int DB_VERSION = 1;

更高階的升級數據庫玩法可以看看第一行代碼:

 

\

 

細節:switch 中每一個case 的最後都是沒有使用break的,

為什麼要這麼做呢?這是為了保證在跨版本升級的時候,每一次的數據庫修改都能被全部執行到。比如用戶當前是從第二版程序升級到第三版程序的,那麼case 2 中的邏輯就會執行。而如果用戶是直接從第一版程序升級到第三版程序的,那麼case 1 和case 2 中的邏輯都會執行。使用這種方式來維護數據庫的升級,不管版本怎樣更新,都可以保證數據庫的表結構是最新的,而且表中的數據也完全不會丟失了。


1.2使用SQL操作數據庫和數據庫查詢:

 

雖然Android 已經給我們提供了很多非常方便的API 用於操作數據庫,不過總會有一些人不習慣去使用這些輔助性的方法,而是更加青睐於直接使用SQL 來操作數據庫。這種人

一般都是屬於SQL 大牛,如果你也是其中之一的話,那麼恭喜,Android 充分考慮到了你們的編程習慣,同樣提供了一系列的方法,使得可以直接通過SQL 來操作數據庫。

下面我就來簡略演示一下,如何直接使用SQL 來完成前面幾小節中學過的CRUD 操作。

添加數據的方法如下:

db.execSQL("insert into Book (name,author, pages, price) values(?, ?, ?, ?)",

new String[] { "The Da VinciCode", "Dan Brown", "454", "16.96" });

db.execSQL("insert into Book (name,author, pages, price) values(?, ?, ?, ?)",

new String[] { "The Lost Symbol","Dan Brown", "510", "19.95" });

更新數據的方法如下:

db.execSQL("update Book set price = ?where name = ?", new String[] { "10.99",

"The Da Vinci Code" });

刪除數據的方法如下:

db.execSQL("delete from Book wherepages > ?", new String[] { "500" });

查詢數據的方法如下:

db.rawQuery("select * from Book",null);

可以看到,除了查詢數據的時候調用的是SQLiteDatabase 的rawQuery()方法,其他的操作都是調用的execSQL()方法。以上演示的幾種方式,執行結果會和前面幾小節中我們學習的CRUD 操作的結果完全相同,選擇使用哪一種方式就看你個人的喜好了。

 

在這裡重點說一下參數最多,最博大精深的query()方法。

先看API。

 

query

public Cursor query(Stringtable,
                    String[]columns,
                    Stringselection,
                    String[]selectionArgs,
                    StringgroupBy,
                    Stringhaving,
                    StringorderBy,
                    Stringlimit)
Query the given table, returning a Cursor over the result set.

 

參數: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.limit - Limits the number of rows returned by the query, formatted as LIMIT clause. Passing null denotes no LIMIT clause.返回:A Cursor object, which is positioned before the first entry另請參見:Cursor 再看我在項目中的源代碼,看了就秒懂啦,Cursor遍歷之前博客說過,哪些參數是String,哪些是String數組,一目了然。

 

 

dbHelper = new MyDatabaseHelper(this, "Meeting.db", null, MyDatabaseHelper.DB_VERSION);
        SQLiteDatabase db = dbHelper.getWritableDatabase();
        String col[] = {"content","owner","time"};
        Cursor cursor = db.query("Room",col,"name=?",new String[]{roomName},null,null,null);
        if (cursor.moveToFirst()) {
            do {
                String contentCur = cursor.getString(cursor
                        .getColumnIndex("content"));
                String ownerCur = cursor.getString(cursor
                        .getColumnIndex("owner"));
                String timeCur = cursor.getString(cursor
                        .getColumnIndex("time"));
                Log.d("權興權意:", "contentCur-" + contentCur);
                Log.d("權興權意:", "ownerCur-" + ownerCur);
                Log.d("權興權意:", "timeCur-" + timeCur);
                Toast.makeText(RoomListActivity.this, "RoomListActivity:" + "contentCur-" + contentCur+"ownerCur-" + ownerCur + "timeCur-" + timeCur,
                        Toast.LENGTH_SHORT).show();
                Room room = new Room(R.drawable.meeting,"發起人:" + ownerCur,"時間:" + timeCur,"會議:" + contentCur);
                roomList.add(room);
            } while (cursor.moveToNext());
        }
        cursor.close();
        db.close();

 

2.Activity之間的數據交互;

這就是Intent的putExtra()、getStringExtra()方法,鍵值對的使用,十分給力。

 

                Intent intent = new Intent();
                intent.setClass(ListActivity.this, RoomListActivity.class);
                intent.putExtra("roomName",room.getName());
                startActivity(intent);

 

 

        Intent i = getIntent();
        String roomName = i.getStringExtra("roomName");
        Toast.makeText(RoomListActivity.this, "RoomListActivity:" + roomName,
                Toast.LENGTH_SHORT).show();

3.自定義ListView

 

 

ListView,Android 中最常用的控件之一,幾乎所有的應用程序都會用到它。

由於手機屏幕空間都比較有限,能夠一次性在屏幕上顯示的內容並不多,當我們的程序中有大量的數據需要展示的時候,就可以借助ListView 來實現。

ListView 允許用戶通過手指上下滑動的方式將屏幕外的數據滾動到屏幕內,同時屏幕上原有的數據則會滾動出屏幕。

相信你其實每天都在使用這個控件,比如查看手機聯系人列表,翻閱微博的最新消息等等。

 

既然ListView 是用於展示大量數據的,那我們就應該先將數據提供好。這些數據可以是從網上下載的,也可以是從數據庫中讀取的,應該視具體的應用程序場景來決定。

不過,數據是無法直接傳遞給ListView 的,我們還需要借助適配器來完成。Android 中提供了很多適配器的實現類,其中我認為最好用的就是ArrayAdapter。它可以通

過泛型來指定要適配的數據類型,然後在構造函數中把要適配的數據傳入即可。ArrayAdapter有多個構造函數的重載,你應該根據實際情況選擇最合適的一種。在ArrayAdapter 的構造函數中依次傳入當前上下文、ListView 子項布局的id,以及要適配的數據。

這樣適配器對象就構建好了。最後,還需要調用ListView 的setAdapter()方法,將構建好的適配器對象傳遞進去,這樣ListView 和數據之間的關聯就建立完成了。

 

之所以說ListView 這個控件很難用,就是因為它有很多的細節可以優化,其中運行效率就是很重要的一點。

仔細觀察,getView()方法中還有一個convertView 參數,這個參數用於將之前加載好的布局進行緩存,以便之後可以進行重用.

可以看到,現在我們在getView()方法中進行了判斷,如果convertView 為空,則使用LayoutInflater 去加載布局,如果不為空則直接對convertView 進行重用。這樣就大大提高了

ListView 的運行效率,在快速滾動的時候也可以表現出更好的性能。我們同時借助一個ViewHolder 來對View 的findViewById()方法來獲取一次控件的實例這部分性能進行優化.

我們新增了一個內部類ViewHolder,用於對控件的實例進行緩存。當convertView 為空的時候,創建一個ViewHolder 對象,並將控件的實例都存放在ViewHolder 裡,然後調用View的setTag()方法,將ViewHolder 對象存儲在View 中。當convertView 不為空的時候則調用View 的getTag()方法,把ViewHolder重新取出。這樣所有控件的實例都緩存在了ViewHolder裡,就沒有必要每次都通過findViewById()方法來獲取控件實例了。通過這兩步的優化之後,我們ListView 的運行效率就已經非常不錯了。


源代碼如下:

 

package com.quan.car.qmeeting;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.TextView;

import java.util.List;

import entitys.Room;

/**
 * Created by 權興權意 on 2016/8/22.
 */
public class RoomAdapter extends ArrayAdapter {

    private int resourceId;

    public RoomAdapter(Context context, int resource, List objects) {
        super(context, resource, objects);
        resourceId = resource;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        Room room = getItem(position);
        View view;
        ViewHolder viewHolder;
        if (convertView == null) {
            view = LayoutInflater.from(getContext()).inflate(resourceId, null);
            viewHolder = new ViewHolder();
            viewHolder.roomImage = (ImageView) view.findViewById(R.id.image_iv_roomItem);
            viewHolder.roomTime = (TextView) view.findViewById(R.id.time_tv_roomItem);
            viewHolder.roomOwner = (TextView) view.findViewById(R.id.owner_tv_roomItem);
            viewHolder.roomContent = (TextView) view.findViewById(R.id.content_tv_roomItem);
            view.setTag(viewHolder);
        } else {
            view = convertView;
            viewHolder = (ViewHolder) view.getTag();
        }
        viewHolder.roomImage.setImageResource(room.getImageId());
        viewHolder.roomTime.setText(room.getTime());
        viewHolder.roomOwner.setText(room.getOwner());
        viewHolder.roomContent.setText(room.getContent());
        return view;
    }

    class ViewHolder {
        ImageView roomImage;
        TextView roomTime;
        TextView roomOwner;
        TextView roomContent;
    }
}

 

最後,在適配器中設置布局、數據源,然後實例化ListView控件,並setAdapter(),大功告成。
        RoomAdapter adapter = new RoomAdapter(RoomListActivity.this,
                R.layout.room_item, roomList);
        ListView roomList_lv_roomlist = (ListView) findViewById(R.id.roomList_lv_roomlist);
        roomList_lv_roomlist.setAdapter(adapter);

 

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved