为大家带来的是开发者裴某的“请求云框架”的“本网络请求框架”被命名为“蹇葭”(JJJia)。改造所不具备的功能。
替换域名都是重载链接,不支持国内的应用一般有域名的,蒹蒭的大范围优势就是动态动态替换域名如了解更多内容,可以直接复制源码:https ://gitee.com/zhongte/JianJia
我们将几个关键点做解释,希望用你的HarmonyOS开发之旅带来一些启示~
在敲代码之前,需要大家下载安装“Huawei DevEco Studio”,如有疑问,可参考官网指南。
● 华为 DevEco Studio 安装指南:
https://developer.harmonyos.com/ ... ll-0000001053582415
为了顺利使用,我们来看一下使用前的一些配置,这里我们主要介绍配置方面,一个是针对代码的保证首先处理的,一个是添加的依赖项。
一、使用前的配置
1.代码重新处理
如果项目开启了代码代码:请在proguard-rules.pro添加
-renamesourcefile 属性源文件
-keepattributes SourceFile,LineNumberTable-dontwarn javax.annotation.**
-keepattributes 签名、内部类、封闭方法、异常
#蒹葭
-不要警告诗歌.jianjia。**
-keep 类诗歌.jianjia.** { *; }
-keepattributes RuntimeVisibleAnnotations,RuntimeVisibleParameterAnnotations
-keepclassmembers,allowshrinking,allowobfuscation interface * {
@poetry.jianjia.http.* <方法>;
}
# OkHttp3-dontwarn okhttp3.logging.**
-保持类okhttp3.internal.**{*;}
-不要警告奥基奥。**
# gson-keep 类 sun.misc.Unsafe { *; }
-keep class com.google.gson.stream.** { *; }
-keepattributes *注解*
-keepclassmembers 类 * 实现 java.io.Serializable {
静态最终长序列版本UID;
私有静态最终 java.io.ObjectStreamField[] serialPersistentFields;
私有无效 writeObject(java.io.ObjectOutputStream);
私人无效读取对象(java.io.ObjectInputStream);
java.lang.Object writeReplace();
java.lang.Object readResolve();
}
# 在示例代码中,com.poetry.jianjia.bean 这个包下面的类实现了序列化接口,
#实现接口的类不能被替换成另一个包,请把com.beany名替换成你自己的名字
-keep class com.poetry.jianjia.bean.**{*;}
2. 添加依赖
添加就是引用类库,详情如下:依赖
1) 在项目根目录下的build.gradle文件中添加mavenCentral()仓库
打开项目目录下的build.gradle文件,在build.gradle文件的repositories闭包下面添加mavenCentral()。
构建脚本 {
存储库{
// 添加maven中央仓库
mavenCentral()
行家{
url 'https://mirrors.huaweicloud.com/repository/maven/'
}
行家{
url 'https://developer.huawei.com/repo/'
}
行家{
url 'http://maven.aliyun.com/nexus/content/repositories/central/'
}
中心()
}
依赖{
类路径 'com.huawei.ohos:hap:2.4.2.5'
类路径'com.huawei.ohos:decctest:1.0.0.6'
}
}
所有项目{
存储库{
// 添加maven中央仓库
mavenCentral()
行家{
url 'https://mirrors.huaweicloud.com/repository/maven/'
}
行家{
url 'https://developer.huawei.com/repo/'
}
行家{
url 'http://maven.aliyun.com/nexus/content/repositories/central/'
}
中心()
}
}
2)在build.gradle文件的依赖项闭包下添加依赖
打开entry目录下的build.gradle文件,在build.gradle文件中的dependencies闭包下添加下面的dependencies。
//蒹葭的核心代码
执行 'io.gitee.zhongte:jianjia:1.0.1'
// 数据密码,密码使用gson来我们解析json,不用我们手动解析json
实现 'io.gitee.zhongte:converter-gson:1.0.1'
实施“com.google.code.gson:gson:2.8.2”
// 可以通过日志拦截器,通过日志拦截器查看请求头、请求体、响应头、响应体
实现 'com.squareup.okhttp3:logging-interceptor:3.7.0'
// 如果服务的json有字符,比如中文的双引号,gson在解析的结果特殊字符进行转义端
//可以就可以将义之后的字符串进行转义,对特殊符号进行义和义义转义
实现'commons-lang:commons-lang:2.6'
3)在配置文件中添加以下权限
ohos.permission.INTERNET
二、
用法
“解解解法”中的一种可以推广和一种方法和一种方法/解法在进行网络请求的时候,就需要解调各种参数的注意事项,了解需要的介绍和注意。
1.获取注解
创建接口,在方法里面GET解,GET使用注释类型用于一个GET请求,方法的返回值是调用,泛型是响应体,其实可以是泛型的实体对象,注我们也将在“对象”中
16.添加数据密码“中详说。
蒹葭如何完成网络请求?使用构造者模式创建jianjia对象,baseUrl就是域名,在创建jianjia对象的时候就必须指定域名。
调用创建方法的实例,调用 wan.get 一个接口。
公共接口万{
@GET("横幅/json")
调用<ResponseBody> getBanner();
}
建家建家=新建家.Builder()
.baseUrl("https://www.wanandroid.com")
。建造();
Wan wan = jianJia.create(Wan.class);
wan.getBanner().enqueue(new Callback<ResponseBody>() {
@覆盖
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
尝试 {
字符串 json = response.body().string();
} 捕捉(IOException e){
e.printStackTrace();
}
}
@覆盖
public void onFailure(Call<ResponseBody> call, Throwable t) {
LogUtils.info("云飞", t.getMessage());
}
});
2.BaseUrl注解
国内的一般有多个域名的,应用都可以针对自己设置的域名。
公共接口万{
@BaseUrl("https://api.apiopen.top")
@GET("getJoke")
Call<ResponseBody> getJoke(@QueryMap Map<String, String> 参数);
}
3.路径注解
路径注解在路径中替换指定的参数值,定义下面的方法。可以看到我们定义了一个getArticle方法,方法接收一个页面参数,并且我们的@GET注解中使用{page}声明了访问路径,这里你可以把{page}做位符,而实际运行中会通过@Path("page")所标注的参数进行替换。
公共接口万{
@GET("文章/列表/{page}/json")
Call<ResponseBody> getArticle(@Path("page") int page);
}
4.查询注解
查询注解用于“get请求”添加请求参数,被注解物质的参数类型可以是查询、集合、字符串等。
公共接口万{
@GET("wxarticle/list/405/1/json")
Call<ResponseBody> search(@Query("k") String k);
@GET("wxarticle/list/405/1/json")
Call<ResponseBody> search(@Query("k") String...k);
@GET("wxarticle/list/405/1/json")
调用<ResponseBody> search(@Query("k") List<String> k);
}
5.QueryMap注解
QueryMap注解以map的形式添加查询参数,被QueryMap注解物质的参数必须类型是Map对象。
公共接口万{
@GET("wxarticle/list/405/1/json")
Call<ResponseBody> search(@QueryMap Map<String, String> 参数);
}
6. SkipCallbackExecutor注解
在Harmony 将服务端使用的方法回应到主线程中,在主线程上调用,在服务器端的回调函数中解决问题,将服务器端的结果返回到主线程。
公共接口万{
@SkipCallbackExecutor
@GET("wxarticle/list/405/1/json")
Call<ResponseBody> search(@QueryMap Map<String, String> 参数);
}
7.FormUrlEncoded注解和Field注解
“FormUrl 解”发送一个表单编码的注解在方法中的参数中用于注解,被解物质的参数类型可以是字段,使用字段,集合,字符串等。
公共接口万{
@POST("用户/登录")
@FormUrlEncoded
Call<ResponseBody> login(@Field("username") String username, @Field("password") String password);
}
8.FormUrlEncoded注解和FieldMap注解
多注释字段的形式,如果使用字段注释形式的比较,如果使用字段注释参数的方法,参数比较会比较多,此时就可以使用字段地图注释的形式,解以地图的形式发送一个形式。类型,只要报异常。如果map的键值对为空,也会报异常。
公共接口万{
@POST("用户/登录")
@FormUrlEncoded
Call<ResponseBody> login(@FieldMap Map<String, String> map);
}
9.身体注解
服务端json字符串作为请求把发给服务端就可以直接使用B解定义的直接服务器端化客户端请求的结果类。作为请求体发送出去。
如果被正文注解物质的参数的类型是RequestBody对象,那调用者可以不用添加数据密码,内部会使用默认的数据密码。
如果被身体注解物质的参数的类型不是RequestBody对象,是一个具体的实体类,那调用者需要自定义一个类,并且继承Converter.Factory。
public interface Wan {
/**
* 被Body注解修饰的参数的类型是RequestBody对象,那调用者可以不添加数据转换器,内部会使用默认的数据转换器
*
* @param body
* @return
*/
@POST("user/register") Call<ResponseBody> register(@Body RequestBody body);
/**
* 被Body注解修饰的参数的类型不是RequestBody对象,是一个具体的实体类,那调用者需要自定义一个类,并且继承Converter.Factory
*
* @param user
* @return
*/
@POST("user/register") Call<ResponseBody> register(@Body User user);
}
10.网址注解
Url注解用于解决接口的完整地址。在Retrofit中,如果接口的域名解析与对象指定的域名之间添加地址,就可以使用Url注解来解决问题。提供了BaseUrl来解决该问题。
public interface Wan {
@GET() Call<ResponseBody> getArticle(@Url String url);
}
11.页眉注解
标头注解是作用于参数上的注解,用于添加请求头。
public interface Wan {
@GET() Call<ResponseBody> foo(@Header("Accept-Language") String lang);
}
12. 标头注解
标头注解作用于方法上的注解,用于添加一个或多个请求头。
public interface Wan {
@Headers("Cache-Control: max-age=640000")
@GET("/")
Call<ResponseBody> getArticle(@Url String url);
@Headers({
"X-Foo: Bar",
"X-Ping: Pong"
})
@GET("/")
Call<ResponseBody> getArticle(@Url String url);
}
13. HeaderMap注解
HeaderMap解是作用于参数上的注解,以Map的形式请求头,Map中每一个异常的键和注值都可以调用,否则会报出。
public interface Wan {
@GET("/search")
Call<ResponseBody> list(@HeaderMap Map<String, String> headers);
}
14. 多部分注解和部分注解
多部分注和部分注用于解上传解文件。
在配置文件中添加以下两个权限,这两个权限需要动态申请
ohos.permission.READ_MEDIA
ohos.permission.WRITE_MEDIA
定义了一个上传方法,方法参数使用注释Body,参数类型必须是Multipart.Part。
public interface Wan {
/**
* 上传文件,需要使用Multipart注解和Part注解
*
* @param photo 本地文件的路径
* @return
*/
@Multipart
@POST()
Call<ResponseBody> upload(@Part MultipartBody.Part photo);
}
// 文件路径
File file = new File(getExternalCacheDir(), "icon.png");
// 创建请求体对象
RequestBody photoBody = RequestBody.create(MediaType.parse("image/png"), file);
MultipartBody.Part photo = MultipartBody.Part.createFormData("photos", "icon.png", photoBody);
JianJia jianJia = new JianJia.Builder()
.baseUrl("https://www.wanandroid.com")
.build();
Wan wan = jianJia.create(Wan.class);
// 上传文件
wan.upload(photo).enqueue(new Callback<ResponseBody>() {
@Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
// 上传成功
}
@Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
LogUtils.info("yunfei", t.getMessage());
}
});
15. PartMap注解和Multipart注解
PartMap注解和Multipart注解用于上传多个文件在配置文件中添加下面两个权限,这两个权限需要动态申请:
ohos.permission.READ_MEDIA
ohos.permission.WRITE_MEDIA
被部分地图注解物质的地图,地图的第一个泛型必须是字符串:
public interface Wan {
/**
* 使用PartMap注解上传多个文件
*
* @param params 第一个泛型必须是String
* @return
*/
@Multipart
@POST()
Call<ResponseBody> upload(@PartMap Map<String, RequestBody> params);
}
File photoFile = new File(getExternalCacheDir(), "photo.png");
RequestBody photoBody = RequestBody.create(MediaType.parse("image/png"), photoFile);
File avatarFile = new File(getExternalCacheDir(), "avatar.png");
RequestBody avatarBody = RequestBody.create(MediaType.parse("image/png"), avatarFile);
Map<String, RequestBody> photos = new HashMap<>();
photos.put("photo", photoBody);photos.put("avatar", avatarBody);
JianJia jianJia = new JianJia.Builder()
.baseUrl("https://www.wanandroid.com")
.build();
Wan wan = jianJia.create(Wan.class);
// 上传文件
wan.upload(photos).enqueue(new Callback<ResponseBody>() {
@Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
// 上传成功
}
@Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
LogUtils.info("yunfei", t.getMessage());
}
});
16. 添加数据网关
泛在接口里面定义方法(GET解中)的时候,我们的返回值调用对象,我们的返回值类型是ResponseBody。在这种情况下,服务端返回给客户端的方法是在ResponseBody里面,客户端需要事先手动解析json,将json解析成一个实体类。
是的,我们没有必要手动解析json,可以让gson帮我们解析json。蝌蚪支持添加数据进来,在创建对象的时候添加数据方法,也就是把gson添加进去。类对象了,gson帮我们把json解析成了一个实体类。
public interface Wan {
@GET("banner/json")
Call<Banner> getBanner();
}
JianJia jianJia = new JianJia.Builder()
.baseUrl("
.addConverterFactory(GsonConverterFactory.create())
.build();
Wan wan = jianJia.create(Wan.class);
wan.getBanner().enqueue(new Callback<Banner>() {
@Override
public void onResponse(Call<Banner> call, Response<Banner> response) {
try {
if (response.isSuccessful()) {
Banner banner = response.body();
}
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void onFailure(Call<Banner> call, Throwable t) {
LogUtils.info("yunfei", t.getMessage());
}
});
三、Demo演示
我们用一个简单的演示来演示我们如何使用蒹葑,效果如下:
示例中的网页地址:
https://www.wanandroid.com/blog/show/2
显示是一个网页上的文章列表。客户端通过使用该网站请求提供的接口葭网络库该网站提供的接口,然后来获取网页的文章列表,显示成功,文章列表将当视频在访问后页面上。
下面为Demo代码关键步骤的详解:
1.在compoetry.jianjia.net创建了一些接口,把所有的请求都放在下面一个接口里面,就可以单独创建多个类了
/**
* @author 裴云飞
* @date 2021/1/23
*/
public interface Wan {
@GET("article/list/{page}/json")
Call<ResponseBody> getArticle(@Path("page") int page);
@GET("article/list/{page}/json")
Call<Article> getHomeArticle(@Path("page") int page);
@GET()
Call<ResponseBody> getArticle(@Url String url);
@GET("wxarticle/list/405/1/json")
Call<ResponseBody> search(@Query("k") String k);
@GET("wxarticle/list/405/1/json")
Call<ResponseBody> search(@Query("k") String... k);
@GET("wxarticle/list/405/1/json")
Call<ResponseBody> search(@Query("k") List<String> k);
@GET("wxarticle/list/405/1/json")
Call<ResponseBody> search(@QueryMap Map<String, String> param);
@GET("article/list/0/json")
Call<ResponseBody> getArticle(@QueryMap Map<String, String> param);
@BaseUrl("https://api.apiopen.top")
@GET("getJoke")
Call<ResponseBody> getJoke(@QueryMap Map<String, String> param);
@POST("user/login")
@FormUrlEncoded
Call<ResponseBody> login(@Field("username") String username, @Field("password") String password);
@POST("user/login")
@FormUrlEncoded
Call<ResponseBody> login(@FieldMap Map<String, String> map);
@GET("banner/json")
Call<Banner> getBanner();
}
2. 创建“ianjia”对象,整个项目只需一个 jianjia 对象即可。
示例如何确保只有一个 jianjia 运行起来之后,首先会创建 AbilityPackage,调用AbilityPackage 的方法在,AbilityPackage 上然后启动AbilityPackage 就是一个执行对象。所以在AbilityPackage 里面创建的就是执行对象。一个单对象。只在里面创建 jianjia 的对象,确保整个项目只有一个 jianjia。AbilityPackage 类不需要手动创建,在创建类的项目的时候,编译器会自动创建一个继承于 bilityPackage 。
public class BaseApplication extends AbilityPackage {
private static BaseApplication instance;
private JianJia mJianJia; private Wan mWan;
public static BaseApplication getInstance() {
return instance;
}
/**
* 获取全局的蒹葭对象
*
* @return 全局的蒹葭对象
*/
public JianJia getJianJia() {
return mJianJia;
}
/**
* 获取全局的接口实例对象
*
* @return 全局的接口实例对象
*/
public Wan getWan() {
return mWan;
}
@Override
public void onInitialize() {
super.onInitialize();
instance = this;
// 创建全局的蒹葭对象
mJianJia = new JianJia.Builder()
.baseUrl("
.addConverterFactory(GsonConverterFactory.create())
.build();
mWan = mJianJia.create(Wan.class);
}
}
比如上面的代码,BaseApplication继承AbilityPackage,在Initialize方法创建对象的对象。其他地方只需要通过下面的方式能够获取蒹葭对象和接口实例对象。
// 获取全局的蒹葭对象
BaseApplication.getInstance().getJianJia();
// 获取全局的接口实例对象
BaseApplication.getInstance().getWan();
3.MainAbilitySlice里面添加ListContainer,ListContainer的用处,请查看官方文档,此处关于不再赘述。
● 官方文档
https://developer.harmonyos.com/ ... er-0000001060007847
调用“ getHomeArticle方法”请求服务器,“getHomeArticle方法”会获取在AbilityPackage里面创建好的对象,然后执行网络请求,成功后调用“ setHomeArticle方法”来获取页面。
public class MainAbilitySlice extends AbilitySlice {
private ListContainer mListContainer;
private HomeArticleProvider mHomeArticleProvider;
List<Article.Data.Datas> mDatas;
@Override
public void onStart(Intent intent) {
super.onStart(intent);
super.setUIContent(ResourceTable.Layout_ability_main);
mListContainer = (ListContainer) findComponentById(ResourceTable.Id_list);
mDatas = new ArrayList<>();
mHomeArticleProvider = new HomeArticleProvider(this, mDatas);
mListContainer.setItemProvider(mHomeArticleProvider);
// 从服务端获取数据
getHomeArticle();
}
/**
* 从服务端获取数据
*/
public void getHomeArticle() {
BaseApplication.getInstance().getWan().getHomeArticle(0).enqueue(new Callback<Article>() {
@Override
public void onResponse(Call<Article> call, Response<Article> response) {
if (response.isSuccessful()) {
// 请求成功
setHomeArticle(response.body());
}
}
@Override
public void onFailure(Call<Article> call, Throwable t) {
// 请求失败
LogUtils.info("yunfei", t.getMessage());
}
});
}
@Override
public void onActive() {
super.onActive();
}
@Override
public void onForeground(Intent intent) {
super.onForeground(intent);
}
public void setHomeArticle(Article article) {
if (article == null || article.data == null || article.data.datas == null) {
return;
}
mDatas.addAll(article.data.datas);
// 刷新列表
mHomeArticleProvider.notifyDataChanged();
}
}
四、关于转义字符问题的解决
儿子在解析的时候,以特殊的义义端,就将义后的字符串进行转义。
如何将转义后的蜡烛添加到这个名义库中?
// commons-lang可以对特殊字符进行转义和反转义
implementation 'commons-lang:commons-lang:2.6'
调用字符串中的字符串转义字符,不直接返回原字符串,而不是直接返回原字符串,在字符串中的字符串方法中进行字符串的方法,如果有代码,则可以示例。
// json里面有一些特殊符号,特殊符号会被gson转义,
// StringEscapeUtils可以对转义的字符串进行反转义
String title = StringEscapeUtils.unescapeHtml(data.title);
componentHolder.title.setText(title);
后续义,特殊字符可以正常显示。