排球概论

Volley是由Google开发并在Google I / O 2013期间引入的网络库。之所以开发它,是因为Android SDK中缺少能够在不干扰用户体验的情况下运行的网络类。

在Volley发行之前,规范的Java类java.net.HttpURLConnection和Apache org.apache.http.client是Android程序员可用于在客户端和远程后端之间开发 RESTful系统的唯一工具。

暂时将这两个类都排除在错误之外,应该注意的是,超出了简单HTTP事务的所有内容都必须重新编写 如果要缓存图像或优先处理请求,则必须从头开始进行开发

幸运的是,现在有Volley,它是为满足这些需求而量身定制的。

1.为什么选择凌空?

避免使用HttpUrlConnectionHttpClient

在较低的API级别上(主要在Gingerbread和Froyo上), HttpUrlConnectionHttpClient远非完美。 有一些已知的问题错误从未修复。 而且, HttpClient在上一次API更新(API 22)中已弃用 ,这意味着它将不再维护,并且可能在以后的版本中删除。

这些是决定切换到更可靠的方式来处理网络请求的充分理由。

并且也避免AsyncTask

自从引入Honeycomb(API 11)以来,必须在与主线程不同的单独线程上执行网络操作。 这一重大变化导致大量使用AsyncTask<Params, Progress, Result>规范的方式。

使用AsyncTask ,您首先要在onPreExecute定义一些准备操作,例如上下文的定义。 然后,您可以使用doInBackground方法执行异步任务。 最后,在onPostExecute处理结果。 它非常简单,比服务的实现要容易得多,并且附带了大量示例和文档。

但是,主要问题是调用的序列化。 使用AsyncTask类,您无法确定哪个请求优先,哪个必须等待。 一切都按照先进先出的先入先出的顺序进行。

例如,当您必须加载附加了缩略图的项目列表时,就会出现问题。 当用户向下滚动并期待新的结果时,您不能告诉您的活动首先加载下一页的JSON,然后再加载上一页的图像。 这可能成为诸如Facebook或Twitter之类的应用程序中严重的用户体验问题,其中新项目的列表比与之关联的缩略图更重要。

Volley旨在通过包含强大的取消API来解决此问题。 您不再需要在执行调用时检入onPostExecute活动是否已销毁。 这有助于避免不必要的 NullPointerException

快多了

不久前,Google +团队针对可用于在Android上发出网络请求的每种不同方法进行了一系列性能测试。 在RESTful应用程序中使用Volley时,其得分比其他替代方法高出十倍。

缓存一切

Volley自动缓存请求,这确实可以挽救生命。 让我们回到前面给出的示例中。 您有一个项目列表(比如说一个JSON数组),每个项目都有一个描述和与之关联的缩略图。 现在考虑一下如果用户旋转屏幕会发生什么:活动被破坏,列表又被下载,图像也被下载。 长话短说,大量浪费资源和糟糕的用户体验。

事实证明,Volley对于克服此问题非常有用。 它记住它以前所做的调用,并处理活动破坏和重建。 它缓存所有内容,而您不必担心。

小型元数据操作

排球是完美的 用于小型调用,例如JSON对象,列表的一部分,所选项目的详细信息等等。 它是为RESTful应用程序设计的,在这种特殊情况下,它发挥了最大的作用。

但是,当用于流操作和大量下载时,效果不是很好。 与通常的看法相反,Volley的名字并非来自体育词典。 而是将其作为重复的通话组合在一起。 某种程度上说,为什么当您想发射炮弹而不是一排箭时,该库不派上用场。

2.内幕

Volley在三个不同的级别上工作,每个级别都在自己的线程上运行。

排球在引擎盖下

主线

在主线程上,与您在AsyncTask规范中所做的一致,仅允许您触发请求并处理其响应。 仅此而已。

主要结果是您实际上可以忽略doInBackground方法中发生的所有事情。 Volley自动管理HTTP事务和您之前需要关注的捕获网络错误。

缓存和网络线程

当您将请求添加到队列时,后台发生了几件事。 首先,Volley检查是否可以从缓存中处理请求。 如果可以,则读取,解析和传递缓存的响应。 否则,它将被传递到网络线程。

在网络线程上,具有一系列线程的循环机制一直在工作。 第一个可用的网络线程使请求出队,发出HTTP请求,解析响应并将其写入缓存。 最后,它将已解析的响应分派回主线程,您的侦听器将在该主线程中等待处理结果。

3.入门

步骤1:汇入Volley

排球不是很方便设置。 似乎没有可用的官方Maven存储库,这真是令人困惑。 您必须依靠官方源代码。 您可以采用以下几种方法之一导入Volley。

首先,请从其存储库下载Volley源。 如果您对此有信心,请使用此Git   命令可以为您完成所有工作:

git clone https://android.googlesource.com/platform/frameworks/volley

直到几周前,您可以使用ant命令行(将android update project -p .然后是ant jarant jar并使用简单的compile files('libs/volley.jar') )将JAR库导入Android Studio项目compile files('libs/volley.jar')

不过,最近,Google将Volley更新为Android Studio的构建样式,这使得创建独立的JAR更加困难。 您仍然可以执行此操作,但只能使用旧版本的库。 我个人不鼓励您使用此选项,即使它看起来最快。

您应该以经典方式设置Volley,即将源作为模块导入。 在Android Studio中,打开项目,然后选择“ 文件”>“新建模块” ,然后选择“ 导入现有项目” 。 选择您刚刚下载源代码的目录并进行确认。 一个名为Volley的文件夹将显示在您的项目结构中。 Android Studio自动更新您的settings.gradle文件以包含Volley模块,因此您只需将其添加到依赖项compile project(':volley')就可以了。

还有第三种方式。 您可以将以下行添加到build.gradle文件的依赖项部分:

compile 'com.mcxiaoke.volley:library-aar:1.0.15'

它是Google官方存储库的镜像副本,会定期进行同步和更新。 这可能是最简单,最快的入门方法。 但是,请注意,这是一个非官方的 Maven存储库,不做任何保证,也不得到Google的支持。

我认为,最好花几分钟的时间来导入官方源代码。 这样,您可以轻松跳转到原始定义和实现,以便在有疑问的情况下始终可以依赖Volley官方来源,甚至可以根据需要进行更改。

步骤2:使用Volley

Volley主要只使用两个类RequestQueueRequest 。 首先,您创建一个RequestQueue ,它管理工作线程并将解析的结果传递回主线程。 然后,您将一个或多个Request对象传递给它。

Request构造函数始终将方法类型(GET,POST等),资源的URL和事件侦听器作为参数。 然后,根据请求的类型,它可能会要求更多的变量。

在下面的示例中,我创建一个RequestQueue   通过调用Volley的一种便捷方法Volley.newRequestQueue 。 这将建立一个RequestQueue   对象,使用Volley定义的默认值。

String url = "http://httpbin.org/html";

// Request a string response
StringRequest stringRequest = new StringRequest(Request.Method.GET, url,
            new Response.Listener<String>() {
    @Override
    public void onResponse(String response) {

        // Result handling 
        System.out.println(response.substring(0,100));

    }
}, new Response.ErrorListener() {
    @Override
    public void onErrorResponse(VolleyError error) {
        
        // Error handling
        System.out.println("Something went wrong!");
        error.printStackTrace();

    }
});

// Add the request to the queue
Volley.newRequestQueue(this).add(stringRequest);

如您所见,它非常简单。 您创建请求并将其添加到请求队列。 这样就完成了。

请注意,侦听器语法与AsyncTask.onPostExecute相似,只是变为onResponse 。 这不是巧合。 致力于Volley的开发人员故意使该库的API与AsyncTask方法相似。 这使从使用AsyncTask到Volley的过渡变得容易得多。

如果必须在多个活动中触发多个请求,则应避免使用上述方法Volley.newRequestQueue.add 。 很多   最好实例化一个共享请求队列并在您的项目中使用它:

MySingletonClass.getInstance().getRequestQueue().add(myRequest);

在本系列的下一个教程中, 我们将专门开发类似的东西。

把手放在面团上

处理标准要求

Volley可以方便地实现三种非常常见的请求类型:

  • StringRequest
  • ImageRequest
  • JsonRequest

这些类均扩展了我们先前使用的Result类。 我们已经在前面的示例中查看了StringRequest 。 让我们看看JsonRequest是如何工作的。

String url = "http://httpbin.org/get?site=code&network=tutsplus";

JsonObjectRequest jsonRequest = new JsonObjectRequest
        (Request.Method.GET, url, null, new Response.Listener<JSONObject>() {
            @Override
            public void onResponse(JSONObject response) {
                // the response is already constructed as a JSONObject!
                try {
                    response = response.getJSONObject("args");
                    String site = response.getString("site"),
                            network = response.getString("network");
                    System.out.println("Site: "+site+"\nNetwork: "+network);
                } catch (JSONException e) {
                    e.printStackTrace();
                }
            }
        }, new Response.ErrorListener() {

            @Override
            public void onErrorResponse(VolleyError error) {
                error.printStackTrace();
            }
        });

Volley.newRequestQueue(this).add(jsonRequest);

美丽。 是不是 如您所见,结果类型已经设置为JSONObject 。 您也可以使用JsonArrayRequest而不是JsonObjectRequest来请求JSONArray

和以前一样,构造函数的第一个参数是要使用的HTTP方法。 然后,您提供URL以从中获取JSON。 上例中的第三个变量为null 。 这很好,因为它表明不会随请求一起发布任何参数。 最后,您有一个侦听器来接收JSON响应和一个错误侦听器。 如果要忽略错误,则可以传递null

提取图像需要更多的工作。 请求图像有三种可能的方法。 ImageRequest 是标准之一。 它在公共ImageView显示您请求的图片,并通过提供的URL进行检索。 您可能希望Volley执行的所有解码和调整大小操作都在工作线程上进行。 第二个选项是ImageLoader类,您可以将其视为大量ImageRequests ,例如,用图像填充ListView 。 第三个选项是NetworkImageView ,它是ImageView布局项的一种XML替代。

让我们来看一个例子。

String url = "http://i.imgur.com/Nwk25LA.jpg";
mImageView = (ImageView) findViewById(R.id.image);

ImageRequest imgRequest = new ImageRequest(url,
        new Response.Listener<Bitmap>() {
    @Override
    public void onResponse(Bitmap response) {
        mImageView.setImageBitmap(response);
    }
}, 0, 0, ImageView.ScaleType.FIT_XY, Bitmap.Config.ARGB_8888, new Response.ErrorListener() {
    @Override
    public void onErrorResponse(VolleyError error) {
        mImageView.setBackgroundColor(Color.parseColor("#ff0000"));
        error.printStackTrace();
    }
});

Volley.newRequestQueue(this).add(imgRequest);

第一个参数是图片的URL,第二个参数是结果的侦听器。 第三个和第四个参数是整数maxWidthmaxHeight 。 您可以将它们设置为0以忽略这些参数。 之后, ImageRequest 询问您用于计算所需图像大小的ScaleType以及将位图解码为的格式。 我建议始终使用Bitmap.Config.ARGB_8888 。 最后,我们传入一个错误侦听器。

请注意,Volley会自动将此请求的优先级设置为LOW

// Snippet taken from ImageRequest.java, 
// in the Volley source code
@Override
public Priority getPriority() {
    return Priority.LOW;
}

发出POST请求

从GET请求切换到POST请求很简单。 您需要在请求的构造函数中更改Request.Method并重写getParams方法,以返回包含请求参数的正确Map<String, String>

String url = "http://httpbin.org/post";

StringRequest postRequest = new StringRequest(Request.Method.POST, url,
        new Response.Listener<String>() {
            @Override
            public void onResponse(String response) {
                try {
                    JSONObject jsonResponse = new JSONObject(response).getJSONObject("form");
                    String site = jsonResponse.getString("site"),
                            network = jsonResponse.getString("network");
                    System.out.println("Site: "+site+"\nNetwork: "+network);
                } catch (JSONException e) {
                    e.printStackTrace();
                }
            }
        },
        new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError error) {
                error.printStackTrace();
            }
        }
) {
    @Override
    protected Map<String, String> getParams()
    {
        Map<String, String>  params = new HashMap<>();
        // the POST parameters:
        params.put("site", "code");
        params.put("network", "tutsplus");
        return params;
    }
};
Volley.newRequestQueue(this).add(postRequest);

取消请求

如果要取消所有请求,请在onStop方法中添加以下代码段:

@Override
protected void onStop() {
    super.onStop();
    mRequestQueue.cancelAll(new RequestQueue.RequestFilter() {
        @Override
        public boolean apply(Request<?> request) {
            // do I have to cancel this?
            return true; // -> always yes
        }
    });
}

这样,您不必担心调用onResponse时用户已经销毁了活动的可能性。 在这种情况下将抛出NullPointerException

但是,即使用户更改了活动,POST和PUT请求也应继续。 我们可以使用标签来做到这一点。 构造GET请求时,向其添加标签。

// after declaring your request
request.setTag("GET");
mRequestQueue.add(request);

要取消每个待处理的GET请求,我们只需添加以下代码行:

mRequestQueue.cancelAll("GET");

这样,您仅取消GET请求,而其他请求保持不变。 请注意,您现在必须手动处理活动被过早销毁的情况。

管理Cookie和请求优先级

Volley没有提供设置请求的Cookie的方法,也没有提供其优先级。 由于这是一个严重的遗漏,将来可能还会。 但是,暂时,您必须扩展Request类。

为了管理cookie,您可以使用请求的标头,并覆盖getHeaders方法:

public class CustomRequest extends JsonObjectRequest {

    // Since we're extending a Request class
    // we just use its constructor
    public CustomRequest(int method, String url, JSONObject jsonRequest,
                         Response.Listener<JSONObject> listener, Response.ErrorListener errorListener) {
        super(method, url, jsonRequest, listener, errorListener);
    }

    private Map<String, String> headers = new HashMap<>();

    /**
     * Custom class!
     */
    public void setCookies(List<String> cookies) {
        StringBuilder sb = new StringBuilder();
        for (String cookie : cookies) {
            sb.append(cookie).append("; ");
        }
        headers.put("Cookie", sb.toString());
    }

    @Override
    public Map<String, String> getHeaders() throws AuthFailureError {
        return headers;
    }
    
}

通过此实现,您可以使用setCookies直接向请求提供cookie列表。

// Firstly, you create the list of the cookies,
// conformed to the HTTP conventions
// i.e. key=value
List<String> cookies = new ArrayList<>();
cookies.add("site=code");
cookies.add("network=tutsplus");

// then you invoke your custom method
customRequest.setCookies(cookies);

// and finally add the request to the queue
Volley.newRequestQueue(this).add(customRequest);

对于优先级,还需要扩展Request类,以覆盖getPriority方法。 这是实现的样子:

Priority mPriority;

public void setPriority(Priority priority) {
    mPriority = priority;
}

@Override
public Priority getPriority() {
    // If you didn't use the setPriority method,
    // the priority is automatically set to NORMAL
    return mPriority != null ? mPriority : Priority.NORMAL;
}

然后,在主线程上,调用以下代码行以设置请求的优先级:

customRequest.setPriority(Priority.HIGH);

您可以从四个可能的优先级状态之一中进行选择,如下所示:

Priority.LOW // images, thumbnails, ...
Priority.NORMAL // residual
Priority.HIGH // descriptions, lists, ...
Priority.IMMEDIATE // login, logout, ...

结论

在本文中,我们研究了Volley网络库的工作方式。 我们首先看到了为什么以及何时最好使用Volley代替Android SDK中已经包含的另一种解决方案。 然后,我们深入研究库的详细信息,查看其工作流程和受支持的请求类型。 最后,我们通过创建简单的请求并实现用于处理cookie和优先级的自定义请求来处理问题。

在有关Volley的本系列的下一部分中,我们将创建一个利用Volley的简单应用程序。 我将向您展示如何使用好奇号流动站在火星上收集的天气数据为火星制作气象应用程序。

如果您进行了大量Android开发,为什么不使用Envato Market上数千种有用的Android应用模板之一来加快工作流程呢? 或与Envato Studio上的一位Android开发人员联系以为您的项目提供帮助-他们甚至可以从头开始为您设计应用!

翻译自: https://code.tutsplus.com/tutorials/an-introduction-to-volley--cms-23800

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值