Android 图片异步加载,延时加载的一些思路

 
 

写在前面:此博文为概念性、思路方面的阐述,并无太多可参考的代码。

我们通常会遇到这样一个情况,有一张图片保存在不确定的服务端,我们需要下载图片并显示。按照这样一个思路来写Android程序:假如我们已经写好了一个确定可以在java的编译器中编译运行的函数 DownImage(),此函数返回的是一个Bitmap对象,如果我们在Activity的Oncreat函数中加入此函数,并将返回丢给一个ImageView的话,多半情况我们什么都得不到或者是直接得到了一个系统错误。这里就要提到Android的一种机制或者说是,即“非常耗时”且执行过程不可预测的方法不能在主线程中运行。也许读者看到这里会抱怨:“靠,这么坑爹啊!!”。但是请注意分析这样一个过程,当程序正在初始化的时候,你居然让主线程等着你“吃个早点”再做事,那无疑会让程序的稳定性、可靠性都出很大的问题。

所以,言归正传,我们需要异步加载,我们需要一个合理的方法来加载那些并非触手可及的东西。一种常见的方法是,在主线程中新建一个线程,让这个线程去下载图片,并把结果反馈回来。关于如何反馈结果,又有两种方法,一种是使用Handler来通信,你可以将结果封装在一个Bundle对象中,然后在msg中附加Bundle发送给主线程的“特定”Handler处理。对于这种方法一种简单的模型如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
package  com.example.test;
import  android.os.Bundle;
import  android.os.Handler;
import  android.os.Message;
import  android.annotation.SuppressLint;
import  android.app.Activity;
import  android.view.Menu;
public  class  TestAc  extends  Activity {
     public  static  Handler myhandler;
     @SuppressLint( "HandlerLeak" )
     @Override
     protected  void  onCreate(Bundle savedInstanceState) {
         super .onCreate(savedInstanceState);
         setContentView(R.layout.activity_test);
         myhandler= new  Handler(){
             @Override
             public  void  handleMessage(Message msg) {
                 msg.getData().getString( "Msg" );
             }
         };
     }
     @Override
     public  boolean onCreateOptionsMenu(Menu menu) {
         // Inflate the menu; this adds items to the action bar if it is present.
         getMenuInflater().inflate(R.menu.test, menu);
         return  true ;
     }
      class  MyThread  implements  Runnable{
         @Override
         public  void  run() {
             // TODO 自动生成的方法存根
             Message msg= new  Message();
             Bundle b= new  Bundle();
             b.putString( "Msg" "这是一个子线程发来的消息" );
             msg.setData(b);
             TestAc.myhandler.sendMessage(msg);
         }}
}


另外的一种方法是通过系统广播来实现,根据不同的应用需求,朋友们可以选择不同的方式来实现。

写到这里,也才算是写完前沿,因为到现在我还没有开始讨论异步的一些实现原理和方法:

通常来看,如果我们使用ListView、GridView、甚至是ViewPager来动态加载数据的时候,我们的数据在网络中,下载数据的过程很缓慢,以至于我们不太愿意在程序运行的头几分钟让用户干等着。所以,一种比较合适的方法是用上面的方法来动态加载数据。对于ListView或者GridView来说,我们可以对他们的Adapter进行一下的操作:

假如有一个Adapter的名字叫做MyAdapter,通常我们在创建Adapter的时候会给他一个数据源。这个数据如果后面我们不动他,他就是固定的,死的,希望朋友们注意我的这句提示。假如有个Adatper的例子如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
package  com.example.test;
import  java.util.List;
import  android.view.View;
import  android.view.ViewGroup;
import  android.widget.BaseAdapter;
public  class  MyAdapter  extends  BaseAdapter{
     private  List mlist;
     @Override
     public  int  getCount() {
         // TODO 自动生成的方法存根
         return  mlist.size();
     }
     @Override
     public  Object getItem( int  position) {
         // TODO 自动生成的方法存根
         return  mlist.get(position);
     }
     @Override
     public  long  getItemId( int  position) {
         // TODO 自动生成的方法存根
         return  position;
     }
     @Override
     public  View getView( int  position, View convertView, ViewGroup parent) {
         // TODO 自动生成的方法存根
         return  null ;
     }
     public  List getMlist() {
         return  mlist;
     }
     public  void  setMlist(List mlist) {
         this .mlist = mlist;
     }
}


样例的代码中有个mlist变量,用来存在数据。对于所有的Adapter而言,它都会有自己的一个用来存放数据的变量,不行的话你可以去看看SimpleAdapter的源码。通常来讲,如果我们要动态的更新ListView或者GridView的内容,我只需要做两件事情:

1.更新对应的Adapter的数据,如上例中我们只要更新mlist变量;

2.通知Adapter数据已经更新了,使用Adapter.notifyDataSetChanged()可以通知数据的更新。

同样的,在ViewPager中的操作也几乎差不多,这里就不重复说明了。

原文出处:http://www.nuatar.com/Article.aspx?id=cfd1811415c54fc18a30b49302f7db36

你可能感兴趣的:(Android)