SimpleCursorAdapter中的图片

6

我正在尝试使用带有 ViewBinderSimpleCursorAdapter 从数据库中获取图像并将其放入我的 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);时出现问题。有没有人知道我做错了什么?

3个回答

11

我扩展了SimpleCursorAdapter,虽然我没有使用ViewBinder,但以下是我的代码,用于在ListView中使用存储为blob的图像在SQLite数据库中。这是从我读到的一篇文章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_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/select_item">

<ImageView 
    android:id="@+id/pic"
    android:layout_width="40dp"
    android:layout_height="40dp"
    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_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="center_vertical" 
    android:orientation="vertical" >

    <LinearLayout
        android:id="@+id/linearLayout1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" >

        <TextView
            android:id="@+id/label"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            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_width="wrap_content"
            android:layout_height="wrap_content"
            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_width="wrap_content"
        android:layout_height="wrap_content"
        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);
}

}

这是最终的效果

在这里输入图片描述


3
如果我打算在getView中手动构建视图,那么使用SimpleCursorAdapter并告诉它列的来源有什么意义? - Radu

4

使用ListView和SimpleCursorAdapter实现带有联系人照片和过滤/搜索功能的联系人列表

我一直在寻找更简单的解决方案,我的最终解决方案与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_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
    <FrameLayout
        android:layout_width="fill_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:background="@android:color/holo_blue_light"
        android:padding="8dip">

        <android.support.v7.widget.SearchView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="@android:color/white"
            android:id="@+id/searchView"/>
    </FrameLayout>
    <LinearLayout
        android:id="@+id/ll_contactList"
        android:layout_width="fill_parent"
        android:layout_height="0dp"
        android:layout_weight="9"
        android:orientation="vertical" >
        <ListView
            android:id="@+id/lv_ContactList"
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            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_width="fill_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal"
    android:descendantFocusability="blocksDescendants">

    <FrameLayout
        android:layout_height="match_parent"
        android:layout_width="0dp"
        android:layout_weight="1"
        android:gravity="center">

        <ImageView
            android:id="@+id/imgContact"
            android:layout_width="35dip"
            android:layout_height="35dip"
            android:layout_gravity="center"
            android:layout_margin="5dip" />
    </FrameLayout>

    <TextView
        android:id="@+id/contact_name"
        android:layout_height="match_parent"
        android:layout_width="0dp"
        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);
    }
}

4

我认为 cursor.moveToFirst() 没有被调用,所以游标会抛出 android.database.CursorIndexOutOfBoundsException 异常。

在使用 cursor 之前,您应该始终检查游标是否为空,方法是调用 cursor.moveToFirst()。这也将把游标定位到第一个位置。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接