okhttp
<uses-permission android:name="android.permission.INTERNET"/>
implementation 'com.squareup.okhttp3:okhttp:4.9.1'
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
implementation 'com.squareup.retrofit2:adapter-rxjava2:2.9.0'
implementation 'io.reactivex.rxjava2:rxandroid:2.1.1'
implementation 'io.reactivex.rxjava2:rxjava:2.2.20'
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_marginHorizontal="160dp"
android:layout_height="wrap_content">
<TextView
android:id="@+id/tv_content"
android:paddingVertical="16dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!" />
<Button
android:id="@+id/btn_test"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/btn_test"/>
</LinearLayout>
</ScrollView>
添加拦截器
retrofit
爬虫关注点
主要文件
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.sam.test_int">
<uses-permission android:name="android.permission.INTERNET"/>
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.Test_int">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
ApiService.java
package com.sam.test_int;
import io.reactivex.Observable;
import okhttp3.ResponseBody;
import retrofit2.Call;
import retrofit2.http.Field;
import retrofit2.http.FormUrlEncoded;
import retrofit2.http.GET;
import retrofit2.http.POST;
import retrofit2.http.Path;
import retrofit2.http.Query;
public interface ApiService {
// get请求
@GET("api/users")
// 获取到返回值,已经序列化成java对象,请求的名字,请求参数
Call<PageResponseBean> listUsers(@Query("page") Integer page);
@POST("api/users")
@FormUrlEncoded // 给post请求添加参数的话要用这个,给url序列化
Call<UserBean> createUser(@Field("name") String name,@Field("job") String job);
@GET("api/users") // Observable一定选的是io.reactivex
Observable<PageResponseBean> rxListUser(@Query("page") Integer page);
@POST("api/users")
@FormUrlEncoded
Observable<UserBean> rxCreateUser(@Field("name") String name,@Field("job") String job);
@POST("api/login")
@FormUrlEncoded
Observable<LoginBean> login(@Field("email") String email,@Field("password") String password);
@GET("api/users/{userId}")
Observable<UserDetailBean> rxUserInfo(@Path("userId") Integer userId);
@GET("img/faces/{path}")
Observable<ResponseBody> getAvater(@Path("path") String path);
}
Logginginterceptor.java
package com.sam.test_int;
import android.util.Log;
import org.jetbrains.annotations.NotNull;
import java.io.IOException;
import okhttp3.Interceptor;
import okhttp3.Request;
import okhttp3.Response;
// 拦截器
public class Logginginterceptor implements Interceptor {
private static final String TAG = "yuanrenxue";
@NotNull
@Override
public Response intercept(@NotNull Chain chain) throws IOException {
Request request = chain.request();
long t1 = System.nanoTime();
Response response = chain.proceed(request);
long t2 = System.nanoTime();
Log.d(TAG,"intercept:" + (t2 - t1));
return response;
}
}
LoginBean.java
package com.sam.test_int;
import com.google.gson.annotations.SerializedName;
public class LoginBean {
@SerializedName("token")
String token;
}
MainActivity.java
package com.sam.test_int;
import androidx.appcompat.app.AppCompatActivity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import org.jetbrains.annotations.NotNull;
import java.io.IOException;
import io.reactivex.Observable;
import io.reactivex.ObservableSource;
import io.reactivex.Observer;
import io.reactivex.Scheduler;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.annotations.NonNull;
import io.reactivex.disposables.Disposable;
import io.reactivex.functions.Consumer;
import io.reactivex.functions.Function;
import io.reactivex.schedulers.Schedulers;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.FormBody;
import okhttp3.HttpUrl;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import okhttp3.ResponseBody;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;
import retrofit2.converter.gson.GsonConverterFactory;
// 这里View.OnClickListener写好后要Alt+Enter引入第一个东西
public class MainActivity extends AppCompatActivity implements View.OnClickListener{
private static final String TAG = "yuanrenxue";
// 创建okhttp的客户端
private final OkHttpClient client = new OkHttpClient.Builder()
.addInterceptor(new Logginginterceptor())
.build();
private TextView tvContent;
private ImageView ivAvatar;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.btn_test).setOnClickListener(this);
tvContent = findViewById(R.id.tv_content);
ivAvatar = findViewById(R.id.iv_avatar);
}
@Override
public void onClick(View v) {
finalDemo();
}
// 同步请求
void okhttpDemo(){
// 重要无论什么情况,安卓的网络请求都不能在主线程中发送,会报错
Request request = new Request.Builder().url("https://reqres.in/api/users?page=2").build();
tvContent.setText("请求中...");
// 网络请求不能在主线程中,新起线程
new Thread(new Runnable() {
@Override
public void run() {
try {
Response response = client.newCall(request).execute();
Log.d(TAG,"okhttpDemo" + response.body().string());
// UI的修改要在UI线程中
runOnUiThread(new Runnable() {
@Override
public void run() {
tvContent.setText("请求返回的状态码为:" + response.code());
}
});
}catch (Exception e){
e.printStackTrace();
}
}
}).start();
}
// 异步请求
void okhttpAysncDemo(){
Request request = new Request.Builder().url("https://reqres.in/api/users?page=2").build();
tvContent.setText("请求中...");
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(@NotNull Call call, @NotNull IOException e) {
Log.d(TAG,"onFailure:请求失败");
}
@Override
public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
Log.d(TAG,"onResponse:"+response.body().string());
runOnUiThread(new Runnable() {
@Override
public void run() {
tvContent.setText("请求返回的状态码为:" + response.code());
}
});
}
});
}
// url的参数拼接
void okhttpParams(){
HttpUrl.Builder builder = HttpUrl.parse("https://reqres.in/api/users").newBuilder();
builder.addQueryParameter("page","2");
String url = builder.build().toString();
Log.d(TAG,"okhttpParams:" + url);
}
// post请求
void okhttpPostDemo(){
RequestBody body = new FormBody.Builder()
.add("name","yuanrenxue")
.add("job","developer")
.build();
Request request = new Request.Builder().url("https://reqres.in/api/users")
.post(body)
.build();
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(@NotNull Call call, @NotNull IOException e) {
}
@Override
public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
Log.d(TAG,"onResponse:" + response.body().string());
}
});
}
void retrofitGetDemo(){
tvContent.setText("请求中...");
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://reqres.in")
// json转java对象
.addConverterFactory(GsonConverterFactory.create())
.build();
// enqueue(new retrofit2.Callback<PageResponseBean>()后面这些东西可以通过new Ca.. 然后回车第一个就能生成
retrofit.create(ApiService.class).listUsers(2).enqueue(new retrofit2.Callback<PageResponseBean>() {
@Override
public void onResponse(retrofit2.Call<PageResponseBean> call, retrofit2.Response<PageResponseBean> response) {
Log.d(TAG,"onResponse:" + response.body().page);
// retrofit在这里会自动切换回主线程,所以能直接在这里改UI
tvContent.setText("请求状态码为:" + response.code());
}
@Override
public void onFailure(retrofit2.Call<PageResponseBean> call, Throwable t) {
}
});
}
void retrofitPostDemo(){
tvContent.setText("请求中...");
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://reqres.in")
// json转java对象
.addConverterFactory(GsonConverterFactory.create())
.build();
retrofit.create(ApiService.class).createUser("yuanrenxue","developer").enqueue(new retrofit2.Callback<UserBean>() {
@Override
public void onResponse(retrofit2.Call<UserBean> call, retrofit2.Response<UserBean> response) {
Log.d(TAG,"onResponseWW:" + response.body().name);
// retrofit在这里会自动切换回主线程,所以能直接在这里改UI
tvContent.setText("请求状态码为WW:" + response.code());
}
@Override
public void onFailure(retrofit2.Call<UserBean> call, Throwable t) {
}
});
}
void rxJavaGetDemo(){
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://reqres.in")
// json转java对象
.addConverterFactory(GsonConverterFactory.create())
// 比retrofit多个这个,添加rxJava的依赖
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build();
retrofit.create(ApiService.class).rxListUser(2)
// 把请求放在子线程执行
.subscribeOn(Schedulers.io())
// 后面下面的内容放再放回主线程中执行
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<PageResponseBean>() {
@Override
public void onSubscribe(@NonNull Disposable d) {
// 请求刚开始的时候
tvContent.setText("请求中...");
}
@Override
public void onNext(@NonNull PageResponseBean pageResponseBean) {
Log.d(TAG, "onNext: " + pageResponseBean.totalPages);
}
@Override
public void onError(@NonNull Throwable e) {
e.printStackTrace();
}
@Override
public void onComplete() {
tvContent.setText("请求完成");
}
});
}
void rxJavaPostDemo(){
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://reqres.in")
// json转java对象
.addConverterFactory(GsonConverterFactory.create())
// 比retrofit多个这个,添加rxJava的依赖
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build();
retrofit.create(ApiService.class).rxCreateUser("yuanrenxue","developer")
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<UserBean>() {
@Override
public void onSubscribe(@NonNull Disposable d) {
tvContent.setText("请求中...");
}
@Override
public void onNext(@NonNull UserBean userBean) {
tvContent.setText("用户创建成功:" + userBean.name);
}
@Override
public void onError(@NonNull Throwable e) {
}
@Override
public void onComplete() {
}
});
}
/**
1. 获取⽤户列表 GET: https://reqres.in/api/users?page=2
2. 显示⽤户列表⽤户总个数 total
3. 创建新⽤户 POST: https://reqres.in/api/users
4. 显示创建的⽤户的名字 name
5. 登录 POST: https://reqres.in/api/login
6. 显示登录的token token
7. 获取单个⽤户信息 GET: https://reqres.in/api/users/2
8. 显示⽤户的头像 avatar
*/
void finalDemo(){
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://reqres.in")
// json转java对象
.addConverterFactory(GsonConverterFactory.create())
// 比retrofit多个这个,添加rxJava的依赖
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build();
// 获取⽤户列表 GET: https://reqres.in/api/users?page=2
retrofit.create(ApiService.class).rxListUser(2)
.subscribeOn(Schedulers.io()) // 把上面的网络请求切换到异步请求
.observeOn(AndroidSchedulers.mainThread()) // 把下面对界面修改的内容,也就是请求返回的内容,切换到主线程
.doOnNext(new Consumer<PageResponseBean>() {
@Override
public void accept(PageResponseBean pageResponseBean) throws Exception {
tvContent.setText("总人数为:" + pageResponseBean.total);
}
}) // 到此为止完成显示用户列表用户总个数 total
.observeOn(Schedulers.io()) // 再次切换到异步线程
.flatMap(new Function<PageResponseBean, ObservableSource<UserBean>>() {
@Override
public ObservableSource<UserBean> apply(@NonNull PageResponseBean pageResponseBean) throws Exception {
return retrofit.create(ApiService.class).rxCreateUser("yuanrenxue","developer");
}
}) // 到此完成创建一个新用户
.observeOn(AndroidSchedulers.mainThread())
.doOnNext(new Consumer<UserBean>() {
@Override
public void accept(UserBean userBean) throws Exception {
tvContent.setText("当前用户名字是:" + userBean.name);
}
}) // 到此完成显示当前用户名
.observeOn(Schedulers.io()) // 将线程切换回异步
.flatMap(new Function<UserBean, ObservableSource<LoginBean>>() { // 接收UserBean,返回LoginBean
@Override
public ObservableSource<LoginBean> apply(@NonNull UserBean userBean) throws Exception {
return retrofit.create(ApiService.class).login("eve.holt@reqres.in","cityslicka");
}
})
.observeOn(AndroidSchedulers.mainThread()) // 切换回主线程
.doOnNext(new Consumer<LoginBean>() { // 接收LoginBean
@Override
public void accept(LoginBean loginBean) throws Exception {
tvContent.setText("当前用户的token为:" + loginBean.token);
}
}) // 登录获取用户的token 并且显示出来
.observeOn(Schedulers.io())
.flatMap(new Function<LoginBean, ObservableSource<UserDetailBean>>() {
@Override
public ObservableSource<UserDetailBean> apply(@NonNull LoginBean loginBean) throws Exception {
return retrofit.create(ApiService.class).rxUserInfo(2);
}
})
.observeOn(AndroidSchedulers.mainThread())
.flatMap(new Function<UserDetailBean, ObservableSource<String>>() {
@Override
public ObservableSource<String> apply(@NonNull UserDetailBean userDetailBean) throws Exception {
return Observable.just(userDetailBean.data.avatar);
}
}) // 返回用户头像地址
.observeOn(Schedulers.io())
.flatMap(new Function<String, ObservableSource<ResponseBody>>() {
@Override
public ObservableSource<ResponseBody> apply(@NonNull String s) throws Exception {
String[] paths = s.split("/");
String path = paths[paths.length - 1];
return retrofit.create(ApiService.class).getAvater(path);
}
})
.map(new Function<ResponseBody, Bitmap>() { // 获取用户头像并转化成bitmap
@Override
public Bitmap apply(@NonNull ResponseBody responseBody) throws Exception {
return BitmapFactory.decodeStream(responseBody.byteStream());
}
})
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<Bitmap>() {
@Override
public void onSubscribe(@NonNull Disposable d) {
tvContent.setText("请求中...");
}
@Override
public void onNext(@NonNull Bitmap bitmap) {
ivAvatar.setImageBitmap(bitmap);
}
@Override
public void onError(@NonNull Throwable e) {
}
@Override
public void onComplete() {
}
});
}
}
PageResponseBean.java
package com.sam.test_int;
import com.google.gson.annotations.SerializedName;
public class PageResponseBean {
// 将返回值的字段序列化成java的对象
@SerializedName("page")
Integer page; // 新起的变量名
@SerializedName("total_pages")
Integer totalPages;
@SerializedName("total")
Integer total;
}
UserBean.java
package com.sam.test_int;
import com.google.gson.annotations.SerializedName;
public class UserBean {
// 有这个字段就会处理,没有也不会报错的,会赋一个空值
@SerializedName("name")
String name;
@SerializedName("avatar")
String avatar;
}
UserDetailBean.java
package com.sam.test_int;
import com.google.gson.annotations.SerializedName;
public class UserDetailBean {
@SerializedName("data")
UserBean data;
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_marginHorizontal="160dp"
android:layout_height="wrap_content">
<TextView
android:id="@+id/tv_content"
android:paddingVertical="16dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!" />
<Button
android:id="@+id/btn_test"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/btn_test"/>
<ImageView
android:src="@mipmap/ic_launcher"
android:id="@+id/iv_avatar"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</LinearLayout>
</ScrollView>