Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
DiDi
DoraemonKit
提交
d9ea8c76
D
DoraemonKit
项目概览
DiDi
/
DoraemonKit
12 个月 前同步成功
通知
166
Star
19623
Fork
3062
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
D
DoraemonKit
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
d9ea8c76
编写于
2月 17, 2020
作者:
J
jackjintai
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
modify:
1、兼容代驾kop环境数据mock功能
上级
4b7c6a49
变更
8
隐藏空白更改
内联
并排
Showing
8 changed file
with
152 addition
and
38 deletion
+152
-38
Android/config.gradle
Android/config.gradle
+1
-1
Android/doraemonkit-rpc/src/main/java/com/didichuxing/doraemonkit/kit/network/rpc/RpcMockInterceptor.java
...uxing/doraemonkit/kit/network/rpc/RpcMockInterceptor.java
+15
-7
Android/doraemonkit/src/main/java/com/didichuxing/doraemonkit/kit/network/okhttp/interceptor/MockInterceptor.java
...onkit/kit/network/okhttp/interceptor/MockInterceptor.java
+14
-5
Android/doraemonkit/src/main/java/com/didichuxing/doraemonkit/kit/network/room_db/DokitDbManager.java
...uxing/doraemonkit/kit/network/room_db/DokitDbManager.java
+88
-23
Android/doraemonkit/src/main/java/com/didichuxing/doraemonkit/kit/network/ui/MockTemplatePreviewFragment.java
...raemonkit/kit/network/ui/MockTemplatePreviewFragment.java
+11
-0
Android/doraemonkit/src/main/java/com/didichuxing/doraemonkit/kit/network/ui/NetWorkMockFragment.java
...uxing/doraemonkit/kit/network/ui/NetWorkMockFragment.java
+2
-2
Android/doraemonkit/src/main/java/com/didichuxing/doraemonkit/kit/network/ui/TemplateMockAdapter.java
...uxing/doraemonkit/kit/network/ui/TemplateMockAdapter.java
+1
-0
Android/doraemonkit/src/main/res/layout/dk_fragment_mock_template_preview.xml
...src/main/res/layout/dk_fragment_mock_template_preview.xml
+20
-0
未找到文件。
Android/config.gradle
浏览文件 @
d9ea8c76
...
...
@@ -4,7 +4,7 @@ ext {
// 线上包不会接入DoraemonKit,测试包会自动接入
applyPlugin
:
true
,
//上传到仓库时需要打开
uploadArchives
:
fals
e
,
uploadArchives
:
tru
e
,
//是否发布插件到远程仓库
publishPluginToRemote:
false
,
localRepoURL
:
"/Users/didi/project/dokit_repo"
...
...
Android/doraemonkit-rpc/src/main/java/com/didichuxing/doraemonkit/kit/network/rpc/RpcMockInterceptor.java
浏览文件 @
d9ea8c76
...
...
@@ -47,9 +47,10 @@ public class RpcMockInterceptor implements RpcInterceptor<HttpRpcRequest, HttpRp
}
//path /test/upload/img
String
path
=
URLDecoder
.
decode
(
url
.
encodedPath
(),
"utf-8"
);
//兼容滴滴内部外网映射环境 该环境的 path上会多一级/kop_xxx/路径
String
queries
=
url
.
query
();
String
interceptMatchedId
=
DokitDbManager
.
getInstance
().
isMockMatched
(
path
,
queries
,
DokitDbManager
.
MOCK_API_INTERCEPT
);
String
templateMatchedId
=
DokitDbManager
.
getInstance
().
isMockMatched
(
path
,
queries
,
DokitDbManager
.
MOCK_API_TEMPLATE
);
String
interceptMatchedId
=
DokitDbManager
.
getInstance
().
isMockMatched
(
path
,
queries
,
DokitDbManager
.
MOCK_API_INTERCEPT
,
DokitDbManager
.
FROM_SDK_DIDI
);
String
templateMatchedId
=
DokitDbManager
.
getInstance
().
isMockMatched
(
path
,
queries
,
DokitDbManager
.
MOCK_API_TEMPLATE
,
DokitDbManager
.
FROM_SDK_DIDI
);
try
{
//是否命中拦截规则
...
...
@@ -79,20 +80,22 @@ public class RpcMockInterceptor implements RpcInterceptor<HttpRpcRequest, HttpRp
//判断是否需要重定向数据接口
//http https
String
scheme
=
url
.
scheme
();
MockInterceptApiBean
interceptApiBean
=
(
MockInterceptApiBean
)
DokitDbManager
.
getInstance
().
getInterceptApiByIdInMap
(
path
,
interceptMatchedId
);
MockInterceptApiBean
interceptApiBean
=
(
MockInterceptApiBean
)
DokitDbManager
.
getInstance
().
getInterceptApiByIdInMap
(
path
,
interceptMatchedId
,
DokitDbManager
.
FROM_SDK_DIDI
);
if
(
interceptApiBean
==
null
)
{
return
matchedTemplateRule
(
oldResponse
,
path
,
templateMatchedId
);
}
String
selectedSceneId
=
interceptApiBean
.
getSelectedSceneId
();
//开关是否被打开
if
(!
interceptApiBean
.
isOpen
())
{
return
matchedTemplateRule
(
oldResponse
,
path
,
templateMatchedId
);
}
//判断是否有选中的场景
if
(
TextUtils
.
isEmpty
(
selectedSceneId
))
{
return
matchedTemplateRule
(
oldResponse
,
path
,
templateMatchedId
);
}
StringBuffer
sb
=
new
StringBuffer
();
String
newUrl
;
if
(
NetworkManager
.
MOCK_SCHEME_HTTP
.
contains
(
scheme
.
toLowerCase
()))
{
...
...
@@ -101,6 +104,8 @@ public class RpcMockInterceptor implements RpcInterceptor<HttpRpcRequest, HttpRp
newUrl
=
sb
.
append
(
NetworkManager
.
MOCK_SCHEME_HTTPS
).
append
(
NetworkManager
.
MOCK_HOST
).
append
(
"/api/app/scene/"
).
append
(
selectedSceneId
).
toString
();
}
LogHelper
.
i
(
"MOCK_INTERCEPT"
,
"name===>"
+
interceptApiBean
.
getMockApiName
()
+
" newUrl=====>"
+
newUrl
);
HttpRpcRequest
mockRequest
=
oldRequest
.
newBuilder
()
.
setMethod
(
HttpMethod
.
GET
,
null
)
.
setUrl
(
newUrl
).
build
();
...
...
@@ -128,7 +133,11 @@ public class RpcMockInterceptor implements RpcInterceptor<HttpRpcRequest, HttpRp
if
(
TextUtils
.
isEmpty
(
templateMatchedId
))
{
return
response
;
}
MockTemplateApiBean
templateApiBean
=
(
MockTemplateApiBean
)
DokitDbManager
.
getInstance
().
getTemplateApiByIdInMap
(
path
,
templateMatchedId
);
MockTemplateApiBean
templateApiBean
=
(
MockTemplateApiBean
)
DokitDbManager
.
getInstance
().
getTemplateApiByIdInMap
(
path
,
templateMatchedId
,
DokitDbManager
.
FROM_SDK_DIDI
);
if
(
templateApiBean
==
null
)
{
return
response
;
}
LogHelper
.
i
(
"MOCK_TEMPLATE"
,
"name=====>"
+
templateApiBean
.
getMockApiName
()
+
" isOpen===>"
+
templateApiBean
.
isOpen
());
if
(
templateApiBean
.
isOpen
())
{
//保存老的response 数据到数据库
response
=
saveResponse2DB
(
response
,
templateApiBean
);
...
...
@@ -235,7 +244,6 @@ public class RpcMockInterceptor implements RpcInterceptor<HttpRpcRequest, HttpRp
//这里不能直接使用response.body().string()的方式输出日志
//因为response.body().string()之后,response中的流会被关闭,程序会报错,我们需要创建出一
//个新的response给应用层处理
if
(
response
.
getEntity
()
!=
null
&&
response
.
getEntity
().
getContent
()
!=
null
)
{
return
true
;
}
...
...
Android/doraemonkit/src/main/java/com/didichuxing/doraemonkit/kit/network/okhttp/interceptor/MockInterceptor.java
浏览文件 @
d9ea8c76
...
...
@@ -51,8 +51,8 @@ public class MockInterceptor implements Interceptor {
//path /test/upload/img
String
path
=
URLDecoder
.
decode
(
url
.
encodedPath
(),
"utf-8"
);
String
queries
=
url
.
query
();
String
interceptMatchedId
=
DokitDbManager
.
getInstance
().
isMockMatched
(
path
,
queries
,
DokitDbManager
.
MOCK_API_INTERCEPT
);
String
templateMatchedId
=
DokitDbManager
.
getInstance
().
isMockMatched
(
path
,
queries
,
DokitDbManager
.
MOCK_API_TEMPLATE
);
String
interceptMatchedId
=
DokitDbManager
.
getInstance
().
isMockMatched
(
path
,
queries
,
DokitDbManager
.
MOCK_API_INTERCEPT
,
DokitDbManager
.
FROM_SDK_OTHER
);
String
templateMatchedId
=
DokitDbManager
.
getInstance
().
isMockMatched
(
path
,
queries
,
DokitDbManager
.
MOCK_API_TEMPLATE
,
DokitDbManager
.
FROM_SDK_OTHER
);
try
{
//网络的健康体检功能 统计流量大小
if
(
DokitConstant
.
APP_HEALTH_RUNNING
)
{
...
...
@@ -144,8 +144,11 @@ public class MockInterceptor implements Interceptor {
//判断是否需要重定向数据接口
//http https
String
scheme
=
url
.
scheme
();
MockInterceptApiBean
interceptApiBean
=
(
MockInterceptApiBean
)
DokitDbManager
.
getInstance
().
getInterceptApiByIdInMap
(
path
,
interceptMatchedId
);
MockInterceptApiBean
interceptApiBean
=
(
MockInterceptApiBean
)
DokitDbManager
.
getInstance
().
getInterceptApiByIdInMap
(
path
,
interceptMatchedId
,
DokitDbManager
.
FROM_SDK_OTHER
);
if
(
interceptApiBean
==
null
)
{
matchedTemplateRule
(
oldResponse
,
path
,
templateMatchedId
);
return
oldResponse
;
}
String
selectedSceneId
=
interceptApiBean
.
getSelectedSceneId
();
//开关是否被打开
if
(!
interceptApiBean
.
isOpen
())
{
...
...
@@ -166,6 +169,8 @@ public class MockInterceptor implements Interceptor {
newUrl
=
sb
.
append
(
NetworkManager
.
MOCK_SCHEME_HTTPS
).
append
(
NetworkManager
.
MOCK_HOST
).
append
(
"/api/app/scene/"
).
append
(
selectedSceneId
).
toString
();
}
LogHelper
.
i
(
"MOCK_INTERCEPT"
,
"path===>"
+
path
+
" newUrl=====>"
+
newUrl
);
Request
newRequest
=
oldRequest
.
newBuilder
()
.
method
(
"GET"
,
null
)
.
url
(
newUrl
).
build
();
...
...
@@ -195,7 +200,11 @@ public class MockInterceptor implements Interceptor {
if
(
TextUtils
.
isEmpty
(
templateMatchedId
))
{
return
;
}
MockTemplateApiBean
templateApiBean
=
(
MockTemplateApiBean
)
DokitDbManager
.
getInstance
().
getTemplateApiByIdInMap
(
path
,
templateMatchedId
);
MockTemplateApiBean
templateApiBean
=
(
MockTemplateApiBean
)
DokitDbManager
.
getInstance
().
getTemplateApiByIdInMap
(
path
,
templateMatchedId
,
DokitDbManager
.
FROM_SDK_OTHER
);
if
(
templateApiBean
==
null
)
{
return
;
}
LogHelper
.
i
(
"MOCK_TEMPLATE"
,
"path=====>"
+
path
+
"isOpen===>"
+
templateApiBean
.
isOpen
());
if
(
templateApiBean
.
isOpen
())
{
//保存老的response 数据到数据库
saveResponse2DB
(
oldResponse
,
templateApiBean
);
...
...
Android/doraemonkit/src/main/java/com/didichuxing/doraemonkit/kit/network/room_db/DokitDbManager.java
浏览文件 @
d9ea8c76
...
...
@@ -136,15 +136,34 @@ public class DokitDbManager<T extends AbsMockApiBean> {
/**
* 内存中获取指定的 template api
* 数据库中获取指定的mock intercept api
*/
public
T
getInterceptApiByIdInDb
(
String
id
)
{
return
(
T
)
DokitViewManager
.
getInstance
().
getDb
().
mockApiDao
().
findInterceptApiById
(
id
);
}
/**
* 内存中中获取指定的mock intercept api
*/
public
T
getTemplateApiByIdInMap
(
String
path
,
String
id
)
{
if
(
mGlobalTemplateApiMaps
.
get
(
path
)
==
null
)
{
public
T
getInterceptApiByIdInMap
(
String
path
,
String
id
,
int
fromSDK
)
{
if
(
mGlobalInterceptApiMaps
==
null
)
{
return
null
;
}
//先进行全匹配
List
<
T
>
mGlobalInterceptApis
=
mGlobalInterceptApiMaps
.
get
(
path
);
if
(
mGlobalInterceptApis
==
null
)
{
path
=
dealPath
(
path
,
fromSDK
);
mGlobalInterceptApis
=
mGlobalInterceptApiMaps
.
get
(
path
);
}
//再进行滴滴内部匹配
if
(
mGlobalInterceptApis
==
null
)
{
return
null
;
}
T
selectedMockApi
=
null
;
for
(
T
mockApi
:
mGlobal
TemplateApiMaps
.
get
(
path
)
)
{
for
(
T
mockApi
:
mGlobal
InterceptApis
)
{
if
(
mockApi
.
getId
().
equals
(
id
))
{
selectedMockApi
=
mockApi
;
break
;
...
...
@@ -154,24 +173,26 @@ public class DokitDbManager<T extends AbsMockApiBean> {
return
selectedMockApi
;
}
/**
* 数据库中获取指定的mock intercept api
*/
public
T
getInterceptApiByIdInDb
(
String
id
)
{
return
(
T
)
DokitViewManager
.
getInstance
().
getDb
().
mockApiDao
().
findInterceptApiById
(
id
);
}
/**
* 内存中中获取指定的mock intercept api
* 内存中获取指定的 template api
*/
public
T
getInterceptApiByIdInMap
(
String
path
,
String
id
)
{
if
(
mGlobalInterceptApiMaps
.
get
(
path
)
==
null
)
{
public
T
getTemplateApiByIdInMap
(
String
path
,
String
id
,
int
fromSDK
)
{
if
(
mGlobalTemplateApiMaps
==
null
)
{
return
null
;
}
List
<
T
>
mGlobalTemplateApis
=
mGlobalTemplateApiMaps
.
get
(
path
);
//先进行全匹配
if
(
mGlobalTemplateApis
==
null
)
{
path
=
dealPath
(
path
,
fromSDK
);
mGlobalTemplateApis
=
mGlobalTemplateApiMaps
.
get
(
path
);
}
//再进行滴滴内部匹配
if
(
mGlobalTemplateApis
==
null
)
{
return
null
;
}
T
selectedMockApi
=
null
;
for
(
T
mockApi
:
mGlobal
InterceptApiMaps
.
get
(
path
)
)
{
for
(
T
mockApi
:
mGlobal
TemplateApis
)
{
if
(
mockApi
.
getId
().
equals
(
id
))
{
selectedMockApi
=
mockApi
;
break
;
...
...
@@ -311,6 +332,15 @@ public class DokitDbManager<T extends AbsMockApiBean> {
*/
public
static
final
int
MOCK_API_TEMPLATE
=
2
;
/**
* 来自滴滴内部SDK
*/
public
static
int
FROM_SDK_DIDI
=
100
;
/**
* 来自外部SDK
*/
public
static
int
FROM_SDK_OTHER
=
101
;
/**
* 返回命中的id
*
...
...
@@ -319,29 +349,64 @@ public class DokitDbManager<T extends AbsMockApiBean> {
* @param operateType
* @return
*/
public
String
isMockMatched
(
String
path
,
String
strLocalQuery
,
int
operateType
)
{
T
mockApi
=
mockMatched
(
path
,
strLocalQuery
,
operateType
);
public
String
isMockMatched
(
String
path
,
String
strLocalQuery
,
int
operateType
,
int
fromSDK
)
{
T
mockApi
=
mockMatched
(
path
,
strLocalQuery
,
operateType
,
fromSDK
);
if
(
mockApi
==
null
)
{
return
""
;
}
return
mockApi
.
getId
();
}
/**
* 兼容滴滴内部外网映射环境 该环境的 path上会多一级/kop_xxx/路径
*
* @param oldPath
* @param fromSDK
* @return
*/
private
String
dealPath
(
String
oldPath
,
int
fromSDK
)
{
if
(
fromSDK
==
FROM_SDK_OTHER
)
{
return
oldPath
;
}
String
newPath
=
oldPath
;
//包含多级路径
if
(
oldPath
.
contains
(
"/kop"
)
&&
oldPath
.
split
(
"\\/"
).
length
>
1
)
{
String
[]
childPaths
=
oldPath
.
split
(
"\\/"
);
String
endPath
=
childPaths
[
childPaths
.
length
-
1
];
if
(!
endPath
.
contains
(
"kop"
))
{
newPath
=
"/"
+
endPath
;
}
}
return
newPath
;
}
/**
* 通过path和query查询指定的对象
*
* @param path
* @param strLocalQuery
* @param operateType 1:代表拦截 2:代表模板
* @param operateType
1:代表拦截 2:代表模板
* @return
*/
private
T
mockMatched
(
String
path
,
String
strLocalQuery
,
int
operateType
)
{
List
<
T
>
mockApis
;
if
(
operateType
==
1
)
{
private
T
mockMatched
(
String
path
,
String
strLocalQuery
,
int
operateType
,
int
fromSDK
)
{
List
<
T
>
mockApis
=
null
;
if
(
operateType
==
DokitDbManager
.
MOCK_API_INTERCEPT
)
{
//先进行一次全匹配
mockApis
=
mGlobalInterceptApiMaps
.
get
(
path
);
}
else
{
//滴滴内部sdk匹配
if
(
mockApis
==
null
)
{
path
=
dealPath
(
path
,
fromSDK
);
mockApis
=
mGlobalInterceptApiMaps
.
get
(
path
);
}
}
else
if
(
operateType
==
DokitDbManager
.
MOCK_API_TEMPLATE
)
{
//先进行一次全匹配
mockApis
=
mGlobalTemplateApiMaps
.
get
(
path
);
//滴滴内部sdk匹配
if
(
mockApis
==
null
)
{
path
=
dealPath
(
path
,
fromSDK
);
mockApis
=
mGlobalTemplateApiMaps
.
get
(
path
);
}
}
if
(
mockApis
==
null
)
{
return
null
;
...
...
Android/doraemonkit/src/main/java/com/didichuxing/doraemonkit/kit/network/ui/MockTemplatePreviewFragment.java
浏览文件 @
d9ea8c76
...
...
@@ -54,6 +54,7 @@ public class MockTemplatePreviewFragment extends BaseFragment {
TextView
tvPath
=
findViewById
(
R
.
id
.
tv_path
);
tvName
.
setText
(
String
.
format
(
"mock接口名称:%s"
,
DokitDbManager
.
getInstance
().
getGlobalTemplateApiBean
().
getMockApiName
()));
tvPath
.
setText
(
String
.
format
(
"mock接口路径:%s"
,
DokitDbManager
.
getInstance
().
getGlobalTemplateApiBean
().
getPath
()));
JsonRecyclerView
jsonViewQuery
=
findViewById
(
R
.
id
.
json_query
);
JsonRecyclerView
jsonRecycleView
=
findViewById
(
R
.
id
.
jsonviewer
);
TextView
tvUpload
=
findViewById
(
R
.
id
.
tv_upload
);
...
...
@@ -72,6 +73,7 @@ public class MockTemplatePreviewFragment extends BaseFragment {
.
execute
(
new
StringCallback
()
{
@Override
public
void
onSuccess
(
Response
<
String
>
response
)
{
LogHelper
.
i
(
TAG
,
"上传模板===>"
+
response
.
body
());
ToastUtils
.
showShort
(
"上传模板成功"
);
}
...
...
@@ -90,6 +92,15 @@ public class MockTemplatePreviewFragment extends BaseFragment {
return
;
}
try
{
JSONObject
jsonQuery
=
new
JSONObject
(
DokitDbManager
.
getInstance
().
getGlobalTemplateApiBean
().
getQuery
());
if
(
jsonQuery
.
length
()
==
0
)
{
jsonViewQuery
.
setVisibility
(
View
.
GONE
);
}
else
{
jsonViewQuery
.
setVisibility
(
View
.
VISIBLE
);
jsonViewQuery
.
bindJson
(
jsonQuery
);
}
new
JSONObject
(
DokitDbManager
.
getInstance
().
getGlobalTemplateApiBean
().
getStrResponse
());
jsonRecycleView
.
setTextSize
(
16
);
jsonRecycleView
.
bindJson
(
DokitDbManager
.
getInstance
().
getGlobalTemplateApiBean
().
getStrResponse
());
...
...
Android/doraemonkit/src/main/java/com/didichuxing/doraemonkit/kit/network/ui/NetWorkMockFragment.java
浏览文件 @
d9ea8c76
...
...
@@ -769,7 +769,7 @@ public class NetWorkMockFragment extends BaseFragment {
* @return
*/
private
boolean
hasInterceptApiInDb
(
String
path
,
String
id
)
{
MockInterceptApiBean
mockInterceptApi
=
(
MockInterceptApiBean
)
DokitDbManager
.
getInstance
().
getInterceptApiByIdInMap
(
path
,
id
);
MockInterceptApiBean
mockInterceptApi
=
(
MockInterceptApiBean
)
DokitDbManager
.
getInstance
().
getInterceptApiByIdInMap
(
path
,
id
,
DokitDbManager
.
FROM_SDK_OTHER
);
return
mockInterceptApi
!=
null
;
}
...
...
@@ -781,7 +781,7 @@ public class NetWorkMockFragment extends BaseFragment {
* @return
*/
private
boolean
hasTemplateApiInDb
(
String
path
,
String
id
)
{
MockTemplateApiBean
mockTemplateApi
=
(
MockTemplateApiBean
)
DokitDbManager
.
getInstance
().
getTemplateApiByIdInMap
(
path
,
id
);
MockTemplateApiBean
mockTemplateApi
=
(
MockTemplateApiBean
)
DokitDbManager
.
getInstance
().
getTemplateApiByIdInMap
(
path
,
id
,
DokitDbManager
.
FROM_SDK_OTHER
);
return
mockTemplateApi
!=
null
;
}
...
...
Android/doraemonkit/src/main/java/com/didichuxing/doraemonkit/kit/network/ui/TemplateMockAdapter.java
浏览文件 @
d9ea8c76
...
...
@@ -158,6 +158,7 @@ public class TemplateMockAdapter<T extends MultiItemEntity> extends BaseMultiIte
.
execute
(
new
StringCallback
()
{
@Override
public
void
onSuccess
(
Response
<
String
>
response
)
{
LogHelper
.
i
(
TAG
,
"上传模板===>"
+
response
.
body
());
ToastUtils
.
showShort
(
"上传模板成功"
);
}
...
...
Android/doraemonkit/src/main/res/layout/dk_fragment_mock_template_preview.xml
浏览文件 @
d9ea8c76
...
...
@@ -38,8 +38,28 @@
android:text=
"接口路径:"
android:textColor=
"@color/dk_color_333333"
android:textSize=
"16sp"
/>
<LinearLayout
android:layout_width=
"match_parent"
android:layout_height=
"wrap_content"
>
<TextView
android:layout_width=
"wrap_content"
android:layout_height=
"wrap_content"
android:layout_marginTop=
"6dp"
android:layout_marginRight=
"10dp"
android:text=
"query:"
android:textColor=
"@color/dk_color_333333"
android:textSize=
"16sp"
/>
<com.didichuxing.doraemonkit.view.jsonviewer.JsonRecyclerView
android:id=
"@+id/json_query"
android:layout_width=
"match_parent"
android:layout_height=
"wrap_content"
/>
</LinearLayout>
</LinearLayout>
<TextView
android:id=
"@+id/tv_desc"
android:layout_width=
"wrap_content"
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录