`
810364804
  • 浏览: 788136 次
文章分类
社区版块
存档分类
最新评论

使用java concurrent处理异步加载图片功能

 
阅读更多

转载:http://marshal.easymorse.com/archives/3081

java5开始,增加了concurrent api,用于并发处理。比如起多个线程并发从网络上下载图片,然后在本地显示。

这里写个简单的代码,来说明如何使用concurrent api提供的线程连接池。

运行结果类似这样:

start do 1 task … 
>>main thread end. 
start do 2 task … 
start do 1 finished. 
start do 3 task … 
start do 2 finished. 
start do 3 finished.

这里的task1到task3,都做的同样的事情,让它所属的线程休眠2000ms:

private static void doSomething(int id) { 
    System.out.println("start do " + id + " task …"); 
    try { 
        Thread.sleep(1000 * 2); 
    } catch (InterruptedException e) { 
        e.printStackTrace(); 
    } 
    System.out.println("start do " + id + " finished."); 
}

 

如果没有java自带的这个api,需要自己或者使用不标准的第三方线程池api。用concurrent api写起来很简洁:

public static void main(String[] args) { 

    ExecutorService executorService = Executors.newFixedThreadPool(2);

    executorService.submit(new Runnable() { 
        @Override 
        public void run() { 
            doSomething(1); 
        } 
    });

    executorService.submit(new Runnable() { 
        @Override 
        public void run() { 
            doSomething(2); 
        } 
    });

    executorService.submit(new Runnable() { 
        @Override 
        public void run() { 
            doSomething(3); 
        } 
    });

    executorService.shutdown(); 
    System.out.println(">>main thread end.");

}

首先,创建了一个线程池,里面有2个线程:

ExecutorService executorService = Executors.newFixedThreadPool(2);

然后,通过submit()方法,提交一个Runnable的实例,这个实例将交由线程池中空闲的线程执行。

在main线程中直接运行了:

executorService.shutdown();

不必担心,线程池不会直接关闭的,只有当它执行完所有提交的任务后才会关闭。如果不写这行,在本例中,应用将不会停止,因为虽然main线程(就是运行main方法的线程,也叫主线程)退出了,但是线程池中依然有线程运行,因此应用(进程)不会退出。

用Java concurrent编写异步加载图片功能

http://marshal.easymorse.com/archives/3085

android异步加载ListView中的图片中使用异步方式加载的图片,当时要的急,写的很粗糙,是为每个图片加载一个线程来实现的。

可以用java concurrent很简明的实现类似功能,并且用到线程池。

image

这里加载的图片,都是从网上直接获取的。如果用android的UI线程,则需要图片全部加载后才能显示界面。

这里使用了concurrent api通过后台线程并发获取,本例中线程池中只有一个线程,可以设置为多个以加快加载速度。可参见使用java concurrent处理并发需求中的简单示例了解concurrent api的基本机制。

public class LazyLoadImageActivity extends Activity {

    private ExecutorService executorService = Executors.newFixedThreadPool(1);

    /** Called when the activity is first created. */ 
    @Override 
    public void onCreate(Bundle savedInstanceState) { 
        super.onCreate(savedInstanceState); 
        setContentView(R.layout.main); 
        loadImage("http://www.chinatelecom.com.cn/images/logo_new.gif", R.id.image1); 
        loadImage("http://www.baidu.com/img/baidu_logo.gif", R.id.image2); 
        loadImage("http://cache.soso.com/30d/img/web/logo.gif", R.id.image3); 
    }

    @Override 
    protected void onDestroy() { 
        executorService.shutdown(); 
        super.onDestroy(); 
    }

    private void loadImage(final String url, final int id) { 
        final Handler handler=new Handler(); 
        executorService.submit(new Runnable() { 
            @Override 
            public void run() { 
                try { 
                    final Drawable drawable = Drawable.createFromStream( 
                            new URL(url).openStream(), "image.png"); 
                    handler.post(new Runnable() {

                        @Override 
                        public void run() { 
                            ((ImageView) LazyLoadImageActivity.this 
                                    .findViewById(id)) 
                                    .setImageDrawable(drawable); 
                        } 
                    }); 
                } catch (Exception e) { 
                    throw new RuntimeException(e); 
                } 
            } 
        }); 
    } 
}

备注:

 handler.post(new Runnable() {

                        @Override 
                        public void run() { 
                            ((ImageView) LazyLoadImageActivity.this 
                                    .findViewById(id)) 
                                    .setImageDrawable(drawable); 
                        } 
                    }); 
API中的解释:

boolean android.os.Handler.post(Runnable r)

Causes the Runnable r to be added to the message queue. The runnable will be run on the thread to which this handler is attached.

Parameters:
r The Runnable that will be executed.
Returns:
Returns true if the Runnable was successfully placed in to the message queue. Returns false on failure, usually because the looper processing the message queue is exiting.
这是android提供的一种机制,handler对象将通过post方法,将里面的Runnable对象放到UI执行队列中,UI消费这个队列,调用Runnable的run方法。这里并不生成新的线程。

Android中通过Handler对象的post()方法将一个线程加入线程队列的时候,直接调用了Runnable的run()方法,并没有调用start()方法;也就是说Run()方法所执行的内容还是在

主线程中进行,post()方法并没有启动新的线程;

利用handler.post()更新UIhttp://hi.baidu.com/xcmxjge/blog/item/d51d5034d399fd345bb5f52e.html

1.创建一个Handler 2.调用Handler.post(Runnable r)方法 3.Runnable运行在UI所在线程,所以可以直接调用View.invalidate()

public class TestHandler extends Activity {   
     private MyView myView;   
     private Handler mHandler;   
     public void onCreate(Bundle savedInstanceState) {   
         super.onCreate(savedInstanceState);   
         myView = new MyView(this);   
         //创建一个Handler 
         mHandler = new Handler(); 
         //调用Handler.post(Runnable r)方法 
         mHandler.post(new Runnable(){   
             @Override   
             public void run() {   
                 //直接调用View.invalidate(),更新组件 
                 myView.invalidate();   
                 //延迟5毫秒后执行线程 
                 mHandler.postDelayed(this, 5);   
             }   
          });   
         setContentView(myView);   
     }   
        
     class MyView extends View{   
         private float x = 0f;   
         public MyView(Context context) {   
             super(context);   
                
     }   
         protected void onDraw(Canvas canvas) {   
             super.onDraw(canvas);   
             x+=1;   
             Paint mPaint = new Paint();   
             mPaint.setColor(Color.BLUE);   
             canvas.drawRect(x, 40, x+40, 80, mPaint);   
         }   
            
     }   
 }  
在新线程里更新UI,可以直接postInvalidate() ,不需要转到UI线程再进行刷新

	public void onCreate(Bundle savedInstanceState) {    
                super.onCreate(savedInstanceState);    
                this.requestWindowFeature(Window.FEATURE_NO_TITLE);    
	   
                myView = new MyView(this);
	       this.setContentView(this.myView);    
	       new Thread(new myThread()).start();   
	}    
   
     class myThread implements Runnable {    
	          public void run() {   
	              while (!Thread.currentThread().isInterrupted()) {    
	                   try {
	                	      myView.postInvalidate(); 
	                        Thread.sleep(100);     
	                   } catch (InterruptedException e) {    
	                        Thread.currentThread().interrupt();    
	                   }    
	               }    
	          }    
     } 

分享到:
评论

相关推荐

    Java并发编程实战

    1.2.3 异步事件的简化处理 1.2.4 响应更灵敏的用户界面 1.3 线程带来的风险 1.3.1 安全性问题 1.3.2 活跃性问题 1.3.3 性能问题 1.4 线程无处不在 第一部分 基础知识 第2章 线程安全性 2.1 什么是线程安全...

    memcached的三种java客户端jar

    2.spymemcached,支持异步,单线程的memcached客户端,用到了java1.5版本的concurrent和nio,存取速度会高于前者,但是稳定性不好,测试中常 报timeOut等相关异常。 3.xmemcached,XMemcached也使用得比较广泛,而且...

    高级java笔试题-Android-Interview:收集知识点自学使用

    设计一套图片异步加载缓存方案 Android UI适配 第二部分 Java JavaSE JavaCollection JavaConcurrent JVM 第三部分 数据结构与算法分析 数据结构 算法分析 Sort LeetCode 剑指Offer 其他 第四部分 计算机相关 ...

    Java面试宝典-经典

    54、简述synchronized和java.util.concurrent.locks.Lock的异同 ? 34 55、设计4个线程,其中两个线程每次对j增加1,另外两个线程对j每次减少1。写出程序。 36 56、子线程循环10次,接着主线程循环100,接着又回到...

    java面试题

    14. 简述synchronized和java.util.concurrent.locks.Lock的异同 ? 11 15. 当一个线程进入一个对象的一个synchronized方法后,其它线程是否可进入此对象的其它方法? 11 16. abstract class和interface有什么区别? 12...

    java 面试题 总结

     GC是垃圾收集的意思(Gabage Collection),内存处理是编程人员容易出现问题的地方,忘记或者错误的内存回收会导致程序或系统的不稳定甚至崩溃,Java提供的GC功能可以自动监测对象是否超过作用域从而达到自动回收...

    Java面试宝典2010版

    54、简述synchronized和java.util.concurrent.locks.Lock的异同 ? 34 55、设计4个线程,其中两个线程每次对j增加1,另外两个线程对j每次减少1。写出程序。 36 56、子线程循环10次,接着主线程循环100,接着又回到...

    java面试题大全(2012版)

    54、简述synchronized和java.util.concurrent.locks.Lock的异同 ? 34 55、设计4个线程,其中两个线程每次对j增加1,另外两个线程对j每次减少1。写出程序。 36 56、子线程循环10次,接着主线程循环100,接着又回到...

    java面试宝典

    77、简述synchronized和java.util.concurrent.locks.Lock的异同 ? 18 78、abstract class Name { private String name; public abstract boolean isStupidName(String name) {}}这有何错误? 18 79、public class ...

    java面试宝典2012版.pdf

    54、简述synchronized和java.util.concurrent.locks.Lock的异同 ? 55、设计4个线程,其中两个线程每次对j增加1,另外两个线程对j每次减少1。写出程序。 56、子线程循环10次,接着主线程循环100,接着又回到子线程...

    最新Java面试宝典pdf版

    54、简述synchronized和java.util.concurrent.locks.Lock的异同 ? 34 55、设计4个线程,其中两个线程每次对j增加1,另外两个线程对j每次减少1。写出程序。 36 56、子线程循环10次,接着主线程循环100,接着又回到...

    asyn4j for java 1.4

    asyn4j是一个java异步方法调用框架,本人对源码做了一些修改,使其支持java 1.4或更高的版本。

    22 尚硅谷Java JUC线程高级视频

    教程视频:在 Java 5.0 提供了 java.util.concurrent(简称JUC)包,在此包中增加了在并发编程中很常用的工具类, 用于定义类似于线程的自定义子系统,包括线程池,异步 IO 和轻量级任务框架;还提供了设计用于多线程上下文...

    java面试宝典2012

    54、简述synchronized和java.util.concurrent.locks.Lock的异同 ? 38 55、设计4个线程,其中两个线程每次对j增加1,另外两个线程对j每次减少1。写出程序。 40 56、子线程循环10次,接着主线程循环100,接着又回到...

    Java面试笔试资料大全

    54、简述synchronized和java.util.concurrent.locks.Lock的异同 ? 34 55、设计4个线程,其中两个线程每次对j增加1,另外两个线程对j每次减少1。写出程序。 36 56、子线程循环10次,接着主线程循环100,接着又回到...

    java基础题 很全面

    50. 简述synchronized和java.util.concurrent.locks.Lock的异同 ? 13 51. 排序都有哪几种方法?请列举。用JAVA实现一个快速排序。 13 52. JAVA语言如何进行异常处理,关键字:throws,throw,try,catch,finally分别代表...

    JAVA面试宝典2010

    54、简述synchronized和java.util.concurrent.locks.Lock的异同 ? 34 55、设计4个线程,其中两个线程每次对j增加1,另外两个线程对j每次减少1。写出程序。 36 56、子线程循环10次,接着主线程循环100,接着又回到...

    多线程,高并发.pdf

    1. stop() 和 suspend() 方法为何不推荐使用? 2. sleep() 和 wait() 有什么区别? 3. 同步和异步有何异同,...5. 简述 synchronized 和 java.util.concurrent.locks.Lock 的异同? 6. 概括的解释下线程的几种可用状态。

    Java面试宝典2012新版

    54、简述synchronized和java.util.concurrent.locks.Lock的异同 ? 34 55、设计4个线程,其中两个线程每次对j增加1,另外两个线程对j每次减少1。写出程序。 36 56、子线程循环10次,接着主线程循环100,接着又回到...

Global site tag (gtag.js) - Google Analytics