如何在ListView的視圖里顯示圖片呢,?很多初學(xué)者應(yīng)該會被這個問題難倒,因為既不知道如何瀏覽圖片,,也不知道如何將圖片嵌入到ListView中,。這邊就演示一個例子將圖片嵌入到ListView中,并使用ContentProvider對ListView里的數(shù)據(jù)進行增刪改查。
首先需要一個sqlite數(shù)據(jù)庫文件,因為我們要使用ContentProvider跟它進行交互,。我們先確定表結(jié)構(gòu),在這邊我們創(chuàng)建一個有5列的表,,表名是:contact,表結(jié)構(gòu)如下圖所示:
這邊我們設(shè)置_id是Integer型,,是主鍵,,age是Integer型,其他則都是TEXT型,。avatar是用來記錄圖片的Uri路徑,,我們不把圖片的二進制信息記錄到數(shù)據(jù)庫中,因為讀取數(shù)據(jù)庫中的二進制肯定沒有直接讀取文件快,。對應(yīng)這個數(shù)據(jù)庫表結(jié)構(gòu),,創(chuàng)建一個類來記錄列信息和訪問它對應(yīng)的Uri。
ContentMeta.java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
package com.android777.listviewimage.provider;
import android.net.Uri;
import android.provider.BaseColumns;
public class ContentMeta {
/**
* 開發(fā)組織署名,,Android就是通過這個名字來尋找對應(yīng)的provider
*/
public static final String AUTHORITY = "com.android777.listviewimage" ;
private ContentMeta(){}
/**
*
* 記錄Contact表相關(guān)的信息,,在這邊implements BaseColumns接口是因為,
* BaseColumns有提供靜態(tài)字段,,_id和_count,,這2個都是默認在Cursor可讀取的屬性
*
*/
public static final class ContactColumns implements BaseColumns {
private ContactColumns(){}
/**
* 訪問它的uri
*/
public static final Uri CONTENT_URI = Uri.parse( "content://" + AUTHORITY + "/contacts" );
/**
* 數(shù)據(jù)庫字段影射
*/
public static final String NAME = "name" ;
public static final String AGE = "age" ;
public static final String AVATAR = "avatar" ;
public static final String ADDRESS = "address" ;
}
}
|
接著創(chuàng)建一個MainActivity.java,,這個類主要用來將所有的Contact信息顯示到ListView中,并添加Option Menu,,讓用戶可以添加Contact,,同時監(jiān)聽ListView的click事件,當用戶點擊Contact時可以對其進行編輯,。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
|
package com.android777.listviewimage;
import com.android777.listviewimage.provider.ContentMeta.ContactColumns;
import android.app.ListActivity;
import android.content.ContentUris;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.ListView;
import android.widget.SimpleCursorAdapter;
public class MainActivity extends ListActivity {
/** Called when the activity is first created. */
Cursor cursor;
/**
* 需要讀取的數(shù)據(jù)庫列
*/
String[] PROJECTION = new String[]{
ContactColumns._ID,
ContactColumns.NAME,
ContactColumns.AGE,
ContactColumns.AVATAR,
ContactColumns.ADDRESS,
};
@Override
public void onCreate(Bundle savedInstanceState) {
super .onCreate(savedInstanceState);
cursor = managedQuery(ContactColumns.CONTENT_URI, PROJECTION, null , null , null );
SimpleCursorAdapter adapter = new SimpleCursorAdapter( this ,
R.layout.list_item_contact,
cursor,
PROJECTION,
new int []{ R.id.person_id , R.id.person_name,R.id.person_age , R.id.person_avatar, R.id.person_address });
setListAdapter(adapter);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.person_list_options_menu, menu);
return super .onCreateOptionsMenu(menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()){
case R.id.menu_add :
Intent intent = new Intent(Intent.ACTION_INSERT);
intent.setClass( this , ContactActivity. class );
startActivity(intent);
break ;
}
return super .onOptionsItemSelected(item);
}
@Override
protected void onListItemClick(ListView l, View v, int position, long id) {
Uri uri = ContentUris.withAppendedId(ContactColumns.CONTENT_URI, id);
Intent intent = new Intent(Intent.ACTION_EDIT);
intent.setData(uri);
intent.setClass( this , ContactActivity. class );
startActivity(intent);
}
}
|
list_item_contact.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
|
<? xml version = "1.0" encoding = "utf-8" ?>
< LinearLayout
xmlns:android = "http://schemas./apk/res/android"
android:orientation = "horizontal"
android:layout_width = "fill_parent"
android:layout_height = "fill_parent" >
< ImageView
android:layout_height = "100dip"
android:layout_width = "100dip"
android:layout_margin = "10dip"
android:id = "@+id/person_avatar"
/>
< LinearLayout android:layout_width = "fill_parent"
android:layout_height = "fill_parent"
android:orientation = "vertical"
>
< TextView
android:layout_width = "fill_parent"
android:layout_height = "wrap_content"
android:textSize = "20sp"
android:id = "@+id/person_id"
/>
< TextView
android:layout_width = "fill_parent"
android:layout_height = "wrap_content"
android:textSize = "20sp"
android:id = "@+id/person_name"
/>
< TextView
android:layout_width = "fill_parent"
android:layout_height = "wrap_content"
android:id = "@+id/person_age"
/>
< TextView
android:layout_width = "fill_parent"
android:layout_height = "wrap_content"
android:id = "@+id/person_address"
/>
</ LinearLayout >
</ LinearLayout >
|
上面代碼通過ContentProvider來獲取ListView的數(shù)據(jù)源,,所以當這個Activity在onCreate中調(diào)用managedQuery方法時,,Android OS就會根據(jù)第一個參數(shù)Uri的格式來確定由哪個ContentProvider來處理這個查詢請求,而到這里我們都還沒編寫任何ContentProvider,,所以接下來要做的就是編寫一個ContentProvider,。這個ContentProvider的主要功能就是與Sqlite數(shù)據(jù)庫進行交互,它就像是一個中間者,,Activity通過Uri跟它進行交互,,它通過判斷Uri的格式(了解Uri),跟內(nèi)部對應(yīng)的Sqlite數(shù)據(jù)庫表進行交互,,這樣分層的架構(gòu)逐步降低復(fù)雜度,,使代碼更清晰,使維護代碼變得更簡單,。
因為ContentProvider需要有一個內(nèi)部的Sqlite數(shù)據(jù)庫,,所以我們在其內(nèi)部編寫一個私有靜態(tài)內(nèi)部類,用來操作內(nèi)部的數(shù)據(jù)庫,。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
private static class DatabaseHelper extends SQLiteOpenHelper{
public DatabaseHelper(Context context){
super (context, DATABASE_NAME, null , DATABASE_VERSION);
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL( "CREATE TABLE " + TABLE_NAME + "("
+ ContactColumns._ID + " INTEGER PRIMARY KEY, "
+ ContactColumns.NAME + " TEXT, "
+ ContactColumns.AGE + " INTEGER, "
+ ContactColumns.AVATAR + " TEXT, "
+ ContactColumns.ADDRESS + " TEXT);"
);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL( "DROP TABLE IF EXISTS " + TABLE_NAME);
onCreate(db);
}
}
|
上面的數(shù)據(jù)庫helper類,,需要引用到數(shù)據(jù)庫的文件名、表名,、版本信息,。所以我們需要在ContentProvider的頂部先定義這些控制信息,同時配置UriMatcher讓ContentProvider能使用它對Uri格式進行解析:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
private static final String DATABASE_NAME = "database.db" ;
private static final String TABLE_NAME = "contact" ;
private static final int DATABASE_VERSION = 3 ;
DatabaseHelper dbhelper;
private static final int CONTACTS = 1 ;
private static final int CONTACT_ID = 2 ;
private static final UriMatcher sUriMatcher;
static {
sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
sUriMatcher.addURI(ContentMeta.AUTHORITY, "contacts" , CONTACTS);
sUriMatcher.addURI(ContentMeta.AUTHORITY, "contacts/#" , CONTACT_ID);
}
|
然后要做的就是重寫ContentProvider中的增刪改查方法,,并在它的onCreate方法中創(chuàng)建一個數(shù)據(jù)庫連接輔助對象,,就是上面的DatabaseHelper類。
1
2
3
4
5
6
7
|
@Override
public boolean onCreate() {
dbhelper = new DatabaseHelper(getContext());
return true ;
}
|
接下來我們首先寫重寫query方法,,因為應(yīng)用一進來就需要在ListView中顯示Contact的信息,,所以會第一個先調(diào)用query方法,在這個方法里,,我們要根據(jù)Uri的格式來做判斷,,因為Uri要讀取的可能是目錄信息,也可能是單條信息:
目錄信息: content://com.android777.listviewimage/contacts
單條信息: content://com.android777.listviewimage/contacts/1
然后根據(jù)不同的信息對數(shù)據(jù)庫做不同的查詢操作,,query方法代碼如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
@Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
SQLiteDatabase db = dbhelper.getReadableDatabase();
SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
switch (sUriMatcher.match(uri)){
case CONTACTS :
qb.setTables(TABLE_NAME);
return qb.query(db, projection, selection, selectionArgs, null , null , sortOrder);
case CONTACT_ID :
String contactId = uri.getPathSegments().get( 1 );
qb.setTables(TABLE_NAME);
qb.appendWhere(ContactColumns._ID + "=" + contactId);
return qb.query(db, projection, selection, selectionArgs, null , null , sortOrder);
default :
throw new IllegalArgumentException( "unknow Uri: " + uri);
}
}
|
然后記得要在AndroidMenifest.xml文件中聲明改Provider:
1
|
< provider android:name = ".provider.ContactProvider" android:authorities = "com.android777.listviewimage" />
|
代碼的運行效果如下:
當用戶點擊menu菜單,,需要提供一個按鈕讓其可以添加Contact信息,,這個在上面MainActivity代碼中已經(jīng)有了:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.person_list_options_menu, menu);
return super .onCreateOptionsMenu(menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()){
case R.id.menu_add :
Intent intent = new Intent(Intent.ACTION_INSERT);
intent.setClass( this , ContactActivity. class );
startActivity(intent);
break ;
}
|
上面使用MenuInflater從資源文件中加載menu信息,然后當用戶點擊時創(chuàng)建一個Action是INSERT的Intent,,設(shè)置對應(yīng)的Activity類是:ContactActivity.class,,然后跳轉(zhuǎn)到新建頁面。person_list_options_menu.xml文件的信息如下:
1
2
3
4
5
6
7
8
|
<? xml version = "1.0" encoding = "utf-8" ?>
< menu xmlns:android = "http://schemas./apk/res/android" >
< item android:id = "@+id/menu_add"
android:icon = "@android:drawable/ic_input_add"
android:alphabeticShortcut = 'a'
android:title = "添加人物" />
</ menu >
|
這時候點擊事件也有了,,添加Contact菜單的事件也有了,,還缺少一個用來顯示和添加Contact信息的界面:ContactActivity.java ,我們可以先創(chuàng)建它,,然后先不用寫任何東西?,F(xiàn)在運行起來效果是:
接下來下一篇就要編寫ContactActivity界面,然后進行新增和修改操作,。
|