使用AsyncTaskLoader获取本地数据(图片)

在项目中用到了AsyncTaskLoader来获取本地的图片,没错,就是它,不是AsyncTask;刚看见这个类的时候有些疑惑,想必它肯定和AsyncTask有什么联系,于是网上查找了一些资料,其实它们最主要的区别就是:AsyncTaskLoader只用来获取数据,它不考虑和UI交互,而AsyncTask可以获取数据并将数据展示在UI上。于是,写了一个demo使用AsyncTaskLoader类来获取本地图片。废话少说,进入正题。


首先,需要获取一个加载器的管理对象,然后初始化加载器

getSupportLoaderManager().initLoader(0,null,this);

这通常在onCreate()方法中进行

initLoader的三个参数:

0代表加载器的唯一标识id

null指传递给加载器的参数,这里为null

this指实现了LoaderCallbacks接口的Activity(注意是v4包下面的LoaderCallbacks)


然后接着实现LoaderCallbacks接口的两个方法

/**
 * 创建数据加载器
 * @param id
 * @param args
 * @return
 */
@Override
public Loader<List<ImageBean>> onCreateLoader(int id, Bundle args) {
    return new ImagesLoader(this);
}
这个是返回带List<ImageBean>  数据的加载器。 ImageBean是具体的数据,它实现了Parcelable接口,便于传递数据

而ImagesLoader就是继承AsyncTaskLoader类的获取本地图片数据的加载器

/**
 * 数据加载完成之后的操作
 * @param loader
 * @param data
 */
@Override
public void onLoadFinished(Loader<List<ImageBean>> loader, List<ImageBean> data) {
    mBeans.clear();
    mBeans.addAll(data);
    mAdapter.notifyDataSetChanged();
}
这个方法就是数据加载完成之后更新UI


最后就是ImagesLoader类的具体实现,继承AsyncTaskLoader,并实现关键的几个方法。直接上代码吧(代码是最好的老师)

package com.crazy.wang.net;

import android.content.Context;
import android.database.Cursor;
import android.provider.MediaStore;
import android.support.v4.content.AsyncTaskLoader;

import com.crazy.wang.model.ImageBean;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * @author Cloudsoar(wangyb)
 * @datetime 2015-11-30 21:52 GMT+8
 * @email 395044952@qq.com
 */
public class ImagesLoader extends AsyncTaskLoader<List<ImageBean>> {
    private List<ImageBean> mImages = null;
    public ImagesLoader(Context context){
        super(context);
    }

    @Override
    public List<ImageBean> loadInBackground() {
        List<ImageBean> imageList = new ArrayList<ImageBean>();
        /**
         * 查询本地图片的数据
         */
        Cursor imageCursor = getContext().getContentResolver().query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, new String[]{MediaStore.Images.Media.DATA, MediaStore.Images.Media._ID}, null, null, MediaStore.Images.Media._ID);

        if (imageCursor != null && imageCursor.getCount() > 0) {

            while (imageCursor.moveToNext()) {
                ImageBean item = new ImageBean(imageCursor.getString(imageCursor.getColumnIndex(MediaStore.Images.Media.DATA)), false);
                imageList.add(item);
            }
        }

        if (imageCursor != null) {
            imageCursor.close();
        }

        // show newest photo at beginning of the list
        Collections.reverse(imageList);
        return imageList;
    }

    /* Runs on the UI thread */
    @Override
    public void deliverResult(List<ImageBean> images) {
        if (isReset()) {
            // An async query came in while the loader is stopped
            if (images != null) {
                images.clear();
                images = null;
            }
            return;
        }
        List<ImageBean> oldImages = mImages;
        mImages = images;

        if (isStarted()) {
            super.deliverResult(images);
        }

        if (oldImages != null && oldImages != mImages) {
            oldImages.clear();
            oldImages = null;
        }
    }

    @Override
    protected void onStartLoading() {
        if (mImages != null && mImages.size() > 0) {
            deliverResult(mImages);
        }

        if (takeContentChanged() || mImages == null) {
            forceLoad();
        }
    }

    /**
     * Must be called from the UI thread
     */
    @Override
    protected void onStopLoading() {
        // Attempt to cancel the current load task if possible.
        cancelLoad();
    }

    @Override
    public void onCanceled(List<ImageBean> images) {
        if (images != null) {
            images.clear();
            images = null;
        }
    }

    @Override
    protected void onReset() {
        super.onReset();

        // Ensure the loader is stopped
        onStopLoading();

        if (mImages != null) {
            mImages.clear();
            mImages = null;
        }
    }
}

考虑到以后保存有图片相关信息的ImageBean可以方便的传递,于是让其实现了Parcelable接口。

实现Parcelable接口的注意事项已经写在代码中,已经很详细了,相信大家能看懂

package com.crazy.wang.model;

import android.os.Parcel;
import android.os.Parcelable;

/**
 * @author Cloudsoar(wangyb)
 * @datetime 2015-11-30 21:29 GMT+8
 * @email 395044952@qq.com
 */
public class ImageBean implements Parcelable {

    private String mPath;
    private boolean isSelected;

    public ImageBean(String path, boolean isSelected){
        this.mPath = path;
        this.isSelected = isSelected;
    }

    /**
     *
     * @return 内容描述,返回0即可
     */
    @Override
    public int describeContents() {
        return 0;
    }

    /**
     * 需要传递的数据都需要通过该方法将数据放入Parcel对象中
     * 变量放入的顺序必须是变量声明的顺序,否则会报错
     * @param dest
     * @param flags
     */
    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(mPath);
        dest.writeInt(isSelected ? 1 : 0);
    }

    /**
     * 实现Parcelable接口的bean必须实例化一个Creator对象,且对象名必须是CREATOR
     */
    public static final Creator<ImageBean> CREATOR = new Creator<ImageBean>() {

        /**
         * Parcel对象中取出数据组装成bean
         * 这里的数据来自于writeToParcel方法
         * 读取数据时必须是按变量声明的顺序
         * @param source
         * @return
         */
        @Override
        public ImageBean createFromParcel(Parcel source) {
            return new ImageBean(source.readString(),
                    source.readInt() == 1 ? true : false);
        }

        /**
         * 返回数组bean
         * @param size
         * @return
         */
        @Override
        public ImageBean[] newArray(int size) {
            return new ImageBean[size];
        }
    };

    public String getPath() {
        return mPath;
    }

    public void setPath(String path) {
        mPath = path;
    }

    public boolean isSelected() {
        return isSelected;
    }

    public void setIsSelected(boolean isSelected) {
        this.isSelected = isSelected;
    }
}

在Adapter中,展示图片的时候,使用到了ImageLoader组件

ImageLoader.getInstance().displayImage("file://" + mBeans.get(position).getPath(),
        holder.mImageView, DisplayImageOptionsUtil.defaultOptions);


将RecycleView实现为GridView效果很简单,只需要一步搞定(在这里每行显示3张图片)

/**
 * DividerGridItemDecoration   GridView的分割线
 */
mRecyclerView.addItemDecoration(new DividerGridItemDecoration(this));
/**
 * RecyclerView设置为GridView的样式
 */
mRecyclerView.setLayoutManager(new GridLayoutManager(this,3));

最后,项目中用到了两个自定义的组件

DividerGridItemDecoration   将RecycleView实现为GridView效果的时候增加分割线

SquareToWidthRelativeLayout     设置保存图片的容器

这两个类的代码就不贴出了。


源码下载

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值