Android里超级好用的AsyncTask模版

 

Android里的AsyncTask是一个很好用的异步加载数据的工具类,我们是可以定义一个抽象类,其继承于AsyncTask,可接收不同类型的参数。定义如下:

import android.annotation.WorkerThread;
import android.content.ContentResolver;
import android.database.Cursor;
import android.net.Uri;
import android.os.AsyncTask;
import android.support.annotation.MainThread;
import android.util.Log;

import java.util.concurrent.Executor;

/**
 * {@link AsyncTask} that defaults to executing on its own single threaded Executor Service.
 *
 * @param <Params>   执行时需要的参数,传给doInBackground使用.
 * @param <Progress> the type of the progress units published during the background computation.
 * @param <Result>   doInBackground执行完后返回的数据类型,它会被系统作为参数传给        
 *                   onPostExecute。
 */
public abstract class AsyncDbTask<Params, Progress, Result> extends AsyncTask<Params, Progress, Result> {
    private static final String TAG = "AsyncDbTask";
    private static final boolean DEBUG = true;

    private final Executor mExecutor;
    boolean mCalledExecuteOnDbThread;

    protected AsyncDbTask(Executor mExecutor) {
        this.mExecutor = mExecutor;
    }

    @SafeVarargs
    @MainThread
    public final void executeOnDbThread(Params... params) {
        mCalledExecuteOnDbThread = true;
        executeOnExecutor(mExecutor, params);
    }

    public abstract static class LoadSkywayClientDBTask<Params, Progress, Result> extends AsyncDbTask<Params, Progress, Result> {
        private final ContentResolver mContentResolver;
        private final Uri mUri;
        private final String[] mProjection;
        private final String mSelection;
        private final String[] mSelectionArgs;
        private final String mOrderBy;

        public LoadSkywayClientDBTask(Executor executor,
                                      ContentResolver contentResolver,
                                      Uri uri, String[] projection,
                                      String selection,
                                      String[] selectionArgs,
                                      String orderBy) {
            super(executor);
            mContentResolver = contentResolver;
            mUri = uri;
            mProjection = projection;
            mSelection = selection;
            mSelectionArgs = selectionArgs;
            mOrderBy = orderBy;
        }

        @Override
        public Result doInBackground(Params... params) {
            Log.d(TAG, "LoadSkywayClientDBTask's doInBackground called in " + Thread.currentThread().getName());
            if (!mCalledExecuteOnDbThread) {
                IllegalStateException e = new IllegalStateException(this + " should only be executed using executeOnDbThread, "
                        + "but it was called on thread "
                        + Thread.currentThread());
                Log.w(TAG, e);
            }

            if (isCancelled()) {
                // This is guaranteed to never call onPostExecute because the task is canceled.
                return null;
            }

            if (DEBUG) {
                Log.v(TAG, "Starting query for " + this);
            }

            try (Cursor c = mContentResolver.query(mUri, mProjection, mSelection, mSelectionArgs, mOrderBy)) {
                if (c != null && !isCancelled()) {
                    Result result = onQuery(c);
                    if (DEBUG) {
                        Log.v(TAG, "Finished query for " + this);
                    }
                    c.close();
                    return result;
                } else {
                    if (c == null) {
                        Log.e(TAG, "Unknown query error for " + this);
                    } else {
                        if (DEBUG) {
                            Log.d(TAG, "Canceled query for " + this);
                        }
                        c.close();
                    }
                    return null;
                }
            } catch (Exception e) {
                Log.d("wujiang", "doInBackground: error = " + e.getMessage());
            }

            return null;
        }

        /**
         * Return the result from the cursor.
         *
         * <p><b>Note</b> This is executed on the DB thread by {@link #doInBackground(Params...)}
         */
        @WorkerThread
        protected abstract Result onQuery(Cursor c);

        @Override
        public String toString() {
            return this.getClass().getName() + "(" + mUri + ")";
        }
    }
}

假如我现在有个需求,要从一个数据库中加载数据,这个数据库存储数据的字段有channelid、name、logoUrl等等,现在只想查找这三个字段的数据,然后放到一个HaspMap里。我们可以定义一个LoadChannelListTask类,其继承于AsyncDbTask.LoadSkywayClientDBTask。

public class LoadChannelListTask extends AsyncDbTask.LoadSkywayClientDBTask<Void, Void, HashMap<String, SkywayChannelEntity>> {
        protected LoadChannelListTask(Executor executor,
                                     ContentResolver contentResolver,
                                     Uri uri, String[] projection,
                                     String selection,
                                     String[] selectionArgs,
                                     String orderBy) {
            super(executor, contentResolver, uri, projection, selection, selectionArgs, orderBy);
        }

        @Override
        protected void onPostExecute(HashMap<String, SkywayChannelEntity> skywayChannelEntityHashMap) {
            Log.d("wujiang", "LoadChannelListTask's onPostExecute: call this fun in " + Thread.currentThread().getName());
            mSkywayChannelList.clear();

            if (skywayChannelEntityHashMap != null) {
                mSkywayChannelList.putAll(skywayChannelEntityHashMap);
            }

            /** 打印 **/
            /*Set<Map.Entry<String, SkywayChannelEntity>> setEntry = mSkywayChannelList.entrySet();
            Iterator<Map.Entry<String, SkywayChannelEntity>> iterator = setEntry.iterator();

            while (iterator.hasNext()) {
                Map.Entry<String, SkywayChannelEntity> entry = iterator.next();
                String channelId = entry.getKey();
                SkywayChannelEntity skywayChannelEntity = entry.getValue();

                Log.d("wujiang", "channelId = " + channelId);
                Log.d("wujiang", "channelName = " + skywayChannelEntity.getChannelName());
                Log.d("wujiang", "channelLogoUrl = " + skywayChannelEntity.getChannelLogoUrl());
            }*/
        }

        @Override
        protected HashMap<String, SkywayChannelEntity> onQuery(Cursor c) {
            HashMap<String, SkywayChannelEntity> hashMap = new HashMap();

            if (c != null) {
                //Log.d("wujiang", "onQuery: count = " + c.getCount());
                while (c.moveToNext()) {
                    if (isCancelled()) {
                        Log.d("wujiang", "LoadChannelListTask's onQuery: isCancelled ");
                        return hashMap;
                    }

                    String channelId = c.getString(c.getColumnIndex("channelid"));
                    String channelName = c.getString(c.getColumnIndex("name"));
                    String channelLogoUrl = c.getString(c.getColumnIndex("logoUrl"));

                    SkywayChannelEntity skywayChannelEntity = new SkywayChannelEntity();
                    skywayChannelEntity.setChannelId(channelId);
                    skywayChannelEntity.setChannelName(channelName);
                    skywayChannelEntity.setChannelLogoUrl(channelLogoUrl);

                    hashMap.put(channelName, skywayChannelEntity);
                }
            }

            if (hashMap == null) {
                Log.d("wujiang", "LoadChannelListTask's onQuery: hashMap = null ");
            }
            return hashMap;
        }
    }

SkywayChannelEntity.java如下:

public class SkywayChannelEntity {
    String channelId;
    String channelName;
    String channelLogoUrl;

    public SkywayChannelEntity() {

    }

    public SkywayChannelEntity(String channelId, String channelName, String channelLogoUrl) {
        this.channelId = channelId;
        this.channelName = channelName;
        this.channelLogoUrl = channelLogoUrl;
    }

    public String getChannelId() {
        return channelId;
    }

    public void setChannelId(String channelId) {
        this.channelId = channelId;
    }

    public String getChannelName() {
        return channelName;
    }

    public void setChannelName(String channelName) {
        this.channelName = channelName;
    }

    public String getChannelLogoUrl() {
        return channelLogoUrl;
    }

    public void setChannelLogoUrl(String channelLogoUrl) {
        this.channelLogoUrl = channelLogoUrl;
    }
}

AsyncDbTask.LoadSkywayClientDBTask<Void, Void, HashMap<String, SkywayChannelEntity>>里,第一个Void表示不需要任何参数,第二个Void表示不需要显示进度,HashMap<String, SkywayChannelEntity>表示doInBackground的返回类型,即onPostExecute形参类型。这里没有实现doInBackground方法,是因为我们这里查询时没有设置一些特定的过滤条件(稍后会介绍设置过滤条件的例子),那执行时就调用了父类的doInBackground。

那怎么使用LoadChannelListTask呢?代码如下:

private ExecutorService DB_EXECUTOR = Executors.newSingleThreadExecutor(new NamedThreadFactory("query-skywayclient-db"));

private static final String[] SKYWAY_CHANNEL_LIST_PROJECTION = {
            "channelid",
            "name",
            "logoUrl"
    };

public void loadChannelListFromSkywayClient() {
        Log.d("wujiang", "loadChannelListFromSkywayClient: call this fun in " + Thread.currentThread().getName());
        LoadChannelListTask loadChannelListTask = new LoadChannelListTask(DB_EXECUTOR,
                mContext.getContentResolver(),
                SkyWayClientUtils.CHANNELLIST_URI,
                SKYWAY_CHANNEL_LIST_PROJECTION,
                null, null, null);
        loadChannelListTask.executeOnDbThread();
    }

SkyWayClientUtils.CHANNELLIST_URI为数据库的URI,不用多说;SKYWAY_CHANNEL_LIST_PROJECTION就是要查询的字段。这样执行完成后,数据就保存到了mSkywayChannelList里。

OK,我们继续。

假如有个数据库,里面存储了很多EPG的数据,多的时候几万条。何为EPG?简单点说,就是指的一个电视台的时刻表,即几点到几点播放什么内容,比如CCTV1 19:00-19:30播放新闻联播,19:30-20:30播放动物世界,CCTV5 19:00-19:30 播放什么,19:30-20:00播放什么,等等。那么我们数据库里可能就存储了很多台从今天开始的7天内的EPG信息。现在有需求,需要查询一些指定台指定时间范围内的EPG数据,如我想查找CCTV1、CCTV3、CCTV5、深圳卫视,湖南卫视等诸多台今天的EPG信息。我这里就定义了一个类:LoadChannelProgramsTask。

private HashMap<Integer, ArrayList<SkywayProgramEntity>> mChannelsProgramMap;

public class LoadChannelProgramsTask extends AsyncDbTask.LoadSkywayClientDBTask<QueryParams, Void, Boolean> {
        protected LoadChannelProgramsTask(Executor executor,
                                          ContentResolver contentResolver,
                                          Uri uri, String[] projection,
                                          String selection,
                                          String[] selectionArgs,
                                          String orderBy) {
            super(executor, contentResolver, uri, projection, selection, selectionArgs, orderBy);
        }

        @Override
        protected Boolean onQuery(Cursor c) {
            return true;
        }

        @Override
        public Boolean doInBackground(QueryParams... queryParams) {
            boolean ret = false;
            long load_db_start_time = System.currentTimeMillis();
            int startTime = queryParams[0].getStartTime();
            int endTime = queryParams[0].getEndTime();
            ArrayList<Integer> channelIdList = queryParams[0].getQueryChannels();

            //Log.d("wujiang", "LoadChannelProgramsTask's doInBackground: thread name = " + Thread.currentThread().getName());
            //Log.d("wujiang", "LoadChannelProgramsTask's doInBackground: startTime = " + startTime);
            //Log.d("wujiang", "LoadChannelProgramsTask's doInBackground: endTime = " + endTime);

            for (Integer channel_lcn : channelIdList) {
                ArrayList<SkywayProgramEntity> programArrayList = queryOneChannelPrograms(channel_lcn, startTime, endTime);
                Log.d("wujiang", "LoadChannelProgramsTask's doInBackground: channel lcn = " + channel_lcn);
                Log.d("wujiang", "LoadChannelProgramsTask's doInBackground: programArrayList = " + programArrayList.size());
                mChannelsProgramMap.remove(channel_lcn);
                mChannelsProgramMap.put(channel_lcn.intValue(), programArrayList);

                if (programArrayList.size() > 0) {
                    ret = true;
                }
            }

            Log.d(TAG, "doInBackground: spend time = " + (System.currentTimeMillis() - load_db_start_time));
            return ret;
        }

        @Override
        protected void onPostExecute(Boolean retValue) {
            //Log.d("wujiang", "LoadChannelProgramsTask's onPostExecute: thread name = " + Thread.currentThread().getName());
            Log.d("wujiang", "LoadChannelProgramsTask's onPostExecute: retValue = " + retValue);
            if (!retValue) {
                Log.d("wujiang", "LoadChannelProgramsTask's onPostExecute: 没有查询到数据,不需要更新UI");
                return;
            }

            for (QueryFinishListener listener : mListenerList) {
                listener.queryFinishCallback();
            }
        }
    }

 /**
     * 查询节目从startTime开始的epg信息
     * @param channel_lcn
     * @param startTime 单位秒
     * @param endTime   单位秒
     * @return
     */
    private ArrayList<SkywayProgramEntity> queryOneChannelPrograms(int channel_lcn, int startTime, int endTime) {
        ArrayList<SkywayProgramEntity> programsList = new ArrayList<>();
        programsList.clear();

        SkywayProgramEntity lastReadProgram = null;
        Cursor cursor = null;

        try {
            cursor = mContext.getContentResolver().query(
                    SkyWayClientUtils.CHANNEL_EPG_URI,
                    null,
                    SkywayProgramEntity.LCN_FILED + "=? and " + SkywayProgramEntity.STARTTIME_INTEGER_FILED + ">=?",
                    new String[]{String.valueOf(channel_lcn), String.valueOf(startTime)},
                    SkywayProgramEntity.STARTTIME_INTEGER_FILED);

            if (cursor != null && cursor.getCount() > 0) {
                Log.d("wujiang", "queryOneChannelPrograms: channel_lcn = " + channel_lcn);
                Log.d("wujiang", "queryOneChannelPrograms: cursor.getCount() = " + cursor.getCount());
                cursor.moveToFirst();

                while(!cursor.isAfterLast()) {
                    // to do your things

                    cursor.moveToNext();
                }
            }
        } finally {
            try {
                if (null != cursor && !cursor.isClosed()) {
                    cursor.close();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }


        return programsList;
    }

public class QueryParams {
        private int startTime;
        private int endTime;
        private ArrayList<Integer> queryChannels;

        public QueryParams(int startTime, int endTime, ArrayList<Integer> queryChannels) {
            this.startTime = startTime;
            this.endTime = endTime;
            this.queryChannels = queryChannels;
        }

        public int getStartTime() {
            return startTime;
        }

        public int getEndTime() {
            return endTime;
        }

        public ArrayList<Integer> getQueryChannels() {
            return queryChannels;
        }
    }

这里查询数据库时指定了条件,startTime表示EPG开始时间,endTime表示EPG的结束时间,queryChannels表示要查询的节目。所以AsyncDbTask.LoadSkywayClientDBTask<QueryParams, Void, Boolean>的第一个参数就表示过滤的参数,第三个参数表示有没有查询到数据。和第一个例子不同,这里实现了doInBackground,那是因为我们需要接收QueryParams参数。执行完成后查询到的EPG数据就保存在了mChannelsProgramMap里。

怎么使用LoadChannelProgramsTask?代码如下:

    /**
     *
     * @param startTime 秒单位
     * @param endTime   秒单位
     * @param queryLcnArrayList
     */
    public void loadProgramOfChannelsFromSkywayClient(int startTime, int endTime, ArrayList<Integer> queryLcnArrayList) {
        QueryParams queryParams = new QueryParams(startTime, endTime, queryLcnArrayList);
        LoadChannelProgramsTask loadChannelProgramsTask = new LoadChannelProgramsTask(DB_EXECUTOR,
                mContext.getContentResolver(),
                SkyWayClientUtils.CHANNEL_EPG_URI, null, null, null, null);
        loadChannelProgramsTask.executeOnDbThread(queryParams);
    }

到此就介绍完了,感觉怎么样呢?需要您的评价,谢谢!

 

                                                                                                                             THE               END

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值