问题
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.setImageBitmapyou're trying to change aViewin 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
setImageBitmapmight 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