0

我正在编写一个 flickr 客户端,作为我正在阅读的书中项目的一部分。在其中我创建了一个 HandlerThread 的子类,它从 flickr 下载图像,然后将它们设置在 ImageView 中。我在程序的前面设置了一个占位符 .png 并且它绑定(但有延迟)但是当我尝试替换它时没有任何反应。占位符保留在那里并且不会被替换。似乎发生了一些事情,这阻止了我的 HandlerThread 正常运行。我尝试使用调试器逐步完成此操作并查看 logcat,但是自上次更新到 android studio 以来,logcat 一直特别无用。如果有的话,它可以部分工作。对了,我没有收到任何错误消息。早些时候我收到一个说我有一个空指针异常,但我无法看到它来自哪里,并且在再次运行应用程序时它就消失了。我正在发布我的代码示例,包括用作 UI 线程的主 Fragment,以及作为我的 HandlerThread 子类的 ThumbnailDownloader 类。

public class PhotoGalleryFragment extends Fragment {
private static final String TAG = "PhotoGalleryFragment";

private RecyclerView mRecyclerView;
private List<GalleryItem> mItems = new ArrayList<>();
private ThumbnailDownloader<PhotoHolder> mThumbnailDownloader;

public static PhotoGalleryFragment newInstance(){
    return new PhotoGalleryFragment();
}

@Override
public void onCreate(Bundle savedInstanceState){
    super.onCreate(savedInstanceState);
    setRetainInstance(true);
    new FetchItemsTask().execute();

    Handler responseHandler = new Handler();
    mThumbnailDownloader = new ThumbnailDownloader<>(responseHandler);
    mThumbnailDownloader.setThumbnailDownloadListener( new ThumbnailDownloader.ThumbnailDownloadListener<PhotoHolder>() {
        @Override
        public void onThumbnailDownloaded(PhotoHolder target, Bitmap bitmap) {
            Log.i(TAG, "setThumbnailDownloadListener() called!");
            Drawable drawable = new BitmapDrawable(getResources(), bitmap);
            target.bindDrawable(drawable);

        }
    });
    mThumbnailDownloader.start();
    mThumbnailDownloader.getLooper();
    Log.i(TAG, "background thread started!");
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
    View v = inflater.inflate(R.layout.fragment_photo_gallery, container, false);

    mRecyclerView = (RecyclerView) v.findViewById(R.id.photo_recycler_view);
    mRecyclerView.setLayoutManager(new GridLayoutManager(getActivity(), 3));

    setupAdapter();

    return v;
}

public void onDestroyView(){
    super.onDestroyView();
    mThumbnailDownloader.clearQueue();
}

@Override
public void onDestroy(){
    super.onDestroy();
    mThumbnailDownloader.quit();
    Log.i(TAG, "background thread destroyed!");
}

private void setupAdapter(){
    if (isAdded()){
        mRecyclerView.setAdapter(new PhotoAdapter(mItems));
    }
}

private class PhotoHolder extends RecyclerView.ViewHolder{
    private ImageView mItemImageView;

    public PhotoHolder(View itemView){
        super(itemView);

        mItemImageView = (ImageView) itemView.findViewById(R.id.item_image_view);
    }

    public void bindDrawable(Drawable drawable){
        mItemImageView.setImageDrawable(drawable);
    }
}//end PhotoHolder inner class

private class PhotoAdapter extends RecyclerView.Adapter<PhotoHolder>{

    private List<GalleryItem> mGalleryItems;

    public PhotoAdapter(List<GalleryItem> items){
        mGalleryItems = items;
    }

    @Override
    public PhotoHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
        LayoutInflater layoutInflater = LayoutInflater.from(getActivity());
        View view = layoutInflater.inflate(R.layout.list_item_gallery, viewGroup, false); 
        return new PhotoHolder(view);
    }

    @Override
    public void onBindViewHolder(PhotoHolder photoHolder, int position) {
        GalleryItem galleryItem = mGalleryItems.get(position);
        Drawable placeholder = getResources().getDrawable(R.drawable.wait); <--this is the placeholder image
        photoHolder.bindDrawable(placeholder);//this <--this sets the placeholder but seems to wait for the thumbnail download to complete for some reason

        mThumbnailDownloader.queueThumbnail(photoHolder, galleryItem.getUrl());
    }

    @Override
    public int getItemCount() {
        return mGalleryItems.size();
    }
}

private class FetchItemsTask extends AsyncTask<Void, Void, List<GalleryItem>>{

    @Override
protected List<GalleryItem> doInBackground(Void... params) {
   return new FlickrFetchr().fetchItems();
}

@Override
protected void onPostExecute(List<GalleryItem> items){
    mItems = items;
    setupAdapter();
}
}//end FetchItemsTask inner class

}//end class

这是我的 HandlerThread 实现:

public class ThumbnailDownloader<T> extends HandlerThread {
private static final String TAG = "ThumbnailDownloader";
private static final int MESSAGE_DOWNLOAD = 0;

private boolean mHasQuit = false;
private Handler mRequestHandler = new Handler();
private Handler mResponseHandler = new Handler();
private ThumbnailDownloadListener<T> mThumbnailDownloadListener;
private ConcurrentMap<T, String> mRequestMap = new ConcurrentHashMap<>();

public interface ThumbnailDownloadListener<T>{
    void onThumbnailDownloaded(T target, Bitmap bitmap);
}

public void setThumbnailDownloadListener(ThumbnailDownloadListener<T> listener){
    mThumbnailDownloadListener = listener;
}

public ThumbnailDownloader(Handler responseHandler){
    super(TAG);
    mResponseHandler = responseHandler;
    Log.i(TAG, "ThumbnailDownloader created!");
}

@Override
protected void onLooperPrepared(){
    mRequestHandler = new Handler(){
        @Override
        public void handleMessage(Message msg){
            if (msg.what == MESSAGE_DOWNLOAD){
                T target = (T) msg.obj;
                Log.i(TAG, "got a request for a url:" + mRequestMap.get(target));
                handleRequest(target);
            }
        }
    };
}

@Override
public boolean quit(){
    mHasQuit = true;
    return super.quit();
}

public void queueThumbnail(T target, String url){
    Log.i(TAG, "got a url: " + url);

    if(url == null){
        mRequestMap.remove(target);
    }else {
        mRequestMap.put(target, url);
        mRequestHandler.obtainMessage(MESSAGE_DOWNLOAD, target).sendToTarget();
    }

}

public void clearQueue(){
    mRequestHandler.removeMessages(MESSAGE_DOWNLOAD);
    mRequestMap.clear();
}

private void handleRequest(final T target){
    try{
        final String url = mRequestMap.get(target);

        if (url == null){
            return;
        }
        byte[] bitmapBytes = new FlickrFetchr().getUrlBytes(url);
        final Bitmap bitmap = BitmapFactory.decodeByteArray(bitmapBytes, 0, bitmapBytes.length);
        Log.i(TAG, "Bitmap created!"); //<---this is output in the logcat at the terminal but not the android monitor
        mResponseHandler.post(new Runnable(){

            @Override
            public void run() {
                if (mRequestMap.get(target) != null || mHasQuit){
                    return;
                }
                mRequestMap.remove(target);
                mThumbnailDownloadListener.onThumbnailDownloaded(target, bitmap);
            }
        });
    }catch (IOException ioe){
        Log.e(TAG, "error downloading image: ", ioe);
    }
}

}

老实说,在这一点上,我什至不确定问题出在哪里。queueThumbnail 似乎从未运行过。但是仅设置占位符 wait.png 需要很长时间,以至于在绑定到 ViewHolder 时,占位符和下载的图像之间似乎存在一些混淆。我只是不确定它可能在哪里。我添加了评论来指出这一点。

4

0 回答 0