UI与耗时操作

 做过Android手机开发的人都知道,手机UI是一个单独的线程在运行,并且该线程最好不会因为用户的操作而阻塞。换句话说,如果用户进行的操作需要耗时几十秒甚至几十分钟,那么在这段时间内占用UI线程是一个非常不明智的做法。它会阻塞掉UI线程,导致手机不再显示或者接受用户新的操作,给用户一种死机的感觉。
       因此最好的方法是将用户耗时较长的操作放到另一个线程中去,并且用监听者模式来监听操作的完成。比如,手机服务通过http协议与服务器建立通讯,为了使此通讯不会阻塞手机其他功能的显示,需要开辟一个新线程传输数据,一旦数据传输完毕,则会调用监听者的回调函数,将结果显示在手机屏幕上。本文将介绍一种UI和耗时操作分离的方法:

每个复杂操作我们需要将其抽象成一个Task:

?
//定义一个BaseTask基类,其中taskParameter是需要执行任务所要传递的参数
//而execute()函数将在派生类中被重写
public  abstract  class  BaseTask {        Object  taskParameter;
         abstract  Object execute() throws Exception;
}在基类基础上,定义派生类: public  class  AsynMethodTask extends BaseTask {
 
         public  AsynMethodTask(AsynMethodTaskParameter taskParameter) {
                 this .taskParameter = taskParameter;
         }
 
         //重写execute函数,这里利用了Java提供的Method类,instance是需要执行的类,而methodName是需要执行的方法,methodParameter是需要传递的参数
         @Override
         public  Object execute() throws Exception {
                 AsynMethodTaskParameter parameters = (AsynMethodTaskParameter) this .taskParameter;
                 Method method = MethodHelper.getMethod(parameters.instance,
                                 parameters.methodName, parameters.methodParameters);
                 if  (method != null ) {                       
                                 return  method.invoke(parameters.instance,
                                                 parameters.methodParameters);                       
                 }
                 return  null ;
         }
         //工厂模式,返回一个Task的实例
         public  static  AsynMethodTask CreateTask(Object instance, String methodName,
                         Object... parameters) {
                 return  new  AsynMethodTask( new  AsynMethodTaskParameter(instance,
                                 methodName, parameters));
         }
}

AsynMethodTaskParameter定义如下:

?
public  class  AsynMethodTaskParameter{
  public  Object instance;
  public  String methodName;
  public  Object[] methodParameters;
  public  AsynMethodTaskParameter (Object instance , String methodName,Object[] methodParameters )
  {
          this .instance = instance;
          this .methodName = methodName;
          this .methodParameters = methodParameters;
  }
}

这样,一个基本的TASK方法已经实现,那么如何使用它呢?我们需要一个Request类来发送请求,并且异步启用task:

?
public  class  Request extends AsyncTask<RequestParameter, Integer, Object> {
 
         private  RequestListener emmaRequestListener = null ;
         private  Object data = null ;
         private  Exception _errorException = null ;
 
         //在后台异步启动TASK,AsyncTask提供了异步功能,需要重载其中的回调函数
         @Override
         protected  Object doInBackground(RequestParameter... parameter) {
                 try  {
                         RequestParameter emmaRequestParameter = parameter[0];
                         emmaRequestListener = emmaRequestParameter.requestListener;
                         data = emmaRequestParameter.data;
 
                         BaseTask task = emmaRequestParameter.task;
                         return  task.execute();
                 }       
                 catch  (InvocationTargetException e) {
                         Throwable baseException = e.getCause() ;
                         if  (baseException == null )
                                 _errorException = new  LocalGeneralException(e.getMessage());       
                         else  {
                                 if  (baseException instanceof ServerGeneralException)
                                 {
                                         _errorException = new  ServerGeneralException(baseException.getMessage());
                                 }
                                 else  if  (baseException instanceof ServerAuthException)
                                 {
                                         _errorException = new  ServerAuthException(baseException.getMessage());
                                 }
                                 else  {                                       
                                         _errorException = new  LocalGeneralException(baseException.getMessage());
                                 }
                         }
                 }
                 catch  (Exception e) {
                         _errorException = new  LocalGeneralException(e.getMessage());
                 }
                 return  _errorException;
                 
         }
                 //执行结束后,如果没有异常,则调用回调函数
         @Override
         protected  void  onPostExecute(Object result) {
                 if  (_errorException == null ) {
                         emmaRequestListener.onRequestSuccess(result, data);
                 } else  {
                         emmaRequestListener.onRequestFailed(_errorException, data);                       
                 }
         }
         //中途如果被cancel掉
         @Override
         protected  void  onCancelled() {
                 emmaRequestListener.onRequestCanceled(data);
         }
 
         public  interface  RequestListener {
                 void  onRequestSuccess(Object result, Object data);
 
                 void  onRequestFailed(Object result, Object data);
                 
//                void onRequestCanceled(Object data);
         }
 
         //定义执行过程,需要加入task,如果成功会调用RequestListener所定义的函数
         public  static  Request executeAsynRequest(BaseTask task,
                         RequestListener requestListener, Object data) {
                 RequestParameter requestParameter = new  RequestParameter(task,
                                 requestListener, data);
                 Request r = new  Request();
                 r.execute(requestParameter);
                 
                 return  r;
         }
}

最后我们只需要定义好Method的名字:

?
public  final static  class  Methods
         {
                 public  static  String getProfileView = "getProfileView" ;
                 public  static  String uploadProfileView = "uploadProfileView" ;
                 public  static  String getUserProfile = "getUserProfile" ;
         }

就可以正常调用了: 

?
AsynMethodTask task = AsynMethodTask.CreateTask(profileModel, ProfileModel.Methods.uploadProfileView, profileUploadData);
Request.executeAsynRequest(task, this , TASK_UPLOAD_PROFILE);

整个过程相当简单,最重要的是熟悉观察者模式,以及AsyncTask类的运行方式,重载其中的回调函数,让我们的任务在后台运行。返回的值为Object对象,需要通过强制类型转换成为我们需要的值。而传递进去的参数可以通过无限制数目的参数传递。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值