如何实现 Asynctask 在 ArrayAdapter 中加载图像

Posted

技术标签:

【中文标题】如何实现 Asynctask 在 ArrayAdapter 中加载图像【英文标题】:How to implement Asynctask to load images in ArrayAdapter 【发布时间】:2018-06-28 20:29:33 【问题描述】:

我正在开发一个课程列表应用程序,该应用程序通过 ArrayAdapter 将每个课程标题与课程图像一起加载到列表视图中,我想实现异步任务以在列表视图和 ArrayAdapter 之间加载图像,因为列表视图在滚动时会滞后,请帮帮我。

MainActivity.java

package com.emmakade.okt;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;

import java.util.List;

public class MainActivity extends AppCompatActivity 


    protected List<Course> data;

    @Override
    protected void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        data = DataProvider.getData();

        ArrayAdapter<Course> courseArrayAdapter =
                new CourseArrayAdapter(this, 0, data);
        ListView listView = (ListView) findViewById(android.R.id.list);
        listView.setAdapter(courseArrayAdapter);

        listView.setOnItemClickListener(new AdapterView.OnItemClickListener() 
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) 
                Course course = data.get(position);
                displayDetail(course);
            
        );

    


    @Override
    public boolean onCreateOptionsMenu(Menu menu) 
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    

    @Override
    public boolean onOptionsItemSelected(MenuItem item) 
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) 
            return true;
        

        return super.onOptionsItemSelected(item);
    

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) 
        if (requestCode == DETAIL_REQUEST_CODE) 
            if (resultCode == RESULT_OK) 
                String msg = data.getStringExtra("resultMessage");
                Toast.makeText(this, msg, Toast.LENGTH_LONG).show();
            
        
    

    class CourseArrayAdapter extends ArrayAdapter<Course>

        Context context;
        List<Course> objects;

        public CourseArrayAdapter(Context context, int resource, List<Course> objects) 
            super(context, resource, objects);

            this.context = context;
            this.objects = objects;
        

        @Override
        public View getView(int position, View convertView, ViewGroup parent) 

            Course course = objects.get(position);

            LayoutInflater inflater =
                    (LayoutInflater) context.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);

            View view = inflater.inflate(R.layout.course_item, null);

            TextView tv = (TextView) view.findViewById(R.id.tvTitle);
            tv.setText(course.getTitle());

            ImageView iv = (ImageView) view.findViewById(R.id.imageCourse);
            int res = context.getResources().getIdentifier(
                    "image_" + course.getCourseNumber(), "drawable",
                    context.getPackageName()
            );
            iv.setImageResource(res);

            return view;
        
    

activity_main.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_
    android:layout_
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".MainActivity">

    <ImageView
        android:layout_
        android:layout_
        android:id="@+id/imageLogo"
        android:layout_alignParentStart="true"
        android:layout_alignParentTop="true"
        android:src="@drawable/academy"/>
    <TextView
        android:id="@+id/txtOutput"
        android:layout_
        android:layout_
        android:text="@string/course_catalog"
        android:layout_alignBottom="@+id/imageLogo"
        android:layout_toEndOf="@+id/imageLogo"
        android:layout_marginStart="20dp"
        android:layout_marginBottom="15dp"
        android:textSize="28sp" />

    <ListView
        android:layout_
        android:layout_
        android:id="@android:id/list"
        android:layout_below="@+id/imageLogo"
        android:layout_marginTop="10dp"
        android:layout_alignParentStart="true" />

</RelativeLayout>

course_item.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_
    android:layout_
    android:padding="10dp">

    <ImageView
        android:layout_
        android:layout_
        android:id="@+id/imageCourse" />
    <TextView
        android:layout_
        android:layout_
        android:id="@+id/tvTitle"
        android:layout_toEndOf="@+id/imageCourse"
        android:layout_marginStart="10dp"
        android:textSize="18sp"/>
</RelativeLayout>

enter image description here

【问题讨论】:

【参考方案1】:

我建议您使用Glide 库进行异步图像加载、缓存和显示。

添加依赖

implementation 'com.github.bumptech.glide:glide:4.5.0'
annotationProcessor 'com.github.bumptech.glide:compiler:4.5.0'

在适配器中这样使用

Glide.with(this).load("url").into(imageView);

ImageView iv = (ImageView) view.findViewById(R.id.imageCourse);
        int res = context.getResources().getIdentifier(
                "image_" + course.getCourseNumber(), "drawable",
                context.getPackageName()
        );
 Glide.with(this).load(res).into(iv);

【讨论】:

将库加载到我的 build.gradle 时出错。它说找不到 Gradle DSL 方法:'implementation()' 使用编译'com.github.bumptech.glide:glide:3.6.1'【参考方案2】:

您可以使用 handler,因为 asynctask 将在另一个线程上工作,但您不能从另一个线程而不是主线程更新 ui。还可以考虑使用glide、picasso 之类的库。这些库可以有效地缓存图像并以更高的性能工作。

有一个Handler的例子。

Handler handler = new Handler();
            handler.post(() -> 
                profilephoto.setImageBitmap(pp);
            );

【讨论】:

复制粘贴即可。 "profilephoto" 是你的 imageview,"pp" 是你的位图。

以上是关于如何实现 Asynctask 在 ArrayAdapter 中加载图像的主要内容,如果未能解决你的问题,请参考以下文章

我应该如何实现我的 AsyncTask 类?

如何在 Android 中运行 AsyncTask?

如何在 AsyncTask 中更新 ArrayList 的内容?

Android:如何将参数传递给 AsyncTask 的 onPreExecute()?

Android_AsyncTask学习

AsyncTask 替代背景图像下载? (AsyncTask ---------已弃用)