使用多线程使带有图像的 ListView 更快 (Android API 10)

Making faster ListView with images using multi-threading (Android API 10)

我搜索了答案,但 none 似乎对我的情况有所帮助。 应用最小 SDK - API 10

问题 - 带图像的 ListView 速度慢。

原因 - 数据加载在 UI 线程上(没有图像一切正常)并且可能是我获取图像资源 ID 的方式。


我有一个带有两个 TextView 和一个 ImageView 的 ListView。我使用 SQLiteAssetHelper 从插入的数据库填充 ListView 文本。

table例子:

specie_table
_id | LITHUANIAN          |   LATIN
0   | Paprastasis varnėnas| Sturnus vulgaris
1   | Juodasis strazdas   | Turdus merula

图片加载

我将 PNG 图片保存在 drawable 文件夹中。

我从数据库中的数据中获取图片资源id:

在specie_table.db "Regulus regulus" -> getImageName(name) returns "regulus_regulus" -> getResId(name, class) returns drawable id -> setImage(ImageView, name) 设置ImageView的资源

我应该采取不同的方法吗?


List_item.xml

<ImageView
    android:id="@+id/icon"
    android:layout_width="100dp"
    android:layout_height="100dp"
    android:layout_marginTop="6dip"
    android:layout_marginLeft="6dip"
    android:layout_marginRight="10dip"
    android:src="@drawable/ic_bird_grey"
    />

<LinearLayout
    android:layout_width="fill_parent"
    android:layout_height="100dp"
    android:orientation="vertical"
    android:layout_toRightOf="@id/icon"
    android:paddingTop="15dp">

    <TextView
        android:id="@+id/firstLine"
        android:layout_width="match_parent"
        android:layout_height="35sp"
        android:text="Lithuanian title"
        android:textSize="20sp"
        />
    <TextView
        android:id="@+id/secondLine"
        android:layout_width="match_parent"
        android:layout_height="24dp"
        android:text="Latin title"
        android:textSize="12sp" />

</LinearLayout>


SpecieCursorAdapter.java

public class SpecieCursorAdapter extends CursorAdapter {


SpecieCursorAdapter(Context context, Cursor cursor) {
    super(context, cursor, 0);
}

@Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
    return LayoutInflater.from(context).inflate(R.layout.list_item, parent, false);
}

@Override
public void bindView(View view, Context context, Cursor cursor) {

    SpecieHolder holder = null;

    holder = new SpecieHolder();
    holder.imgIcon = (ImageView) view.findViewById(R.id.icon);
    holder.txtTitle1 = (TextView) view.findViewById(R.id.firstLine);
    holder.txtTitle2 = (TextView) view.findViewById(R.id.secondLine);

    String nameLT = cursor.getString(cursor.getColumnIndex(SpecieTable.LIT_COL));
    String nameLOT = cursor.getString(cursor.getColumnIndex(SpecieTable.LAT_COL));


    holder.txtTitle1.setText(nameLT);
    holder.txtTitle2.setText(nameLOT);
    setImage(holder.imgIcon, nameLOT);  //this makes everything laggy but i dont know how to make it as seperate thread.

}
static class SpecieHolder
{
    ImageView imgIcon;
    TextView txtTitle1;
    TextView txtTitle2;
}

public void setImage(ImageView mainImage, String resource){ //these methods are for getting the image resource id from String (latin name).

    int id = getResId(getImageName(resource), R.drawable.class);
    if(id != -1)
        mainImage.setImageResource(id);
    else
        mainImage.setImageResource(R.drawable.ic_bird_grey);

}
public int getResId(String resourceName, Class<?> c) {
    try {
        Field idField = c.getDeclaredField(resourceName);
        return idField.getInt(idField);
    } catch (Exception e) {
        return -1;
    }
}
public String getImageName(String resource){
    String string = resource.toLowerCase();
    string = string.replace(' ', '_');
    string = string.replace(".", "");
    return string;
}}

ListActivity.java

public class ListActivity extends AppCompatActivity {

public final static String EXTRA_MESSAGE = "bird info";
ListView listView;
ListActivity context = this;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_list);
    Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
    setSupportActionBar(toolbar);

    listView = (ListView)findViewById(R.id.listView);

    Intent intent = getIntent();
    Habitats habitat = Habitats.detachFrom(intent); //this is an enum type sent as String, converted back to enum.

    Cursor cursor;

    DatabaseAccess databaseAccess = DatabaseAccess.getInstance(this);
    databaseAccess.open();
    cursor = databaseAccess.getCursorByHabitat(habitat);
    databaseAccess.close();

    SpecieCursorAdapter adapter = new SpecieCursorAdapter(this, cursor);

    listView.setAdapter(adapter);// how to seperate the image loading?

}

例子会很有帮助!我会插入任何需要的额外代码。

尝试使用 Volley HTTP 库来加快数据传输和图像加载速度。 Volley 是一个 HTTP 库,它使 Android 应用程序的网络更容易,最重要的是,速度更快。

点击这些链接

https://developer.android.com/training/volley/index.html

An example listview with image loading using Volley library

您可以使用@abhilash 建议的现有库,也可以自行实现

在 android 中,在列表视图中显示带有图像的项目是这样的(示例):

  • 列表视图需要显示位置 #35 的项目
  • listview 要求其适配器为位于 #35 的项目填充 listviewitemview
  • listviewitemview 要么从不再可见的旧 listviewitemview 回收,要么创建新的 listviewitemview
  • 每个 listviewitemview 都有一个对应的带有 imageID 的 viewHolder 和一个 bitmap-gui 元素
  • listviewitemview 中的图像最初加载了一个占位符图像,该图像在图像加载完成之前一直可见。
  • 适配器开始在后台加载图像(异步任务),获取带有 imageID 的 viewHolder。
  • 当背景中的图像加载完成时,viewholder-gui 元素获取加载的图像。

GridView 和 ListView 的工作方式相同。

这是来自 APhotoManager. It contains a GalleryCursorFragment 的工作示例,其中包含带有嵌入式 GridCellViewHolder

的 gridview

对于异步图像加载(和缓存),使用为此创建的库,例如 Glide or Fresco

按照@Neil 和@shelll 的建议,我使用了Glide 库。我相应地修改了我的代码:

添加到build.gradle

compile 'com.github.bumptech.glide:glide:3.7.0'

通过更改

修改了 bindView() 方法
setImage(holder.imgIcon, nameLOT);

int imageId = getResId(getImageName(nameLOT), R.drawable.class);
if(imageId == -1)
    imageId = R.drawable.ic_bird_grey;

Glide
        .with(holder.imgIcon.getContext())
        .load(imageId)
        .into(holder.imgIcon);