Универсальный загрузчик изображений java.io.EOFException

Я пытаюсь получить данные JSON и отобразить их в своем ListView с помощью ArrayAdapter. В любом случае, в моем адаптере я использую Universal Image Loader с https://github.com/nostra13/Android-Universal-Image-Loader и другие данные были загружены правильно, за исключением изображений. Некоторые изображения отображались корректно, некоторые не должны были быть на конкретном элементе, а некоторые загружались не полностью.

Это мой вызывающий фрагмент:

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);
    }
}}

Это мой пользовательский адаптер:

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;
}}

Пока это мой класс приложения:

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);
}}

Это также журнал:

    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)

Были ли какие-либо настройки, которые я сделал неправильно или пропустил в своем классе приложения для загрузчика изображений? Я искал то же самое исключение, но, кажется, ничто не приближается к исправлению. Подойдет любая помощь. Большое спасибо!


person Compaq LE2202x    schedule 24.06.2013    source источник


Ответы (1)


Я давно работаю с универсальным загрузчиком изображений. Итак, я предпочитаю, чтобы его настройки были в классе, тогда мое приложение может просто получить к нему доступ.

Это класс настроек универсального загрузчика изображений. У меня есть пакет утилит, и этот класс находится в этом пакете. Вы можете сделать углы изображения кривыми, комментируя строки в 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;
    }
}

В вашем классе адаптера сначала вам нужно переместить все определения в if (view == null) {...}method. Мой образец адаптера, который похож на этот. Вы можете игнорировать моего слушателя из-за кнопки, которая есть у меня в каждой строке.

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;
    }
}

Одно предложение вместо такой проверки: if (holder.tvTitle != null && null != objBean.getTitle() && objBean.getTitle().trim().length() > 0) {...} просто используйте TextUtils, который является статическим методом. , например: if(!TextUtils.isEmpty(objBean.getTitle);

===========

Обновить

===========

О вашем вопросе относительно отображения индикатора выполнения поверх изображения: это просто и сложно :) есть два способа, 1-й способ основан на вашем коде: 1-определить интерфейс внутри класса ImageDownloader, такой как мой интерфейс внутри адаптера. должно быть что-то вроде этого:

public interface OnImageDownloaderListener {
    public void OnDownloadStarted();
    public void OnDownloadFinished();
}

2- Объявите это в части деклерации

OnImageDownloaderListener listener;

3- Измените этих двух слушателей, как это

@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- Добавьте этот метод в класс ImageDownloader

public void setOnImageDownloaderListener(OnImageDownloaderListener listener) {
        this.listener = listener;
    }

5- В вашем адаптере и ниже этой строки:

imageDownloader = ImageDownloader.getInstance(context); 

реализовать эти два метода следующим образом:

imageDownloader.setOnImageDownloaderListener(new ImageDownloader.OnImageDownloaderListener{
    @Override
    public void OnDownloadStarted() {
        pbar.start();
    }

    @Override
    public void OnDownloadFinished(){
        pbar.stop();
    }
}
);

Это должно помочь вам. Однако на вашем месте я использую второй подход, который заключается в создании нового компонента. Компонент включает в себя два представления: представление изображения и индикатор выполнения сверху (такой же, как у вас сейчас). Затем добавьте все вышеперечисленные методы внутри этого класса компонентов. Таким образом, легко через ваше приложение вы можете в любом действии, которое вы хотите, добавить свое представление и просто передать URL-адрес, тогда компонент отвечает за отображение индикатора выполнения и его остановку. На основе вашего кода, если у вас есть 10 похожих действий, вам нужно скопировать/вставить код выше.

Надеюсь, это поможет вам :)

person Hesam    schedule 24.06.2013
comment
Ух ты! Это сработало! Я использовал ваш класс ImageDownloader в своем классе приложения и его метод displayImage. Плюс мне нравятся закругленные углы! Большое спасибо. Но мне любопытно, что заставило мои настройки не работать? Это был кеш? - person Compaq LE2202x; 24.06.2013
comment
Я помню, что у меня были похожие проблемы, когда я начал интегрировать эту библиотеку в свое первое приложение. Теперь я использую его в своем четвертом приложении, и это пока самое оптимизированное. Про настройки понятия не имею! :( - person Hesam; 24.06.2013
comment
Я понимаю, и это мое первое приложение, использующее UIL, поэтому я не был уверен, какие оптимальные настройки использовать. Действительно благодарен за это! Кстати, как мне вызвать прослушиватель для displayImage? Я хотел бы использовать его для моего индикатора выполнения. - person Compaq LE2202x; 24.06.2013
comment
Я не понял, что вы имеете в виду? ваш диалоговый индикатор прогресса или у вас есть индикатор прогресса поверх изображения? - person Hesam; 24.06.2013
comment
У меня есть индикатор выполнения поверх моего изображения и в моем предыдущем адаптере (см. мой код), объявленный как pbar, где я управляю его видимостью в onLoadingStarted, onLoadingFailed и onLoadingComplete. - person Compaq LE2202x; 24.06.2013
comment
Я сделал настройку и добавил параметр для индикатора выполнения. Еще раз спасибо. - person Compaq LE2202x; 24.06.2013