日期: 2021 年 8 月 30 日

前端,把 api 封装到一个文件夹到底有没有必要

*近在改一个 vue 项目,看了很多 api 接口封装的文章,似乎这是主流的处理方式?

于是尝试了一下发现了几个问题。

首先,管理是集中了,不过有点类似于 vuex 的思维方式。看过很多人不提倡把请求放在 vuex 里,而使用就近原则,不过本题的 api 接口封装,虽然只是把一些基本实例写好在导入到模板文件中,但是还是让人感觉到了 vuex 那个味。

其次,修改起来感觉没有独立方便,导入还有改名什么的有点麻烦了,感觉 api 端口修改频率都不如参数的修改高。尤其是需要改名的时候,忘记改一个地方的情况经常发生。

所以想问问,这种方案真的是主流的处理方式嘛?真的有必要嘛?

API vuex 封装 修改24 条回复 • 2021-08-30 16:35:37 +08:00
hackyuan 1
hackyuan 6 小时 53 分钟前
选中函数名 F2
acthtml 2
acthtml 6 小时 48 分钟前
抽象出来,放在一个独立的文件夹主要解决:

1. 多个前端组件可能对同一个 [后端服务复用] 。
2. 组件不依赖于服务,而是依赖于服务的产生的数据,方便 [前端组件的复用] 。
3. 结构清晰,如果后端服务改动,可以很容易做修改。
zarvin 3
zarvin 6 小时 45 分钟前
vue 开发全局搜索用得多,看了几个开源项目好像都是这样
shzx1994529 4
shzx1994529 6 小时 41 分钟前
一个路由一个 api.js 呗,这玩意无所谓啊,能让别人看懂就行
Yooe 5
Yooe 6 小时 40 分钟前
我怎么记得之前好像看到过这个帖子?= =
Kusoku 6
Kusoku 6 小时 40 分钟前 ❤️ 1
小的项目放在一起就是为了方便统一维护,根据模块拆分到不同的小文件也是为了按需要引入,这种组织方式可以适应*大部分项目的需要。如果按模块划分子文件夹,然后再每个子文件夹再划分各种小文件夹,有部分公共请求也需要单独拿出来,实际上还不如单独用一个文件夹来放请求接口配置的内容,区分公共部分和模块部分,这样清楚明晰方便定位。
chenluo0429 7
chenluo0429 6 小时 39 分钟前
api 接口封装就是为了对组件屏蔽后端的具体实现,同时统一处理接口的变更。
如果有参数变更,封装反而可以通过默认值等手段来快速适配。如果有破坏性的变更需要全部修改,封装的你都能忘记,独立的你就一定改得全?
mozhizhu 8
mozhizhu 6 小时 38 分钟前
你经历过后端改请求方式吗?经历过后端改路由吗?
cydysm 9
cydysm 6 小时 33 分钟前
不同项目有不同的处理方式,没有银弹,写得多了就知道怎么办了。
netwjx 10
netwjx 6 小时 24 分钟前 ❤️ 2
没有显著必要, 曾经多年 java 和 dotnet, 熟悉各种 MVC, ORM

在前端领域, 将 ajax 调用抽取成函数, 99%是脱裤子放屁

因为 ajax 请求的代码量很少, 后端是因为这部分业务逻辑比较多, 必须复用

前端就算写 3 遍 ajax 调用, 重复的只有 1~2 行, 所谓封装, 只是将这部分重复的代码, 变成了重复的函数调用, 并没有实质意义, 反而增加了一层映射关系(函数名 -> ajax URL)

不重复的部分是如何生成不同的 ajax 请求参数, 而切实有效的封装, 是真能减少重复业务逻辑的

比如根据业务逻辑

– 规整各种 ajax 请求参数: id 必须转换成有效数字, 而不能是字符串
– 处理 ajax 响应参数: 转换成适合前端使用的格式

另一类需要集中处理的逻辑, 用 ajax 模块插件实现

– 认证和授权, 引导到登录界面, 申请权限界面
– 异常处理, 上报和用户友好提示
– 接口缓存
– 并发控制

libook 11
libook 6 小时 20 分钟前
抛开场景谈对错都是耍流氓。

一个 Vue 项目是由各种类别的模块组成的(如组件、服务、路由……),对于不同项目来说;不同类别的模块规模不同,比如可能营销项目路由路由巨多、组件和服务很少,后台项目路由很少、组件和服务巨多;模块之间的对应关系也不一样,比如有的项目服务可以被所有组件复用,也有的项目服务是从属于各个组件的,不可跨组件使用。
Vue 提供了项目文件结构的灵活性,那么自然在不同场景下可以设计成不同的文件结构,*终都是服务于开发效率。
Biwood 12
Biwood 5 小时 55 分钟前 ❤️ 1
我也觉得有些多余,明明 request 工具在组建里面直接请求就行了,还要多封装一层,而且这些请求函数复用性特别低,*大部分都只在一个模块用到了一次而已。真有复用的情况,也是跟着组件一起,而不是单独调用。有种过度设计的感觉。

@libook
楼主说的应该是那种纯粹的 api 封装,只是提前固定了路径和 method 而已,不携带具体的业务数据,你说的“服务”的概念其实已经在 api 基础上做了其他业务逻辑了。
lin07hui 13
lin07hui 5 小时 55 分钟前
我这边之前的人封装的
// src/api/index.js
export * from “./xxx.js”;

// src/api/xxx.js
export const xxxDetail = (id) => { … };
export const xxxList = ({ page, … }) => { … };
export const xxxSave = ({ id, … } ) => { … };

// src/store/modules/xxx.js
import { xxxDetail, xxxList, xxxSave } from “@/utils/api”;
import { createState } from “@/utils/state”;

const options = createState({ detail: { api: xxxDetail, … }, list: { api: xxxList, … }, save: { api: xxxSave, … });

export default {
namespaced: true,
…options
};

// src/utils/state — 248 行代码
// createState
/**
* Create a store options
* @param {Promise} list.api – 获取分页列表数据接口
* @param {Object} list.params – 发送给接口的参数
* @param {Function} list.beforeSet – 设置数据之前执行,beforeSet(接口数据)
* @param {Promise} detail.api – 获取单条数据接口
* @param {Object} detail.params – 发送给接口的参数
* @param {Promise} save.api – 保存接口
* @param {Function} save.success – 保存成功后运行:success({ commit, state, dispatch }, record)
* ….还有很多
*/
Biwood 14
Biwood 5 小时 53 分钟前
当然,如果是 TypeScript 项目,这样写比较方便提前约定前后端字段的对应关系,类似于 adapter 的概念
lin07hui 15
lin07hui 5 小时 51 分钟前
@lin07hui #13 import { xxxDetail, xxxList, xxxSave } from “@/api”;
ansenJ 16
ansenJ 5 小时 51 分钟前
初期多人开发的时候 别说 API 了 Store Router 都是每人一个文件, 等项目稳定了再汇总的。多人操作一个文件的那位, 你是爱上解决 git 冲突吗?
fernandoxu 17
fernandoxu 3 小时 52 分钟前
按领域组织更好,
Sapp 18
Sapp 3 小时 12 分钟前
现在 api 不都是自动生成函数么?还有人手写???
chairuosen 19
chairuosen 3 小时 6 分钟前 ❤️ 2
说不需要的都没写过大项目?
cloudzqy 20
cloudzqy 2 小时 37 分钟前
现在基本 typescript 了,基本都封,定义类型比较方便。
kennhuang 21
kennhuang 2 小时 16 分钟前 via iPhone
写 unit tests 的同学就知道封装出来的好处了?
hitaoguo 22
hitaoguo 1 小时 52 分钟前
我用装饰器做的封装,代码类似这样。

然后页面里就直接这样用

ccraohng 23
ccraohng 1 小时 25 分钟前
api 配置对象配合 ts 输出 一个类似 service 的对象
chairuosen 24
chairuosen 52 分钟前
不封在一起,所有请求通用的:鉴权、域名配置、封装协议解构、异常判断、日志、重试、超时、token 过期重拿、mock 、监控、、、、、等等等等写在哪里。后端换个域名、path 、封装协议,甚至接口实现要所有地方挨个找么?

按道理,所有非你项目代码实现的部分,都不应该直接在业务逻辑里调(比如 http 接口,RN 里的客户端接口,SDK 的接口),应该有个 adapter 层来做对接,都是不可信的,没准哪天对方心情不好想改就改的,他改了你不可能全局搜代码改吧。

“微型业务”用啥数据库软件啊?

这里的“微型业务”大概就是一些访问量很低、仅面向很少数量的用户、跑在低配置机器上的一些用到数据库的网站或服务吧。主要面向于个人或者小团队内部、homelab 。 例如:跑在*便宜的那一档 VPS 的机器上(如:单核 CPU 512M 内存 10G 硬盘)的、树莓派 3 代那个级别的开发板、甚至 openwrt 软路由。

此前看了看 MySQL 、PostgresQL,空闲时占用的内存也挺高的。而 SQLite 似乎在处于鄙视链底端?这才想着来问问。

要求:SQL 数据库、开源。

数据库 软路 链底端 来问问25 条回复 • 2021-08-30 16:58:47 +08:00
tanranran 1
tanranran 2 小时 5 分钟前
SQLite
KomiSans 2
KomiSans 2 小时 4 分钟前
H2 吧
qping 3
qping 2 小时 1 分钟前
H2 理由:支持并发(些微)
eason1874 4
eason1874 1 小时 51 分钟前
我投 SQLite 一票,多语言,跨平台

那么多巨型 APP 用 SQLite,说明不会太差
Soar360 5
Soar360 1 小时 49 分钟前
推荐 SQLite
xiaopc 6
xiaopc 1 小时 48 分钟前
微信都是 SQLite (
Kilerd 7
Kilerd 1 小时 31 分钟前
我 rust + sqlite 写的服务,常年占用 10M 内存+20M 储存,就自己用舒服到不行,套一个 docker 体积*多占用多 10M
serco 8
serco 1 小时 16 分钟前
@xiaopc 那是客户端吧。。
wellsc 9
wellsc 1 小时 12 分钟前
跑个 client 不行吗,干嘛要跑 server,另外,sqlite 是地表*强数据库,不知道为什么会在鄙视链低端
Mithril 10
Mithril 1 小时 12 分钟前
SQLite
你搞个正常的数据库,性能消耗不说,带来的复杂度成本太高。完全没必要。

cmdOptionKana 11
cmdOptionKana 1 小时 11 分钟前
谁说 SQLite 处于鄙视链底端?没听过这个说法,通常都是说 sqlite 各种好。
sprite82 12
sprite82 1 小时 4 分钟前
推 h2 的不看描述吗 都说 512M 内存了 难道还要装个 Java ?
thtznet 13
thtznet 1 小时 1 分钟前
Firebird embedded
hushao 14
hushao 54 分钟前 via iPhone
这种场合 sqlite 再适合不过了

另外,sqlite 可一点都不差,无论性能还是评价
zjsxwc 15
zjsxwc 50 分钟前
问就是推荐 mariadb/mysql

楼主说什么空载运行内存 cpu 占用多之类的,问题都能通过修改默认配置参数解决

https://mariadb.com/kb/en/mariadb-memory-allocation/
shyangs 16
shyangs 47 分钟前
@zjsxwc
512M RAM 還要分給 OS 和 AP, 你這 MySQL 安裝完 能啟動嗎?
daysv 17
daysv 46 分钟前
不好意思, sqlite 是地表*强数据库, 处于鄙视链顶端
felixcode 18
felixcode 45 分钟前
sqlite 很强的。
zjsxwc 19
zjsxwc 45 分钟前
@shyangs

innodb_buffer_pool_size 默认值就是 128M,你把它改小点不行吗
wolfan 20
wolfan 41 分钟前
sqlite yyds
zjsxwc 21
zjsxwc 39 分钟前
https://stackoverflow.com/questions/40189226/how-to-make-mysql-use-less-memory

这个帖子和楼主同样的问题,
第二个回帖把 performance_schema = off 关掉 mysql 的性能优化策略后,mysql 内存占用只有 37M
ipwx 22
ipwx 39 分钟前
sqlite 反正能用 orm
wangkun025 23
wangkun025 39 分钟前
建议花 500 块钱升级下配置。
hushao 24
hushao 37 分钟前 via iPhone
@zjsxwc 一直 37M 也不太可能,但他这 500m 的机器怎么玩都够了
kwanzaa 25
kwanzaa 21 分钟前
就这个配置,没法鄙视 sqlite 。

.net 那边有了 blazor, Java 这边会出类似的东西吗

除去语言大战的),好像大家更多关注的都是wasm啊,实际上blazor有server模式的,而且现在用的更多好像都是server模式

blazor Java NET 类似38 条回复 • 2021-08-30 17:10:11 +08:00
thtznet 1
thtznet 6 小时 20 分钟前
.Net 有微软,Java 有啥?甲骨文?算了算,不要想了。
不是我吹冷风,这种大踏步的变格,没有实例雄厚的主导厂商基本是没有可能做出来的,即便做出来,易用性也差得很,所谓开源,在离开了大厂商的情况下,以目前的业态来说,只能做一些小格局的东西,业界形态的大踏步的推进没有巨头基本是不可能的事。
虽然现在 Java 还是如日中天,但是按目前甲骨文的这个德性,.Net 生态慢慢追平 Java 是时间问题,当然这个时间会很厂,中间微软要给力,甲骨文要继续作死。
huang119412 2
huang119412 6 小时 4 分钟前 ❤️ 3
@thtznet 无知者无畏,连微软的孝子都有,微软做的恶罄竹难书,到现在还有很多开源社区不愿意和微软扯上关系。Oracle 做了什么?安卓的 Java API 是法律问题,连美国大法官们都在争论不休,你操个什么心。真的难以想象,连微软都能洗白。
love 3
love 5 小时 58 分钟前
@thtznet 你把我看乐了,可能是有恋父情结,没个好爸爸就用不安心
iikebug 4
iikebug 5 小时 57 分钟前
微软现在到拥抱开源,只要不作死,还是可以期待下的。
wanguorui123 5
wanguorui123 5 小时 51 分钟前
微软的东西就是半吊子,公鸡拉屎头节硬。
h82258652 6
h82258652 5 小时 50 分钟前
虽然我也在做 .net 相关的,但是也不看好 blazor 。webassembly 模式老浏览器跑不动,而且 GC 要几 M 。websocket 模式量大了会拖垮服务器。注定 ToC 场景不适合。
那也就只能做做 ToB 的,但是除了小公司,一般公司都会有前端开发,那又用不上了。小公司也不会用到这么新的玩意。
之前想来想去,也就两个地方适合,一个是搭配 electron 开发本地 app,一个是开发 chrome 插件,毕竟这两个性能要求不算高,带一个 GC 也不算大多少。
thtznet 7
thtznet 5 小时 45 分钟前 ❤️ 2
Blazor 不一定会更变什么风潮,但是按目前 .Net 的更新速度和变革速度,Java 再慢慢脱节。楼上诸公认清现实,语言只是工具,哪个好用用哪个,没那么多政治正确。
各位去问问看给各位家里装修的木工,会不会因为博世工具政治不正确去选博达工具?干活的人是务实的,务实!
chouchoui 8
chouchoui 5 小时 42 分钟前 ❤️ 8
又到了开源魔怔人的微软 PTSD 表演时间
MakHoCheung 9
MakHoCheung 5 小时 40 分钟前
就是用 c# 写前端吗,java 的话好早之前不是有 gwt 吗,虽然很拉垮。jvm 系的话,未来会有 javafx for web 和 compose for web,现在的话有 flutter 。感觉*终还是回归 js 。
Rwing 10
Rwing 5 小时 36 分钟前
blazor 归根到底还是 webassembly,其他很多语言也都有 webassembly 的方案。
虽然看起来 webassembly 是前端的*终归宿,但是要考虑语言的惯性和更新换代的成本,所以 5 年内 webassembly 都没可能超越 js 在前端的地位,至于说 5 年后,谁知道呢,前端本来就千变万化。
至于说.net 为什么要上 webassembly,我认为是.net 一直都有很好的客户端基因,例如 winform/wpf/winui 等等,所以自然而然的做一个 webassembly 没什么问题。

综上,.net 如果只靠 blazor 就想夺回市场,那是不可能的,与 java 无关,与 webassembly 有关。

zxCoder 11
zxCoder 5 小时 34 分钟前
@h82258652
@Rwing

webassembly 模式还不成熟,不过 sever 模式我觉得还行啊,类似前端的 ssr 概念
Leviathann 12
Leviathann 5 小时 32 分钟前 via iPhone
有编译到 js 支持 react 的 kotlin?
认真的说对后端语言编译到 js wasm 这套都不看好
darknoll 13
darknoll 5 小时 26 分钟前
微软的东西谁学谁穷
为啥总有人愿意当他的脑残粉啊
pixiaotiao 14
pixiaotiao 5 小时 24 分钟前 via Android
微软这尿性 学不动了啊
cxe2v 15
cxe2v 5 小时 21 分钟前
@darknoll #13 在微软公司工作的人穷吗?水平不行进不了大公司怪微软咯
yousabuk 16
yousabuk 4 小时 33 分钟前 via iPhone
微软的不碰,学不动,跟不动,伤不起。
agagega 17
agagega 4 小时 31 分钟前 via iPhone
.net core 和 server side swift 一样,火不了
Fule 18
Fule 4 小时 4 分钟前 ❤️ 1
至少*低程度上这东西有解决我实在是不想写太复杂 JavaScript 的东西的潜力。而且,这个项目*初感觉还是以“兴趣”和“探索可能性”的目的而创建的,我也很意外竟然如此之快就挂到了正式集成并发布的阶段。如果是面向全互联网用户的产品,我不好说,但是如果是用于用户可控的企业内产品的话,倒可能是一种潜在可行的方案。目前认为*便利的地方之一是一些 POCO 的类型定义可以直接共享而不需要 C# <-> JSON 之间的转换。
aguesuka 19
aguesuka 3 小时 47 分钟前
JVM 上有不是只有 Java. Kotlin 在”比 Java 强”这件事情上比 C# 强 100 倍.
Rwing 20
Rwing 3 小时 42 分钟前
@aguesuka 愿闻其详
yannxia 21
yannxia 3 小时 29 分钟前
@love 这个也是实事求是···现在都是公司级开源,或者由公司牵头成立基金会的模式,不过 Oracle 在 Java 上还算是投入了,现在存粹小公司开源的确不怎么敢用,有钱才有人维护。
echo1937 22
echo1937 3 小时 6 分钟前
@agagega #17 .net core 又改名了,你猜猜*新的名字叫啥。

微软*大的投入怕是改名部。
lower 23
lower 3 小时 0 分钟前
我们不用担心,,你先保证你软的那个东西不改名再说吧……
aguesuka 24
aguesuka 2 小时 54 分钟前
@Rwing
WebAssembly 模式: Kotlin 原生, Java 使用第三方库如 TeaVM.
服务端模式: GWT 框架.

ps. 我现在的项目就用到了 GWT, 它是我现在的噩梦, 我的感受就是不基于几篇经典的论文发明的框架注定走不远.
Rwing 25
Rwing 2 小时 52 分钟前
没想到 V2EX 的无脑黑也这么说,我还以为程序员都有自己的脑子自己的思考呢……
一个公司的产品的改名自然有他的原因,各大科技公司都不少,例如 google 的

谷歌改名部调整多款通讯类产品名称 原小娜负责人现在管理谷歌通讯软件

同样的,各大公司的死掉的产品也是大把大把,例如 google 的
https://www.zhihu.com/question/19550227

其次,题主问的是 java 会有这边东西吗,各位无脑黑微软是不是跑题了呢?

*后,各位如果自认是优秀的工程师,那么发言的时候还是带点脑子好
x940727 26
x940727 2 小时 47 分钟前
Java 在脱节是 Java 在脱节还是 Javaer 在脱节,这个要分清楚,目前来看 Java 是属于目前来说开源阵营*锐意进取的语言之一了,无论是 GraalVM 还是 Native Stack 都是在努力拥抱前沿生态,包括 Spring 也是,但是 Javaer 就不一样了,用着 Java8 写 Java6,连 Java9 摸都没摸过,这你不能怪 Java 不行吧?如果怪你就只能怪 Java8 太强了,性能足够,语法也足够,Spring 也挺好使。
namelosw 27
namelosw 2 小时 35 分钟前 ❤️ 2
类似 Blazor 的东西有一天会火起来的,毕竟 WASM 是方向,然后其他语言会跟进,*后 Java 社区会跟进。因为现在来说 Java 社区不够「酷」,所以这些开拓进取的事情 Java 社区做得比较少,大多都是企业级场景有需要才会推进。

另外个人感觉 Blazor server 感觉还比较实验性,没有 Phoenix Liveview 的实现方式那么 production ready 。

Stateful WebSocket 真正的困难在于性能和部署模型。比如每个用户都有一个独立的 counter 对象,每个有自己的状态:*个问题是这个框架怎么自动把不同用户的 counter 均匀的分散在所有的 server 上,这样才能横向扩展支持大量用户。第二个问题是用户从 load balancer 过来,每次请求的 server 可能不一样,怎么即不靠 sticky session,又能让每次用户可以和自己的 counter 互动。

Phoenix Liveview 的方式是靠 Erlang process group 构成全联通网络,不仅能支撑大量连接,还不需要 sticky session,看起来是比较合理的方式。这种方式不流行是因为这个实现方式主要依赖 Erlang 独特的虚拟机模型,其他语言的技术栈很难模仿。

我之前看的时候 Blazor server 似乎必须单机 / sticky session / 用 Azure SignalR,不知道现在还是不是这样,如果还是的话横向扩展性明显有问题。不过我感觉如果解决这个需要动上层 API 或者修改 C# / CLR,都是很大的工程,而且会影响到框架的用户。
ikas 28
ikas 2 小时 26 分钟前
teavm.org/live-examples/todomvc/#/
msaionyc 29
msaionyc 2 小时 1 分钟前
@huang119412 微软作了什么恶,不是阴阳怪气,是真的不了解
Mirage09 30
Mirage09 2 小时 1 分钟前
@cxe2v lol 微软这种 tier 2 公司还真挺好进的
Itoktsnhc 31
Itoktsnhc 1 小时 48 分钟前
@namelosw 类比 erlang,blazor-server+Orleans 可能更类似,状态都基于 Actor(grain)来实现
cassyfar 32
cassyfar 1 小时 40 分钟前
真的有人用 .net 吗?上一次使用还是 10 几年前在课堂上写一个桌面的记事本。。。现在拿 .net 写什么呢?流量都走向移动了,桌面应用也全是跨平台的 UI 了。
thtznet 33
thtznet 1 小时 26 分钟前 ❤️ 1
@cassyfar 这个世界不是只有 抖音、微信、知乎、美团、携程的,这个世界还有山崎马扎克、西门子、博世、通快、ASML 、台塑、英特尔、金田豪迈、GE 、FAG 、波音等行业巨头,计算机软件已经深入各行各业,工业界的应用深度比消费界大得不知道哪里去了,只是不常在媒体上蹦跶罢了。
namelosw 34
namelosw 1 小时 25 分钟前
@Itoktsnhc 是,但是又少了 Blazor 那层。不知道微软为啥没搞 Blazor + Orleans 的技术栈。

可能是比起 Blazor Orleans 更非主流一点…… 而 Blazor 微软希望有天能当主流技术用。 微软不可能把 CLR 改成 Erlang BEAM,Orleans 实现只能靠很多 code gen 。
ccppgo 35
ccppgo 22 分钟前
@chouchoui 你这句话我竟然看不懂你在嘲讽哪边, 是微软还是开源
leeg810312 36
leeg810312 19 分钟前
@ccppgo 我的理解他应该是嘲讽微软黑,有些人自认为被微软坑了,所以要一辈子黑微软
leeg810312 37
leeg810312 16 分钟前
@cassyfar 所以你会用的所有技术都是 10 几年前么
yejinmo 38
yejinmo 12 分钟前
@cassyfar

.Net 早已变成了后端为主的语言了

如何终止一个正在进行的协程?

利用 context.WithCancel()来终止协程,但存在一个问题:cancel()执行后,必须等 for 循环执行完毕 goroutine 才退出。

for {
select {
case <-Ctx.Done():
return
default:
for i := 0; i < 100; i++ {
// 业务逻辑
}
}
}
需求为:cancel()后协程立马退出不再执行后面的循环。
目前我的解决方法:单独起一个协程用来监听退出信号,然后通过全局变量通知业务逻辑循环退出。

flag := false
go func() {
for {
select {
case <-Ctx.Done():
flag = true
return
}
}()

for i:=0; i < 100; i++ {
if flag {
return
}
// 业务逻辑
}
请问*佳实践应该是如何退出?

第 1 条附言 · 1 小时 23 分钟前
是这样一个场景:用户创建任务,起一个 goroutine 去执行,执行过程中,用户想要取消这个任务。
第 2 条附言 · 1 小时 16 分钟前
for i := 0; i < 100; i++ {
select {
case <-Ctx.Done():
return
default:
// 业务逻辑
}
}
感谢大家的回答,每次循环都检测一次退出信号就好了。
延伸出另一个问题:用户取消任务,如何让default里的业务逻辑立马终止?

第 3 条附言 · 56 分钟前
看了一下os.exec.cmd.Start()的源码

if c.ctx != nil {
c.waitDone = make(chan struct{})
go func() {
select {
case <-c.ctx.Done():
c.Process.Kill()
case <-c.waitDone:
}
}()
}
另起一个goroutine监听cancel(),然后kill掉执行的process。
类比本问题,一个协程执行任务,一个协程监听任务的cancel(),任务取消直接kill掉执行任务的协程且监听协程也退出。

协程 return flag for10 条回复 • 2021-08-30 17:11:31 +08:00
dream10201 1
dream10201 1 小时 53 分钟前
瞎想的,你把 select case 放到 for 循环里面不行?
dream10201 2
dream10201 1 小时 52 分钟前
for {
for i := 0; i < 100; i++ {
select {
case <-Ctx.Done():
return
default:
// 业务逻辑
}
}
}
rimutuyuan 3
rimutuyuan 1 小时 50 分钟前
“`
for {
for i := 0; i < 100; i++ {
select {
case <-Ctx.Done():
return
default:
// 业务逻辑
}
}
}“`
BBCCBB 4
BBCCBB 1 小时 50 分钟前
这种可以在 for 里每次检测 ctx.Done()… 不过不是*佳实践.
和你图中这个方法差不多,, 不过不知道你图中这个方法有没有变量可见性的问题? 导致 flag=true 后在当前协程并不可见?
777777 5
777777 1 小时 27 分钟前
@BBCCBB 是可见的
777777 6
777777 1 小时 24 分钟前
@dream10201 这样有问题吧,如果不调用 cancel(),*外面 for 循环不会退出。
sadfQED2 7
sadfQED2 1 小时 10 分钟前 via Android
这个问题我在 java 里面也研究过,*后结果就是无解,只能业务代码里面每次循环都判断
xx6412223 8
xx6412223 1 小时 4 分钟前
直接退出就不是合理的设计。
caryqy 9
caryqy 52 分钟前
执行前检查 Done,

执行后提交前再次检查 Done,根据结果来收尾。

考虑的粒度即使再细都会碰到 执行中取消 这个问题,所以到某个程度之后就 禁止用户取消
haochen2 10
haochen2 6 分钟前
如果业务逻辑超时运行或着阻塞,根本走不到 ctx.Done 那个 case 的地方

10 Android 开发工具兼容性/版本搭配

由于几个月前电脑 CPU 烧了,被迫换了 M1 的 Mac Mini,所以整个开发环境重新搭建了一遍。趁这个机会,我想整理几个基础工具的版本搭配策略、兼容性、以及在 M1 芯片上的表现。对于版本搭配和兼容性的一些讨论不局限于当前使用的版本和平台。

下方提及的版本分别是:

  • Zulu JDK: 11.0.11
  • Kotlin: 1.5.21
  • Gradle: 7.1.1
  • Android Gradle Plugin ( AGP ): 7.0 & 7.1
  • Android Studio: Arctic Fox 2020.3.1 & BumbleBee 2021.1.1 Canary 6

JDK

自 AGP 7.0 起,JDK 11 便是*低要求。JDK 11 成为 LTS ( Long-term Support) 版本已经有将近 3 年历史( Sep 2018 ),自身经历了 12 个小版本( 11.0.12 )的迭代目前相对成熟了。作为对比,上一个 LTS 的 JDK 8 2014 年发布,已经陪着我们走过了 7 年时光和 300 个小版本迭代。事实上作为 Android 开发者,即便目前项目是 Java 为主的情况,一般 Language Level 也仅 target to 1.8 (一些 9-12 的特性 D8 、R8 有支持,Android 11 12 也有融入)。Android 官方虽然说不会放弃 Java,但实际上对 Kotlin 的支持确实更给力。

从这个角度来看,JDK 11 带来给我们的更多是:

  • Kotlin Compiler 、Gradle 、IDE 层面上性能的升级;
  • JDK 8 将停止维护的情况下( 3 年后),安全层面的持续保障;
  • 适应新的发布机制,每半年一个小版本,三年一个 LTS 大版本,减少历史包袱跑得更快;

而 JDK 的升级策略我认为是:

  • 保守派:如果不在意新语言特性,可以等每年 AGP 升级的情况来决定 JDK 的版本,因为 IDE 一般 bundle 了一个 JDK,Kotlin 编译器、Gradle 一直追着*新 JDK 并有不错的向下兼容——所以根据木桶原理等 AGP 升级了再升即可,目前看来 AGP 可能也只跟进比较稳定的 LTS 版本;
  • 激进派:Gradle 支持后即可测试;

在 M1 Mac 上,由于 Oracle 还未有的 ARM64 版本,所以目前主流的做法是安装 Azul 维护的 Zulu JDK11

%title插图%num

需要注意的是,常用的 JDK 管理工具 SDKMAN! 在我的测试中依旧跑在 Rosetta 2 的转译环境中。这会造成即便你是安装的 Zulu JDK11,通过 SDKMAN! 的脚本启动依然会显示 Gradle java 的进程跑在 Intel ABI 下。故目前建议从官网下载安装,等后续配套工具支持后再考虑切换。

%title插图%num

Kotlin

Kotlin 的版本搭配限制相对不多,一般我考虑三个点:

  • 有没有特别吸引人的新功能,比如刚放出稳定版的 Coroutine 、Flow,或者新版本 Kotlin Multiplatform Mobile 的更好支持等;
  • 用不用大迭代的*个版本,例如观察刚发布时的 1.4.01.5.0,这条其实广泛适用于各类 Library ;
  • Gradle 目前 bundle/test 的 Kotlin 的版本,例如*新的 7.1.1 stable 依旧是用的 1.4.31 的 Kotlin ( 7.2 RC 则跳到 1.5.21 了);

关于*后一点,如果使用的 Kotlin 版本和 Gradle bundle 的不一致,会出现如下 Warning:

w: Runtime JAR files in the classpath should have the same version. >These files were found in the classpath: … /Users/2bab/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib-jdk7/1.4.31/84ce8e85f6e84270b2b501d44e9f0ba6ff64fa71/kotlin-stdlib-jdk7-1.4.31.jar (version 1.4) /Users/2bab/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib/1.5.21/2f537cad7e9eeb9da73738c8812e1e4cf9b62e4e/kotlin-stdlib-1.5.21.jar (version 1.5) /Users/2bab/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib-common/1.5.21/cc8bf3586fd2ebcf234058b9440bb406e62dfacb/kotlin-stdlib-common-1.5.21.jar (version 1.5) w: Consider providing an explicit dependency on kotlin-reflect 1.5 to prevent strange errors w: Some runtime JAR files in the classpath have an incompatible version. Consider removing them from the

用一个简单的例子看下问题是怎么发生的:

plugins {
    id("com.android.application")
    // 没有指定版本,用的就是 Gradle bundle 的版本,
    // Gradle 7.1.1 对应的就是 Kotlin 1.4.31 的各种类库和编译工具
    kotlin("android") 
}

dependencies {
    // 而这里我们却用了 1.5.21 的*新版 Kotlin,就会出现如上问题
    implementation("org.jetbrains.kotlin:kotlin-stdlib:1.5.21")
}

解决起来也很简单:

plugins {
    id("com.android.application")
    // 手动指定版本
    kotlin("android") version "1.5.21"
}

Kotlin 官方的文档直接就演示了加版本号的写法。但是,这个版本是 Kotlin 基于 Gradle 测试通过,而 Gradle 自身还没有基于它测试过并打包进去(见 Gradle 部分的配图),若出现了问题可能难以解决

所以我推荐的升级策略是:

  • 保守派:等 Gradle 升级的时候再升级,例如 1.5.0 到 1.5.21 中间仅隔了两个月,Gradle 就跟进了;
  • 激进派:有实用的新功能或者大版本迭代后的*个补丁版本就升。

Gradle

前面提到 Kotlin 的官方文档解释了各类和 Gradle 配合兼容的情况,反过来 Gradle 这边也有一个标明了 Java 、Kotlin 、Android 等各语言和平台的支持文档。

 

像前面提到的 Java 版本支持,Kotlin 版本支持在这里便一目了然。除了 Kotlin 的支持会稍落后一两个月,其他工具的*新版本兼容都不成问题。而 Gradle 自身的向下兼容我觉得还不错,我基本上每个版本都升级。而上层的 AGP DSL,特别是老版本,则挺经常有大改动(好在 7.0 后终于强多了)。

所以我推荐的升级策略是:

  • 保守派:根据 AGP 的文档按*低版本进行升级(详见下图),例如 AGP 4.2.0+ 对应 Gradle 6.7.1+;
  • 激进派:每个补丁版本(x.y.1/2/3)或者每个版本都升( Gradle 没有 -betaX 的版本习惯,一般就是 Nightly 和 RC )。

%title插图%num

另外,Gradle 7.0 后的版本原生支持了 M1,我个人的使用体验还不错。

Android Gradle Plugin

AGP 的版本搭配限制我们在前面基本都介绍完了,以 7.0 为例,我们来看官方 Release Note 的兼容说明:

%title插图%num

额外补充一点:从 AGP 7.0 起,其版本会同步 Gradle 的 major 版本,严格遵守 Semantic Versioning 体系(之前同步的是 AS 的版本)。也即 AGP 7.x 会适配 Gradle 7.x 的版本。不过 AGP 的发布时间依旧是随着 AS 一起发布,并且目前来看其 alpha/beta 的数字是跟随 AS 的,所以其实可以当成三者形成了某种默契的同步机制。

所以我推荐的升级策略是:

  • 保守派:随 AS 正式版升级(或适当跳过*个大版本更迭);
  • 激进派:每个版本都升,或从 alpha/beta 开始升级,例如要做 Gradle 插件适配。

Android Studio

AS 基本上没有什么搭配限制,只要你用的之前正式版的 AGP,AS 就可以向下兼容。我推荐的升级策略是:

  • 保守派:适当跳过*个大版本更迭;
  • 激进派:每个版本都升,或从 alpha/beta 开始升级,例如要做 IDE 插件适配或者对 Compose 、调试工具新功能等有需求的。

另外,由于 AS 基于的 IDEA 社区版二次开发,整体稳定性、新特性支持的速度都不如 IDEA Ultimate,例如 Gradle 的 nesting Composite Build 目前就不在 AS 支持范围,见该 issue。

*后,自 Arctic Fox 2020.3.1 起,AS 原生支持了 M1,但如果想有更流畅的体验,我认为 BumbleBee 2021.1.1 Canary 效果更好一些。

IDEA

IDEA 的主要搭配限制来自于 Android Plugin ( Android IDE 插件)的版本适配。一般来说,在 AS 新的正式版本发布之后,下一个 IDEA 的正式版本就会带上该新版插件,从而对 Android 开发包括 AGP 做支持。

%title插图%num

偶尔也有等比较久的时候,比如今年 AS&AGP 4.2 在 4 月发布,而直到 7 月 IDEA 2021.2 发布时,才更新了 Android Plugin,官方的说法是 Google 放出 AGP 4.2 的源码时间晚了些,导致没赶上 2021.1 的版本。

我推荐的升级策略是:

  • 保守派:仅升级正式版本;
  • 激进派:从 EAP 或 RC 开始升级,例如会获得比较好的 Kotlin 支持、更早的 AGP 支持,以及 M1 平台的优化等。

*后,2021.2 也是让我在 M1 感觉终于不再有什么卡顿的版本了。

总结

我自己由于使用 M1 的平台 + 适配一些 Gradle Plugin,经常会使用 beta 甚至 alpha 的 AGP (作为 Runtime 的 library ),配合*新的 IDEA Ultimate 开发起来还是挺顺手。

而公司项目,现阶段 x86 平台我觉得可以使用如下配置,ARM M1 则根据上文调整对应的工具版本:

  • JDK 11 (由于 AGP 升了迟早要升级)
  • Gradle 7.1.1 ( 7.2 支持 1.5.21 后可以升级)
  • Kotlin 1.4.31
  • AGP 4.2.2 ( 7.0 稳定了新版的 Variant API,马上 7.1 也稳定新版的 DSL,不需要 Compose 的话可以观望观望)
  • AS 4.2.2 (不需要 Compose 的话可以观望观望)
  • IDEA 2021.2

请教下 ViewModel 和 Adapter 该如何结合以实现动态加载

如题,我的 ViewModel 类中有一个列表结构的数据,需要动态加载,代码如下:

class TimelineViewModel : ViewModel() {
    val timelines = MutableLiveData<List<TimelineModel>>(emptyList())

    private var nextTime = System.currentTimeMillis()

    fun getTimeline() {
    	viewModelScope.launch {
            try {
                val respData = Repository.getTimeline(nextTime)
                if (respData.data != null) {
                    nextTime = respData.data.feeds.nextTime
                    val timelineModels = respData.data.feeds.data.filterNotNull().map {
                        TimelineModel(it)
                    }
                    timelines.value = timelines.value.let {
                        if (it == null) {
                            timelineModels
                        } else {
                            it + timelineModels
                        }
                    }
                }
            } catch (e: Exception) {
                Log.e(TAG, "Network Request Fail", e)
            }
        }
    }
}
  • 如果在视图层直接使用 MutableLiveData#observe 方法观察这个数据,那么观察到的是整个 List 数据的变化,那么该怎么将其转化为 Adapter 的添加元素的行为?
  • 或者应该怎么处理这种需要修改列表数据的场景?

nexttime

val

viewmodel

lue

3 条回复    2021-08-24 19:57:24 +08:00

omysho
    1

omysho   15 天前 via Android   ❤️ 1

有个东西叫 DiffUtil

还有个东西叫 AsyncListDiffer

还有个东西叫 ListAdapter 继承自 Recycler.Adapter 需要一个 ItemDiffCallback 作为构造参数

pigspy
    2

pigspy   15 天前

@omysho

非常感谢

122006
    3

122006   5 天前

androidx 的 recycleview 自带,直接继承 listadapter 就行

华为市场上架,多次被拒都是说 App 无法启动(闪退)

华为市场上架,多次被拒都是说 App 无法启动(闪退),但各种测试都没办法复现闪退问题,华为没有给更多的有效信息……

 

3dot14159 · 18 天前 · 2499 次点击

已经尝试的操作:

  • 本地的好几部华为手机上反复尝试,无闪退
  • 之前给一些用户试用,无闪退
  • 华为提供的云真机服务,无闪退
  • App 有接入 Sentry,也没有收到任何报错信息
  • 其他几个应用市场审核时也没有说遇到闪退

问客服要要 stack trace 、logcat 之类,但客服只给了一张截图,截图内容就是纯粹的手机的桌面,标注着点了一下 App 按钮。然而这似乎并没有什么有效信息用来调试……

请教各位大佬,应该怎么处理?

25 条回复    2021-08-25 17:01:01 +08:00

xieqiqiang00
    1

xieqiqiang00   18 天前 via Android

提交一个 debugger 上架?
EarthChild
    2

EarthChild   18 天前   ❤️ 1

放弃华为客户,转化潜在华为客户去其他手机品牌。贵司提高运维费用,提供非华为手机设备等方案。
3dot14159
    3

3dot14159   18 天前

@xieqiqiang00 平时 Sentry 捕捉异常做的挺好,然而看 sentry 控制台没有收到任何上报信息,猜测是闪退的位置在非常靠前的位置,导致连 sentry 都抓不到……
zlhsvc
    4

zlhsvc   18 天前

有试过无卡只有 wifi 吗
janus77
    5

janus77   18 天前

有可能是流程问题,其实他们也不知道是否真的闪退了,只是按流程拒了而已,说不定真实情况是搞错了。
我的办法是等几天说已解决,然后提交一个新版本,其实是原封不动的。
3dot14159
    6

3dot14159   18 天前

@zlhsvc 试了,没问题
@janus77 提交好多次了
YaakovZiv
    7

YaakovZiv   18 天前

如果华为商城一直没有给解决,有以下办法
1 、反馈到华为的花粉俱乐部。
2 、邮件反馈给华为开发者联盟
3 、你们的官网提供 APP 的安装包,让用户直接网站下载安装
4 、找个专门测试 APP 的平台批量测各种华为手机场景。
kkocdko
    8

kkocdko   18 天前 via Android

华为的应用审核总是独树一帜,要我说,能过 Google Play 审核的应用,就理应通过所有第三方商店的审核。
之前看到过一个帖子: /t/789757 不知道对你有没有帮助,没帮助当我没说
3dot14159
    9

3dot14159   18 天前

@YaakovZiv 2,3 都试过,我再试下 1,4
@kkocdko 那个帖子好像不太一样
darkengine
    10

darkengine   18 天前

找客服要测试机的型号,系统版本,语言这些环境信息,然后买一台自己试试。

 

zhigang1992
    11

zhigang1992   18 天前

如果 splash screen 太大了,在某一些设备 上可能会直接奔溃

这种的话 Sentry 也没有机会收集到奔溃日志,因为一启动就奔了

gangoogle
    12

gangoogle   18 天前

华为有个自动化测试,你可以试一试 我之前的项目就在某些机型上出 bug 一般是因为系统版本兼容问题
doveyoung
    13

doveyoung   18 天前

小黄鱼买一台同型号
NEVERCODE
    14

NEVERCODE   18 天前

没有崩溃反馈吗?或者直接写个大 try……
3dot14159
    15

3dot14159   18 天前

@darkengine @doveyoung 客服给了,但客服反馈好几台不同型号的测试机都出问题(我们仍然没法复现)
@zhigang1992 启动页就是个居中的小图标,挺小的
@NEVERCODE 没有;估计是安卓启动阶段的问题吧……我们是 Flutter 应用,理论上 flutter 的安卓代码不应该有这种低级错误的
@gangoogle 用过云真机,试过好多设备都没有复现
sagowave2
    16

sagowave2   18 天前

我们一开始是华为闪退 后来上架小米也闪退 但是在云测平台和真机测试中 都没有闪退 怪得很
Maxbee
    17

Maxbee   18 天前

上周上架一个 iOS app 也是这样,改了几次实在不知道什么原因,回复了个邮件给审核人员,过了几天居然上架了~
wvitas
    18

wvitas   18 天前

哎,华为的应用市场净整些乱七八糟的,
1 、app 的 icon 角标上有个”热门”被拒,其他应用商店和 ios 的也有,一样过。
2 、之前都审核好好的,一个提交表单的弹框,底部有”用户协议”和”隐私”,但是没有 CheckBox,被拒,说我们强制用户同意, 其他应用商店和 ios 审核过。
wvitas
    19

wvitas   18 天前

还补充一点,之前有 CheckBox 的你还不能默认选中,也被拒过。ios 被拒的频率都没有它高
thtznet
    20

thtznet   17 天前

做安卓开发,也要有点追求,不能自甘堕落,先通过 Google Play 。
yikuo
    21

yikuo   17 天前 via Android

手机区域和网络因素考虑了吗?审核人员有时候是用英国区域的。
BotStrong
    22

BotStrong   17 天前

问客户要一下 bugreport

获取并阅读错误报告:
https://developer.android.com/studio/debug/bug-report?hl=zh-cn

然后看里面的日志

Danmen123
    23

Danmen123   17 天前

1.集成华为分析里面的崩溃分析 SDK
2. 再次提交等他们测试,如果他们测试还是有崩溃信息的话,
3. 华为分析后台里面的崩溃分析里面就可以看到崩溃的日志,
我自己的应用都是这么干的,要注意一点如果有混淆的话,记得配置自动上传混淆文件的代码,这些他文档里面都有。
另附上直通车: https://developer.huawei.com/consumer/cn/doc/development/AppGallery-connect-Guides/agc-crash-introduction-0000001055732708
ericgui
    24

ericgui   17 天前

华为的用户量有多少?
lijianqiang12
    25

lijianqiang12   4 天前

是不是打包的时候只打了 v8?把 v7a 也加进去吧,不然老手机上会崩。

Jetpack MVVM Android 业务架构一览图分享

感谢小伙伴们实事求是的交流,经过长达 2 年的互动和演化,本示例项目的架构流程已基本确立,

此处分享一份架构流程图,感兴趣可自行保存和查阅。

架构 一览 流程图 mvvm8 条回复 • 2021-08-27 17:18:44 +08:00
KunMinX 1
KunMinX 4 天前
经过我们的调研,70% 以上的公司仍在使用 java 开发或维护项目,而 java 项目又是 “null 安全一致性问题” 高发的场景,因而关于 Jetpack MVVM,我们专注且只分享 java 语言背景的案例,

kotlin 如今官方推广已有 4 年,有条件请及早上车 kotlin,以及尝试 compose 等框架。
huangshengjie 2
huangshengjie 4 天前
好家伙,我在 V2 学 Android !
glovebx 3
glovebx 3 天前
新项目不建议用 LiveData,Flow 是正道
ParfoisMeng 4
ParfoisMeng 3 天前
Google 的更新迭代属实迷糊(狗头
KunMinX 5
KunMinX 3 天前 ❤️ 2
自从上周 google 在播客中提到 “flow 是否会取代 liveData”,之后各种关于 “LiveData 被下岗” 的人云亦云不*于耳,

事实上,Flow 在处理 “表现层” 逻辑及 “页面间通信” 逻辑时的表现糟糕透顶,至少目前来看完全不足以胜任这方面的精细化定制需求,

flow 本来就是操作业务数据的工具,硬生生为其加入 state 等表现层的概念,试图通过 repeatOnLifecycle 等半生不熟的函数来取代 LiveData 在这方面的工作 …

个人预计 “将 flow 用于改变 UI 状态和页面间通信” 的设计,至少 1 年内都不足以演化为在线上环境使用。
cenbiq 6
cenbiq 3 天前
我理解的异步 /请求等通通 flow,消息传递用 liveData
iovekkk 7
iovekkk 3 天前
好贴,顶大佬
bugmaker233 8
bugmaker233 2 天前
@glovebx flow 配合 livedata 使用美滋滋,怎么就不建议了

华为第三方 rom 怎样才能移植原系统 EMUI 的”定时开关机”功能?

华为第三方 AOSP rom 为何都不移植 EMUI”定时开关机”功能?
VKRUSSIA · 2 天前 · 1724 次点击
第三方 rom 怎样才能移植原系统 EMUI 的”定时开关机”功能?

emui ROM 关机 移植9 条回复 • 2021-08-28 16:11:36 +08:00
timpaik 1
timpaik 2 天前 via Android ❤️ 1
可能是有硬件实现,没有驱动吧
ysc3839 2
ysc3839 2 天前 via Android
尝试逆向看看吧。
Ehend 3
Ehend 2 天前
定时关机可能还好说,开机不通过硬件怎么可能
NSAgold 4
NSAgold 2 天前 via Android
华为这种解 bl 锁都只能深水宝的,哪来开发者作第三方包
WebKit 5
WebKit 2 天前
华为还有第三方 ROM 。记忆里很早就禁止 OEM 解锁了啊
treo 6
treo 2 天前
这个功能很老年人
dingwen07 7
dingwen07 2 天前 via iPhone
@timpaik #1 Android 的驱动应该在 Linux 内核里,肯定是开源的
zxcslove 8
zxcslove 2 天前
二奶机必备功能
0x11901 9
0x11901 1 天前
@dingwen07 nope,为了让驱动不开源,Google 想了个“点子”绕过了 GPL,所以安卓被 Linux 内核除名。

iOS对象(数组)转化为JSon字符串

– (void)seabc

{

    NSArray *arry=[NSArray arrayWithObjects:@”0081″,@”0082″,@”0083″, nil];

    NSString *ss = [self objArrayToJSON:arry];

    NSString * datsa = [NSString stringWithFormat:@”pictures=%@”,ss];

    NSLog(@”jsonStr==%@”,datsa);

    NSString *url = [NSString stringWithFormat:@”http://app.y-x-q.cn/index.php/interfaces/Articleapi/test1″];

    

    [RequstHttp postWithPathURL:url params:datsa succes:^(NSData *json) {

        NSLog(@”json:%@”,[[NSString alloc]initWithData:json encoding:NSUTF8StringEncoding]);

    } failure:^(NSError *error) {

    }];

    

}

//把多个json字符串转为一个json字符串

– (NSString *)objArrayToJSON:(NSArray *)array {

    

    NSString *jsonStr = @”[“;

    

    for (NSInteger i = 0; i < array.count; ++i) {

        if (i != 0) {

            jsonStr = [jsonStr stringByAppendingString:@”,”];

        }

        jsonStr = [jsonStr stringByAppendingString:array[i]];

    }

    jsonStr = [jsonStr stringByAppendingString:@”]”];

    

    return jsonStr;

}

友情链接: SITEMAP | 旋风加速器官网 | 旋风软件中心 | textarea | 黑洞加速器 | jiaohess | 老王加速器 | 烧饼哥加速器 | 小蓝鸟 | tiktok加速器 | 旋风加速度器 | 旋风加速 | quickq加速器 | 飞驰加速器 | 飞鸟加速器 | 狗急加速器 | hammer加速器 | trafficace | 原子加速器 | 葫芦加速器 | 麦旋风 | 油管加速器 | anycastly | INS加速器 | INS加速器免费版 | 免费vqn加速外网 | 旋风加速器 | 快橙加速器 | 啊哈加速器 | 迷雾通 | 优途加速器 | 海外播 | 坚果加速器 | 海外vqn加速 | 蘑菇加速器 | 毛豆加速器 | 接码平台 | 接码S | 西柚加速器 | 快柠檬加速器 | 黑洞加速 | falemon | 快橙加速器 | anycast加速器 | ibaidu | moneytreeblog | 坚果加速器 | 派币加速器 | 飞鸟加速器 | 毛豆APP | PIKPAK | 安卓vqn免费 | 一元机场加速器 | 一元机场 | 老王加速器 | 黑洞加速器 | 白石山 | 小牛加速器 | 黑洞加速 | 迷雾通官网 | 迷雾通 | 迷雾通加速器 | 十大免费加速神器 | 猎豹加速器 | 蚂蚁加速器 | 坚果加速器 | 黑洞加速 | 银河加速器 | 猎豹加速器 | 海鸥加速器 | 芒果加速器 | 小牛加速器 | 极光加速器 | 黑洞加速 | movabletype中文网 | 猎豹加速器官网 | 烧饼哥加速器官网 | 旋风加速器度器 | 哔咔漫画 | PicACG | 雷霆加速