Reputation: 1047
Goal
Display a default image when no image is downloaded from server.
Problem
I have a listview with an imageview(along with a few textbox but thats not important). My imageview downloads images for students but when the student has no image I am trying to display a default image. I have tried two things I thought should work, set a default image, or the code below. This code is taken from an activity file where I write the values from the database columns to variables (only showed img to maintain simplicity)
//Image path returned
if (javaRealObject.getString("img").equals(""))
{
imgv = (ImageView)findViewById(R.id.ivImage);
imgv.setImageResource(R.drawable.emptyhead);
Log.d("Test", "Empty");
}
else//No image found in column
{
student.setImage(javaRealObject.getString("img"));
Log.d("Test","Not Empty");
}
However I am getting a null refernce on imgv = (ImageView)findViewById(R.id.ivImage);
and I am not sure why since my image view is being declared.
Any help ti acheive the effect of a default image when none is
supplied from the column will be appreciated.
For a bit more context, the code above is an activity that calls the listview.xml, which then calls the row.xml. the imageview in question is in row.xml file.
ROW.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/LinearLayout1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="4dp"
android:orientation="vertical" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<ImageView
android:id="@+id/ivImage"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:src="@drawable/empty_head" /> //default image here
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical" >
<TextView
android:id="@+id/tvFirstName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/primary"
android:textAppearance="?android:attr/textAppearanceLarge" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
List that calls row
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ListView
android:id="@+id/list"
android:layout_width="match_parent"
android:layout_height="450dp"
tools:listitem="@layout/row" >
</ListView>
</LinearLayout>
Adapter:
public class DriverAdapter extends ArrayAdapter<Drivers> {
ArrayList<Drivers> ArrayListDrivers;
int Resource;
Context context;
LayoutInflater vi;
public DriverAdapter(Context context, int resource, ArrayList<Drivers> objects) {
super(context, resource, objects);
ArrayListDrivers = objects;
Resource = resource;
this.context = context;
vi = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null) {
convertView = vi.inflate(Resource, null);
holder = new ViewHolder();
holder.imageview = (ImageView) convertView.findViewById(R.id.ivImage);
holder.tvName = (TextView) convertView.findViewById(R.id.tvFirstName);
holder.tvDescription = (TextView) convertView.findViewById(R.id.tvLastName);
holder.tvClientid = (TextView) convertView.findViewById(R.id.tvid);
holder.tvExpires = (TextView) convertView.findViewById(R.id.tv_expdate);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
holder.imageview.setImageResource(R.drawable.ic_launcher);
new DownloadImageTask(holder.imageview).execute(ArrayListDrivers.get(position).getImage());
Glide.with(holder.imageview.getContext())
.load(new DownloadImageTask(holder.imageview).execute(ArrayListDrivers.get(position).getImage()) )
.centerCrop()
.placeholder(R.drawable.ic_launcher)
.crossFade()
.into(holder.imageview);
holder.tvName.setText(ArrayListDrivers.get(position).getFirstname());
holder.tvDescription.setText(ArrayListDrivers.get(position).getLastname());
holder.tvClientid.setText(ArrayListDrivers.get(position).getClient_id());
holder.tvExpires.setText("Expiry Date:"+ArrayListDrivers.get(position).getExpires());
return convertView;
}
static class ViewHolder {
public ImageView imageview;
public TextView tvName;
public TextView tvDescription;
public TextView tvClientid;
public TextView tvExpires;
}
private class DownloadImageTask extends AsyncTask<String, Void, Bitmap> {
ImageView bmImage;
public DownloadImageTask(ImageView bmImage) {
this.bmImage = bmImage;
}
protected Bitmap doInBackground(String... urls) {
String urldisplay = urls[0];
Bitmap cImg1 = null;
try {
byte[] decodedString = Base64.decode(urldisplay, Base64.DEFAULT);
cImg1 = BitmapFactory.decodeByteArray(decodedString, 0, decodedString.length);
} catch (Exception e) {
Log.e("Error", e.getMessage());
e.printStackTrace();
}
return cImg1;
}
protected void onPostExecute(Bitmap result) {
bmImage.setImageBitmap(result);
}
}
}
Upvotes: 17
Views: 52030
Reputation: 832
Add gradle dependency:
implementation 'com.github.bumptech.glide:glide:4.11.0'
implementation 'jp.wasabeef:glide-transformations:4.0.0'
In order to use it:
Glide.with(mActivity.getApplicationContext())
.load(EndPoints.ROWS_IMAGE_URL + ImageUrl)
.asBitmap()
.centerCrop()
.transform(new CropCircleTransformation(mActivity.getApplicationContext()))
.apply(new RequestOptions().
.placeholder(drawable)
.error(drawable)
.override(AppConstants.ROWS_IMAGE_SIZE, AppConstants.ROWS_IMAGE_SIZE))
.into(target);
The following line of code causes a default image to be displayed in the event of an error:
.placeholder(drawable)
Upvotes: 2
Reputation: 2285
Your Listview's adapter is responsible for managing your rows' views. What is your adapter looks like? (the object that you call listview.setAdapter(Adapter) on).
Inside your adapter, there is a method call getView that you need to override and return a view object. You need to call view.findviewbyId() on this view object, not on your activity
UPDATE Try remove these lines
holder.imageview.setImageResource(R.drawable.ic_launcher);
new DownloadImageTask(holder.imageview).execute(ArrayListDrivers.get(position).getImage());
P/s can you explain the purpose of calling Glide.with(Context).load(object)? thank you
Upvotes: 2
Reputation: 1047
I solved this by doing something very simple. In post exeucte of the aync method I simply said.
if (result != null){
bmImage.setImageBitmap(result);
}
That way if it is null, the default imageview will not be over written with "null" . Thanks for the guidance
Upvotes: 2
Reputation: 2188
In your AsyncTask constructor
try to initialize your Image view like this
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View convertView = inflater.inflate(R.layout.row, null, false);
ivImage= (ImageView ) convertView.findViewById(R.id.ivImage);
here row.xml
where you declare ImageView ... and make sure ivImage is global variable... now ivImage is not null. i checked it.. but its better to use adapter
class for managing a listview row....
Upvotes: 1
Reputation: 76942
There is a better way to do that, you can use one of the image loading libs like:
An image loading and caching library for Android focused on smooth scrolling
and it will take you just one line to do what you want.
Glide.with(myFragment)
.load(url)
.placeholder(R.drawable.loading_spinner)
.into(myImageView);
it's easier and cleaner.
Upvotes: 23
Reputation: 89
This method would work - Set a default image in your xml code, which will be displayed when student has no image. Dynamically set image using setImageResource(...) if you got an image.
Recheck the id of your ImageView as you are getting null reference error and if this does not solve the problem then please post the complete activity code.
Upvotes: 1