Σ(っ °Д °;)っ重要的话终究还是讲了三遍...Android主要有三种形式实现网络编程
传送门?
HttpURLConnection:https://blog.csdn.net/nishigesb123/article/details/89328097
Apache HTTP Client:https://blog.csdn.net/nishigesb123/article/details/89352227
前文已经提到了两种,当然今天并不是要讲最后的那种,而是介绍一个优秀的网络通信框架——Volley,学习了HttpURLConnection和Apache HTTP Client之后,虽然已经能够实现大部分网络编程的需求,但是显然它们还是有些复杂,而它们的使用率也是居高不下,重复使用比比皆是。为了解决这个矛盾,就有了Volley(当然不只是Volley还有其他的)试图去简化网络通信操作。
项目地址:https://github.com/google/volley
git克隆:
git clone https://android.googlesource.com/platform/frameworks/volley
mvnrepository上也可以找到,算曲线救国嘛?
https://mvnrepository.com/artifact/com.mcxiaoke.volley/library
然后Android Studio并不需要特地去搞到Jar...
之前文章提到了通过Android Studio直接添加Gson依赖的步骤,步骤就不重复了,可以看到volley也是可以搜的到的
RequestQueue是一个请求队列对象。
创建RequestQueue对象:
RequestQueue mQueue = Volley.newRequestQueue(context);
- 它可以缓存所有的HTTP请求, 然后按照一定的算法并发地发出这些请求。
- RequestQueue内部的设计就是非常合适高并发的
- 我们不必为每一次HTTP请求都创建一个RequestQueue对象,这是非常浪费资源的
- 基本上在每一个需要和网络交互的Activity中创建一个RequestQueue对象就足够了。
出处:https://blog.csdn.net/guolin_blog/article/details/17482095(包括?许多内容的出处)
要发出一条HTTP请求,需要创建一个StringRequest对象:
发送一个字符串的请求
StringRequest stringRequest = new StringRequest('http://ww.baidu.com,new Response.Listener() {
public void onResponse(String response) { Log.d("TAG", responsel);}},
new Response.Errorlistener() {
public void onErrorResponse(VolleyError error) {
Log.e("TAG", error.getMessage(), error);
}
};
发出一条POST请求
StringRequest stringRequest = new StringRequest(Method.POST, url, listener, errorlistener){
protected Map getParams() throws AuthFailureError {
Map map = new HashMap();
map.put("params1", "value1");
map.put("params2", "value2");
return map;
}
};
StringRequest的构造函数需要传入三个参数:
将StringRequest对象添加到RequestQueue
mQueue.add(stringRequest);
涉及网络,所以也需要必要的网络权限。
需要一个按钮,配置对应点击事件
package com.example.a4_16volley;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import com.android.volley.Request;
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;
public class MainActivity extends AppCompatActivity {
RequestQueue queue=null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//创建一个请求队列
queue = Volley.newRequestQueue(this);
}
//发送一个字符串的请求
public void StringRequest(View view){
String url="https://blog.csdn.net";
//创建一个字符串请求 参数(请求方式,URL,响应的回调接口,错误的回调接口)
StringRequest request=new StringRequest(Request.Method.GET,
url, new Response.Listener() {
@Override
public void onResponse(String response) {
System.out.println(response);
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
System.out.println(error);
}
});
queue.add(request);
}
}
效果如?
输出信息:
包括部分上面案例的代码,同样需要一个按钮。
package com.example.a4_16volley;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import com.android.volley.AuthFailureError;
import com.android.volley.Request;
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.util.HashMap;
import java.util.Map;
public class MainActivity extends AppCompatActivity {
RequestQueue queue=null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//创建一个请求队列
queue = Volley.newRequestQueue(this);
}
//发送一个字符串的请求
public void StringRequest(View view){
String url="https://blog.csdn.net";
//创建一个字符串请求 参数(请求方式,URL,响应的回调接口,错误的回调接口)
StringRequest request=new StringRequest(Request.Method.GET,
url, new Response.Listener() {
@Override
public void onResponse(String response) {
System.out.println(response);
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
System.out.println(error);
}
});
queue.add(request);
}
//发送一个带参数的POST请求
public void sendParansPostString(View view){
//需要准备一个服务器...
String url = "http://10.0.2.2:8080/contact/android";
StringRequest request = new StringRequest(Request.Method.POST, url, new Response.Listener() {
@Override
public void onResponse(String response) {
System.out.println(response);
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
System.out.println(error);
}
}){
@Override
protected Map getParams() throws AuthFailureError {
Map params=new HashMap<>();
params.put("username","admin");
params.put("password","admin");
return params;
}
};
queue.add(request);
}
}
效果如?
客户端:
服务器端:
如果接到的数据的Json,可以用JsonRequest去创建一个请求。
这部分没有合适的API,就不演示了,代码中示范的API数据实际上是string类型的...
参考代码:
//发送一个JsonRequest
public void sendJsonRequest(View view) {
//毒霸天气的API,最后的数字0表示本地
String url = "http://weather.123.duba.net/static/weather_info/0.html";
/***
* //请求参数对象封装为为JSONObject 放在JsonObjectRequest的jsonRequest对象,就是下面null的位置
* // JSONObject jsonObject=new JSONObject();
* // try {
* // jsonObject.put("param","value");
* // } catch (JSONException e) {
* // e.printStackTrace();
* // }
*/
//参数(请求方式,URL,请求参数,响应的回调接口,错误的回调接口)
JsonObjectRequest request = new JsonObjectRequest(Request.Method.GET, url, null, new Response.Listener() {
@Override
public void onResponse(JSONObject response) {
System.out.println(response);
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
System.out.println(error);
}
});
queue.add(request);
}
ImageRequest是一个图片请求对象,它继承自Request
步骤类似的
创建RequestQueue对象。
创建ImageRequest对象。
将ImageRequest对象添加到RequestQueue里面。
ImageRequest的构造函数接收六个参数:
第一个参数就是图片的URL地址,这个没什么需要解释的。
第二个参数是图片请求成功的回调,这里我们把返回的Bitmap参数设置到ImageView中。
第三第四个参数分别用于指定允许图片最大的宽度和高度,如果指定的网络图片的宽度或高度大于这里的最大值,则会对图片进行压缩,指定成0的话就表示不管图片有多大,都不会进行压缩。
第五个参数用于指定图片的颜色属性,Bitmap.Config下的几个常量都可以在这里使用,其中ARGB_8888可以展示最好的颜色属性,每个图片像素占据4个字节的大小,而RGB_565则表示每个图片像素占据2个字节大小。
第六个参数是图片请求失败的回调。
出处:https://blog.csdn.net/UUUUUltraman/article/details/89329891#t3
需要注意的是,为了显示测试效果,ImageRequest搭配了一个ImageView,请读者自行添加并注册组件。
//发送一个ImageRequest
public void sendImageRequest(View view){
String url="https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1555568604477&di=68c94aa34a2971979975c8c193869a2d&imgtype=0&src=http%3A%2F%2Finews.gtimg.com%2Fnewsapp_bt%2F0%2F8511061308%2F641";
ImageRequest request=new ImageRequest(url, new Response.Listener() {
@Override
public void onResponse(Bitmap response) {
imageView.setImageBitmap(response);
}
}, 0, 0, Bitmap.Config.RGB_565, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
System.out.println(error);
}
});
queue.add(request);
}
效果如? (用黑洞会被告侵权吗 {{{(>_<)}}} 233
除了ImageRequest,Volley还内置了一种加载网络图片的实现办法——ImageLoader
使用步骤稍有不同:
//使用ImageLoader加载网络图片
public void ImageLoader(View view){
String url="https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1555568604477&di=68c94aa34a2971979975c8c193869a2d&imgtype=0&src=http%3A%2F%2Finews.gtimg.com%2Fnewsapp_bt%2F0%2F8511061308%2F641";
//新建一个ImageLoader对象
ImageLoader imageLoader=new ImageLoader(queue, new ImageLoader.ImageCache() {
//对图片进行缓存
@Override
public Bitmap getBitmap(String url) {
return null;
}
@Override
public void putBitmap(String url, Bitmap bitmap) {
}
});
//获取一个ImageListener对象
//getImageListener()方法接收三个参数
// 第一个参数指定用于显示图片的ImageView控件
// 第二个参数指定加载图片的过程中显示的图片
// 第三个参数指定加载图片失败的情况下显示的图片
ImageLoader.ImageListener listener=ImageLoader.getImageListener(imageView,R.mipmap.ic_launcher,R.mipmap.ic_launcher);
//加载图片,参数1为url地址,参数2为ImageListener对象,参数3、4最大宽高
imageLoader.get(url,listener,500,500);
}
效果如下? (ImageView共享的上一个案例的,URL也没有改)
前文提到ImageLoader要比ImageRequest更加高效,上面的案例无法体现ImageLoader的优越性。
对代码进行一定的修改,我们自己写一个BitmapCache
//使用ImageLoader加载网络图片
public void ImageLoader(View view) {
String url = "https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1555568604477&di=68c94aa34a2971979975c8c193869a2d&imgtype=0&src=http%3A%2F%2Finews.gtimg.com%2Fnewsapp_bt%2F0%2F8511061308%2F641";
//新建一个ImageLoader对象
ImageLoader imageLoader = new ImageLoader(queue, new BitmapCache());
//获取一个ImageListener对象
//getImageListener()方法接收三个参数
// 第一个参数指定用于显示图片的ImageView控件
// 第二个参数指定加载图片的过程中显示的图片
// 第三个参数指定加载图片失败的情况下显示的图片
ImageLoader.ImageListener listener = ImageLoader.getImageListener(imageView, R.mipmap.ic_launcher, R.mipmap.ic_launcher);
//加载图片,参数1为url地址,参数2为ImageListener对象,参数3、4最大宽高
imageLoader.get(url, listener, 500, 500);
}
//创建BitmapCache实现ImageCache接口
private class BitmapCache implements ImageLoader.ImageCache {
private LruCache cache;
//最大缓存大小
private int maxCache = 10 * 1024;
public BitmapCache() {
cache = new LruCache(maxCache);
}
@Override
public Bitmap getBitmap(String url) {
return cache.get(url);
}
@Override
public void putBitmap(String url, Bitmap bitmap) {
cache.put(url, bitmap);
}
}
效果的话,和?的案例是一样的,就不再演示截图了。
主要是性能上的优化(第一次网络加载,第二次及以后读取缓存,而上一个案例,每点击一次都会进行加载)
万万没想到,Volley加载图片还有一种方式(Volley是有多喜欢加载图片...)——NetworkImageView
既然是类似ImageView的组件,一开始的配置自然和ImageView差不多
布局文件配置完毕后需要注册组件,?下面两句放哪里就不用多说了吧
private NetworkImageView networkImageView;
networkImageView = findViewById(R.id.networkImageView);
一般来讲然后直接在下面接上相关设置语句就算是配置完成了,优雅一点可以封装成一个方法
networkImageView.setDefaultImageResId(默认的);
networkImageView.setErrorImageResId(失败的);
networkImageView.setImageUrl("yoururl",imageLoader);
然后参数需要一个,imageLoader的话可以参考上面的案例的相关内容
放一个这篇文章的完整代码,最下面就是networkImageView的代码
package com.example.a4_16volley;
import android.graphics.Bitmap;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.LruCache;
import android.view.View;
import android.widget.ImageView;
import com.android.volley.AuthFailureError;
import com.android.volley.Request;
import com.android.volley.RequestQueue;
import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.ImageLoader;
import com.android.volley.toolbox.ImageRequest;
import com.android.volley.toolbox.JsonObjectRequest;
import com.android.volley.toolbox.NetworkImageView;
import com.android.volley.toolbox.StringRequest;
import com.android.volley.toolbox.Volley;
import org.json.JSONObject;
import java.util.HashMap;
import java.util.Map;
public class MainActivity extends AppCompatActivity {
RequestQueue queue = null;
private ImageView imageView;
private NetworkImageView networkImageView;
private String url = "https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1555568604477&di=68c94aa34a2971979975c8c193869a2d&imgtype=0&src=http%3A%2F%2Finews.gtimg.com%2Fnewsapp_bt%2F0%2F8511061308%2F641";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//创建一个请求队列
queue = Volley.newRequestQueue(this);
imageView = findViewById(R.id.imageView);
networkImageView = findViewById(R.id.networkImageView);
networkImageView();
}
//发送一个字符串的请求
public void StringRequest(View view) {
String url = "https://blog.csdn.net";
//创建一个字符串请求 参数(请求方式,URL,响应的回调接口,错误的回调接口)
StringRequest request = new StringRequest(Request.Method.GET,
url, new Response.Listener() {
@Override
public void onResponse(String response) {
System.out.println(response);
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
System.out.println(error);
}
});
queue.add(request);
}
//发送一个带参数的POST请求
public void sendParansPostString(View view) {
//需要准备一个服务器...
String url = "http://10.0.2.2:8080/contact/android";
StringRequest request = new StringRequest(Request.Method.POST, url, new Response.Listener() {
@Override
public void onResponse(String response) {
System.out.println(response);
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
System.out.println(error);
}
}) {
@Override
protected Map getParams() throws AuthFailureError {
Map params = new HashMap<>();
params.put("username", "admin");
params.put("password", "admin");
return params;
}
};
queue.add(request);
}
//发送一个JsonRequest
public void sendJsonRequest(View view) {
//毒霸天气的API,最后的数字0表示本地
String url = "http://weather.123.duba.net/static/weather_info/0.html";
/***
* //请求参数对象封装为为JSONObject 放在JsonObjectRequest的jsonRequest对象,就是下面null的位置
* // JSONObject jsonObject=new JSONObject();
* // try {
* // jsonObject.put("param","value");
* // } catch (JSONException e) {
* // e.printStackTrace();
* // }
*/
//参数(请求方式,URL,请求参数,响应的回调接口,错误的回调接口)
JsonObjectRequest request = new JsonObjectRequest(Request.Method.GET, url, null, new Response.Listener() {
@Override
public void onResponse(JSONObject response) {
System.out.println(response);
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
System.out.println(error);
}
});
queue.add(request);
}
//发送一个ImageRequest
public void sendImageRequest(View view) {
ImageRequest request = new ImageRequest(url, new Response.Listener() {
@Override
public void onResponse(Bitmap response) {
imageView.setImageBitmap(response);
}
}, 0, 0, Bitmap.Config.RGB_565, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
System.out.println(error);
}
});
queue.add(request);
}
/* //使用ImageLoader加载网络图片
public void ImageLoader(View view) {
String url = "https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1555568604477&di=68c94aa34a2971979975c8c193869a2d&imgtype=0&src=http%3A%2F%2Finews.gtimg.com%2Fnewsapp_bt%2F0%2F8511061308%2F641";
//新建一个ImageLoader对象
ImageLoader imageLoader = new ImageLoader(queue, new ImageLoader.ImageCache() {
//对图片进行缓存
@Override
public Bitmap getBitmap(String url) {
return null;
}
@Override
public void putBitmap(String url, Bitmap bitmap) {
}
});
//获取一个ImageListener对象
//getImageListener()方法接收三个参数
// 第一个参数指定用于显示图片的ImageView控件
// 第二个参数指定加载图片的过程中显示的图片
// 第三个参数指定加载图片失败的情况下显示的图片
ImageLoader.ImageListener listener = ImageLoader.getImageListener(imageView, R.mipmap.ic_launcher, R.mipmap.ic_launcher);
//加载图片,参数1为url地址,参数2为ImageListener对象,参数3、4最大宽高
imageLoader.get(url, listener, 500, 500);
}*/
//使用ImageLoader加载网络图片
public void ImageLoader(View view) {
//新建一个ImageLoader对象
ImageLoader imageLoader = new ImageLoader(queue, new BitmapCache());
//获取一个ImageListener对象
//getImageListener()方法接收三个参数
// 第一个参数指定用于显示图片的ImageView控件
// 第二个参数指定加载图片的过程中显示的图片
// 第三个参数指定加载图片失败的情况下显示的图片
ImageLoader.ImageListener listener = ImageLoader.getImageListener(imageView, R.mipmap.ic_launcher, R.mipmap.ic_launcher);
//加载图片,参数1为url地址,参数2为ImageListener对象,参数3、4最大宽高
imageLoader.get(url, listener, 500, 500);
}
//创建BitmapCache实现ImageCache接口
private class BitmapCache implements ImageLoader.ImageCache {
private LruCache cache;
//最大缓存大小
private int maxCache = 10 * 1024;
public BitmapCache() {
cache = new LruCache(maxCache);
}
@Override
public Bitmap getBitmap(String url) {
return cache.get(url);
}
@Override
public void putBitmap(String url, Bitmap bitmap) {
cache.put(url, bitmap);
}
}
//networkImageView
private void networkImageView() {
networkImageView.setDefaultImageResId(R.mipmap.ic_launcher);
networkImageView.setErrorImageResId(R.mipmap.ic_launcher);
networkImageView.setImageUrl(url,new ImageLoader(queue,new BitmapCache()));
}
}
效果的话如?,因为启动Activity就调用了,所以会直接在对应位置显示图片