(原创)使用AsyncTask(带修改线程池方式)+自定义ImageLoader+LRU算法对图片三级缓存及其显示优化(只有在ListView滑动停止的时候才去网络请求获取图片数据)

前言:

以前看了些关于图片优化处理缓存比较全的视频(感谢慕风网),现在回顾觉得还是挺好的也就总结出来下,感觉针对图片做处理这块还真的用的比较多,本文章只要使用异步线程AsyncTask、自定义的ImageLoader和LRU算法来实现,还专门对AsyncTask针对线程管理和自定义核心线程和总运行线程并针对某些可能比较耗时没处理完阻塞线程进行的管理,当然这块有很多第三方框架可以实现,但还是自己写些自己见解的东西比较好,希望对你们有所帮助!

文章总体实现几点:

1、通过异步加载避免阻塞UI线程

2、通过自定义ImageLoader+LRU算法机制实现三级缓存图片

3、通过监听ListView的滑动状态尽可能的优化获取图片资源方式


效果图:



1、先说下什么叫异步加载?

其实顾名思义就是使用异步去访问加载网络请求数据(╯﹏╰);这不是跟没说一样吗?其实我也没有合理的解释,除非你懂啥叫异步?不就是不同步嘛(妖,那还不是跟没说一样(╯﹏╰))。好吧,所谓异步线程就是开启多条不是可以同步处理的线程处理,当然这线程数还是需要加以控制管理的,不然会造成程序特别耗性能,也就是我们常用到的AsyncTask。


2、那为什么需要使用异步?

首先,为了提高用户的体验,加载页面数据不会感觉到明显的卡顿,当然还有一点Android机制是main线程不可以进行些耗时操作,不然会阻塞UI线程报ANR异常,所以不得不开启子线程来处理。


3、异步加载有哪几种方式?

(1)、多线程/线程池实现。

(2)、AsyncTask(当然这种方式也就是线程池和handler进行了封装)


4、先来了解下AsyncTask

1、看一个类当然是从它的构造方法,首先分析下其都做了哪些操作

public AsyncTask() {
mWorker = new WorkerRunnable<Params, Result>() {
public Result call() throws Exception {
mTaskInvoked.set(true);


Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
return postResult(doInBackground(mParams));
}
};

mFuture = new FutureTask<Result>(mWorker) {
@Override
protected void done() {
try {
final Result result = get();

postResultIfNotInvoked(result);
} catch (InterruptedException e) {
android.util.Log.w(LOG_TAG, e);
} catch (ExecutionException e) {
throw new RuntimeException("An error occured while executing doInBackground()",
e.getCause());
} catch (CancellationException e) {
postResultIfNotInvoked(null);
} catch (Throwable t) {
throw new RuntimeException("An error occured while executing "
+ "doInBackground()", t);
}
}
};
}


首先构造方法里面创建了两个对象WorkerRunnable和FutureTask,然后我们继续接着看下这两个对象在什么情况下给调用呢?

public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,

Params... params) {

if (mStatus != Status.PENDING) {

switch (mStatus) {

case RUNNING:

throw new IllegalStateException("Cannot execute task:"

+ " the task is already running.");

case FINISHED:

throw new IllegalStateException("Cannot execute task:"

+ " the task has already been executed "

+ "(a task can be executed only once)");

}

}

mStatus = Status.RUNNING;

onPreExecute();

mWorker.mParams = params;

exec.execute(mFuture);

return this;

}
这里看到最后使用了exec.execute(mFruture)调用了,这里是线程池启动器,此时启动了线程池。并执行了FutureTask,而WorkerRunnable是作为了callback的回调。最终执行了mWorker里面的call方法。对于线程池,其代码比较复杂也就大概了解至此。对于开启线程就需要先申请内存空间,再执行run方法,线程池就是需要开启多条线程,其实预先申请5条(默认),要是之后的呢?那么就先将其转为task任务暂存,等条件达到也就是有空余的线程可以出来处理时再去取task执行。线程处理完成任务之后当然需要更新UI上的数据,那么这就需要使用到了handler机制了,再继续往下看源代码。

private void finish(Result result) {

if (isCancelled()) {

onCancelled(result);

} else {

onPostExecute(result);

}

mStatus = Status.FINISHED;

}

方法调用了他,我们继续看谁调用了finish

private static class InternalHandler extends Handler {

@SuppressWarnings({"unchecked", "RawUseOfParameterizedType"})

@Override

public void handleMessage(Message msg) {

AsyncTaskResult result = (AsyncTaskResult) msg.obj;

switch (msg.what) {

case MESSAGEPOSTRESULT:

// There is only one result

result.mTask.finish(result.mData[0]);

break;

case MESSAGEPOSTPROGRESS:

result.mTask.onProgressUpdate(result.mData);

break;

}

}

}

在finish 线程 结束前,这里就使用handler接收处理Message,然后执行了onProgressUpdapte()方法,这就是可以进行UI更新操作了。

最后说下Handler还有AsyncTask的描述为什么是The task instance must be created on the UI thread ? 了解Handler机制的人就知道,其实Handler在处理消息队列(MessageQueue)的时候就需要使用到轮询器(Looper)来进行循环获取消息,虽然我们可以new 很多个Handler但是他们本身就只存在一个Looper,当然UI线程中系统就默认帮我们开启了一个Looper,这样主线程就不需要去创建Looper了,要是不在UI线程初始化使用AsyncTask,那么在子线程中就需要自身去创建 个Looper提供给Handler使用,不然就会报异常。当然这样做还是会出现问题,因为AsyncTask使用到prepare需要在更新UI数据,其必须是在UI主线程的Looper中才可以实现(因为AsyncTask本身使用的就是UI线程下的Handler处理),它还是会因为创建出来的Looper不是UI Looper导致异常。所以要想使用AsyncTask就必须要在UI线程中初始化使用,还有一个AsyncTask对象只能调用一次excuste且需要在UI线程中调用。

AsyncTask总体运行机制:FutureTask获取任务执行run方法,run方法中调用了WorkerRunnable的call方法回调然后调用了doInBackground方法,doInbackground方法再将处理结果通过handler处理调用onProgressUpdapte和onPostExecute或者onCancelled方法进行数据更新操作(当然这只是一小部分)。


5、接下来就讲解下AsyncTask初始化参数信息和其里面几个方法的作用

先说下AsyncTask初始化参数代表的含义:
/**
  *Params:doInBackground方法的参数类型;请求类型,如:url就是String类型的网址链接
  *Progress:AsyncTask所执行的后台任务的进度类型;如果不需要更新进度就直接返回void
  *Result:后台任务的返回结果类型。
**/
public abstract class AsyncTask<Params, Progress, Result> 

AsyncTask的调用无非就以下几个方法:

onPreExecute() //此方法会在后台任务执行前被调用,用于进行一些准备工作
doInBackground(Params... params) //此方法中定义要执行的后台任务,在这个方法中可以调用publishProgress来更新任务进度(publishProgress内部会调用onProgressUpdate方法)
onProgressUpdate(Progress... values) //由publishProgress内部调用,表示任务进度更新
onPostExecute(Result result) //后台任务执行完毕后,此方法会被调用,参数即为后台任务的返回结果
onCancelled() //此方法会在后台任务被取消时被调用

6、接着编写自定义的ImageLoader+LRU算法组合实现图片加载缓存(三级缓存)

思路:
存:
1、先异步访问网络获取图片资源
2、将网络获取到的图片资源通过LRU算法缓存到SD卡和内存中

取:

1、先从运行内存中获取图片对象

2、内存中没有在到本地SD卡上获取

3、本地SD卡上也没有再去网络上获取

实现代码:

package com.example.lainanzhou.imagecachedemo.utils;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.os.Environment;
import android.os.Message;
import android.os.StatFs;
import android.util.Log;
import android.util.LruCache;
import android.widget.ImageView;
import android.widget.ListView;

import com.example.lainanzhou.imagecachedemo.R;
import com.example.lainanzhou.imagecachedemo.adapter.NewsAdapter;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * TODO:
 * 通过AsyncTask和LRU算法实现图片三级缓存的图片操作类
 * 存:
 * 1.先网络获取
 * 2.存到运行内存中和写到sd卡上
 * 取:
 * 1.先取运行内存中的图片缓存
 * 2.再取sd卡图片缓存资源
 * 3.最后取网络上的图片资源
 * 还有避免图片出现显示错乱情况(ListView的缓存机制复用convertView导致)
 * 设置View的Tag即可避免
 *
 * @author Joker
 * @createDate 2016/7/15.
 */
public class ImageLoader {
    private static ImageLoader mImageLoader;
    private ImageView iv;
    private String mUrl;
    public static LruCache<String, Bitmap> mLruCache;
    private static final int FREE_SD_SPACE_NEEDED_TO_CACHE = 10;
    private android.os.Handler mHandler = new android.os.Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            if (iv.getTag() == mUrl) {//获取ImageView的tag区别设置图片避免图片显示错乱
                Bitmap bitmap = (Bitmap) msg.obj;
                iv.setImageBitmap(bitmap);
            }
        }
    };
    private int mCorePoolSize = 10;
    private int  mMaximumPoolSize = 20;
    private int mKeepAliveTime ;
    private TimeUnit unit = TimeUnit.MILLISECONDS;
    // BlockingQueue<Runnable> workQueue = new
    // ArrayBlockingQueue<Runnable>(10);// 阻塞队列
    private BlockingQueue<Runnable> workQueue = new
            LinkedBlockingQueue<Runnable>();// 阻塞队列
    private ThreadFactory threadFactory = Executors.defaultThreadFactory();
    // RejectedExecutionHandler handler = new
    // ThreadPoolExecutor.AbortPolicy();//如果出现错误,则直接抛出异常
    // RejectedExecutionHandler handler = new
    // ThreadPoolExecutor.CallerRunsPolicy();// 如果出现错误,直接执行加入的任务

    // RejectedExecutionHandler handler = new
    // ThreadPoolExecutor.DiscardOldestPolicy();//
    // 如果出现错误,移除第一个任务,执行加入的任务
    private RejectedExecutionHandler handler = new ThreadPoolExecutor.DiscardPolicy();// 如果出现错误,不做处理
    //第一种设置AsyncTask线程池方式
    private ThreadPoolExecutor mExecutor = new ThreadPoolExecutor(mCorePoolSize,// 核心线程数 : 10
            mMaximumPoolSize,// 最大线程数 : 20
            mKeepAliveTime,// 保持的时间长度
            unit,// keepAliveTime单位
            workQueue,// 任务队列
            threadFactory,// 线程工厂
            handler);// 错误捕获器
    //第二种修改AsyncTask线程池方式
    private ExecutorService mExecutorService = Executors.newFixedThreadPool(10);

    public synchronized static ImageLoader instance() {
        if (mImageLoader == null) {
            mImageLoader = new ImageLoader();
            //获取程序运行时最大内存空间
            long maxMemory = Runtime.getRuntime().maxMemory();
            int cacheSize = (int) (maxMemory / 4);
            mLruCache = new LruCache<String, Bitmap>(cacheSize) {
                //获取每次加载对象缓存的内存大小;默认返回的是元素的个数而非内存大小
                @Override
                protected int sizeOf(String key, Bitmap value) {
                    //每次存对象都会走的方法
                    return value.getByteCount();
                }
            };
        }
        return mImageLoader;
    }

    private ImageLoader() {

    }

    /**
     * 直接开启线程处理方式显示图片
     * 加锁避免疯狂滑动开启多余线程处理同个url
     *
     * @param imageView
     * @param url
     */
    public void showImageFromThread(final ImageView imageView, final String url) {
        //取缓存
        Bitmap bitmap = getBitmapFromCache(url);
        //缓存存在就直接显示
        if (bitmap != null) {
            imageView.setImageBitmap(bitmap);
            Log.d(getClass().getSimpleName(), "取内存缓存" + url);
        } else {
            synchronized (url) {
                new Thread() {
                    @Override
                    public void run() {
                        super.run();
                        iv = imageView;
                        mUrl = url;
                        Bitmap bitmap = getBitmapFromUrl(url);
                        //缓存图片
                        addBitmap2Cache(url, bitmap);
                        Message mes = Message.obtain();
                        mes.obj = bitmap;
                        mHandler.sendMessage(mes);
                    }
                }.start();
            }
        }
    }

    /**
     * 从Url获取bitmap对象
     *
     * @param urlString
     * @return
     */
    private Bitmap getBitmapFromUrl(String urlString) {
        Bitmap bitmap = null;
        InputStream is = null;
        try {
            URL url = new URL(urlString);
            HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
            is = new BufferedInputStream(urlConnection.getInputStream());
            bitmap = BitmapFactory.decodeStream(is);//将流对象转成bitmap对象
            urlConnection.disconnect();//释放资源
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (is != null)
                    is.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return bitmap;
    }

    public void showImageFromAsyncTask(ImageView imageView, String urlString, boolean isLoader) {
        //取缓存
        Bitmap bitmap = getBitmapFromCache(urlString);
        if (bitmap == null) {
            if (isLoader) {
                bitmap = getBitmapFromSdCard(urlString);
                if (bitmap == null && isLoader)
//                    new ImageAsyncTask(imageView).execute(urlString);//缓存没有就网络加载
                    new ImageAsyncTask(imageView,urlString);//缓存没有就网络加载
                else if (imageView.getTag().equals(urlString)) {
                    addBitmap2Cache(urlString, bitmap);//缓存到内存
                    imageView.setImageBitmap(bitmap);//有缓存就直接显示
                    Log.d(getClass().getSimpleName(), "取Sd卡缓存" + urlString);
                }
            } else if (imageView.getTag().equals(urlString)) {
                imageView.setImageResource(R.mipmap.ic_launcher);//设置默认图片
            }
        } else if (imageView.getTag().equals(urlString)) {
            imageView.setImageBitmap(bitmap);//有缓存就直接显示
            Log.d(getClass().getSimpleName(), "取内存缓存" + urlString);
        }

    }

    class ImageAsyncTask extends AsyncTask<String, Void, Bitmap> {
        private ImageView mImageView;
        private String url;

        public ImageAsyncTask(ImageView imageView,String... parmas) {
            this.executeOnExecutor(mExecutor,parmas);
//            this.executeOnExecutor(mExecutorService,parmas);
            mImageView = imageView;
        }

        @Override
        protected Bitmap doInBackground(String... params) {
            url = params[0];
            Bitmap bitmap = getBitmapFromUrl(url);
            //缓存图片
            if (bitmap != null) {
                addBitmap2Cache(url, bitmap);
                writeBitmap2SdCard(bitmap, url);
            }
            return bitmap;
        }

        @Override
        protected void onPostExecute(Bitmap bitmap) {
            super.onPostExecute(bitmap);
            if (bitmap == null && mImageView.getTag().equals(url))
                mImageView.setImageResource(R.mipmap.ic_launcher);//设置默认图片
            else if (mImageView.getTag().equals(url))
                mImageView.setImageBitmap(bitmap);
        }
    }

    /**
     * 加载停止可见的图片资源
     *
     * @param start
     * @param visibleCount
     */
    public void loadVisibleImages(ListView listView, int start, int visibleCount, boolean isLoader) {
        for (int i = start; i < visibleCount; i++) {
            //            new ImageAsyncTask(imageView).execute(urlList.get(i).getImageUrl());
            ImageView imageView = (ImageView) listView.findViewWithTag(NewsAdapter.mUrls[i]);
            showImageFromAsyncTask(imageView, NewsAdapter.mUrls[i], isLoader);
        }
    }

    /**
     * 添加图片到缓存中
     *
     * @param url
     * @param bitmap
     */
    private void addBitmap2Cache(String url, Bitmap bitmap) {
        if (getBitmapFromCache(url) == null) {
            mLruCache.put(url, bitmap);
            Log.d(getClass().getSimpleName(), "内存缓存" + url);
        }
    }

    /**
     * 从缓存中获取图片资源
     *
     * @param url
     * @return
     */
    private Bitmap getBitmapFromCache(String url) {
        return mLruCache.get(url);
    }

    private void writeBitmap2SdCard(Bitmap bitmap, String path) {
        if (bitmap == null) {
            return;
        }
        //判断sdcard上的空间
        if (FREE_SD_SPACE_NEEDED_TO_CACHE > freeSpaceOnSd()) {
            //SD空间不足
            return;
        }
        //创建缓存目录,系统一运行就得创建缓存目录的
        String filename = convertUrlToFileName(path);
        String dir = getDirectory();
        File dirFile = new File(dir);
        if (!dirFile.exists())
            dirFile.mkdirs();
        File file = new File(dirFile + "/" + filename);
        try {
            file.createNewFile();
            OutputStream outStream = new FileOutputStream(file);
            bitmap.compress(Bitmap.CompressFormat.JPEG, 100, outStream);
            outStream.flush();
            outStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 计算sdcard上的剩余空间
     **/
    private int freeSpaceOnSd() {
        StatFs stat = new StatFs(Environment.getExternalStorageDirectory().getPath());
        double sdFreeMB = ((double) stat.getAvailableBlocks() * (double) stat.getBlockSize()) / 1024 * 1024;
        return (int) sdFreeMB;
    }

    private Bitmap getBitmapFromSdCard(String url) {
        String path = getDirectory() + "/" + convertUrlToFileName(url);
        File file = new File(path);
        if (file.exists()) {
            Bitmap bmp = BitmapFactory.decodeFile(path);
            if (bmp == null) {
                file.delete();
            } else {
                return bmp;
            }
        }
        return null;
    }

    /**
     * 取SD卡路径
     **/
    private String getSDPath() {
        boolean sdCardExist = Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED);
        //判断sd卡是否存在
        if (sdCardExist) {
            //获取根目录
            return Environment.getExternalStorageDirectory().getPath();
        }
        return "";
    }

    /**
     * 将url转成文件名
     **/
    private String convertUrlToFileName(String url) {
        String[] strs = url.split("/");
        return strs[strs.length - 1];
    }

    /**
     * 获得缓存目录
     **/
    private String getDirectory() {
        String dir = getSDPath() + "/" + "imgCache";
        return dir;
    }
}

7.设置Adapter针对ListView的滑动事件的监听

只有在滑动状态是停止的时候才去访问网络加载数据。

代码实现:

package com.example.lainanzhou.imagecachedemo.adapter;

import android.content.Context;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;

import com.example.lainanzhou.imagecachedemo.R;
import com.example.lainanzhou.imagecachedemo.bean.NewsBean;
import com.example.lainanzhou.imagecachedemo.utils.ImageLoader;

import java.util.List;

/**
 * TODO:
 * 处理ListView显示数据和监听当前ListView滑动状态来加载数据
 *
 * @author Joker
 * @createDate 2016/7/15.
 */
public class NewsAdapter extends BaseAdapter implements AbsListView.OnScrollListener {
    private LayoutInflater mLayoutInflater;
    private List<NewsBean> mBeanList;
    private boolean isFirst = false;
    private int start;
    private int end;
    private ListView mListView;
    public static String[] mUrls;

    public NewsAdapter(Context context, ListView listView, List<NewsBean> data) {
        mLayoutInflater = LayoutInflater.from(context);
        mBeanList = data;
        mListView = listView;
        mListView.setOnScrollListener(this);
    }

    @Override
    public int getCount() {
        return mBeanList == null ? 0 : mBeanList.size();
    }

    @Override
    public Object getItem(int position) {
        return mBeanList == null ? null : mBeanList.get(position);
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolder viewHolder;
        if (convertView == null) {
            viewHolder = new ViewHolder();
            convertView = mLayoutInflater.inflate(R.layout.item_layout, null);
            viewHolder.iv = (ImageView) convertView.findViewById(R.id.imageView);
            viewHolder.tv_titile = (TextView) convertView.findViewById(R.id.title);
            viewHolder.tv_content = (TextView) convertView.findViewById(R.id.content);
            convertView.setTag(viewHolder);
        } else {
            viewHolder = (ViewHolder) convertView.getTag();
        }
        String ivUrl = mBeanList.get(position).getImageUrl();
        viewHolder.iv.setTag(ivUrl);
        //设置网路图片
        //        mImageLoader.showImageFromAsyncTask(viewHolder.iv, ivUrl);
        //        ImageLoader.instance().showImageFromAsyncTask(viewHolder.iv, ivUrl);
        viewHolder.tv_titile.setText(mBeanList.get(position).getTitle());
        viewHolder.tv_content.setText(mBeanList.get(position).getContent());

        return convertView;
    }

    @Override
    public void onScrollStateChanged(AbsListView view, int scrollState) {
        //只有滑动状态发生改变才会走的方法,首次进来不会走
        if (scrollState == SCROLL_STATE_IDLE) {//停止状态
            //网络加载停止时可见项
            //            ImageLoader.instance().loadVisibleImages(mListView, start, end);
            showImageLoader(start, end, true);
        } else {//其他状态
            //停止网络加载任务
            showImageLoader(start, end, false);
        }
    }

    @Override
    public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
        //滑动就会走的方法,首次进来也会走
        start = firstVisibleItem;
        end = start + visibleItemCount;
        if (!isFirst && visibleItemCount > 0) {
            if (mUrls == null)
                mUrls = new String[mBeanList.size()];
            //            ImageLoader.instance().loadVisibleImages(mListView, start, end);
            for (int i = start; i < start + mBeanList.size(); i++) {
                mUrls[i] = mBeanList.get(i - start).getImageUrl();
            }
            showImageLoader(start, end, true);
            isFirst = true;
            return;
        }
        showImageLoader(start, end, false);

    }

    class ViewHolder {
        private ImageView iv;
        private TextView tv_titile;
        private TextView tv_content;
    }

    private void showImageLoader(int firstVisibleItem, int visibleCounts, boolean isLoader) {
        ImageLoader.instance().loadVisibleImages(mListView, firstVisibleItem, visibleCounts, isLoader);
        Log.d(getClass().getSimpleName(), "滑动状态:" + isLoader);
    }
}

8.MainActivity的调用

代码实现:

package com.example.lainanzhou.imagecachedemo;

import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.widget.ListView;

import com.example.lainanzhou.imagecachedemo.adapter.NewsAdapter;
import com.example.lainanzhou.imagecachedemo.bean.NewsBean;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity {

    private ListView mListView;
    private String url = "http://www.imooc.com/api/teacher?type=4&num=30";
    private List<NewsBean> mBeanList = new ArrayList<>();
    private int start, visibleCounts;//可见item条目起始标志
    private boolean isFirst;
    private NewsAdapter mNewsAdapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mListView = (ListView) findViewById(R.id.listView);
        new NewsAsyncTask().execute(url);//启动异步请求
    }

    class NewsAsyncTask extends AsyncTask<String, Void, List<NewsBean>> {

        @Override
        protected List<NewsBean> doInBackground(String... params) {
            return getJsonDataFromUrl(params[0]);//传进来的参数只有一个url
        }

        @Override
        protected void onPostExecute(List<NewsBean> newsBeen) {
            super.onPostExecute(newsBeen);
            //更新UI数据界面
            mNewsAdapter = new NewsAdapter(MainActivity.this, mListView, mBeanList);
            mListView.setAdapter(mNewsAdapter);
        }
    }

    /**
     * 从url中获取结果
     *
     * @param param
     * @return
     */
    private List<NewsBean> getJsonDataFromUrl(String param) {
        try {
            InputStream is = new URL(url).openStream();
            String jsonString = radStream(is);
            try {
                JSONObject jsonObject = new JSONObject(jsonString);
                JSONArray jsonArray = jsonObject.getJSONArray("data");
                for (int i = 0; i < jsonArray.length(); i++) {
                    NewsBean newsBean = new NewsBean();
                    jsonObject = jsonArray.getJSONObject(i);
                    newsBean.setImageUrl(jsonObject.getString("picSmall"));
                    newsBean.setTitle(jsonObject.getString("name"));
                    newsBean.setContent(jsonObject.getString("description"));
                    mBeanList.add(newsBean);
                }
            } catch (JSONException e) {
                e.printStackTrace();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return mBeanList;
    }

    /**
     * 获取输入流结果
     *
     * @param is
     * @return
     */
    private String radStream(InputStream is) {
        String result = "";
        try {
            String line = "";
            //将输入字节流转化为字符流来处理
            InputStreamReader isr = new InputStreamReader(is, "utf-8");
            //读取字符流
            BufferedReader br = new BufferedReader(isr);
            try {
                while ((line = br.readLine()) != null) {
                    result += line;
                }
                //关闭流
                br.close();
                isr.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return result;
    }


}


最后附带项目链接地址:点击打开链接


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 内容概要 《计算机试卷1》是一份综合性的计算机基础和应用测试卷,涵盖了计算机硬件、软件、操作系统、网络、多媒体技术等多个领域的知识点。试卷包括单选题和操作应用两大类,单选题部分测试学生对计算机基础知识的掌握,操作应用部分则评估学生对计算机应用软件的实际操作能力。 ### 适用人群 本试卷适用于: - 计算机专业或信息技术相关专业的学生,用于课程学习或考试复习。 - 准备计算机等级考试或职业资格认证的人士,作为实战演练材料。 - 对计算机操作有兴趣的自学者,用于提升个人计算机应用技能。 - 计算机基础教育工作者,作为教学资源或出题参考。 ### 使用场景及目标 1. **学习评估**:作为学校或教育机构对学生计算机基础知识和应用技能的评估工具。 2. **自学测试**:供个人自学者检验自己对计算机知识的掌握程度和操作熟练度。 3. **职业发展**:帮助职场人士通过实际操作练习,提升计算机应用能力,增强工作竞争力。 4. **教学资源**:教师可以用于课堂教学,作为教学内容的补充或学生的课后练习。 5. **竞赛准备**:适合准备计算机相关竞赛的学生,作为强化训练和技能检测的材料。 试卷的目标是通过系统性的题目设计,帮助学生全面复习和巩固计算机基础知识,同时通过实际操作题目,提高学生解决实际问题的能力。通过本试卷的学习与练习,学生将能够更加深入地理解计算机的工作原理,掌握常用软件的使用方法,为未来的学术或职业生涯打下坚实的基础。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值