編輯:關於Android編程
概述 小小說明 一別之後二地相懸 都說是三四月誰又知五六年 七弦琴無心彈八行書不可傳 九連環從中折斷十裡長亭望眼欲穿 披荊斬棘
在開始考慮Android的數據庫操作之前,我們先回想一下Web方面的數據庫操作。如果我們只是停留在JDBC的簡單使用和封裝上(比如純JDCB,或者DBUtils),即使我們對數據庫的增刪改查操作進行了接口的抽取,代碼依舊會和業務有很強的耦合性。
經過我們分析,解除耦合性的關鍵在於如何解決自動映射“實體類 與 數據庫表”之間的對應關系。如果能夠做到這一步,那麼我們就能夠更好的解耦了,也能降低我們的代碼重復率。
如果我們再跨前一步,使用更為優秀的框架(比如:Hibernate),這一切都會變得簡單和方便。Hibernate為我們提供了兩種建立“實體類(bean) - 數據庫表”之間關系的方式。
一種是使用配置文件,在配置文件中對表名、字段、實體間的關系進行配置,Hibernate就能夠為我們做好一切,下面提供一段配置文件示例:
另一種,則是使用注解的方式。Hibernate為我們提供了@Entity
、@Table
、@Id
、@Column
、@GeneratedValue
諸如此類很多的注解。我們只需要在合適的地方加上這些注解,為我們的類、字段配置好關系,Hibernate也能夠為我們做好一切,下面提供一段配置文件示例:
@Entity(name=brand) /* 實體bean */
@Table(name=brand_t) /* 指定生成表的名字*/
public class Brand implements Serializable {
/** @Fields code : ID使用UUID生成 **/
private String code;
/** @Fields name : 品牌名稱 **/
private String name;
/** @Fields visible : 是否可見 **/
private Boolean visible = true;
/** @Fields logopath : logo路徑 **/
private String logopath;
public Brand(String name, String logopath) {
this.name = name;
this.logopath = logopath;
}
@Id
@Column(name=code, length=36) /* UUID是36 */
@GeneratedValue(generator = system-uuid)
@GenericGenerator(name = system-uuid, strategy = uuid)
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
@Column(length=40, nullable=false)
public String getName() {
return name;
}
@Column(nullable=false)
public Boolean getVisible() {
return visible;
}
/*/images/brand/2012/12/8/9/sss.gif */
@Column(length=80,nullable=true)
public String getLogopath() {
return logopath;
}
}
番外話說完,回到我們熱愛的Android中,我們應該如何在Android寫出一個通用的數據庫增刪改查操作,可能也需要借鑒Hibernate的優秀思想。
不過,世間萬物都是一步一步進行演化的,我們的代碼同樣是如此,從不通用到通用,我會通過幾篇博客一一向大家展示,但是由於本人經驗和學識有限,無法構建出一個完整的開源項目,望大家海涵。有興趣的可以聯系我大家一起嘗試做一下(每當你在感歎,如果有這樣一個東西就好了的時候,請注意,其實這是你的機會)。
整個例子會以一條新聞實體作為基本元素,並貫穿整個例子。新聞實體很簡單,我們給它起個名字叫做News
,字段由id
、title
、summary
構成。以下是示例代碼:
public class News {
private int id;
private String title;
private String summary;
// 此處省略get、set方法
}
另外,在SQLite數據庫中,存東西絕大多數是String類型的,只有涉及到主鍵、自增的才會使用int。
最後,想章節名太痛苦,就在網上找了一些有趣的詩詞作為章節了,大家按順序看哦。
實體對象我們已經有了,那麼現在就差數據庫表了。現在回想一下Android中,數據庫表的操作步驟,繼承SQLiteOpenHelper,修改一些構造函數,再在onCreate中使用db執行一下建表語句,好像就完成了(數據庫版本升級後續再講)。請看示例代碼:
public class DBHelper extends SQLiteOpenHelper {
private static final int VERSION = 1;
private static final String NAME = bzh.db;
public DBHelper(Context context) {
super(context, NAME, null, VERSION);
}
// 新聞表:主鍵+標題+摘要
public static final String TABLE_ID = _id;
public static final String TABLE_NEWS_NAME = news;
public static final String TABLE_NEWS_TITLE = title;
public static final String TABLE_NEWS_SUMMARY = summary;
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(CREATE TABLE + TABLE_NEWS_NAME + ( + //
TABLE_ID + integer primary key autoincrement , + //
TABLE_NEWS_TITLE + varchar(50) , + //
TABLE_NEWS_SUMMARY + varhcar(200))//
);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
}
仔細看一下代碼,其中我們把各個字段和表名都抽取成為了常量字段,這樣可以更方便我們寫數據庫增刪改查操作的時候使用。
現在,實體和表都有了,是時候寫增刪改查的操作了。既然是增刪改查,那麼肯定有對應的insert
、delete
、update
、findAll
等操作咯。
而我們作為有經驗的開發人員(偷笑),肯定是要面向接口編程咯,那就先寫一個NewsDao
吧,整體上很簡單,就不寫注釋了。代碼如下:
public interface NewsDao {
long insert(News news);
int delete(int id);
int update(News news);
List findAll();
}
看起來一切都很順利,下面是時候寫Dao的實現類了,我們就叫做NewsDaoImpl
吧,並實現NewsDao
接口。代碼如下:
public class NewsDaoImpl implements NewsDao {
private Context context;
private DBHelper helper;
private SQLiteDatabase db;
public NewsDaoImpl(Context context) {
super();
this.context = context;
this.helper = new DBHelper(context);
this.db = helper.getWritableDatabase();
}
@Override
public long insert(News news) {
return 0;
}
@Override
public int delete(int id) {
return 0;
}
@Override
public int update(News news) {
return 0;
}
@Override
public List findAll() {
return null;
}
}
貌似架子就是這個樣子了,為了執行增刪改查等語句,我們需要一個之前寫的DBHelper實例,而DBHelper又要求傳入Context對象。然後DBHelper又給了我們一個操作數據庫SQLiteDatabase實例。
一切很順利,不過增刪改查方法都是空著的,看來接下來只需要填空就好了。
既然是填空,那麼我們就只能一個一個來了,太麻煩了(怪不得程序員喜歡偷懶,喵喵!)。
就先從insert
開始吧。
@Override
public long insert(News news) {
ContentValues values = new ContentValues();
values.put(DBHelper.TABLE_NEWS_TITLE, news.getTitle());
// ... 此處省略N行代碼
return db.insert(DBHelper.TABLE_NEWS_NAME, null, values);
}
當然,我這些只是示例性的代碼,你看省略的好多呢,整個insert
的內容一點也不復雜。首先,把字段名和實體字段的對應關系存一個一個入ContentValues
中,然後再執行一下db.insert
,並填入要插入的表名和數據,搜一的一下,就成功了。
接下來是delete
,這麼貌似更容易了。在delete
中指定表的名稱、過濾條件、以及過濾條件對應的參數,就OK了。
@Override
public int delete(int id) {
return db.delete(DBHelper.TABLE_NEWS_NAME, DBHelper.TABLE_ID + =?, new String[] { id + });
}
下面是update
方法。為更新准備一下數據,在update
填入對應的表名、更新值、過濾條件、以及過濾條件對應的參數,這就完成了。當然,為了偷懶,還是省略了一下代碼。我保證下個肯定寫完整。
@Override
public int update(News news) {
ContentValues values = new ContentValues();
values.put(DBHelper.TABLE_NEWS_TITLE, news.getTitle());
// ... 此處省略N行代碼
return db.update(DBHelper.TABLE_NEWS_NAME, values, DBHelper.TABLE_ID + =?, new String[] { news.getId() + });
}
輪到findAll
方法了,這個比較重要,大家仔細聽。我們通過db.query()
查詢數據,並獲取到游標(不要忘記關閉哦),然後就開始移動游標,拿出數據並封裝到News
實體中,然後再一個一個加入到List
中。好吧,我承認,這裡又偷懶了,嘿嘿。
@Override
public List findAll() {
List result = null; // List
Cursor cursor = db.query(DBHelper.TABLE_NEWS_NAME, null, null, null, null, null, null);
if (cursor != null) {
result = new ArrayList();
while (cursor.moveToNext()) {
News news = new News(); // M m = new M();
int columnIndex = cursor.getColumnIndex(DBHelper.TABLE_NEWS_NAME);
String title = cursor.getString(columnIndex);
news.setTitle(title);
// ... 此處省略N行代碼
result.add(news);
}
}
// 關閉游標
cursor.close();
return result;
}
一步一步下來,貌似一個有關News
實體的增刪改查的Dao
就出爐了,但是,作為一名程序員,寫一個這樣子的還是可以承受的,那麼萬一有更多的User
、AAA
、BBB
、CCC
等等出現怎麼辦?
難道還要寫出來一大堆UserDao
、UserDaoImpl
、AAADao
、AAADaoImpl
等等的一大堆類和方法? 老天,你還是殺了我吧。
那麼,問題來了,上述的代碼需要解決什麼問題,才能變成通用的?
接下來我們從insert
、delete
、update
、findAll
這些方法中依次分析,看看是哪些問題阻擋了我們通用化的腳步。
insert
中,
ContentValues values = new ContentValues();
values.put(DBHelper.TABLE_NEWS_TITLE, news.getTitle());
// ... 此處省略N行代碼
如果這些代碼能夠,以一種“自動”的方式,那麼我們的雙手就算解放出來一步了,我們需要面對的問題是:如何將實體中的數據,按照對應關系導入到對應的表之中。
return db.insert(DBHelper.TABLE_NEWS_NAME, null, values);
再看看這句,好像在Java中,寫死就等於耦合、等於不方便。而DBHelper.TABLE_NEWS_NAME
好像也固定在語句之中了,看來這句代碼也阻擋了我們解放雙手的步伐,嘿嘿,又出來一個。我們需要面對的問題是:如何獲取表名。
這個方法是沒有了,接下來看看delete
,
return db.delete(DBHelper.TABLE_NEWS_NAME, DBHelper.TABLE_ID + =?, new String[] { id + });
其中的DBHelper.TABLE_NEWS_NAME
我們已經記錄下來了,那麼,後面的DBHelper.TABLE_ID
又是怎麼回事? 哦,原來是主鍵,也是固定寫死的。看來這也是我們面對的問題:明確實體中的主鍵是誰,並獲取到主鍵中封裝的值。
再看看update
方法,仔細瞅瞅~ 好像沒有耶!那麼就繼續下一個findAll
方法。
News news = new News(); // M m = new M();
int columnIndex = cursor.getColumnIndex(DBHelper.TABLE_NEWS_NAME);
String title = cursor.getString(columnIndex);
news.setTitle(title);
// ... 此處省略N行代碼www.2cto.com
這裡是將游標中的數據取出來,並放入到對應的實體屬性中去,這裡最容易出現錯誤、並且也是寫死的。看來這裡也是問題之一:將數據庫表中列的數據,按照對應關系導入到實體之中。
分析完後,我們已經可以總結出一二三四五六七八條了。哈哈。(貌似沒有這麼多。)
以上就是全部問題所在了,如果能夠搞定這些,在Android中的數據庫通用操作也就應運而生了。
時間是怎樣一種東西,它能改變一切、帶走一切、更可留下一切。昨天仿佛還在眼前,今天卻悄悄過去,我們的生命總是那麼有限,那些屬於你我的年輕亦是如此缥缈,擁有時並無察覺,待往事已成過眼雲煙,方才了解自己荒廢了那大好的時光,歲月仍在,流星劃過的剎那,卻忘記在心中默默許下那卑微的心願。
1,需要權限 2,下載 RootTools.jar包。3,兩個關鍵方法。主要是獲取shell,並執行命令行。方法如下: private
從Android的官方開發者博客找了一份幻燈片,介紹了一些Android UI設計,我們把這個教程整理出來,希望大家喜歡。為開發者,為啥我們要關心UI,前面
為了讓界面可以在平板上更好地展示,Android在3.0版本引入了Fragment(碎片)功能。首先需要注意,Fragment是在3.0版本引入的,如果你使用的是3.0之
本文實例講述了Android實現模仿UCweb菜單效果的方法。分享給大家供大家參考。具體如下:UCWeb的菜單看起來不錯,自己模仿做一個,思路實現如下:1、保留menu按
錯誤日志:Error:java.lang.RuntimeExceptio