JAVA中的Executors使用

 一  . Java通过Executors提供四种线程池

1 . newCachedThreadPool :创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。

private void notWorkCachedThread() {
    ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
    for (int i = 0; i < 10; i++) {
        final int index = i;
        try {
            Thread.sleep(index * 1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        cachedThreadPool.execute(new Runnable() {
            public void run() {
                System.out.println(index);
            }
        });
    }
}
线程池为无限大,当执行第二个任务时第一个任务已经完成,会复用执行第一个任务的线程,而不用每次新建线程。

2 . newFixedThreadPool  :  创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。

private void notWorkFixedThread(){
    ExecutorService fixedThreadPool = Executors.newFixedThreadPool( 3 );
    for (int i = 0; i < 10; i++) {
        final int index = i;
        fixedThreadPool.execute(new Runnable() {
            public void run() {
                try {
                    System.out.println(index);
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
    }
}
因为线程池大小为3,每个任务输出index后sleep 2秒,所以每两秒打印3个数字。
定长线程池的大小最好根据系统资源进行设置。如Runtime.getRuntime().availableProcessors()

3 . newScheduledThreadPool : 创建一个定长线程池,支持定时及周期性任务执行。

public  void notWorkScheduledThread(String[] args) {
    ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);
    scheduledThreadPool.schedule(new Runnable() {
        public void run() {
            System.out.println("delay 3 seconds");
        }
    }, 3, TimeUnit.SECONDS);//表示延迟3秒执行
}

public  void notWorkScheduledThread2(String[] args) {
    ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);
    scheduledThreadPool.scheduleAtFixedRate(new Runnable() {
        public void run() {
            System.out.println("delay 1 seconds, and excute every 3 seconds");
        }
    }, 1, 3, TimeUnit.SECONDS); //表示延迟1秒后每3秒执行一次
}

4 . newSingleThreadExecutor  :创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。

public static void notWorkSingleThreadExecutor(String[] args) {
    ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
    for (int i = 0; i < 10; i++) {
        final int index = i;
        singleThreadExecutor.execute(new Runnable() {
            public void run() {
                try {
                    System.out.println(index);
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
    }
}
结果依次输出,相当于顺序执行各个任务。

二 . LruCachec缓存

在Android中,有一个叫做LruCache类专门用来做图片缓存处理的。它有一个特点,当缓存的图片达到了预先设定的值的时候,那么近期使用次数最少的图片就会被回收掉LruCache里面的键值对分别是URL和对应的图片。

看代码:

public class MemoryCache extends LruCache< String ,Bitmap > {
   /**
    * @param maxSize for caches that do not override {@link #sizeOf}, this is
    *                the maximum number of entries in the cache. For all other caches,
    *                this is the maximum sum of the sizes of the entries in this cache.
    *                //1.如果重写sizeOf方法的话,构造函数中maxsize的值代表的是缓存中对象所占用的内存总量
    *                //2.如果不重写sizeOf方法的话,构造函数中maxSize的值代表的是缓存中的对象个数
    *                手机内存的获取方式:int MAXMEMONRY = (int) (Runtime.getRuntime() .maxMemory() / 1024);
    */
   public MemoryCache(int maxSize) {
      super(maxSize);
   }

   @Override
   protected int sizeOf( String key , Bitmap value ) {
      return value.getByteCount();
   }
}

学习了 java 中的Executors 和Android中的LruCache,接下来我来写一个简单网络框架。

网络请求不外乎就是请求图片和请求字符串。

看代码:

public abstract class Request< A > {
    //接口对象
    private Callback mCallback;
    //网址
    private String url;
    //请求方式
    private Method method;
    //枚举成员
    public enum Method {
        GET, PSOT
    }

    /**
     * 构造方法
     */
    public Request(String url, Method method, Callback callback) {
        this.url = url;
        this.method = method;
        mCallback = callback;
    }

    /**
     * 属性封装方法
     * @return
     */
    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url ;
    }

    public Method getMethod() {
        return method ;
    }

    public void setMethod( Method method ) {
        this.method = method ;
    }

    /**
     * 返回接口对象
     * @return
     */
    public Callback getCallback() {
        return mCallback ;
    }

    /**
     * 接口
     * 有一个泛型 T 作为 onSucess方法参数的类型
     */
    public interface Callback<T> {
        //两个抽象方法
        void onSucess(T data);
        void onError(Exception exception);
    }

    /**
     * 抽象方法
     * 发起网络请求 URL 链接后请求下来的是字节数组 把自己数组传进去返回一个A
     * 用户象要发起网络请求时,就要根据url 和自己的想要请求方式创建一个Request对象,
     * 然后重写这个反方,在创建这个对象时 ,指定一个泛型 最后在重写这个方法的时候就对字节数组进行处理返回这个类的对象
     * 返回一个泛型 A
     * @param data
     * @return
     */
    abstract public A parseNetworkResponse(byte[] data);

    /**
     * (这个方法在网络数据请求下来后(bayt数组)调用这个方法)
     * 把字节数组转化成  A 泛型的类型 。
     * 在调用接口的方法(方法的参数的类型的是泛型的  A 把 a 传进去 )
     * 用户在创建接口对象时必须要成写接口的两个方法
     * 所以 mCallback.onSucess(a);执行的代码是用户端冲写的方法里面的代码
     * 这样我们就可以对  a  进行处理了 。
     * @param data
     */
    public void dispatchResult( byte[] data ) {
        A a = parseNetworkResponse( data ) ;
        mCallback.onSucess( a ) ;
    }

    /**
     * 这个方法主要用来post请求的时候
     * 用户端发起请求的时候 如果是post请求就要重写这个方法(因为这里返回的是null)
     * map集合里面装得是请求的参数
     * 我们重写这个方法后 ,就可以返回我们想要请求的参数的map集合
     * @return
     */
    public Map<String , String> getPostParams() {
        return  null ;
    }
}
 抽象Request类是对请求参数的封装。里面有Url , 请求方式 , 数据请求下来后回调的接口,有一个抽象方法。请求有Iamger Request请求,String Request请求。这个抽象方法的作用在后面说明。(这里使用的是java中的策略模式思想)。

 参数有了,就链接网络了,网络请求的耗时任务必须放在工作线程中,所以请求的代码应该写在Runnable 的run方法中。

看代码:

public class NetWorkRunnable implements Runnable{

    private static final int OUTTIEM = 5000 ;
    private Request request ; //自写的一个类,封装请求参数的一个类,里面有url ,请求的方式 ,和数据请求下来后回调的接口
    /**
     * 构造方法
     * request 此次请求的参数封装在这个类中。
     */
    public NetWorkRunnable( Request request ){
        this.request = request ;
    }

    /**
     * 根据请求参数类取请求方式
     * @param method
     * @return
     */
    public static String getStringMethod( Request.Method method ){
        if (method == Request.Method.GET) return "GET";
        if (method == Request.Method.PSOT) return "POST";
        //默认返回GET请求
        return "GET" ;
    }

    @Override
    public void run() {
        InputStream is = null ;
        try {
            URL url = new URL( request.getUrl() ) ;
            HttpURLConnection connt = ( HttpURLConnection) url.openConnection() ;
            connt.setRequestMethod( getStringMethod( request.getMethod())) ; //设置请求的方式
            connt.setConnectTimeout( OUTTIEM ) ;  //设置连接的超时时间
            if( request.getMethod() == Request.Method.PSOT ){//判断是否是post请求
                //允许写出(默认为false)
                connt.setDoOutput( true ) ;  //设置允许允许输出
                //获取输出流
                OutputStream out = connt.getOutputStream() ;
                //遍历map集合(找出请求的参数)
                HashMap<String,String> params = (HashMap<String , String>) request.getPostParams() ;
                String postParsms = "" ;
                //获取迭代器
                Iterator<Map.Entry< String  , String >> iterator = params.entrySet().iterator() ;
                //遍历map集合(找出请求的参数)
                while ( iterator.hasNext() ){
                    Map.Entry<String,String> entry = iterator.next() ;
                    String temp = entry.getKey()+"="+entry.getValue() ;
                    postParsms += temp+ "&" ;
                }
                //去掉最后一个字符
                postParsms = postParsms.substring( 0 , postParsms.length() - 1 ) ;
                out.write( postParsms.getBytes() ) ;//发送参数
                //一定要刷新一下
                out.flush() ;
            }
            //链接
            connt.connect() ;
            if( connt.getResponseCode() == HttpURLConnection.HTTP_OK ){
                int len = -1 ;
                byte[] buf = new byte[1024] ;
                is = connt.getInputStream() ;
                ByteArrayOutputStream baos = new ByteArrayOutputStream() ;
                while ( (len = is.read(buf))!=-1 ){
                    baos.write( buf ,0 ,len ) ;
                }
                //关键是请求数据下来后要怎样的处理( 调用request对象的dispatchResult())
                request.dispatchResult( baos.toByteArray() ) ;  //回调
            } 
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if ( is != null ){
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

用到接口回调的思想,数据请求下来后,进行回调在

request.dispatchResult( baos.toByteArray() ) ;

图片请求时 ,看代码:

public class ImageRequest extends Request <Bitmap> {
    /**
     * 构造方法
     * @param url
     * @param method
     * @param callback
     */
    public ImageRequest(String url, Method method, Callback callback) {
        super(url, method, callback) ;
    }


    @Override
    public Bitmap parseNetworkResponse(byte[] data) {

        /**
         * 文件目录
         * 这个文件的目录在终极类里面,初始化终极类的时候就初始化了这个目录
         */
        String cacheDir = HttpUltimate.CACHE_DIR  ;

        /**
         *这里是把图片缓存到内存中去
         */
        if ( cacheDir != null ){
            String fileName = getFileName( getUrl() ) ;  //Request类有getUrl()方法( 所以可以直接使用 )
            File file = new File( cacheDir + "/" + fileName ) ;
            try {
                //把图片写到磁盘上
                FileOutputStream fos = new FileOutputStream( file ) ;
                fos.write( data , 0 ,data.length ) ;
                fos.flush() ;
                fos.close() ;
            } catch (FileNotFoundException e) {
                e.printStackTrace() ;
            } catch (IOException e) {
                e.printStackTrace() ;
            }
        }
        //创建bitmap位图
        Bitmap bm = BitmapFactory.decodeByteArray( data , 0 , data.length );
        return bm ;
    }

    /**
     * 把url字符串转换成可以用来命名文件名的字符串
     * @return
     */
    public static String getFileName( String url){
        String fileName = url.replace("/" , "-").replace(":" ,"-").replace("?" ,"-") ;
        return fileName;
    }
}


字符串数据请求时:

public class StringRequest extends Request< String > {
    /**
     * 构造方法
     * @param url
     * @param method
     * @param callback
     */
    public StringRequest( String url , Method method , Callback callback ) {
        super( url , method , callback ) ;
    }

    /**
     * 重写的抽象方法
     * @param data
     * @return
     */
    @Override
    public String parseNetworkResponse( byte[] data ) {
        return new String( data ) ;
    }
}

看完这两个类应该知道这个抽象方法的作用了吧。体现了策略模式的编程思想。

使用到Executors和lruCache缓存缓存图片

看代码:

public class CoreHttp {
    //线程池对象
    private ExecutorService mThreadPool ;
    /**
     * 构造方法 ,创建线程池实体
     * @param context
     */
    public CoreHttp( Context context ) {
        //创建线程池对象(固定大小的线程池)
        mThreadPool = Executors.newFixedThreadPool( 3 ) ;
    }
    /**
     * 发起网络请求的方法
     * @param ( 参数是个请求类对象 包含请求的网址,和请求方式,还有回调的接口对象 )
     */
    public void sendRequest( Request request ){
        //往线程池塞任务
        mThreadPool.submit( new NetWorkRunnable( request ) ) ;
    }
}
lruCache缓存:

public class MemoryCache extends LruCache< String ,Bitmap > {
   /**
    * @param maxSize for caches that do not override {@link #sizeOf}, this is
    *                the maximum number of entries in the cache. For all other caches,
    *                this is the maximum sum of the sizes of the entries in this cache.
    *                //1.如果重写sizeOf方法的话,构造函数中maxsize的值代表的是缓存中对象所占用的内存总量
    *                //2.如果不重写sizeOf方法的话,构造函数中maxSize的值代表的是缓存中的对象个数
    *                手机内存的获取方式:int MAXMEMONRY = (int) (Runtime.getRuntime() .maxMemory() / 1024);
    */
   public MemoryCache(int maxSize) {
      super(maxSize);
   }

   @Override
   protected int sizeOf( String key , Bitmap value ) {
      return value.getByteCount();
   }
}

工具准备好了就要使用了,先看图片的请求:

public class IamgeLoader {

    //含有线程池类的对象
    private CoreHttp mCoreHttp ;
    //图片加载对象
    private static IamgeLoader iamgeLoader ;
    //缓存对象
    private MemoryCache mMemoryCache ;

    /**
     * 构造方法
     */
    private IamgeLoader( Context context ){
        //线程对象也有了
        mCoreHttp = new CoreHttp( context ) ;
        //因为重写了
        mMemoryCache = new MemoryCache( 1024 * 1024 * 10 );  //10M
    }

    /**
     * 加载图片
     * 1 . 先从缓存读取
     * 2 . 没有 , 在从磁盘度取
     * 3 . 还是没有 , 再走网络
     *
     * @param url
     *
     * @param imageView
     *
     */
    public static void loadImage( final String url , final ImageView imageView ){

        //设置标记
        imageView.setTag( url ) ;
        /**
         * 首先读取LruCache缓存
         */
        Bitmap bm = iamgeLoader.mMemoryCache.get( url ) ; //因为MemoryCache继承LruCache, key是url , Object 是bitmap
        if ( bm != null ){
            imageView.setImageBitmap( bm ) ;
            return ;
        }
        /**
         *没有 , 在读取本地(磁盘)
         */
        String fileName = ImageRequest.getFileName( url ) ;
        bm = getBitmapFromLocalCache( fileName ) ;
        if( bm != null ){
            imageView.setImageBitmap( bm ) ;
            //添加到lruach缓存中去
            iamgeLoader.mMemoryCache.put( url , bm ) ;
        }

        /**
         *还是没有  再图片请求
         */
        ImageRequest imgRequest = new ImageRequest( url , Request.Method.GET , new Request.Callback< Bitmap >() {
            @Override
            public void onSucess( final Bitmap data ) {
                iamgeLoader.mMemoryCache.put( url , data ) ;
                if( imageView.getTag().toString().equals( url )){
                    //一定要在主线程更新UI
                    HttpUltimate.handler.post( new Runnable() {
                        @Override
                        public void run() {
                            imageView.setImageBitmap( data ) ;
                        }
                    }) ;
                }
            }

            @Override
            public void onError( Exception exception) {

            }
        }) ;

        /**
         *  发起网络请求  发起网络请求
         */
        iamgeLoader.mCoreHttp.sendRequest( imgRequest ) ;

    }

    /**
     * 获取实例
     * @param context
     * @return
     */
    public static void initImageLoader(Context context){
        if ( iamgeLoader == null ){
            synchronized ( IamgeLoader.class ){
                if ( iamgeLoader  == null ){
                    /**
                     * new之后  网络请求的核心类有了  mCoreHttp 实例了
                     * mMemoryCache 缓存也有实例了
                     */
                    iamgeLoader = new IamgeLoader( context );
                }
            }
        }
        return ;
    }
    /**
     * 从本地读取图片
     * @param filename
     * @return
     */
    private static Bitmap getBitmapFromLocalCache( String filename ){
        File file = new File( HttpUltimate.CACHE_DIR + "/" + filename ) ;
        if (!file.exists()){
            return null ;
        }
        return     BitmapFactory.decodeFile(filename);
    }
}
再看字符串请求

public class HttpLoader {

    private CoreHttp mCoreHttp ;
    private static HttpLoader httpLoader ;

    /**
     * 构造方法
     * @param context
     */
    private HttpLoader( Context context ){
        //创建这个对象后,线城池也就常见好了
        mCoreHttp = new CoreHttp( context ) ;
    }

    /**
     * 创建本类实例
     * @param context
     */
    public static void initHttpLoader( Context context ){
        if( httpLoader == null ){
            synchronized ( HttpLoader.class ){
                if ( httpLoader == null ){
                    httpLoader = new HttpLoader( context ) ;
                }
            }
        }
    }

    /**
     * 加载网络数据
     * @param request
     */
    public static void loadData( Request request ){
        //为什么使用httpLoader.  调用静态方法中不能使用非静态变量
        httpLoader.mCoreHttp.sendRequest( request ) ;
    }
}

最后的封装,看代码:

public class HttpUltimate {
    //绑定主线程的Looper的Handler对象
    public static Handler handler ;
    //这是个终极类
    //1.可以加载图片
    //2.可以进行网络数据的访问
    //缓存文件的目录
    public static  String CACHE_DIR ;
    /**
     * 初始化实例
     * 图片加载实例
     * 网络数据加载实例
     * 还有初始化缓存目录
     * @param context
     */
    public static void intiHttpUltimate( Context context ){
        //加载网路数据
        HttpLoader.initHttpLoader( context ) ;
        //加载图片数据
        IamgeLoader.initImageLoader( context ) ;
        //初始化缓存的目录
        CACHE_DIR = getCachePath( context ) ;
        //初始handler对象
        handler = new Handler() ;
    }

    /**
     * 加载图片的静态的方法
     * @param url
     * @param imageView
     */
    public static void loadIamge( String url , ImageView imageView ){
        IamgeLoader.loadImage( url , imageView ) ;
    }

    /**
     * 加载网络数据的静态的方法
     * @param request
     */
    public static void loadData( Request request ){
        HttpLoader.loadData( request ) ;
    }

    /**
     * 初始化缓存目录
     */
    public static String getCachePath( Context context ){
        //获取data/data/应用程序包名/Cache目录
        File file = new File( context.getCacheDir().getAbsolutePath() + "/img" );
        //文件夹不存在就不要创建文件夹
        if (!file.exists()){
            file.mkdirs() ;
        }
        return file.getAbsolutePath() ;  //返回文件的绝对路径
    }
}

现在是真正的把工具类准备好了,接下来就是使用了,看代码:

public class BaiKeApplication extends Application {
   @Override
   public void onCreate() {
      super.onCreate();
      //初始化终极类
      HttpUltimate.intiHttpUltimate( getApplicationContext() );
   }
}
先初始化。

//链接URL
String url = AppGlobal.ROOT_URL + imgPath ;
//加载图片
HttpUltimate.loadIamge( url,imageIv ) ;
加载图片。

/**
 * 网络加载数据
 */
private void loadFromNetwork() {

    //创建字符串请求对象
    StringRequest sr = new StringRequest( rooturl + id  , Request.Method.GET , new Callback< String >(){
        @Override
        public void onSucess(String data) {
            try {

                JSONObject json = new JSONObject(data) ;
                final String description = json.getString("description") ;
                final String keywords = json.getString("keywords") ;
                final String img = json.getString("img") ;
                final String message = json.getString("message") ;

                food = new HealthFood( description , keywords ,  id  , img ) ;
                Log.d("page" , " food 数据已经请求下来") ;

                list = fdb.findItme( HistoryTable.history_flag , HistoryTable.id_column+"=? and " +
                                     HistoryTable.img_column + "=?" , new String[]{ id+"" , img });
                if( list == null || list.size() == 0 ){
                    fdb.add( food  , HistoryTable.history_flag ) ;
                }

                //添加到浏览历史列表
                HttpUltimate.handler.post( new Runnable() {
                    @Override
                    public void run() {
                        fillView( description , keywords , img , message ) ;
                        Log.d("page" , "  UI 更新成功") ;
                    }
                }) ;
            } catch (JSONException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onError(Exception exception) {
        }

    }) ;
    //加载网络数据
    HttpUltimate.loadData( sr );
    Log.d("page" , " 发起网络请求了") ;
请求字符串。

写得不好,请多多指教!










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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值