目录
- 网络架构测试
- 声明. 联网权限,非危险权限,xml声明即可
- 一. HttpURLConnection
- 二. okhttp
-
-
- 1. post方法
- 2. Get方法[多一个请求体]
-
- 2.5 封装Okhttp实现自身接口回调,不然得自己写一个接口,也不难。但okhttp自带了
- 三. [Volley架构](https://blog.csdn.net/u012602304/article/details/79170137)
-
-
- 3.5.[Glide组件](https://github.com/bumptech/glide)
-
- 四. [Retrofit2转载出处](https://blog.csdn.net/m0_37796683/article/details/90702095)及基础定义
-
-
- 1. 定义
- 2. 导包
- 3. 其使用了注解与自定义拼接字
- 4 . 优秀的数据解析
- 5. 同步与异步发送网络请求
- 6. 实现回调接口
-
- 五 实例一:Retrofit推荐写法【来自第一行代码】
-
-
- 1. 由于通过Gson解析需要一个实体类
- 2. 新建AppService接口
-
- 六 实例二:Retrofit演示
-
-
- 1. 效果图
- 2. Demo代码块
- 补充资料:
-
网络架构测试
声明. 联网权限,非危险权限,xml声明即可
<uses-permission android:name="android.permission.INTERNET"/>
一. HttpURLConnection
- 最简单的写法
private suspend fun getImageFromNet()= withContext(Dispatchers.IO){
//1. 定义一个Urlval url = URL("https://picjumbo.com/wp-content/uploads/white-swans-near-charles-bridge-in-prague-2210x1473.jpg")//2. 调用openConnection方法即可val connection=url.openConnection() as HttpURLConnection//3. 获取数据流即可val inputStream=connection.inputStreamBitmapFactory.decodeStream(inputStream)}
- 现在网络请求都不放在主线程,具体的去 协程那边看
- 还可以通过connection的setConnectionTimerout和ReadTimerout来进行具体细节设定等等。
二. okhttp
- 注意8.0以后。http需要另外配置文件
- 线程问题, 在4.0之后在主线程里面执行Http请求都会报这个错,大概是怕Http请求时间太长造成程序假死的情况吧。
1. post方法
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)setContentView(R.layout.activity_main)send_request.setOnClickListener {
//1.需要一个clientsendRequestWithOkHttp();}}fun sendRequestWithOkHttp() {
Thread {
try {
//1.建立okhttpclientval client = OkHttpClient()//2.发起请求,需要创建一个request对象val request: Request = Request.Builder().url("http://www.baidu.com").build()//3.调用OkHttpClient的newCall()方法 创建一个Call对象, 并调用它的execute()方法//来发送请求并获取服务器返回的数据val response = client.newCall(request).execute()val responseData = response.body().string()println("1111111"+responseData)response_text.text=responseData} catch (e: Exception) {
e.printStackTrace()}}.start()}
}
2. Get方法[多一个请求体]
- 由於在子綫程建立的okhttp請求,这边使用runOnUiThread在主线程更新。共两种方式
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)setContentView(R.layout.activity_main)send_requestbyget.setOnClickListener {
//1.需要一个clientsendRequestWithOkHttpByGet();}send_requestbypost.setOnClickListener {
sendRequestWithOkHttpByPost();}}fun sendRequestWithOkHttpByGet() {
Thread {
try {
//1.建立okhttpclientval client = OkHttpClient()//2.发起请求,需要创建一个request对象val request: Request = Request.Builder().url("http://www.baidu.com").build()//3.调用OkHttpClient的newCall()方法 创建一个Call对象, 并调用它的execute()方法//来发送请求并获取服务器返回的数据val response = client.newCall(request).execute()val responseData = response.body().string()showResponse(responseData)} catch (e: Exception) {
e.printStackTrace()}}.start()}fun sendRequestWithOkHttpByPost() {
Thread {
try {
//1.建立okhttpclientval client = OkHttpClient()//2.发起请求,需要创建一个request对象//2.5请求体val requestBody: RequestBody = FormBody.Builder().add("username", "admin").add("password", "123456").build()val request: Request = Request.Builder().url("https://www.jd.com").post(requestBody).build()//3.调用OkHttpClient的newCall()方法 创建一个Call对象, 并调用它的execute()方法//来发送请求并获取服务器返回的数据val response = client.newCall(request).execute()val responseData = response.body().string()showResponse(responseData)} catch (e: Exception) {
e.printStackTrace()}}.start()}private fun showResponse(response: String) {
runOnUiThread {
// 在这里进行UI操作, 将结果显示到界面上response_text.setText(response)}}}
2.5 封装Okhttp实现自身接口回调,不然得自己写一个接口,也不难。但okhttp自带了
//普通类的静态方法
public class HttpUtil {
public static void sendOkHttpRequest(String address, okhttp3.Callback callback) {
OkHttpClient client = new OkHttpClient();Request request = new Request.Builder().url(address).build();client.newCall(request).enqueue(callback);}
}//调用时
HttpUtil.sendOkHttpRequest("http://www.baidu.com", new okhttp3.Callback() {
@Overridepublic void onResponse(Call call, Response response) throws IOException {
// 得到服务器返回的具体内容String responseData = response.body().string();} @Overridepublic void onFailure(Call call, IOException e) {
// 在这里对异常情况进行处理}
});
三. Volley架构
- 总体操作
1)创建一个队列,可以封装为单例Singleton(队列较耗资源)
2)创建请求,将其加入队列,volley通过参数回调执行返回结果即可
implementation ‘com.android.volley:volley:1.1.1’
-
样例测试
1)设置布局textView在设置scrollview滚动条布局中,保证放得下
2)新建请求选择StringRequest方法,两个构造函数,其中的一个四/三参数的可以指定请求(Request分两类为StringRequest和GsonRequest)
a. 请求方式,获取或上传(三参数不设置这次)
b. 请求网站
c. 成功回调
d. 错误回调,这两个回调简写就是类lambda表达式,如果用Kotlin写,第一个参数不能指定,找不到Method (暂时原因不明) -
测试结果,注意Volley传送门里作者写的,添加网络请求权限,这个不属于危险权限之一
-
修改获取网上图片(Volley图片加载)
1)改写第二步的请求,使用ImageLoader,第一个参数是请求队列(暂时用不到,第二个建立个cache缓存,内部方法有get和put方法(如果本地有了就拿缓存,具体不处理也能达到一点效果)
2)该对象设置了请求队列,使用get方法传入url和监听对象,并且直接内部成功/失败回调,setImageBitmap代码中设定图片
ImageLoader imageLoader=new ImageLoader(mQueue, new ImageLoader.ImageCache() {
//建立缓存 设置最大缓存量private LruCache<String,Bitmap> cache=new LruCache<>(50);@Overridepublic Bitmap getBitmap(String url) {
return cache.get(url);}@Overridepublic void putBitmap(String url, Bitmap bitmap) {
cache.put(url,bitmap);}});imageLoader.get(url, new ImageLoader.ImageListener() {
@Overridepublic void onResponse(ImageLoader.ImageContainer response, boolean isImmediate) {
imageView.setImageBitmap(response.getBitmap());}@Overridepublic void onErrorResponse(VolleyError error) {
}});
ps:改为Volley自带的NetworkImageview控件,不用监听的话也可以这样写
3.5.Glide组件
非网络架构,但真的很好用,就放同级了
implementation ‘com.github.bumptech.glide:glide:4.11.0’
annotationProcessor ‘com.github.bumptech.glide:compiler:4.11.0’
- 在原第二步基础上改下,就能达到同样效果,这岂不是美滋滋,并且智能缓存,还有更多个性化的操作
Glide.with(this).load(url).placeholder(R.drawable.ic_launcher_background)//占位符.listener(new RequestListener<Drawable>() {
@Overridepublic boolean onLoadFailed(@Nullable GlideException e, Object model, Target<Drawable> target, boolean isFirstResource) {
return false;}@Overridepublic boolean onResourceReady(Drawable resource, Object model, Target<Drawable> target, DataSource dataSource, boolean isFirstResource) {
return false;}}).into(imageView);
四. Retrofit2转载出处及基础定义
1. 定义
- OkHttp侧重的是底层通信的实现,而Retrofit侧重的是上层接口的封装。
- 使用okhttp一般自己也还要再封装一层,见FarawayPlayer。Retrofit就是Square公司在OkHttp的基础上进一步开发出来的应用层网络通信库,使得我们可以用更加面向对象的思维进行网络操作。
- 样例见6.2 PS:Retrofit里可以.client()封一个okhttp,然后里面指定三个时间
3.1 1 分钟搞懂Retrofit 里的各种timeout分别都代表什么,这里指断断续续能连上的状态,亲测断网直接就有失败回调了。
2. 导包
implementation 'com.squareup.retrofit2:retrofit:2.5.0'
3. 其使用了注解与自定义拼接字
- 请求方法注解如get,post等等
- 请求头注解
- 请求参数注解,如Body,post,uri
- 请求和响应格式(标记)注解(两部分)
1)第一部分,创建Retrofit时的.baseUrl设置
//构建Retrofit实例Retrofit retrofit = new Retrofit.Builder()//设置网络请求BaseUrl地址.baseUrl("https://api.uomg.com/")//设置数据解析器.addConverterFactory(GsonConverterFactory.create()).build();
2)第二部分 API方法中获取到注解方式
@GET("api/rand.music")
3)上面地址拼接后的完整地址为:https://api.uomg.com/api/rand.music?sort=&format=,然后通过addConverterFactory设置数据解释器,这里添加的是Gson解释器
添加依赖:
implementation 'com.squareup.retrofit2:converter-gson:2.0.2'
4 . 优秀的数据解析
5. 同步与异步发送网络请求
6. 实现回调接口
五 实例一:Retrofit推荐写法【来自第一行代码】
1. 由于通过Gson解析需要一个实体类
class App(val id: String, val name: String, val version: String)
2. 新建AppService接口
-
这里使用了一个@GET注解,表示当调用getAppData()方法时Retrofit会发起一条GET请求,请求的地址就是我们在@GET注解中传入的具体参数。
-
另外,getAppData()方法的返回值必须声明成Retrofit中内置的Call类型,并通过泛型来指定服务器响应的数据应该转换成什么对象。
interface AppService {
@GET("get_data.json")fun getAppData(): Call<List<App>>
}
- 发送请求并执行回调
//1. 新建一个retrofit对象(可封装为静态synchronized单例对象 //使用@Synchronized注解)val retrofit = Retrofit.Builder().baseUrl("http://10.0.2.2/").addConverterFactory(GsonConverterFactory.create()).build()//2.建立一个appService对象为retrofit通过create方法传递接口类val appService = retrofit.create(AppService::class.java)//3. 通过create对象便可执行对应方法并回调 appService.getAppData().enqueue(object : Callback<List<App>> {
override fun onResponse(call: Call<List<App>>,response: Response<List<App>>) {
val list = response.body()if (list != null) {
for (app in list) {
Log.d("MainActivity", "id is ${
app.id}")Log.d("MainActivity", "name is ${
app.name}")Log.d("MainActivity", "version is ${
app.version}")}}}override fun onFailure(call: Call<List<App>>, t: Throwable) {
t.printStackTrace()}})
六 实例二:Retrofit演示
1. 效果图
2. Demo代码块
- 建立一个Data数据类专门用于处理回调,其中
data为泛型
class Data<T> {
var code = 0var message: String? = nullvar data: T? = nullprivate setfun setData(data: T) {
this.data = data}
}
- 建立泛型对应之一的Info类,这个是要根据APi来创建的
class Info {
var name: String? = nullvar url: String? = nullvar picurl: String? = null}
- 创建API类,存放第二部分的副链接
interface Api {
//get请求@GET("api/rand.music")fun getJsonData(@Query("sort") sort: String?,@Query("format") format: String?): Call<Data<Info?>?>?//post请求 // 请求格式注解,请求实体是一个From表单,每个键值对需要使用@Field注解@FormUrlEncoded@POST("api/comments.163")fun postDataCall(@Field("format") format: String?): Call<Any?>?}
- Main调用
1)get这边指定了回调类为Data的泛型Info
2)post这边直接接收了any。。。比较神奇
class MainActivity : AppCompatActivity() {
companion object {
private val TAG = MainActivity::class.java.simpleName}private var mRetrofit: Retrofit? = nullvar api:Api ?=null/*** @param savedInstanceState*/override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)setContentView(R.layout.activity_main)步骤4:构建Retrofit实例//设置网络请求BaseUrl地址 Retrofit把网络请求的URL 分成了两部分设置 第一部分:在创建Retrofit实例时通过.baseUrl()设置,//第二部分:在网络请求接口的注解设置,就是在上面的APi接口中用GET注解的字符串: @GET("api/rand.music") 及两个query//进行拼接:https://api.uomg.com/api/rand.music?sort=&format=//然后通过addConverterFactory设置数据解释器,这里添加的是Gson解释器。这是为了使来自接口的json结果会自动解析成定义好的字段和类型都相符的json对象接受类mRetrofit = Retrofit.Builder().baseUrl("https://api.uomg.com/").addConverterFactory(GsonConverterFactory.create()).build()// 步骤5:创建网络请求接口API对象实例api = mRetrofit!!.create(Api::class.java)btn1.setOnClickListener{
jsonData}btn2.setOnClickListener{
postJsonData()}}//步骤8:请求处理,输出结果// 步骤5:创建网络请求接口对象实例//步骤6:对发送请求进行封装,传入接口参数//步骤7:发送网络请求(异步)/*** 示例,get加载Json数据*/private val jsonData: Unitprivate get() {
//这种东西访问不到外面的实例的//步骤6:对发送请求进行封装,传入接口参数val jsonDataCall = api?.getJsonData("新歌榜", "json")//步骤7:发送网络请求 同步执行 要自己写接口比较麻烦//Response<Data<Info>> execute = jsonDataCall.execute();//步骤7:发送网络请求(异步) enqueue???、timer用的是schedule/*//异步请求dataCall.enqueue(new Callback<Data<Info>>() {//请求成功回调@Overridepublic void onResponse(Call<Data<Info>> call, Response<Data<Info>> response) {}//请求失败回调@Overridepublic void onFailure(Call<Data<Info>> call, Throwable t) {}});* *///对异步返回的数据进行处理,网络加载完成。get的请求地址为:https://api.uomg.com/api/rand.music?sort=%E6%96%B0%E6%AD%8C%E6%A6%9C&format=jsonLog.e(TAG, "get == url:" + jsonDataCall!!.request().url())jsonDataCall.enqueue(object : Callback<Data<Info?>?> {
@SuppressLint("SetTextI18n")override fun onResponse(call: Call<Data<Info?>?>, response: Response<Data<Info?>?>) {
//步骤8:请求处理,输出结果Toast.makeText(this@MainActivity, "get回调成功:异步执行", Toast.LENGTH_SHORT).show()val body = response.body() ?: returnval info: Info = body.data ?: returntv!!.text = """返回的数据:${
info.name} ${
info.picurl}""".trimIndent()}override fun onFailure(call: Call<Data<Info?>?>, t: Throwable) {
Log.e(TAG, "get回调失败:" + t.message + "," + t.toString())Toast.makeText(this@MainActivity, "get回调失败", Toast.LENGTH_SHORT).show()}})}/*** 示例,Post加载Json数据*/private fun postJsonData() {
//步骤6:对发送请求进行封装:传入参数val call = api?.postDataCall("JSON")//调用api实施的post方法if (call != null) {
call.enqueue(object : Callback<Any?> {
@SuppressLint("SetTextI18n")override fun onResponse(call: Call<Any?>, response: Response<Any?>) {
//步骤8:请求处理,输出结果val body = response.body() ?: returntv.setText("""返回的数据: ${
response.body().toString()}""".trimIndent())Toast.makeText(this@MainActivity, "post回调成功:异步执行", Toast.LENGTH_SHORT).show()}override fun onFailure(call: Call<Any?>, t: Throwable) {
Log.e(TAG, "post回调失败:" + t.message + "," + t.toString())Toast.makeText(this@MainActivity, "post回调失败", Toast.LENGTH_SHORT).show()}})}}
补充资料:
- URL 链接中 井号#、问号?、连接符& 分别有什么作用?