zoukankan      html  css  js  c++  java
  • Android开源框架Afinal第一篇——揭开圣女的面纱

    Android开源框架Afinal第一篇——揭开圣女的面纱

    分类: Android开源框架哪点事

    Afinal

    这是Afinal在github的地址:https://github.com/yangfuhai/afinal

    Afinal这个框架主要分4块:

    1、FinalDB模块:android中的orm框架,一行代码就可以进行增删改查。支持一对多,多对一等查询。

    2、FinalActivity模块:android中的ioc框架,完全注解方式就可以进行UI绑定和事件绑定。无需findViewById和setClickListener等。

    3、FinalHttp模块:通过httpclient进行封装http数据请求,支持ajax方式加载。

    4、FinalBitmap模块:通过FinalBitmap,imageview加载bitmap的时候无需考虑bitmap加载过程中出现的oom和android容器快速滑动时候出现的图片错位等现象。FinalBitmap可以配置线程加载线程数量,缓存大小,缓存路径,加载显示动画等。FinalBitmap的内存管理使用lru算法,没有使用弱引用(android2.3以后google已经不建议使用弱引用,android2.3后强行回收软引用和弱引用,详情查看android官方文档),更好的管理bitmap内存。FinalBitmap可以自定义下载器,用来扩展其他协议显示网络图片,比如ftp等。同时可以自定义bitmap显示器,在imageview显示图片的时候播放动画等(默认是渐变动画显示)。

    这里我们先讲FinalHttp模块,这是它的用法:

    AjaxParams params = new AjaxParams();
      params.put("username", "michael yang");
      params.put("password", "123456");
      params.put("email", "test@tsz.net");
      params.put("profile_picture", new File("/mnt/sdcard/pic.jpg")); // 上传文件
      params.put("profile_picture2", inputStream); // 上传数据流
      params.put("profile_picture3", new ByteArrayInputStream(bytes)); // 提交字节流
    
      FinalHttp fh = new FinalHttp();
      fh.post("http://www.yangfuhai.com", params, new AjaxCallBack(){
            @Override
            public void onLoading(long count, long current) {
                    textView.setText(current+"/"+count);
            }
    
            @Override
            public void onSuccess(String t) {
                textView.setText(t==null?"null":t);
            }
      });

    大家看到了吧,fh.get(baseUrl, params, new AjaxCallBack(){});

    这句话的底层就是HttpClient执行HttpGet或者HttpPost请求的一个封装,其中baseUrl+params拼凑起来就是url,而后面的AjaxCallBack就是对HttpClient对http请求得到的一个HttpResponse响应结果的分析回调。

    我们来看具体的流程步骤:

    第一步:初始化FinalHttp,然后执行get()方法

    public void get( String url, AjaxParams params, AjaxCallBack<? extends Object> callBack) {
            sendRequest(httpClient, httpContext, new HttpGet(getUrlWithQueryString(url, params)), null, callBack);
        }

    第二步:我们看sendRequest()这个方法,这个方法就是把get方法里的参数传递到这个函数,然后发起http请求。

    protected <T> void sendRequest(DefaultHttpClient client, HttpContext httpContext, HttpUriRequest uriRequest, String contentType, AjaxCallBack<T> ajaxCallBack) {
            if(contentType != null) {
                uriRequest.addHeader("Content-Type", contentType);
            }
            new HttpHandler<T>(client, httpContext, ajaxCallBack,charset)
            .executeOnExecutor(executor, uriRequest);
    
        }

    这是一个保护级的方法,其实还是一个马甲,正真执行的还是那个HttpHandler里的exe方法。我们看到这个方法的参数有DefaultHttpClient,这个都不用说了大家都很熟悉,HttpContext就是一个上下文,HttpUriRequest就是一个get,put,delete,post等http请求,然后就是添加头部信息,比如要不要进行压缩,这里貌似用了zip压缩使得传输速率更快,再后面就是回调函数接口,判断请求是否成功失败等。

    第三步:进入HttpHandler类,这是一个处理http请求的类。这个类是继承AsyncTask,但是这个AsyncTask类并不是原生的,而是经过作者精心修改的。没有深入去看AsyncTask,大略看了一下,貌似doInBackground这个方法是放进一个线程池里去执行的。这个线程池配置的很精细,就像批量加载图片那个例子,可以只想你个完上一个线程,就马上执行下一个任务。

    1.这个类还实现了EntityCallBack回调接口,并且接收了AjaxCallBack这个回调实例。我们先看doInBackground方法。

    protected Object doInBackground(Object... params) {
            if(params!=null && params.length == 3){
                targetUrl = String.valueOf(params[1]);
                isResume = (Boolean) params[2];
            }
            try {
                publishProgress(UPDATE_START); // 开始
                makeRequestWithRetries((HttpUriRequest)params[0]);
                
            } catch (IOException e) {
                publishProgress(UPDATE_FAILURE,e,e.getMessage()); // 结束
            }
    
            return null;
        }

    2.可以看到真正执行的方法是makeRequestWithRetries(HttpUriRequest *)方法,进去看看先

    private void makeRequestWithRetries(HttpUriRequest request) throws IOException {
            if(isResume && targetUrl!= null){
                File downloadFile = new File(targetUrl);
                long fileLen = 0;
                if(downloadFile.isFile() && downloadFile.exists()){
                    fileLen = downloadFile.length();
                }
                if(fileLen > 0)
                    request.setHeader("RANGE", "bytes="+fileLen+"-");
            }
            
            boolean retry = true;
            IOException cause = null;
            HttpRequestRetryHandler retryHandler = client.getHttpRequestRetryHandler();
            while (retry) {
                try {
                    if (!isCancelled()) {
                        HttpResponse response = client.execute(request, context);
                        if (!isCancelled()) {
                            handleResponse(response);
                        } 
                    }
                    return;
                } catch (UnknownHostException e) {
                    publishProgress(UPDATE_FAILURE, e,"unknownHostException:can't resolve host");
                    return;
                } catch (IOException e) {
                    cause = e;
                    retry = retryHandler.retryRequest(cause, ++executionCount,context);
                } catch (NullPointerException e) {
                    // HttpClient 4.0.x 之前的一个bug
                    // http://code.google.com/p/android/issues/detail?id=5255
                    cause = new IOException("NPE in HttpClient" + e.getMessage());
                    retry = retryHandler.retryRequest(cause, ++executionCount,context);
                }catch (Exception e) {
                    cause = new IOException("Exception" + e.getMessage());
                    retry = retryHandler.retryRequest(cause, ++executionCount,context);
                }
            }
            if(cause!=null)
                throw cause;
            else
                throw new IOException("未知网络错误");
        }

    其中isResume是断点续传标志,targetUrl判断是文件的话就添加文件大小头部信息。retry是遇到错误是否要重试标志,FinalHttp有这个参数配置,可以设置重试次数。然后就是HttpClient执行Http请求获取响应的操作,如果这个过程中UI上的交互有取消操作的话。可以通过isCancelled()这个方法得知从而取消请求。如果请求顺利会得到一个HttpResponse,而处理这个响应结果是handleResponse()方法。

    3.这是专门处理响应结果的方法

    private void handleResponse(HttpResponse response) {
            StatusLine status = response.getStatusLine();
            if (status.getStatusCode() >= 300) {
                String errorMsg = "response status error code:"+status.getStatusCode();
                if(status.getStatusCode() == 416 && isResume){
                    errorMsg += " 
     maybe you have download complete.";
                }
                publishProgress(UPDATE_FAILURE,new HttpResponseException(status.getStatusCode(), status.getReasonPhrase()),errorMsg);
            } else {
                try {
                    HttpEntity entity = response.getEntity();
                    Object responseBody = null;
                    if (entity != null) {
                        time = SystemClock.uptimeMillis();
                        if(targetUrl!=null){
                            responseBody = mFileEntityHandler.handleEntity(entity,this,targetUrl,isResume);
                        }
                        else{
                            responseBody = mStrEntityHandler.handleEntity(entity,this,charset);
                        }
                            
                    }
                    publishProgress(UPDATE_SUCCESS,responseBody);
                    
                } catch (IOException e) {
                    publishProgress(UPDATE_FAILURE,e,e.getMessage());
                }
                
            }
        }

    通过状态码,判断成功后处理得到的HttpEntity。如果这个response是字符串就由StringEntityHandler这个类去解析,如果是文件就是FileEntityHandler解析。得到结果后,就是publishProgress去推送了,这个方法在前面的方法中都看到有被调用。稍微对AsyncTask熟悉的人就知道这个方法将可以触发onProgressUpdate(* value).这个方法就是告诉你执行的进度,AfinalHttp中AjaxCallback中的onSuccess,onFailure等方法就是根据这个来触发的。

       private final static int UPDATE_START = 1;
        private final static int UPDATE_LOADING = 2;
        private final static int UPDATE_FAILURE = 3;
        private final static int UPDATE_SUCCESS = 4;

    到这里这个过程就完成了。

    看到这么多的处理,会觉得这样是不是会更慢。一个网络请求处理的极其复杂,想FinalHttp很多默认的配置和繁杂的处理响应并通知处理进程,其实这样多多少少拖慢了请求的速度。在实际应用尤其感受深切,一遇到网络慢,跨地域幅度大等教为恶劣的网络环境,AFinal就有点显得捉襟见肘了。

    由于篇幅限制,这次就讲这么多了。

    http://blog.csdn.net/bvin_/article/details/10914197

  • 相关阅读:
    文本挖掘预处理之TF-IDF
    文本挖掘预处理之向量化与Hash Trick
    文本挖掘的分词原理
    MCMC(四)Gibbs采样
    MCMC(三)MCMC采样和M-H采样
    编译c时提示“dereferencing type-punned pointer will break strict-aliasing rules”如何处理?
    ubuntu下添加新的ppa软件源后出现"Error: retrieving gpg key timed out"如何处理?
    如何创建离线网页?
    ubuntu下如何安装wpantund?
    tmux如何调节窗口大小?
  • 原文地址:https://www.cnblogs.com/bigben0123/p/4151560.html
Copyright © 2011-2022 走看看