list 异步加载图片

前段在EOE上讨论了延迟加载,然后做了个,模拟延迟加载的List.估计以后会用到吧.毕竟List还是经常遇到的.

UI线程必须是自己更新,不能由其它线程来更新,这个问题已经很多人讨论过了.而Android使用Handler的HandleMessage来处理把控制返回给UI线程.如果直接一个Runnable是不行的.
由于没有到网络上去载图片,所以线程睡眠了500毫秒来模拟.在这里可以用一个线程去下载图片,然后Notify通知图片已经准备好了.
如果有不对的喜欢指正,讨论.把代码放上来.
有个小问题:在开始时显示的是未选中的图片,没有处理初始化加载图片,而主要关注的是滚动时加载图片.

Java代码
  1. package  com.me.list;  
  2.   
  3. import  java.util.ArrayList;  
  4. import  java.util.HashMap;  
  5. import  android.app.Activity;  
  6. import  android.app.ListActivity;  
  7. import  android.content.Context;  
  8. import  android.graphics.Bitmap;  
  9. import  android.graphics.BitmapFactory;  
  10. import  android.os.Bundle;  
  11. import  android.os.Handler;  
  12. import  android.os.Looper;  
  13. import  android.os.Message;  
  14. import  android.util.Log;  
  15. import  android.view.ContextMenu;  
  16. import  android.view.MenuItem;  
  17. import  android.view.View;  
  18. import  android.view.ContextMenu.ContextMenuInfo;  
  19. import  android.view.LayoutInflater;  
  20. import  android.view.View.OnCreateContextMenuListener;  
  21. import  android.view.ViewGroup;  
  22. import  android.widget.AbsListView;  
  23. import  android.widget.AbsListView.OnScrollListener;  
  24. import  android.widget.AdapterView;  
  25. import  android.widget.ListView;  
  26. import  android.widget.SimpleAdapter;  
  27. import  android.widget.AdapterView.OnItemClickListener;  
  28. import  android.widget.ArrayAdapter;  
  29. import  android.widget.BaseAdapter;  
  30. import  android.widget.ImageView;  
  31. import  android.widget.TextView;  
  32. import  com.me.*;  
  33.   
  34. import  java.util.List;  
  35.   
  36. /**  
  37.  *  
  38.  * @author archko  
  39.  */   
  40. public   class  ListViewLazy3  extends  ListActivity  implements  OnScrollListener{  
  41.   
  42.     private  TextView mStatus;  
  43.     private   boolean  mBusy= false ;  
  44.     //private boolean needToUpdate=false;   
  45.     private   static   final  String TAG= "List13" ;  
  46.     private  AbsListView absListView;  
  47.     private  ArrayList<HashMap<String,Object>> users= new  ArrayList<HashMap<String,Object>>();  
  48.     private  Bitmap mIcon1, mIcon2;  
  49.     private   int  firstPos= 0 ;  
  50.     private  NoLooperThread noLooerThread;  
  51.     private  MySimpleAdapter adapter;  
  52.   
  53.     @Override   
  54.     public   void  onCreate(Bundle savedInstanceState){  
  55.         super .onCreate(savedInstanceState);  
  56.         setContentView(R.layout.list_13);  
  57.         mStatus=(TextView)findViewById(R.id.status);  
  58.         mStatus.setText("Idle" );  
  59.   
  60.         for ( int  i= 0  ; i< 30  ; i++){  
  61.             HashMap<String,Object> user=new  HashMap<String,Object>();  
  62.             user.put("img" ,R.drawable.checkoff);  
  63.             user.put("username" , "姓名(" +i+ ")" );  
  64.             user.put("age" ,( 20 +i)+ "" );  
  65.             users.add(user);  
  66.         }  
  67.   
  68.         // Use an existing ListAdapter that will map an array   
  69.         // of strings to TextViews   
  70.         adapter=new  MySimpleAdapter( this );  
  71.         setListAdapter(adapter);  
  72.   
  73.         getListView().setOnScrollListener(this );  
  74.     }  
  75.   
  76.     //这个方法只要在列表中移动就会调用.   
  77.     @Override   
  78.     public   void  onScroll(AbsListView view, int  firstVisibleItem, int  visibleItemCount, int  totalItemCount){  
  79.         int  lastItem=firstVisibleItem+visibleItemCount- 1 ;  
  80.   
  81.         Log.d(TAG,"firstPos." +firstPos+ " *firstVisibleItem." +firstVisibleItem); //这个位置不太正确,在我这总是会差一个   
  82.         if (firstVisibleItem!=firstPos){  
  83.             firstPos=firstVisibleItem;  
  84.             //needToUpdate=true;   
  85.             //if(needToUpdate){   //需要更新,启动线程   
  86.             this .absListView=view;  
  87.             //Log.d(TAG,"noLooperThread."+noLooerThread+" isAlive."+noLooerThread.isAlive());   
  88.             if (noLooerThread!= null ){  
  89.             //if(noLooerThread.isAlive()){   
  90.                 //noLooerThread.stop();   
  91.                 noLooerThread.interrupt();  
  92.                 Log.d(TAG,"onScroll.noLooerThread.interrupt" );  
  93.                 noLooerThread=null ;  
  94.             }  
  95.             noLooerThread=new  NoLooperThread();  
  96.             noLooerThread.start();  
  97.             //}   
  98.         }  
  99.     }  
  100.   
  101.     //为什么会对称出现呢?更新5个就是从头开始5个和从尾开始5个?   
  102.     @Override   
  103.     public   void  onScrollStateChanged(AbsListView view, int  scrollState){  
  104. //没有使用这个,因为这是在鼠标拖动时才会发生,而上面的只要焦点变化都会触发.   
  105.         //Log.d(TAG,"scrollState."+scrollState);   
  106.         /*switch(scrollState){  
  107.         case OnScrollListener.SCROLL_STATE_IDLE:  
  108.         mBusy=false;  
  109.         this.absListView=view;  
  110.         noLooerThread=new NoLooperThread();  
  111.         noLooerThread.start();  
  112.         mStatus.setText("Idle");  
  113.         break;  
  114.         case OnScrollListener.SCROLL_STATE_TOUCH_SCROLL:  
  115.         mBusy=true;  
  116.         mStatus.setText("Touch scroll");  
  117.         break;  
  118.         case OnScrollListener.SCROLL_STATE_FLING:  
  119.         mBusy=true;  
  120.         mStatus.setText("Fling");  
  121.         break;  
  122.         }*/   
  123.     }  
  124.   
  125.     //更新List里的项,这里只作通知数据更新了.   
  126.     public   void  update(){  
  127.         Log.d(TAG,"update." );  
  128.         adapter.notifyDataSetChanged();  
  129.     }  
  130.     ViewHolder holder;  
  131.   
  132.     class  MySimpleAdapter  extends  BaseAdapter{  
  133.   
  134.         private  LayoutInflater mInflater;  
  135.         //private Bitmap mIcon1, mIcon2;   
  136.         private  Context ctx;  
  137.   
  138.         public  MySimpleAdapter(Context c){  
  139.             mInflater=LayoutInflater.from(c);  
  140.             ctx=c;  
  141.   
  142.             // Icons bound to the rows.   
  143.             mIcon1=BitmapFactory.decodeResource(c.getResources(),R.drawable.checkon);  
  144.             mIcon2=BitmapFactory.decodeResource(c.getResources(),R.drawable.checkoff);  
  145.         }  
  146.   
  147.         public   int  getCount(){  
  148.             return  users.size();  
  149.         }  
  150.   
  151.         public  Object getItem( int  position){  
  152.             return  position;  
  153.         }  
  154.   
  155.         public   long  getItemId( int  position){  
  156.             return  position;  
  157.         }  
  158.         //ViewHolder holder;   
  159.   
  160.         //而convertView只有在Activity初始化时才会是空.   
  161.         @Override   
  162.         // <editor-fold defaultstate="collapsed" desc="comment">   
  163.         public  View getView( int  position,View convertView,ViewGroup parent){  
  164.   
  165.             if (convertView== null ){  
  166.                 convertView=mInflater.inflate(R.layout.list_items,null );  
  167.   
  168.                 // Creates a ViewHolder and store references to the two children views   
  169.                 // we want to bind data to.   
  170.                 holder=new  ViewHolder();  
  171.                 holder.itemTitle=(TextView)convertView.findViewById(R.id.ItemTitle);  
  172.                 holder.itemText=(TextView)convertView.findViewById(R.id.ItemText);  
  173.                 holder.itemIcon=(ImageView)convertView.findViewById(R.id.ItemImage);  
  174.                 //holder.itemIcon.setImageBitmap(mIcon2);   
  175.                 convertView.setTag(holder);  
  176.             }else {  
  177.                 // Get the ViewHolder back to get fast access to the TextView and the ImageView.   
  178.                 holder=(ViewHolder)convertView.getTag();  
  179.             }  
  180.             holder.itemTitle.setText(users.get(position).get("username" ).toString());  
  181.             holder.itemText.setText(users.get(position).get("age" ).toString());  
  182.             int  i=Integer.valueOf(users.get(position).get( "img" ).toString());  
  183.             holder.itemIcon.setImageBitmap(BitmapFactory.decodeResource(ctx.getResources(),i));  
  184.             //Log.d(TAG,"getView.setIcon");   
  185.             return  convertView;  
  186.         }// </editor-fold>   
  187.     }  
  188.   
  189.     static   class  ViewHolder{  
  190.   
  191.         TextView itemTitle, itemText;  
  192.         ImageView itemIcon;  
  193.     }  
  194.   
  195.     class  EventHandler  extends  Handler{  
  196.   
  197.         public  EventHandler(Looper looper){  
  198.             super (looper);  
  199.         }  
  200.   
  201.         public  EventHandler(){  
  202.             super ();  
  203.         }  
  204.   
  205.         public   void  handleMessage(Message msg){  
  206.             //可以根据msg.what执行不同的处理,这里没有这么做   
  207.             switch (msg.what){  
  208.                 case   1 :  
  209.                     Log.d(TAG,"1.EventHandler.handleMessage.before" );  
  210.                     update();  
  211.                     Log.d(TAG,"1.EventHandler.handleMessage.after" );  
  212.                     break ;  
  213.                 case   2 :  
  214.                     Log.d(TAG,"2.EventHandler.handleMessage.before" );  
  215.                     update();  
  216.                     Log.d(TAG,"2.EventHandler.handleMessage.after" );  
  217.                     mBusy=true ;  
  218.                     //needToUpdate=false;   
  219.                     break ;  
  220.                 case   3 :  
  221.                     //不能在非主线程的线程里面更新UI,所以这里通过Log打印收到的消息   
  222.                     Log.e(TAG,(String)msg.obj);  
  223.                     //ownLooperThread.stop();   
  224.                     break ;  
  225.                 default :  
  226.                     //不能在非主线程的线程里面更新UI,所以这里通过Log打印收到的消息   
  227.                     Log.e(TAG,(String)msg.obj);  
  228.                     break ;  
  229.             }  
  230.         }  
  231.     }  
  232.   
  233. //这个Thread可以不用这么复杂的.因为当时还没明白Handler,Message所以也是借用别人的代码.简单点就是new Runnable(){run(){   
  234. XXX..........  
  235. Message msg=new  Message();  
  236. msg.what=XYZ..............;  
  237. mHandler.sendMessage(msg);  
  238. }}  
  239.   
  240. Android为每个线程产生一个Looper这个在程序异常时看Logcat就会明白的.  
  241.     class  NoLooperThread  extends  Thread{  
  242.   
  243.         private  EventHandler mNoLooperThreadHandler;  
  244.         private   boolean  loadIngImg= true ;   //正在加载图片   
  245.         private   boolean  needToUpdate= false//是否需要更新图片列表   
  246.         private  Object lock= new  Object();  
  247.   
  248.         // <editor-fold defaultstate="collapsed" desc="comment">   
  249.         class  InnerThread  extends  Thread{  
  250.   
  251.             public   void  run(){  
  252.                 //Log.d(TAG,"NoLooper.run.loadImg.run");   
  253.                 int  count=absListView.getChildCount();  
  254.                 int  first=absListView.getFirstVisiblePosition();  
  255.                 boolean  flag= false ;  
  256.                 for ( int  i= 0  ; i<count ; i++){  
  257.                     try {  
  258.                         Thread.sleep(500 );  
  259.                     }catch (InterruptedException ex){  
  260.                         Thread.interrupted();//虽然这里捕获到异常了,不过,它还是会继续执行的.线程不会停止,应该设置共享变量来停止非阻塞的线程,暂时没有使用.   
  261.                     }  
  262.                     if (Integer.valueOf(users.get(first+i).get( "img" ).toString())==R.drawable.checkoff){  
  263.                         users.get(first+i).put("img" ,R.drawable.checkon);  
  264.                         Log.d(TAG,"thead." +Thread.currentThread()+ " update ." +(first+i));  
  265.                         flag=true ;  
  266.                     }  
  267.                 }  
  268.                 synchronized (lock){  
  269.                     lock.notify();  
  270.                     loadIngImg=false ; //加载完毕   
  271.                     if (flag){  
  272.                         needToUpdate=true ; //加载后需要更新   
  273.                     }  
  274.                     Log.d(TAG,"NoLooper.run.loadImg.notify" );  
  275.                 }  
  276.             }  
  277.         }// </editor-fold>   
  278.   
  279.         public   void  run(){  
  280.             InnerThread it=new  InnerThread();  
  281.             synchronized (lock){  
  282.                 it.start();  
  283.                 while (loadIngImg){  
  284.                     try {  
  285.                         lock.wait();  
  286.                     }catch (InterruptedException e){  
  287.                         loadIngImg=false ;  
  288.                         it.interrupt();  
  289.                     }  
  290.   
  291.                     Log.d(TAG,"needToUpdate." +needToUpdate);  
  292.                     if (needToUpdate){    //需要更新列表,启动线程.   
  293.                         Looper myLooper, mainLooper;  
  294.                         myLooper=Looper.myLooper();  
  295.                         mainLooper=Looper.getMainLooper();    //这是一个static函数   
  296.                         String obj;  
  297.                         if (myLooper== null ){  
  298.                             mNoLooperThreadHandler=new  EventHandler(mainLooper);  
  299.                             obj="NoLooperThread has no looper and handleMessage function executed in main thread!" ;  
  300.                         }else {  
  301.                             mNoLooperThreadHandler=new  EventHandler(myLooper);  
  302.                             obj="This is from NoLooperThread self and handleMessage function executed in NoLooperThread!" ;  
  303.                         }  
  304.                         Log.d(TAG,"NoLooperThread.run.mNoLooperThreadHandler" );  
  305.                         mNoLooperThreadHandler.removeMessages(0 );  
  306.                         //send message to main thread:   
  307.                         //what=2 when=0 arg1=1 arg2=1 obj=NoLooperThread has no looper and handleMessage   
  308.                         //function executed in main thread!   
  309.                         Message m=mNoLooperThreadHandler.obtainMessage(2 , 1 , 1 ,obj);  
  310.                         mNoLooperThreadHandler.sendMessage(m);  
  311.                     }  
  312.                     loadIngImg=true ;  
  313.                 }  
  314.             }  
  315.         }  
  316.     }  
  317. }  
  318. list_13这个只是一个ListView和一个文本:  
  319. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"   
  320.               android:orientation="vertical"   
  321.               android:layout_width="fill_parent"   
  322.               android:layout_height="fill_parent" >  
  323.   
  324.     <ListView android:id="@android:id/list"   
  325.               android:layout_width="fill_parent"   
  326.               android:layout_height="0dip"   
  327.               android:layout_weight="1"   
  328.               android:drawSelectorOnTop="false" />  
  329.   
  330.     <TextView android:id="@+id/status"   
  331.               android:layout_width="fill_parent"   
  332.               android:layout_height="wrap_content"   
  333.               android:paddingLeft="8dip"   
  334.               android:paddingRight="8dip" />  
  335.   
  336. </LinearLayout>  
  337. 行布局只是一个ImageView和两个TextView,没有特别的.  
  338. 使用Asynctask 是Android专门为线程处理而写的类,封装了一些方法,更易于使用的.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值