I'm trying to fetch JSON data and display it in my ListView using ArrayAdapter. Anyways, in my adapter, I'm using Universal Image Loader from https://github.com/nostra13/Android-Universal-Image-Loader and the other data were loaded correctly except for the images. Some images were displayed correctly, some should not be on a specific item, and some were not loaded completely.
This is my calling fragment:
public class SampleFragment extends Fragment implements
OnItemClickListener {
private ListView songsListView;
private ArrayList<String> list;
private ArrayAdapter<String> dataAdapter;
private View rootView;
private Button selectReferenceSong;
private Fragment memberFragment;
private String[] songsArray;
private ArrayAdapter<String> arrayAdapter;
private ArrayList<ReferenceTracks> arrayOfList;
private String bufferString;
private static final String rssFeed = "https://dl.dropboxusercontent.com/u/32769459/reference_tracks.json";
private static final String TAG_MUSIC = "music";
private static final String TAG_SONG = "song";
private static final String TAG_TITLE = "title";
private static final String TAG_ARTIST = "artist";
private static final String TAG_DURATION = "duration";
private static final String TAG_THUMBURL = "thumb_url";
public SampleFragment() {
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
rootView = inflater.inflate(R.layout.sample_layout, container, false);
songsListView = (ListView) rootView.findViewById(R.id.songsListView);
songsListView.setOnItemClickListener(this);
arrayOfList = new ArrayList<ReferenceTracks>();
if (Utility.isNetworkAvailable(getActivity())) {
new AsynchronousTask().execute(rssFeed);
} else {
Toast.makeText(getActivity().getApplicationContext(),
"No Network Connection!", Toast.LENGTH_SHORT).show();
}
return rootView;
}
@Override
public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
// TODO Auto-generated method stub
}
/**
*
* @Asynchronous class
*/
public class AsynchronousTask extends AsyncTask<String, Void, String> {
ProgressDialog pDialog;
private RowAdapter objRowAdapter;
@Override
protected void onPreExecute() {
super.onPreExecute();
pDialog = new ProgressDialog(getActivity());
pDialog.setMessage("Loading...");
pDialog.setCancelable(false);
pDialog.show();
}
@Override
protected String doInBackground(String... params) {
Thread.currentThread().setPriority(Thread.MAX_PRIORITY);
return Utility.getJSONString(params[0]);
}
@Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
if (null != pDialog && pDialog.isShowing()) {
pDialog.dismiss();
}
if (null == result || result.length() == 0) {
Toast.makeText(getActivity().getApplicationContext(),
"No data found from web.", Toast.LENGTH_SHORT).show();
} else {
try {
JSONObject topObject = new JSONObject(result);
JSONObject musicObject = topObject.getJSONObject(TAG_MUSIC);
JSONArray jsonArray = musicObject.getJSONArray(TAG_SONG);
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject objJson = jsonArray.getJSONObject(i);
ReferenceTracks objItem = new ReferenceTracks();
objItem.setTitle(objJson.getString(TAG_TITLE));
objItem.setArtist(objJson.getString(TAG_ARTIST));
objItem.setDuration(objJson.getString(TAG_DURATION));
objItem.setThumbUrl(objJson.getString(TAG_THUMBURL));
arrayOfList.add(objItem);
}
} catch (JSONException e) {
e.printStackTrace();
}
setAdapterToListview();
}
}
public void setAdapterToListview() {
objRowAdapter = new RowAdapter(getActivity(), R.layout.reference_song_list_item, arrayOfList);
songsListView.setAdapter(objRowAdapter);
}
}}
This is my custom Adapter:
public class RowAdapter extends ArrayAdapter<ReferenceTracks> {
private Context activity;
private ArrayList<ReferenceTracks> items;
private ReferenceTracks objBean;
private int row;
private ImageLoader imageLoader;
private DisplayImageOptions options;
public RowAdapter(Context act, int resource, ArrayList<ReferenceTracks> arrayList) {
super(act, resource, arrayList);
this.activity = act;
this.row = resource;
this.items = arrayList;
imageLoader = ImageLoader.getInstance();
}
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
View view = convertView;
ViewHolder holder;
if (view == null) {
LayoutInflater inflater = (LayoutInflater) activity
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view = inflater.inflate(row, null);
holder = new ViewHolder();
view.setTag(holder);
} else {
holder = (ViewHolder) view.getTag();
}
if ((items == null) || ((position + 1) > items.size()))
return view;
objBean = items.get(position);
holder.tvImage = (ImageView) view.findViewById(R.id.list_image);
holder.tvTitle = (TextView) view.findViewById(R.id.title);
holder.tvArtist = (TextView) view.findViewById(R.id.artist);
holder.tvDuration = (TextView) view.findViewById(R.id.duration);
holder.pbar = (ProgressBar) view.findViewById(R.id.progressbar);
if (holder.tvImage != null) {
if (null != objBean.getThumbUrl()
&& objBean.getThumbUrl().trim().length() > 0) {
final ProgressBar pbar = holder.pbar;
imageLoader.destroy();
imageLoader.init(ImageLoaderConfiguration.createDefault(activity));
imageLoader.displayImage(objBean.getThumbUrl(), holder.tvImage,
options, new ImageLoadingListener() {
@Override
public void onLoadingStarted(String imageUri,
View view) {
// TODO Auto-generated method stub
pbar.setVisibility(View.VISIBLE);
}
@Override
public void onLoadingFailed(String imageUri,
View view, FailReason failReason) {
// TODO Auto-generated method stub
pbar.setVisibility(View.INVISIBLE);
}
@Override
public void onLoadingComplete(String imageUri,
View view, Bitmap loadedImage) {
// TODO Auto-generated method stub
pbar.setVisibility(View.INVISIBLE);
}
@Override
public void onLoadingCancelled(String imageUri,
View view) {
// TODO Auto-generated method stub
}
});
} else {
holder.tvImage.setImageResource(R.drawable.ic_launcher);
}
}
if (holder.tvTitle != null && null != objBean.getTitle()
&& objBean.getTitle().trim().length() > 0) {
holder.tvTitle.setText(Html.fromHtml(objBean.getTitle()));
}
if (holder.tvArtist != null && null != objBean.getArtist()
&& objBean.getArtist().trim().length() > 0) {
holder.tvArtist.setText(Html.fromHtml(objBean.getArtist()));
}
if (holder.tvDuration != null && null != objBean.getDuration()
&& objBean.getDuration().trim().length() > 0) {
holder.tvDuration.setText(Html.fromHtml(objBean.getDuration()));
}
return view;
}
public class ViewHolder {
public ImageView tvImage;
public ProgressBar pbar;
public TextView tvTitle, tvArtist, tvDuration;
}}
While this is my application class:
public class SampleApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
DisplayImageOptions displayimageOptions = new DisplayImageOptions.Builder()
.showStubImage(R.drawable.ic_stub)
.showImageOnFail(R.drawable.ic_error)
.showImageForEmptyUri(R.drawable.ic_empty)
.cacheInMemory()
.cacheOnDisc()
.bitmapConfig(Bitmap.Config.RGB_565)
.imageScaleType(ImageScaleType.IN_SAMPLE_POWER_OF_2)
.build();
File cacheDir = StorageUtils.getCacheDirectory(getApplicationContext());
ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(getApplicationContext())
.threadPoolSize(4)
.threadPriority(Thread.NORM_PRIORITY)
.tasksProcessingOrder(QueueProcessingType.LIFO)
.defaultDisplayImageOptions(displayimageOptions)
.discCacheSize(50 * 1024 * 1024)
.discCacheFileCount(1000000)
.memoryCache(new WeakMemoryCache())
.build();
ImageLoader.getInstance().init(config);
}}
This is also the log:
06-24 11:18:12.935: E/ImageLoader(6428): null
06-24 11:18:12.935: E/ImageLoader(6428): java.io.EOFException
06-24 11:18:12.935: E/ImageLoader(6428): at libcore.io.Streams.readAsciiLine(Streams.java:203)
06-24 11:18:12.935: E/ImageLoader(6428): at libcore.net.http.HttpEngine.readResponseHeaders(HttpEngine.java:561)
06-24 11:18:12.935: E/ImageLoader(6428): at libcore.net.http.HttpEngine.readResponse(HttpEngine.java:801)
06-24 11:18:12.935: E/ImageLoader(6428): at libcore.net.http.HttpURLConnectionImpl.getResponse(HttpURLConnectionImpl.java:274)
06-24 11:18:12.935: E/ImageLoader(6428): at libcore.net.http.HttpURLConnectionImpl.getResponseCode(HttpURLConnectionImpl.java:479)
06-24 11:18:12.935: E/ImageLoader(6428): at com.nostra13.universalimageloader.core.download.BaseImageDownloader.getStreamFromNetwork(BaseImageDownloader.java:113)
06-24 11:18:12.935: E/ImageLoader(6428): at com.nostra13.universalimageloader.core.download.BaseImageDownloader.getStream(BaseImageDownloader.java:84)
06-24 11:18:12.935: E/ImageLoader(6428): at com.nostra13.universalimageloader.core.decode.BaseImageDecoder.getImageStream(BaseImageDecoder.java:84)
06-24 11:18:12.935: E/ImageLoader(6428): at com.nostra13.universalimageloader.core.decode.BaseImageDecoder.decode(BaseImageDecoder.java:73)
06-24 11:18:12.935: E/ImageLoader(6428): at com.nostra13.universalimageloader.core.LoadAndDisplayImageTask.decodeImage(LoadAndDisplayImageTask.java:290)
06-24 11:18:12.935: E/ImageLoader(6428): at com.nostra13.universalimageloader.core.LoadAndDisplayImageTask.tryLoadBitmap(LoadAndDisplayImageTask.java:250)
06-24 11:18:12.935: E/ImageLoader(6428): at com.nostra13.universalimageloader.core.LoadAndDisplayImageTask.run(LoadAndDisplayImageTask.java:131)
06-24 11:18:12.935: E/ImageLoader(6428): at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1076)
06-24 11:18:12.935: E/ImageLoader(6428): at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:569)
06-24 11:18:12.935: E/ImageLoader(6428): at java.lang.Thread.run(Thread.java:856)
Were there any settings I made wrong or missed on my application class for the imageloader? I've been searching for the same exception but nothing seems getting close to the fix. Any help will do. Many thanks!
I'm working with Universal image loader for a long time. So, I prefer to have it's settings in a class then my application is able to access it simply.
This is setting class of Universal image loader. I have a utility package and this class is under this package. You are able to make corners of image curve by commenting out of lines in onLoadingComplete().
public class ImageDownloader {
private static final String TAG = "ImageDownloader";
public static final String DIRECTORY_NAME = "YOUR_DIRECTORY_NAME";
private static ImageDownloader instance = null;
private ImageLoader imageLoader;
protected ImageDownloader(Context context) {
// Exists only to defeat instantiation.
configImageDownloader(context);
}
public static ImageDownloader getInstance(Context context) {
if(instance == null) {
instance = new ImageDownloader(context);
}
return instance;
}
/**
* This constructor will configure loader object in order to display image.
* @param context
*/
private void configImageDownloader(Context context) {
File cacheDir = StorageUtils.getOwnCacheDirectory(context, DIRECTORY_NAME + "/Cache");
// Get singleton instance of ImageLoader
imageLoader = ImageLoader.getInstance();
// Create configuration for ImageLoader (all options are optional)
ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(context).denyCacheImageMultipleSizesInMemory()
.memoryCache(new UsingFreqLimitedMemoryCache(4 * 1024 * 1024))
.discCache(new UnlimitedDiscCache(cacheDir))
.discCacheFileNameGenerator(new HashCodeFileNameGenerator())
.defaultDisplayImageOptions(
new DisplayImageOptions.Builder()
.showStubImage(R.drawable.ic_default_logo)
.resetViewBeforeLoading()
.cacheInMemory()
.cacheOnDisc()
.imageScaleType(ImageScaleType.IN_SAMPLE_POWER_OF_2)
.build())
.tasksProcessingOrder(QueueProcessingType.FIFO)
.build();
// Initialize ImageLoader with created configuration.
imageLoader.init(config);
}
public void displayImage(final ImageView imageView, String imageURI) {
if(imageView == null || imageURI == null) {
Log.e(TAG, "Either of image view or image uri is null");
return;
}
// Load and display image
imageLoader.displayImage(imageURI, imageView, new ImageLoadingListener() {
@Override
public void onLoadingStarted(String imageUri, View view) {}
@Override
public void onLoadingFailed(String imageUri, View view, FailReason failReason) {}
@Override
public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) {
// Bitmap bitmap = ((BitmapDrawable) imageView.getDrawable()).getBitmap();
// imageView.setImageBitmap(getRoundedCornerBitmap(bitmap, 30));
}
@Override
public void onLoadingCancelled(String imageUri, View view) {}
});
}
public static Bitmap getRoundedCornerBitmap(Bitmap bitmap, int pixels) {
Bitmap output = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(output);
final int color = 0xff424242;
final Paint paint = new Paint();
final Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
final RectF rectF = new RectF(rect);
final float roundPx = pixels;
paint.setAntiAlias(true);
canvas.drawARGB(0, 0, 0, 0);
paint.setColor(color);
canvas.drawRoundRect(rectF, roundPx, roundPx, paint);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
canvas.drawBitmap(bitmap, rect, rect, paint);
return output;
}
}
In your adapter class, first you need move all definitions into if (view == null) {...}
method. My sample adapter which is like this. You can ignore my listener which is because of a button that I have in my each row.
public class MyCrowdAdapter extends BaseAdapter {
public interface OnCrowdRemoveUserListener {
public void OnRemoveUserClicked(User user);
}
private final String TAG = "*** MyCrowdAdapter ***";
private Context context;
private OnCrowdRemoveUserListener listener;
private LayoutInflater myInflater;
private ImageDownloader imageDownloader;
private List<User> userList;
public MyCrowdAdapter(Context context) {
this.context = context;
myInflater = LayoutInflater.from(context);
imageDownloader = ImageDownloader.getInstance(context);
}
public void setData(List<User> userList) {
this.userList = userList;
Log.i(TAG, "List passed to the adapter.");
}
@Override
public int getCount() {
try {
return userList.size();
} catch (Exception e) {
e.printStackTrace();
return 0;
}
}
@Override
public Object getItem(int position) {
return null;
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null) {
convertView = myInflater.inflate(R.layout.list_my_crowd_row, null);
holder = new ViewHolder();
Typeface font = Typeface.createFromAsset(context.getAssets(), "fonts/ITCAvantGardeStd-Demi.ttf");
holder.tvUserName = (TextView) convertView.findViewById(R.id.tvUserName);
holder.tvUserName.setTypeface(font);
holder.ivPicture = (ImageView) convertView.findViewById(R.id.ivPicture);
holder.btnRemove = (Button) convertView.findViewById(R.id.btnRemove);
holder.btnRemove.setFocusable(false);
holder.btnRemove.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Integer pos = (Integer)v.getTag();
Log.i(TAG, "Item: " + pos);
listener.OnRemoveUserClicked(userList.get(pos));
}
});
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
holder.btnRemove.setTag(position);
holder.tvUserName.setText(userList.get(position).getFirstName());
imageDownloader.displayImage(holder.ivPicture, userList.get(position).getProfilePictureUrl());
return convertView;
}
public void setOnRemoveClickedListener(OnCrowdRemoveUserListener listener) {
this.listener = listener;
}
static class ViewHolder {
TextView tvUserName;
ImageView ivPicture;
Button btnRemove;
}
}
One suggestion, instead of validation like this: if (holder.tvTitle != null && null != objBean.getTitle() && objBean.getTitle().trim().length() > 0) {...} simply use TextUtils which is static method, like this: if(!TextUtils.isEmpty(objBean.getTitle);
===========
Update
===========
About your question regard displaying progressbar on top of image: It's simple and complex :) there are two ways, 1st way is based on your code: 1-define an interface inside ImageDownloader class like my interface inside adapter. should be something like this:
public interface OnImageDownloaderListener {
public void OnDownloadStarted();
public void OnDownloadFinished();
}
2- Declare it in decleration part
OnImageDownloaderListener listener;
3- Change thosr two listeners like this
@Override
public void onLoadingStarted(String imageUri, View view) {
listener.OnDownloadStarted();
}
@Override
public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) {
// Bitmap bitmap = ((BitmapDrawable) imageView.getDrawable()).getBitmap();
// imageView.setImageBitmap(getRoundedCornerBitmap(bitmap, 30));
listener.OnDownloadFinished();
}
4- Add this method to ImageDownloader class
public void setOnImageDownloaderListener(OnImageDownloaderListener listener) {
this.listener = listener;
}
5- In your adapter and below this line:
imageDownloader = ImageDownloader.getInstance(context);
implement those two methodes like this:
imageDownloader.setOnImageDownloaderListener(new ImageDownloader.OnImageDownloaderListener{
@Override
public void OnDownloadStarted() {
pbar.start();
}
@Override
public void OnDownloadFinished(){
pbar.stop();
}
}
);
It should help you. However, if I were you I does second approach which is creating new component. The component includes two views an image view and progressbar on top (same to what you have currently). Then add all above method inside that component class. So, easily through your app you in whatever activity you want you can add your view and just pass URL then the component is responsible to display progressbar and stop it. Based on your code if you have 10 similr activities you need to copy/paste above code.
Hope it helps you :)