Volley是google在2013年IO大会上发布的一个网络通信工具包,对在android平台上通过消息队列,异步处理,线程池,缓存等方式对http请求的一些常见方法进行了优化,同时对大数据量的请求并发也作了一定的处理,可以随时取消消息的请求。
Volley主要分为两个包:核心包和工具包。核心包主要对消息请求常用的方法进行了封装;工具包则提供了一些常见的消息请求如图片,json。
Volley对消息请求处理的主要流程如下:
1 创建消息请求并放入消息缓存队列,消息缓存处理器在本地缓存里检查该消息是否有缓存,如果有,则直接将消息响应返回;
2 如消息缓存里没有该消息,则将该消息放入消息请求队列;
3 消息请求处理器从队列里依次取出消息请求,
4 消息请求处理器通过网络发送请求;
5 网络对请求作出响应,消息队列处理器对网络响应进行解析处理;
6 将解析后消息响应存入缓存,同时通知发出请求的主线程对响应进行处理。
// 1 创建一个请求队列
RequestQueue requestQueue = Volley.newRequestQueue(VolleyActivity.this);
// 2 创建一个请求
String url = "http://api.m.mtime.cn/PageSubArea/TrailerList.api";
StringRequest stringRequest = new StringRequest(url, new Response.Listener<String>() {
// 正确接收数据回调
@Override
public void onResponse(String s) {
tv_volley_result.setText(s);
}
}, new Response.ErrorListener() {
// 发生异常后的监听回调
@Override
public void onErrorResponse(VolleyError volleyError) {
tv_volley_result.setText("加载失败" + volleyError);
}
});
// 3 将创建的请求添加到请求队列中
requestQueue.add(stringRequest);
一般我们的POST都是要带一些参数的,Volley没有提供附加参数的方法,所以我们必须要在StringRequest的匿名类中重写getParams()方法,代码如下:
// 1 创建一个请求队列
RequestQueue requestQueue = Volley.newRequestQueue(VolleyActivity.this);
// 2 创建一个post请求
String url = "http://api.m.mtime.cn/PageSubArea/TrailerList.api";
StringRequest stringRequest = new StringRequest(Request.Method.POST, url, new Response.Listener<String>() {
@Override
public void onResponse(String s) {
tv_volley_result.setText(s);
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError volleyError) {
tv_volley_result.setText("请求失败" + volleyError);
}
}) {
@Override
protected Map<String, String> getParams() throws AuthFailureError {
Map<String, String> map = new HashMap<String, String>();
// map.put("value1","param1");
return map;
}
};
// 3 将post请求添加到队列中
requestQueue.add(stringRequest);
类似于StringRequest,JsonRequest也是继承自Request类的,不过由于JsonRequest是一个抽象类,因此我们无法直接创建它的实例,那么只能从它的子类入手。JsonRequest有两个直接的子类,JsonObjectRequest和JsonArrayRequest,一个是用于请求一段JSON数据的,一个是用于请求一段JSON数组的。
// 1 创建一个请求队列
RequestQueue requestQueue = Volley.newRequestQueue(VolleyActivity.this);
// 2 创建一个请求
String url = "http://api.m.mtime.cn/PageSubArea/TrailerList.api";
JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(url, null, new Response.Listener<JSONObject>() {
@Override
public void onResponse(JSONObject jsonObject) {
tv_volley_result.setText(jsonObject.toString());
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError volleyError) {
tv_volley_result.setText("请求失败" + volleyError);
}
});
// 3 将创建的请求添加到请求队列中
requestQueue.add(jsonObjectRequest);
// 1 创建一个请求队列
RequestQueue requestQueue = Volley.newRequestQueue(VolleyActivity.this);
// 2 创建一个图片的请求
String url = "http://img5.mtime.cn/mg/2016/10/11/160347.30270341.jpg";
ImageRequest imageRequest = new ImageRequest(url, new Response.Listener<Bitmap>() {
@Override
public void onResponse(Bitmap bitmap) {
// 正确接收到图片
iv_volley_result.setImageBitmap(bitmap);
}
}, 0, 0, Bitmap.Config.RGB_565, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError volleyError) {
iv_volley_result.setImageResource(R.drawable.atguigu_logo);
}
});
// 3 将请求添加到请求队列中
requestQueue.add(imageRequest);
ImageLoader也可以用于加载网络上的图片,不过ImageLoader明显要比ImageRequest更加高效,因为它不仅可以帮我们对图片进行缓存,还可以过滤掉重复的链接,避免重复发送请求。
由于ImageLoader已经不是继承自Request的了,所以它的用法也和我们之前学到的内容有所不同,总结起来大致可以分为以下四步:
创建一个RequestQueue对象。
创建一个ImageLoader对象。
获取一个ImageListener对象。
调用ImageLoader的get()方法加载网络上的图片。
// 创建一个请求队列
RequestQueue requestQueue = Volley.newRequestQueue(VolleyActivity.this);
ImageLoader imageLoader = new ImageLoader(requestQueue, new BitmapCache());
// 加载图片
String url = "http://img5.mtime.cn/mg/2016/10/11/160347.30270341.jpg";
ImageLoader.ImageListener imageListener = imageLoader.getImageListener(iv_volley_result, R.drawable.atguigu_logo, R.drawable.atguigu_logo);
imageLoader.get(url, imageListener);
BitmapCache.java
public class BitmapCache implements ImageLoader.ImageCache {
private LruCache<String, Bitmap> mCache;
public BitmapCache() {
int maxSize = 10 * 1024 * 1024;// 10m
mCache = new LruCache<String, Bitmap>(maxSize) {
@Override
protected int sizeOf(String key, Bitmap bitmap) {
return bitmap.getRowBytes() * bitmap.getHeight();
}
};
}
@Override
public Bitmap getBitmap(String url) {
return mCache.get(url);
}
@Override
public void putBitmap(String url, Bitmap bitmap) {
mCache.put(url, bitmap);
}
}
NetworkImageView继承自ImageView,你可以认为它是一个可以实现加载网络图片的imageview,十分简单好用。这个控件在被从父控件分离的时候,会自动取消网络请求的,即完全不用我们担心相关网络请求的生命周期问题。
<com.android.volley.toolbox.NetworkImageView
android:id="@+id/iv_volley_networkimagview"
android:layout_width="200dp"
android:layout_height="200dp"
android:visibility="gone">
</com.android.volley.toolbox.NetworkImageView>
// 创建一个请求队列
RequestQueue requestQueue = Volley.newRequestQueue(VolleyActivity.this);
// 创建一个Imageloader
ImageLoader imageLoader = new ImageLoader(requestQueue, new BitmapCache());
// 默认图片和异常图片设置
iv_volley_networkimagview.setDefaultImageResId(R.drawable.atguigu_logo);
iv_volley_networkimagview.setErrorImageResId(R.drawable.atguigu_logo);
// 加载图片
String url = "http://img5.mtime.cn/mg/2016/10/11/160347.30270341.jpg";
iv_volley_networkimagview.setImageUrl(url, imageLoader);
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/background"
android:orientation="vertical"
android:padding="20dp">
<EditText
android:id="@+id/edtUrl"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/input_url"
android:textSize="20sp"
android:lines="2" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:layout_marginBottom="10dp"
android:gravity="center"
android:orientation="horizontal">
<Button
android:id="@+id/btnDownload"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="doDownload"
android:textSize="20sp"
android:text="@string/download" />
<Button
android:id="@+id/btnClear"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="doClear"
android:textSize="20sp"
android:text="@string/clear" />
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="#bbbbbb" />
<ScrollView
android:id="@+id/svContent"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/tvContent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#0000ff"
android:textSize="18sp" />
</ScrollView>
</LinearLayout>
<resources>
<string name="app_name">利用Volley下载网页</string>
<string name="input_url">请输入网址</string>
<string name="download">下载</string>
<string name="clear">清空</string>
</resources>
package net.nell.downloadwebpagebyvolley;
import android.os.Bundle;
import android.view.View;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import com.android.volley.RequestQueue;
import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.StringRequest;
import com.android.volley.toolbox.Volley;
import java.io.UnsupportedEncodingException;
public class MainActivity extends AppCompatActivity {
private EditText edtUrl; // 网址编辑框
private TextView tvContent; // 显示网页内容的标签
private RequestQueue mRequestQueue; // 请求队列
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 利用布局资源文件设置用户界面
setContentView(R.layout.activity_main);
// 通过资源标识符获取控件实例
edtUrl = findViewById(R.id.edtUrl);
tvContent = findViewById(R.id.tvContent);
// 创建请求队列
mRequestQueue = Volley.newRequestQueue(getApplicationContext());
}
/**
* 下载按钮单击事件处理方法
*
* @param view
*/
public void doDownload(View view) {
// 获取用户输入的网址
String strUrl = edtUrl.getText().toString();
// 网址非空校验
if (strUrl.length() == 0) {
Toast.makeText(getApplicationContext(), "请输入网址", Toast.LENGTH_SHORT).show();
edtUrl.requestFocus();
return;
}
// 创建字符串请求对象
final StringRequest stringRequest = new StringRequest(
strUrl, // 参数1:目标服务器的URL地址
new Response.Listener<String>() {
// 参数2:服务器响应成功的回调
@Override
public void onResponse(String response) {
try {
// 获取响应内容
String content = new String(response.toString().getBytes("iso8859-1"), "utf-8");
// 将响应内容显示到标签里
tvContent.setText(content);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
},
new Response.ErrorListener() {
// 参数3:服务器响应失败的回调
@Override
public void onErrorResponse(VolleyError error) {
Toast.makeText(MainActivity.this, "服务器响应失败!", Toast.LENGTH_SHORT).show();
}
});
// 添加字符串请求到请求队列
mRequestQueue.add(stringRequest);
}
/**
* 清空单击事件处理方法
*
* @param view
*/
public void doClear(View view) {
// 清空网址编辑框
edtUrl.setText("");
// 清空网页内容标签
tvContent.setText("");
// 让网址编辑框获取焦点
edtUrl.requestFocus();
}
}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/background"
android:orientation="vertical"
android:padding="20dp">
<EditText
android:id="@+id/edtImageUrl"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/input_image_url"
android:textSize="20sp"
android:lines="2" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:layout_marginBottom="10dp"
android:gravity="center"
android:orientation="horizontal">
<Button
android:id="@+id/btnDownload"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="doDownload"
android:textSize="20sp"
android:text="@string/download" />
<Button
android:id="@+id/btnClear"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="doClear"
android:textSize="20sp"
android:text="@string/clear" />
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="#bbbbbb" />
<ScrollView
android:id="@+id/svContent"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/ivImage"/>
</ScrollView>
</LinearLayout>
<resources>
<string name="app_name">利用Volley下载网络图片</string>
<string name="download">下载</string>
<string name="input_image_url">输入图片网址</string>
<string name="clear">清空</string>
</resources>
package net.nell.downloadimagebyvolley;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.view.View;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import com.android.volley.RequestQueue;
import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.ImageRequest;
import com.android.volley.toolbox.Volley;
/**
* 功能:利用Volley下载网络图片
* 作者:华卫
* 日期:2021年01年03日
*/
public class MainActivity extends AppCompatActivity {
private EditText edtImageUrl; // 网址编辑框
private ImageView ivImage; // 显示网络图片的图像控件
private RequestQueue mRequestQueue; // 请求队列
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 利用布局资源文件设置用户界面
setContentView(R.layout.activity_main);
// 通过资源标识符获取控件实例
edtImageUrl = findViewById(R.id.edtImageUrl);
ivImage = findViewById(R.id.ivImage);
// 创建请求队列
mRequestQueue = Volley.newRequestQueue(getApplicationContext());
}
/**
* 下载按钮单击事件处理方法
*
* @param view
*/
public void doDownload(View view) {
// 获取用户输入的网址
String strImageUrl = edtImageUrl.getText().toString();
// 网址非空校验
if (strImageUrl.length() == 0) {
Toast.makeText(getApplicationContext(), "请输入网址", Toast.LENGTH_SHORT).show();
edtImageUrl.requestFocus();
return;
}
// 创建图像请求对象
final ImageRequest imageRequest = new ImageRequest(
strImageUrl, // 参数1:目标服务器的URL地址
new Response.Listener<Bitmap>() {
// 参数2:服务器响应成功的回调
@Override
public void onResponse(Bitmap response) {
ivImage.setImageBitmap(response);
}
},
0, // 参数3:指定允许图片最大的宽度(指定成0,不压缩图片)
0, // 参数4:指定允许图片最大的高度(指定成0,不压缩图片)
Bitmap.Config.RGB_565, // 参数5:指定图片颜色属性(RGB_565表示每个图片像素占据2个字节)
new Response.ErrorListener() {
// 参数6:服务器响应失败的回调
@Override
public void onErrorResponse(VolleyError error) {
Toast.makeText(MainActivity.this, "服务器响应失败!", Toast.LENGTH_SHORT).show();
}
});
// 添加图像请求到请求队列
mRequestQueue.add(imageRequest);
}
/**
* 清空单击事件处理方法
*
* @param view
*/
public void doClear(View view) {
// 清空网址编辑框
edtImageUrl.setText("");
// 清空图像控件内容
ivImage.setImageBitmap(null);
// 让网址编辑框获取焦点
edtImageUrl.requestFocus();
}
}
ImageLoader明显要比ImageRequest更加高效,因为它不仅可以对图片进行缓存,还可以过滤掉重复的链接,避免重复发送请求。
package net.nell.downloadimagebyvolley;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.util.LruCache;
import android.view.View;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import com.android.volley.RequestQueue;
import com.android.volley.toolbox.ImageLoader;
import com.android.volley.toolbox.Volley;
public class MainActivity extends AppCompatActivity {
private EditText edtImageUrl; // 网址编辑框
private ImageView ivImage; // 显示网络图片的图像控件
private RequestQueue mRequestQueue; // 请求队列
private ImageLoader imageLoader; // 图像加载器
private ImageLoader.ImageListener imageListener; // 图像监听器
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 利用布局资源文件设置用户界面
setContentView(R.layout.activity_main);
// 通过资源标识符获取控件实例
edtImageUrl = findViewById(R.id.edtImageUrl);
ivImage = findViewById(R.id.ivImage);
// 创建请求队列
mRequestQueue = Volley.newRequestQueue(getApplicationContext());
}
/**
* 下载按钮单击事件处理方法
*
* @param view
*/
public void doDownload(View view) {
// 获取用户输入的网址
String strImageUrl = edtImageUrl.getText().toString();
// 网址非空校验
if (strImageUrl.length() == 0) {
Toast.makeText(getApplicationContext(), "请输入网址", Toast.LENGTH_SHORT).show();
edtImageUrl.requestFocus();
return;
}
// 创建图像加载器对象
imageLoader = new ImageLoader(mRequestQueue, new BitmapCache());
// 获取图像监听器对象
imageListener = imageLoader.getImageListener(
ivImage, // 参数1:指定用于显示图片的ImageView控件
R.drawable.ic_launcher_background, // 参数2:指定图片加载过程中显示的图片
android.R.drawable.ic_delete // 参数3:指定图片加载失败时显示的图片
);
// 加载网络图片
imageLoader.get(strImageUrl, imageListener);
}
/**
* 清空单击事件处理方法
*
* @param view
*/
public void doClear(View view) {
// 清空网址编辑框
edtImageUrl.setText("");
// 清空图像控件内容
ivImage.setImageBitmap(null);
// 让网址编辑框获取焦点
edtImageUrl.requestFocus();
}
/**
* 绘图缓存类
*/
class BitmapCache implements ImageLoader.ImageCache {
private LruCache<String, Bitmap> mCache;
public BitmapCache() {
int maxSize = 10 * 1024 * 1024;
mCache = new LruCache<String, Bitmap>(maxSize) {
@Override
protected int sizeOf(String key, Bitmap bitmap) {
return bitmap.getRowBytes() * bitmap.getHeight();
}
};
}
@Override
public Bitmap getBitmap(String url) {
return mCache.get(url);
}
@Override
public void putBitmap(String url, Bitmap bitmap) {
mCache.put(url, bitmap);
}
}
}
使用上述代码可以在下载图片时进行优化,但运行效果于上述方法相同,在此便不进行演示。
以上是任务五所涉及到的一部分内容,接下来的时间我将会进行Gson的学习,这部分的学习内容将会明天进行展示。