SimpleCursorAdapter 中的图像
Posted
技术标签:
【中文标题】SimpleCursorAdapter 中的图像【英文标题】:Images in SimpleCursorAdapter 【发布时间】:2011-10-06 08:04:49 【问题描述】:我正在尝试使用SimpleCursorAdapter
和ViewBinder
从数据库中获取图像并将其放入我的ListView
项目视图中。这是我的代码:
private void setUpViews()
mNewsView = (ListView) findViewById(R.id.news_list);
Cursor cursor = getNews();
SimpleCursorAdapter curAdapter = new SimpleCursorAdapter(
getApplicationContext(), R.layout.cursor_item, cursor,
new String[] "title", "content", "image" ,
new int[] R.id.cursor_title, R.id.cursor_content,
R.id.news_image );
ViewBinder viewBinder = new ViewBinder()
public boolean setViewValue(View view, Cursor cursor,
int columnIndex)
ImageView image = (ImageView) view;
byte[] byteArr = cursor.getBlob(columnIndex);
image.setImageBitmap(BitmapFactory.decodeByteArray(byteArr, 0, byteArr.length));
return true;
;
ImageView image = (ImageView) findViewById(R.id.news_image);
viewBinder.setViewValue(image, cursor, cursor.getColumnIndex("image"));
curAdapter.setViewBinder(viewBinder);
mNewsView.setAdapter(curAdapter);
我得到:
android.database.CursorIndexOutOfBoundsException: Index -1 requested, with a size of 60
在执行byte[] byteArr = cursor.getBlob(columnIndex);
时。有谁知道我做错了什么?
【问题讨论】:
【参考方案1】:我扩展了 SimpleCursorAdapter,虽然我没有使用 ViewBinder,但这里是我的代码,用于在列表视图的 sqlite 数据库中使用存储为 blob 的图像。这是改编自我读过的一篇文章here。
我的一行布局文件是:
row_layout_two_line.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_
android:layout_
android:background="@drawable/select_item">
<ImageView
android:id="@+id/pic"
android:layout_
android:layout_
android:layout_marginLeft="10dp"
android:contentDescription="@string/imagedesc"
android:src="@drawable/icon"
android:layout_gravity="center_vertical">
</ImageView>
<LinearLayout
android:id="@+id/linearLayout0"
android:layout_
android:layout_
android:layout_gravity="center_vertical"
android:orientation="vertical" >
<LinearLayout
android:id="@+id/linearLayout1"
android:layout_
android:layout_ >
<TextView
android:id="@+id/label"
android:layout_
android:layout_
android:layout_marginLeft="10dp"
android:text="@+id/label"
android:textStyle="bold"
android:textColor="#000"
android:textSize="20sp" >
</TextView>
<TextView
android:id="@+id/label1"
android:layout_
android:layout_
android:layout_marginLeft="10dp"
android:text="@+id/label1"
android:textStyle="bold"
android:textColor="#000"
android:textSize="20sp" >
</TextView>
</LinearLayout>
<TextView
android:id="@+id/label2"
android:layout_
android:layout_
android:layout_marginLeft="35dp"
android:text="@+id/label2"
android:textColor="#000"
android:textSize="15sp" >
</TextView>
</LinearLayout>
调用代码
...
adapter = null;
mCursor = search();
startManagingCursor(mCursor);
// Now create a new list adapter bound to the cursor.
BaseAdapter adapter = new ImageCursorAdapter(this, // Context.
R.layout.row_layout_two_line, // Specify the row template
// to use (here, two
// columns bound to the
// two retrieved cursor
// rows).
mCursor, // Pass in the cursor to bind to.
// Array of cursor columns to bind to.
new String [] "personImage", "firstName", "lastName", "title",
// Parallel array of which template objects to bind to those
// columns.
new int[] R.id.pic, R.id.label, R.id.label1, R.id.label2 );
// Bind to our new adapter.
setListAdapter(adapter);
...
ImageCursorAdapter.java
import android.content.Context;
import android.database.Cursor;
import android.graphics.BitmapFactory;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.SimpleCursorAdapter;
import android.widget.TextView;
public class ImageCursorAdapter extends SimpleCursorAdapter
private Cursor c;
private Context context;
public ImageCursorAdapter(Context context, int layout, Cursor c, String[] from, int[] to)
super(context, layout, c, from, to);
this.c = c;
this.context = context;
public View getView(int pos, View inView, ViewGroup parent)
View v = inView;
if (v == null)
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = inflater.inflate(R.layout.row_layout_two_line, null);
this.c.moveToPosition(pos);
String firstName = this.c.getString(this.c.getColumnIndex("firstName"));
String lastName = this.c.getString(this.c.getColumnIndex("lastName"));
String titleStr = this.c.getString(this.c.getColumnIndex("title"));
byte[] image = this.c.getBlob(this.c.getColumnIndex("personImage"));
ImageView iv = (ImageView) v.findViewById(R.id.pic);
if (image != null)
// If there is no image in the database "NA" is stored instead of a blob
// test if there more than 3 chars "NA" + a terminating char if more than
// there is an image otherwise load the default
if(image.length > 3)
iv.setImageBitmap(BitmapFactory.decodeByteArray(image, 0, image.length));
else
iv.setImageResource(R.drawable.icon);
TextView fname = (TextView) v.findViewById(R.id.label);
fname.setText(firstName);
TextView lname = (TextView) v.findViewById(R.id.label1);
lname.setText(lastName);
TextView title = (TextView) v.findViewById(R.id.label2);
title.setText(titleStr);
return(v);
这是最后的样子
【讨论】:
如果我要在 getView 中手动构建视图,那么使用 SimpleCursorAdapter 并告诉它来自列的意义何在????【参考方案2】:我认为 cursor.moveToFirst()
尚未被调用,因此光标正在抛出 android.database.CursorIndexOutOfBoundsException.
在使用cursor
之前,您应该始终通过调用cursor.moveToFirst()
检查光标是否为空。这也会将光标定位在第一个位置。
【讨论】:
【参考方案3】:联系人列表使用 ListView 和 SimpleCusorAdapter 以及联系人照片和过滤器/搜索
我一直在寻找一个更简单的解决方案,我的最终解决方案与 Daniel 在这里提到的解决方案非常接近,所以我想我应该在这里分享我的解决方案。我正在使用 Fragment 将设备联系人显示为带有图片的名称列表。结果与 Daniel 的结果非常相似,但仅显示名称。了解代码后,可以很容易地显示更多信息。
在我的例子中,我使用 PHOTO_URI 从 ContactsContract 获取姓名和图片,因此我不必像 Daniel 那样扩展 SimpleCursorAdapter
。
我的示例还包括过滤联系人列表作为SearchView
中的用户类型以查找联系人
我有一个名为FragmentContacts
的片段和两个布局文件,第一个是主布局frag_contacts.xml
,第二个是每个联系人行list_row_contact
。
frag_contacts.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_
android:layout_
android:orientation="vertical">
<FrameLayout
android:layout_
android:layout_
android:layout_weight="1"
android:background="@android:color/holo_blue_light"
android:padding="8dip">
<android.support.v7.widget.SearchView
android:layout_
android:layout_
android:background="@android:color/white"
android:id="@+id/searchView"/>
</FrameLayout>
<LinearLayout
android:id="@+id/ll_contactList"
android:layout_
android:layout_
android:layout_weight="9"
android:orientation="vertical" >
<ListView
android:id="@+id/lv_ContactList"
android:layout_
android:layout_
android:divider="#aaaaaa"
android:dividerHeight="1dp" >
</ListView>
</LinearLayout>
</LinearLayout>
list_row_contact.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_
android:layout_
android:orientation="horizontal"
android:descendantFocusability="blocksDescendants">
<FrameLayout
android:layout_
android:layout_
android:layout_weight="1"
android:gravity="center">
<ImageView
android:id="@+id/imgContact"
android:layout_
android:layout_
android:layout_gravity="center"
android:layout_margin="5dip" />
</FrameLayout>
<TextView
android:id="@+id/contact_name"
android:layout_
android:layout_
android:layout_weight="6"
android:gravity="center_vertical"
android:textSize="18sp"
android:paddingLeft="10dip">
</TextView>
</LinearLayout>
FragmentContacts.java
public class FragmentContacts extends Fragment
implements LoaderManager.LoaderCallbacks<Cursor>
private ListView lv_ContactList;
private SearchView searchView;
private SimpleCursorAdapter mCursorAdapter;
private static final String DISPLAY_NAME = Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB ? Contacts.DISPLAY_NAME_PRIMARY : Contacts.DISPLAY_NAME;
private static final String[] contactsColumns = Contacts._ID, Contacts.LOOKUP_KEY, DISPLAY_NAME, Contacts.PHOTO_URI ;
private final String contactsFilter = "(" +Contacts.HAS_PHONE_NUMBER+ "='1') AND (" + Contacts.IN_VISIBLE_GROUP + "='1')";
private final String contactsSortOrder = DISPLAY_NAME + " COLLATE LOCALIZED ASC";
private final static String[] listDisplayColumns = DISPLAY_NAME, Contacts.PHOTO_URI ;
private final static int[] listDataViewIDs = R.id.contact_name, R.id.imgContact ;
String[] mSelectionArgs;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
View view = inflater.inflate(R.layout.frag_contacts, null);
lv_ContactList = (ListView)view.findViewById(R.id.lv_ContactList);
searchView = (SearchView)view.findViewById( R.id.searchView);
return view;
@Override
public void onResume()
super.onResume();
mCursorAdapter= new SimpleCursorAdapter( getActivity(), R.layout.list_row_contact, null, listDisplayColumns, listDataViewIDs, 0);
lv_ContactList.setAdapter(mCursorAdapter);
getLoaderManager().initLoader(0, null, this);
searchView.setOnQueryTextListener( new SearchView.OnQueryTextListener()
@Override
public boolean onQueryTextSubmit( String query ) return false;
@Override
public boolean onQueryTextChange( String newText )
if( newText.isEmpty() ) mSelectionArgs = null;
else mSelectionArgs = new String[] "%"+newText.trim()+"%";
getLoaderManager().restartLoader( 0, null, FragmentContacts.this );
return false;
);
@Override
public Loader<Cursor> onCreateLoader( int id, Bundle args )
if(mSelectionArgs == null)
return new CursorLoader( getActivity(), Contacts.CONTENT_URI, contactsColumns, contactsFilter, null, contactsSortOrder );
else
return new CursorLoader( getActivity(), Contacts.CONTENT_URI, contactsColumns, contactsFilter + " AND (" + DISPLAY_NAME+" LIKE ?)", mSelectionArgs, contactsSortOrder );
@Override
public void onLoadFinished( Loader<Cursor> loader, Cursor data )
mCursorAdapter.swapCursor(data);
@Override
public void onLoaderReset( Loader<Cursor> loader )
mCursorAdapter.swapCursor(null);
【讨论】:
以上是关于SimpleCursorAdapter 中的图像的主要内容,如果未能解决你的问题,请参考以下文章
SimpleCursorAdapter无法在MainActivity中使用
数据库更改时,Android SimpleCursorAdapter 不会更新
使用详解及源码解析Android中的AdapterBaseAdapterArrayAdapterSimpleAdapter和SimpleCursorAdapter
当 SimpleCursorAdapter 将值从表添加到 listView 时检查列值