Android - Set the Source of an ImageView inside a custom listView adapter from the getView function does not work properly

大憨熊 提交于 2019-12-12 03:07:57

问题


Apologies for the long title.

I am building an Android application where an activity contains a custom listView. In the layout of my custom listView, I have an image view and three textViews. I am fetching the data from the database and I have no issues with the row data as they're accurate. However, I have issues with displaying the ImageViews.

What I do to populate the imageView is that I get the imagePath stored from the database, parse that URL (local server only), then set the ImageViews Bitmap with that.

During the getView function of my customListView class, I create a thread that processes the url from the database and then I parse that, then set that as the ImageView's bitmap.

Here is my getView function:

public View getView(int position, View convertView, ViewGroup parent) {

    if (convertView == null) {

        convertView = layoutInflater.inflate(R.layout.nominees_list_layout, null);
        holder = new ViewHolder();

        holder.firstName = (TextView) convertView.findViewById(R.id.nomineesListFirstName);
        holder.middleName = (TextView) convertView.findViewById(R.id.nomineesListMiddleName);
        holder.lastName = (TextView) convertView.findViewById(R.id.nomineesListLastName);
        holder.photo = (ImageView) convertView.findViewById(R.id.nomineesListCandidatePhoto);


        convertView.setTag(holder);
    }
    else {
        holder = (ViewHolder) convertView.getTag();
    }

    holder.firstName.setText(listData.get(position).getFirst_name());
    holder.middleName.setText(listData.get(position).getMiddle_name());
    holder.lastName.setText(listData.get(position).getLast_name());

    new setDisplayPhoto().execute(listData.get(position).getPicture_path());

    return convertView;
}

As you can see, I am initializing the view components then setting their values based on the listData taken from the database. The data displayed are all correct. Then, what I do for the imageView is that I create an AsyncTask and feed the data there.

Here is my AsyncTask:

private class setDisplayPhoto extends AsyncTask<String, Void, String> {
    String toastMessage = "Downloading nominees photo finished.";

    Bitmap mIcon_val;

    @Override
    protected void onPreExecute() {
        super.onPreExecute();
    }

    @Override
    protected String doInBackground(String... params) {

        Log.d("","doInBackGround Started");

        String photo_url_str  = "http://192.168.0.10:8888/server/path/here/"
                + params[0];

        try {
            Log.d("","photo_url_str = " + photo_url_str);
            newurl = new URL(photo_url_str);
        } catch (MalformedURLException e) {
            e.printStackTrace();
        }
        try {

            mIcon_val = BitmapFactory.decodeStream(newurl.openConnection().getInputStream());

            holder.photo.setImageBitmap(mIcon_val);

        } catch (IOException e) {
            e.printStackTrace();
        }


        return "Executed!";
    }

    @Override
    protected void onPostExecute(String result) {
        super.onPostExecute(result);
        Toast.makeText(context, toastMessage, Toast.LENGTH_LONG).show();
    }

However, the photos do not appear, and if they do, sometimes the photos are jumbled up.

Can someone help me with how to properly set the image source of an imageView during the getView function of the customListView Adapter when the source is taken from a local server? Thank you for any help.


回答1:


the reason it's not working it's because dealing with image download, cache and view recycling is way way more complex than what your code is handling.

I can point it out a few things I can see it's wrong from your code, but for sure there's more:

  • there's no RAM cache, that means the moment the user scrolls a view out if view and then back into view, the image will be downloaded again from the server.
  • there's no disk cache, that means that if the user scrolls too far in a list, or if he/she leaves the app for a few minutes to later come back, the image will be downloaded again from the server
  • on this line holder.photo.setImageBitmap you're trying to change a View in a background thread.
  • AsyncTask (starting on some API) is a mono-thread class, meaning all your downloads will be queue in happen one after the other, so probably the user will be staring at a blank screen for a while before seeing anything.
  • you're not canceling the task, so during recycling, the call setImageBitmap might be happening on the wrong item.

replace the line:

new setDisplayPhoto().execute(listData.get(position).getPicture_path());

with:

Picasso.with(convertView.getContext())
    .load("http://192.168.0.10:8888/server/path/here/" +
                       listData.get(position).getPicture_path())
    .into(holder.photo);

for that to work you'll need one extra libary that you can add by adding the following line on your manifest:

compile 'com.squareup.picasso:picasso:2.5.2'

for more info on the library check this: http://square.github.io/picasso/




回答2:


package com.example.jojo.gridview;
import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;

public class GirdViewAdapter extends BaseAdapter {
    private Activity activity;
    private ArrayList<String> ar;
    private LayoutInflater inflater;

    public GirdViewAdapter(ArrayList<String> ar, Activity con)
    {
        activity = con;
        this.ar=ar;
        inflater = (LayoutInflater) activity
                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    }

    private class ViewHolder {
        public TextView textView;
        public ImageView imageView;
    }

    @Override
    public int getCount() {
        // TODO Auto-generated method stub
        return ar.size();
    }

    @Override
    public Object getItem(int arg0) {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public long getItemId(int arg0) {
        // TODO Auto-generated method stub
        return 0;
    }

    @Override
    public View getView(int position, View arg1, ViewGroup arg2) {
        // TODO Auto-generated method stub
        View rowView = arg1;
        ViewHolder viewHolder;
        if (arg1 == null) {
            rowView = inflater.inflate(R.layout.style_view, null);
            viewHolder = new ViewHolder();
            viewHolder.textView = (TextView) rowView.findViewById(R.id.textView);
            viewHolder.imageView = (ImageView) rowView.findViewById(R.id.imageView);
            rowView.setTag(viewHolder);
        } else
            viewHolder = (ViewHolder) rowView.getTag();
        String rowData[] = this.ar.get(position).split("\\|");
        viewHolder.textView.setText(rowData[0] );
        setImageView(viewHolder.imageView, rowData[1] );
        return rowView;
    }

    private void setImageView(ImageView imageView, String url) {
        class ImageDownloadHelper extends AsyncTask<String, String, Bitmap> {
            @Override
            protected Bitmap doInBackground(String... params) {
                // TODO Auto-generated method stub
                URL url;
                String _url = params[0];
                Log.e("url",_url );

                BufferedOutputStream out;
                InputStream in;
                BufferedInputStream buf;

                try {
                    url = new URL(_url);
                    in = url.openStream();
                    buf = new BufferedInputStream(in);

                    Bitmap bMap = BitmapFactory.decodeStream(buf);
                    if (in != null) {
                        in.close();
                    }
                    if (buf != null) {
                        buf.close();
                    }
                    return bMap;
                } catch (Exception e) {
                    Log.e("Error reading file", e.toString());
                }
                return null;
            }
        }

        ImageDownloadHelper downloadHelper = new ImageDownloadHelper();
        downloadHelper.execute(url);
        try {
            imageView.setImageBitmap(downloadHelper.get());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}


来源:https://stackoverflow.com/questions/29489978/android-set-the-source-of-an-imageview-inside-a-custom-listview-adapter-from-t

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!