女人自慰AV免费观看内涵网,日韩国产剧情在线观看网址,神马电影网特片网,最新一级电影欧美,在线观看亚洲欧美日韩,黄色视频在线播放免费观看,ABO涨奶期羡澄,第一导航fulione,美女主播操b

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

如何在鴻蒙系統(tǒng)弄一個(gè)彩票查詢卡片

OpenHarmony技術(shù)社區(qū) ? 來源:HarmonyOS技術(shù)社區(qū) ? 作者:中軟國際 ? 2021-09-06 09:17 ? 次閱讀

接觸鴻蒙開發(fā)已經(jīng)有 3 個(gè)來月了,最近開始在看鴻蒙卡片開發(fā)。因?yàn)橹暗拈_發(fā)大都是基于 Java UI,但按官方的說法,JS 卡片相比 Java 卡片有更大的優(yōu)勢,故決定寫個(gè) JS 卡片的 demo 來練練手。

碰巧,前幾天和媳婦兒在散步時(shí)撿到 1 元錢,沒能交給警察叔叔,媳婦兒就提議“我們把它昧了吧,買張彩票。”

由于不是老 CM,沒有關(guān)注開獎(jiǎng)的習(xí)慣,想著要是能把開獎(jiǎng)結(jié)果放在手機(jī)桌面顯示就好了,這樣就不會(huì)錯(cuò)過我一夜暴富的機(jī)會(huì)了。有了需求就開擼,然后就有了這篇文章!

項(xiàng)目簡介

①本項(xiàng)目基于 API 6 開發(fā),demo 運(yùn)行在 API 6 以下的手機(jī)上會(huì)出現(xiàn)部分功能不能使用的現(xiàn)象。

②卡片功能上實(shí)現(xiàn)了***、福彩 3D 的最近一期開獎(jiǎng)結(jié)果查詢,點(diǎn)擊卡片“刷新”按鈕,調(diào)用接口更新最新數(shù)據(jù);點(diǎn)擊“查看更多”按鈕,跳轉(zhuǎn)至應(yīng)用主界面。

③應(yīng)用主界面上實(shí)現(xiàn)了***、福彩 3D 近 50 期開獎(jiǎng)結(jié)果查看。

④以上數(shù)據(jù)均使用了聚合數(shù)據(jù)的 https://www.juhe.cn/docs/api/id/300 免費(fèi)接口。

需申請 key,一個(gè) key 一天可免費(fèi)調(diào)用 100 次,如遇 key使 用次數(shù)過多導(dǎo)致接口請求失敗情況時(shí),開發(fā)者可自行申請 key 并替換 Constants.java 文件下的 JH_KEY 常量值),數(shù)據(jù)可能會(huì)有延遲。

⑤卡片開發(fā)部分使用了卡片的 JS UI 框架,但由于系統(tǒng) PA 與 FA 相互調(diào)用的限制問題,卡片的業(yè)務(wù)邏輯部分仍然采用 Java 代碼編寫。

PS:最開始的想法是盡量可能的少依賴 Java 代碼,故嘗試了 JS FA 與 Java PA 相互調(diào)用的方式,但當(dāng)應(yīng)用進(jìn)程被干掉時(shí),Java 端無法再調(diào)用到 JS 端方法。

這樣就導(dǎo)致 JS 只能寫 UI 部分,業(yè)務(wù)邏輯還得 Java 層實(shí)現(xiàn)。有知道解決辦法的也麻煩告知一聲。

⑥卡片業(yè)務(wù)層使用 Java 開發(fā),采用了簡單的 MVP 架構(gòu),網(wǎng)絡(luò)請求和數(shù)據(jù)處理部分使用了 rxjava3+retrofit 框架。

⑦應(yīng)用主界面使用了 JS-UI 框架實(shí)現(xiàn)。

實(shí)現(xiàn)效果

請忽略我粗陋的 UI 設(shè)計(jì)和 GIF 的渣渣像素。

項(xiàng)目代碼結(jié)構(gòu)分析

base:

IBasePresenter:MVP 架構(gòu)中 presenter 基類接口

IBaseView:MVP 架構(gòu)中 view 基類接口

network:

bean,LotteryBean:彩票詳情接口返回對應(yīng) model

CachedLotteryDetailUtil:彩票詳情接口請求工具類,主要作用是防止重復(fù)調(diào)用詳情接口

LogInterceptor:OKhttp 日志攔截工具類

LotteryAPI:接口請求類,通過 retrofit 注解,將接口返回?cái)?shù)據(jù)轉(zhuǎn)化為實(shí)體類

Services:配置 Retrofit 并提供

presenter:

IMainContract:MVP 中 view 與 presenter 的橋梁

MainPresenter:提供彩票詳情接口的請求,并處理接口返回?cái)?shù)據(jù)為卡片需要的 ZSONObject 對象

utils:

LogUtil:日志打印工具類

widget:

controller:FormController:創(chuàng)建卡片時(shí)自動(dòng)生成,卡片管理器的抽象基類;FormControllerManager:創(chuàng)建卡片時(shí)自動(dòng)生成,管理各個(gè) FormController 的工具類

dltwidget.DltWidgetImpl:大樂透卡片管理類,提供了創(chuàng)建卡片、更新卡片、刪除卡片、卡片點(diǎn)擊事件等行為的回調(diào)方法

fcsdwidget.FcsdWidgetImpl:福彩 3D 卡片管理類,提供了創(chuàng)建卡片、更新卡片、刪除卡片、卡片點(diǎn)擊事件等行為的回調(diào)方法

ssqwidget.SsqWidgetImpl:雙色球卡片管理類,提供了創(chuàng)建卡片、更新卡片、刪除卡片、卡片點(diǎn)擊事件等行為的回調(diào)方法

Constants:常量工具類。

MainAbility:HAP 的入口 ability,由 DevEco Studio 自動(dòng)生成。同時(shí)也是各個(gè)卡片對應(yīng)的 Ability,用來項(xiàng)各個(gè) FormController 分發(fā)事件。

default:

common,component/lottery:應(yīng)用首頁列表 item 組件;images :資源圖片

pages,home:應(yīng)用首頁

dlt_widget:

common:資源圖片存放目錄

pages/index,index.css :大樂透卡片 css 樣式;index.hml:大樂透卡片布局文件;index.json:包含頁面默認(rèn)值

fcsd_widget:目錄結(jié)構(gòu)同 dlt_widget。

ssq_widget:目錄結(jié)構(gòu)同 dlt_widget。

詳細(xì)實(shí)現(xiàn)過程

①創(chuàng)建雙色球卡片

在目錄 entry 上點(diǎn)擊右鍵,在彈出的菜單中選擇 New,然后在彈出的子菜單中點(diǎn)擊 Service Widget,如下圖所示:

在模板選擇界面,選擇基本的模板 Grid Pattern,點(diǎn)擊按鈕 Next,進(jìn)入到卡片配置界面:

首先配置卡片的名稱和描述;然后配置卡片關(guān)聯(lián)的 Page Ability;然后配置卡片的編程語言類型是 JS;接下來配置卡片的 JS 組件名稱;最后配置卡片支持的規(guī)格,勾選支持 2x4、4x4 規(guī)格。

重復(fù)上述步驟,創(chuàng)建出大樂透和雙色球卡片。運(yùn)行項(xiàng)目,長按圖標(biāo)打開卡片管理界面,我們能看到剛創(chuàng)建的 3 類卡片,且每類卡片對應(yīng) 3 種不同樣式,如下圖所示:

②繪制雙色球卡片 UI

我們編寫雙色球界面:

《!--index.hml--》《div class=“container”》

《div》

《text class=“text”》雙色球《/text》

《text class=“text-small” style=“margin-left : 15px;” if=“{{ cardType2x4 || cardType4x4 }}”》每周二、四、日開獎(jiǎng)《/text》

《text class=“text” style=“margin-left : 75px;” if=“{{ cardType2x4 || cardType4x4 }}” onclick=“showMore”》 查看更多

《/text》

《/div》

《div style=“margin-top : 10px; align-content : center;”》

《text class=“text-small” style=“margin-right : 10px;”》第{{ lotteryData.lottery_no }}期《/text》

《text class=“text-small” if=“{{ cardType2x4 || cardType4x4 }}”》 開獎(jiǎng)日期:《/text》

《text class=“text-small”》 {{ lotteryData.lottery_date }}《/text》

《/div》

《div style=“flex-wrap : wrap; margin-top : 10px;”》

《text class=“ball” for=“{{ lotteryRed }}” tid=“id”》{{ $item }}《/text》

《text class=“ball” style=“background-color : blue;” for=“{{ lotteryBlue }}” tid=“id”》{{ $item }}《/text》

《/div》

《div class=“amount-box” if=“{{ cardType2x4 || cardType4x4 }}”》

《div style=“flex-direction : column;”》

《text class=“text-small”》本期全國銷量《/text》

《text class=“text-amount”》{{ lotteryData.lottery_sale_amount }}《/text》

《/div》

《text class=“diver”》《/text》

《div style=“flex-direction : column;”》

《text class=“text-small”》累計(jì)獎(jiǎng)池《/text》

《text class=“text-amount”》{{ lotteryData.lottery_pool_amount }}《/text》

《/div》

《/div》

《div style=“flex-direction : column; padding-top : 10px; margin-bottom: 20px;” if=“{{ cardType4x4 }}”》

《div style=“background-color : green;”》

《text class=“text-prize”》獎(jiǎng)項(xiàng)《/text》

《text class=“text-prize”》中獎(jiǎng)條件《/text》

《text class=“text-prize”》中獎(jiǎng)注數(shù)《/text》

《text class=“text-prize”》單注金額(元)《/text》

《/div》

《div for=“{{ lottery_prize }}”》

《text class=“text-prize”》{{ $item.prize_name }}《/text》

《text class=“text-prize”》{{ $item.prize_require }}《/text》

《text class=“text-prize”》{{ $item.prize_num }}《/text》

《text class=“text-prize”》{{ $item.prize_amount }}《/text》

《/div》

《/div》

《div》

《text class=“text-small” if=“{{ cardType2x4 || cardType4x4 }}”》更新時(shí)間:《/text》

《text class=“text-small”》{{ updateTime }}《/text》

《image class=“refresh” src=“/common/image_1.png” onclick=“updateData”》《/image》

《/div》《/div》

《!--index.json--》

{

“data”: {

“cardType2x2”: true,

“cardType2x4”: false,

“cardType4x4”: false,

“l(fā)otteryData”: {

“l(fā)ottery_no”: “21081”,

“l(fā)ottery_date”: “2021-07-20”,

“l(fā)ottery_sale_amount”:“344,437,194”,

“l(fā)ottery_pool_amount”:“997,378,346”

},

“l(fā)otteryRed”:[“01”,“03”,“05”,“18”,“22”,“23”],

“l(fā)otteryBlue”:[“01”],

“updateTime”: “2021/07/07 1459”,

“l(fā)ottery_prize”:[

{

“prize_name”:“一等獎(jiǎng)”,

“prize_num”:“4”,

“prize_amount”:“10,000,000”,

“prize_require”:“6+1”

},

{

“prize_name”:“二等獎(jiǎng)”,

“prize_num”:“135”,

“prize_amount”:“207,725”,

“prize_require”:“6+0”

},

{

“prize_name”:“三等獎(jiǎng)”,

“prize_num”:“879”,

“prize_amount”:“3,000”,

“prize_require”:“5+1”

},

{

“prize_name”:“四等獎(jiǎng)”,

“prize_num”:“45659”,

“prize_amount”:“200”,

“prize_require”:“5+0,4+1”

},

{

“prize_name”:“五等獎(jiǎng)”,

“prize_num”:“1001881”,

“prize_amount”:“10”,

“prize_require”:“4+0,3+1”

},

{

“prize_name”:“六等獎(jiǎng)”,

“prize_num”:“6962930”,

“prize_amount”:“5”,

“prize_require”:“2+1,1+1,0+1”

}

},

“actions”: {

}

}

《!--index.css--》

.container {

width: 100%;

height: 100%;

padding: 10px;

flex-direction: column;

}

.text {

font-size: 15px;

}

.text-small {

font-size: 11px;

}

.text-amount {

font-size: 14px;

font-weight: bold;

color: darkred;

}

.text-prize {

font-size: 11px;

flex-weight: 25;

min-height: 20px;

text-align: center;

}

.ball {

width: 20px;

height: 20px;

text-align: center;

font-size: 12px;

margin: 4px;

color: #FFFFFF;

border-radius: 20px;

background-color: red;

}

.amount-box {

flex-direction: row;

align-items: center;

height: 30px;

}

.diver {

width: 1px;

height: 20px;

background-color: red;

margin-left: 15px;

margin-right: 15px;

}

.refresh {

width: 22px;

height: 22px;

}

編寫完成后,重新運(yùn)行,不出意外你應(yīng)該能看到如下效果:

這里提下卡片 JS-UI 框架的坑:

框架提供了原子布局來控制元素在不同尺寸布局上的隱藏和展示,但怎么說呢 ,一句話概括就是:你以為的并不是你以為的。

可以看到我這里放棄了 display-index 的使用,而采用通過 JAVA 端卡片的類型,來適配不同的 UI。

不同于應(yīng)用開發(fā)中的 JS UI 框架,這里的條件渲染不支持表達(dá)式。

css 不支持標(biāo)簽選擇器。

部分 css 樣式不能被繼承,例如給父 div 元素設(shè)置了 font-size,你會(huì)發(fā)現(xiàn) div 中的 text 組件并沒繼承上述樣式。

列表渲染的 for 循環(huán)的數(shù)組必須是 index.json data 對象的最外層。

不支持雙層 for 循環(huán)。

api6 不兼容 api5 的設(shè)備。

你會(huì)發(fā)現(xiàn)卡片 JSON 文件中的 data 對象數(shù)據(jù)結(jié)構(gòu)同接口返回的數(shù)據(jù)結(jié)構(gòu)有些差異,就是因?yàn)樯鲜鲈驅(qū)е碌摹?/p>

③獲取網(wǎng)絡(luò)數(shù)據(jù)

簡單的 MVP 架構(gòu),采用 Retrofit+RxJava 作為異步網(wǎng)絡(luò)請求框架。

build.gradle 中添加 RxJava 和 Retrofit 的依賴:

// RxJava

api ‘io.reactivex.rxjava33.0.3’

implementation ‘io.openharmony.tpc.thirdlib1.0.0’// retrofit

implementation ‘com.squareup.retrofit22.7.0’

implementation “com.squareup.retrofit22.1.0”

implementation ‘com.squareup.retrofit22.9.0’

config.json 文件中添加網(wǎng)絡(luò)權(quán)限:

// config.json“deviceConfig”: {

“default”: {

“network”: {

“cleartextTraffic”: true,

“securityConfig”: {

“domainSettings”: {

“cleartextPermitted”: true,

“domains”: [

{

subdomains”: true,

“name”: “apis.juhe.cn”

},

{

“subdomains”: true,

“name”: “v.juhe.cn”

}

}

}

}

}

},

“module”: {

。..

“reqPermissions”: [

{

“name”: “ohos.permission.GET_NETWORK_INFO”

},

{

“name”: “ohos.permission.SET_NETWORK_INFO”

},

{

“name”: “ohos.permission.INTERNET”

}

],

。..

}

創(chuàng)建接口請求:

// LotteryAPI.javapublic interface LotteryAPI {

@POST(“/lottery/query”)

@FormUrlEncoded

Observable《LotteryBean》 queryDetail(@Field(“l(fā)ottery_id”) String lottery_id, @Field(“l(fā)ottery_no”) String lottery_no, @Field(“key”) String key);

}

P 層和 V 層的接口比較簡單,不在羅列。編寫 P 層業(yè)務(wù)邏輯:

//MainPresenter.java@Overridepublic void loadLotteryData(long formId, String lotteryId) {

CachedLotteryDetailUtil.getLotteryDetail(lotteryId)

.flatMap((Function《LotteryBean, ObservableSource《ZSONObject》》) res -》 {

if (0 != res.getError_code()) {

Throwable throwable = new Throwable(res.getReason());

return Observable.error(throwable);

}

ZSONObject zsonObject = buildDataByResult(res);

return Observable.just(zsonObject);

})

.subscribeOn(Schedulers.io())

.observeOn(OpenHarmonySchedulers.mainThread())

.subscribe(new Observer《ZSONObject》() {

@Override

public void onSubscribe(@NonNull Disposable d) {

}

@Override

public void onNext(@NonNull ZSONObject result) {

if (mView != null) {

mView.onLoadDataSuccess(formId, result);

}

}

@Override

public void onError(@NonNull Throwable e) {

if (mView != null) {

mView.onLoadDataFailed(e);

}

}

@Override

public void onComplete() {

}

});

}

/**

* 根據(jù)接口返回的數(shù)據(jù),組裝成JS卡片需要的數(shù)據(jù)

*

* @param result

* @return

*/private ZSONObject buildDataByResult(LotteryBean result) {

LotteryBean.DetailBean detailBean = result.getResult();

ZSONObject data = new ZSONObject();

ZSONObject lotteryData = new ZSONObject();

lotteryData.put(“l(fā)ottery_no”, detailBean.getLottery_no());

lotteryData.put(“l(fā)ottery_date”, detailBean.getLottery_date());

lotteryData.put(“l(fā)ottery_sale_amount”, detailBean.getLottery_sale_amount());

lotteryData.put(“l(fā)ottery_pool_amount”, detailBean.getLottery_pool_amount());

data.put(“l(fā)otteryData”, lotteryData);

String[] ballArray = detailBean.getLottery_res().split(“,”);

if (“ssq”.equalsIgnoreCase(detailBean.getLottery_id())){

data.put(“l(fā)otteryRed”, Arrays.copyOfRange(ballArray, 0, 6));

data.put(“l(fā)otteryBlue”, Arrays.copyOfRange(ballArray, 6, 7));

} else if (“dlt”.equalsIgnoreCase(detailBean.getLottery_id())){

data.put(“l(fā)otteryRed”, Arrays.copyOfRange(ballArray, 0, 5));

data.put(“l(fā)otteryBlue”, Arrays.copyOfRange(ballArray, 5, 7));

} else if (“fcsd”.equalsIgnoreCase(detailBean.getLottery_id())){

data.put(“l(fā)otteryRed”, ballArray);

}

data.put(“updateTime”, new SimpleDateFormat(“yyyy-MM-dd HHss”).format(new Date()));

ZSONArray zsonArray = new ZSONArray();

for (LotteryBean.PrizeBean prizeBean : detailBean.getLottery_prize()) {

ZSONObject prize = new ZSONObject();

prize.put(“prize_name”, prizeBean.getPrize_name());

prize.put(“prize_num”, prizeBean.getPrize_num());

prize.put(“prize_amount”, prizeBean.getPrize_amount());

prize.put(“prize_require”, prizeBean.getPrize_require());

zsonArray.add(prize);

}

data.put(“l(fā)ottery_prize”, zsonArray);

return data;

}

④V 層調(diào)用 P 層,更新卡片

這里提下 MainAbility 的 onCreateForm 方法,它在進(jìn)入卡片管理界面時(shí)被調(diào)用,內(nèi)部通過 FormControllerManager 獲取了卡片對應(yīng)的 FormController,并調(diào)用了其 bindFormData() 方法。

由于我們卡片展示的數(shù)據(jù)來源于網(wǎng)絡(luò)請求,在對應(yīng)的 FormController 實(shí)現(xiàn)類中不太好獲得 formId,所以我們稍微改造一下 FormController 的 bindFormData 方法,把 formId 給傳進(jìn)去。

public abstract ProviderFormInfo bindFormData(long formId);

//MainAbility.javapublic class MainAbility extends AceAbility implements IMainContract.View {

private IMainContract.Presenter mPresenter;

@Override

public void onStart(Intent intent) {

。..

}

@Override

public void onStop() {

super.onStop();

}

@Override

protected ProviderFormInfo onCreateForm(Intent intent) {

HiLog.info(TAG, “onCreateForm”);

long formId = intent.getLongParam(AbilitySlice.PARAM_FORM_IDENTITY_KEY, INVALID_FORM_ID);

String formName = intent.getStringParam(AbilitySlice.PARAM_FORM_NAME_KEY);

int dimension = intent.getIntParam(AbilitySlice.PARAM_FORM_DIMENSION_KEY, DEFAULT_DIMENSION_2X2);

HiLog.info(TAG, “onCreateForm: formId=” + formId + “,formName=” + formName);

FormControllerManager formControllerManager = FormControllerManager.getInstance(this);

FormController formController = formControllerManager.getController(formId);

formController = (formController == null) ? formControllerManager.createFormController(formId,

formName, dimension) : formController;

if (formController == null) {

HiLog.error(TAG, “Get null controller. formId: ” + formId + “, formName: ” + formName);

return null;

}

return formController.bindFormData(formId);

}

@Override

protected void onUpdateForm(long formId) {

。..

}

@Override

protected void onDeleteForm(long formId) {

。..

}

@Override

protected void onTriggerFormEvent(long formId, String message) {

。..

}

@Override

public void onNewIntent(Intent intent) {

。..

}

private boolean intentFromWidget(Intent intent) {

。..

}

private String getRoutePageSlice(Intent intent) {

。..

}

private IMainContract.Presenter getPresenter() {

if (mPresenter == null) {

mPresenter = new MainPresenter(this);

}

return mPresenter;

}

/**

* 查詢彩票開獎(jiǎng)詳情

*

* @param formId

* @param lotteryId

*/

public void loadData(long formId, String lotteryId) {

getPresenter().loadLotteryData(formId, lotteryId);

}

@Override

public void onLoadDataSuccess(long formId, ZSONObject data) {

try {

// 更新卡片

updateForm(formId, new FormBindingData(data));

} catch (FormException e) {

e.printStackTrace();

}

}

@Override

public void onLoadDataFailed(Throwable exception) {

。..

}

}

//SsqWidgetImpl.javapublic class SsqWidgetImpl extends FormController{

private static final HiLogLabel TAG = new HiLogLabel(HiLog.DEBUG, 0x0, SsqWidgetImpl.class.getName());

public SsqWidgetImpl(Context context, String formName, Integer dimension) {

super(context, formName, dimension);

}

@Override

public ProviderFormInfo bindFormData(long formId) {

HiLog.info(TAG, “===== ssq bind form data”);

ZSONObject zsonObject = new ZSONObject();

ProviderFormInfo providerFormInfo = new ProviderFormInfo();

boolean is2x2 = dimension == DEFAULT_DIMENSION_2X2;

boolean is2x4 = dimension == DIMENSION_2X4;

boolean is4x4 = dimension == DIMENSION_4X4;

zsonObject.put(“cardType2x2”, is2x2);

zsonObject.put(“cardType2x4”, is2x4);

zsonObject.put(“cardType4x4”, is4x4);

providerFormInfo.setJsBindingData(new FormBindingData(zsonObject));

// 調(diào)用接口更新卡片數(shù)據(jù)

((MainAbility)context).loadData(formId,Constants.LOTTERY_ID_SSQ);

return providerFormInfo;

}

@Override

public void updateFormData(long formId, Object.。. vars) {

}

@Override

public void onTriggerFormEvent(long formId, String message) {

}

@Override

public Class《? extends AbilitySlice》 getRoutePageSlice(Intent intent) {

HiLog.info(TAG, “get the default page to route when you click card.”);

return null;

}

}

⑤簡單的網(wǎng)絡(luò)優(yōu)化

由于 onCreateForm(Intent intent)方法會(huì)被調(diào)用多次,而每個(gè)類型的卡片請求的數(shù)據(jù)一樣,聚合 api 一天 100 次免費(fèi)請求的次數(shù)一會(huì)兒就用完了,故對此進(jìn)行一個(gè)簡單的優(yōu)化。

優(yōu)先看內(nèi)存緩存中是否有,有且為過期(緩存默認(rèn) 10 分鐘有效期)則直接返回,否則阻塞等待接口請求完成,對于并發(fā)請求,若請求隊(duì)列已有相同的請求,則阻塞,否則創(chuàng)建新的請求。

若不關(guān)心接口調(diào)用的可略過本節(jié):

// CachedLotteryDetailUtil.java/**

* CachedLotteryDetailUtil

* 緩存彩票詳情工具類,防止在卡片創(chuàng)建時(shí),重復(fù)調(diào)用接口

*

* @author:xwg

* @since 2021-07-30

*/public class CachedLotteryDetailUtil {

//緩存的有效時(shí)間 默認(rèn)10分鐘

private static final long CACHE_TIME = 10 * 60 * 1000;

// 緩存的彩票結(jié)果

private static volatile ConcurrentHashMap《String, LotteryBean》 cacheResMap = new ConcurrentHashMap《》();

//緩存的請求時(shí)間

private static volatile ConcurrentHashMap《String, Long》 reqTimeMap = new ConcurrentHashMap《》();

//正在請求 對應(yīng)的lotteryId

private static volatile List《String》 requestingLotteryId;

/**

* 獲取彩票詳情

*

* @param lotteryId

* @return

*/

public static Observable《LotteryBean》 getLotteryDetail(String lotteryId) {

if (cacheResMap.get(lotteryId) != null) {

if (!isExpired(lotteryId)) {

return Observable.create(emitter -》 {

if (!emitter.isDisposed()) {

emitter.onNext(cacheResMap.get(lotteryId));

}

});

} else {

cacheResMap.remove(lotteryId);

}

}

if (isRequesting(lotteryId)) {

return waitToRequestEnd(lotteryId);

} else {

return requestDetail(lotteryId);

}

}

/**

* 是否正在請求

*

* @param lotteryId

* @return

*/

private static boolean isRequesting(String lotteryId) {

if (requestingLotteryId == null || lotteryId.isEmpty()) {

return false;

}

return requestingLotteryId.contains(lotteryId);

}

/**

* 阻塞等待請求結(jié)果

*

* @param lotteryId

* @return

*/

private static Observable《LotteryBean》 waitToRequestEnd(final String lotteryId) {

return Observable.create(emitter -》 {

while (isRequesting(lotteryId)) {

try {

Thread.sleep(10);

} catch (InterruptedException e) {

}

}

if (!emitter.isDisposed()) {

try {

if (cacheResMap != null && cacheResMap.get(lotteryId) != null && !isExpired(lotteryId)) {

LotteryBean lotteryBean = cacheResMap.get(lotteryId);

emitter.onNext(lotteryBean);

if (!emitter.isDisposed()) {

emitter.onComplete();

}

} else {

Throwable throwable = new Throwable(“請求異常,請稍后再試”);

emitter.onError(throwable);

}

} catch (Exception e) {

emitter.onError(e);

}

}

});

}

/**

* 聯(lián)網(wǎng)請求彩票詳情

*

* @param lotteryId

* @return

*/

private static Observable《LotteryBean》 requestDetail(final String lotteryId) {

if (requestingLotteryId == null) {

requestingLotteryId = new LinkedList《》();

}

if (!lotteryId.isEmpty() && !requestingLotteryId.contains(lotteryId)) {

requestingLotteryId.add(lotteryId);

}

return Services.createAPI(LotteryAPI.class).queryDetail(lotteryId, “”, Constants.JH_KEY)

.doOnError(throwable -》 {

requestingLotteryId.remove(lotteryId);

reqTimeMap.remove(lotteryId);

})

.doAfterNext(lotteryBean -》 {

requestingLotteryId.remove(lotteryId);

cacheResMap.put(lotteryId, lotteryBean);

reqTimeMap.put(lotteryId, System.currentTimeMillis());

});

}

/**

* 緩存是否已經(jīng)過期

*

* @return

*/

private static boolean isExpired(String lotteryId) {

if (reqTimeMap == null || reqTimeMap.get(lotteryId) == null) {

return true;

}

return System.currentTimeMillis() - reqTimeMap.get(lotteryId) 》 CACHE_TIME;

}

}

⑥給卡片增加刷新事件和查看更多事件

給卡片的 index.json 文件添加 actions,定義 showMore 為 router 事件,觸發(fā)這個(gè)事件會(huì)跳轉(zhuǎn)到指定的 abilityName 對應(yīng)的 Ability。

updateData 為 message 事件,觸發(fā)該事件,會(huì)回調(diào) Ability 中的 onTriggerFormEvent(long formId, String message)方法。

// index.json

{

“data”: {

。..

},

“actions”: {

“showMore”: {

“action”: “router”,

“abilityName”: “com.xwg.lotteryquery.MainAbility”,

“params”: {

“message”: “fcsd”

}

},

“updateData”: {

“action”: “message”,

“params”: {

“key”: “fcsd”

}

}

}

}

卡片的布局文件中添加點(diǎn)擊事件:

《!--跳轉(zhuǎn)應(yīng)用首頁事件--》《text class=“text” style=“margin-left : 120px;” if=“{{ cardType2x4 || cardType4x4 }}” onclick=“showMore”》 查看更多

《/text》

《!--點(diǎn)擊刷新按鈕事件--》《image class=“refresh” src=“/common/refresh.png” onclick=“updateData”》《/image》

// SsqWidgetImpl.java@Overridepublic void onTriggerFormEvent(long formId, String message) {

HiLog.info(TAG, “======== ssq handle card click event.”);

((MainAbility)context).loadData(formId,Constants.LOTTERY_ID_SSQ);

}

添加定時(shí)刷新:打開 config.json,對于標(biāo)簽“scheduledUpdateTime”設(shè)定的時(shí)刻,當(dāng)?shù)竭_(dá)之后,MainAbility 中卡片的回調(diào)方法 onUpdateForm() 就會(huì)被自動(dòng)調(diào)用。

updateDuration 默認(rèn)為 1,下面配置表示:雙色球卡片允許定時(shí)刷新,從 10:30 開始,每隔半小時(shí)刷新一次。

// config.json“forms”: [

{

“jsComponentName”: “ssq_widget”,

“isDefault”: true,

“scheduledUpdateTime”: “10:30”,

“defaultDimension”: “2*2”,

“name”: “SsqWidget”,

“description”: “雙色球”,

“colorMode”: “auto”,

“type”: “JS”,

“supportDimensions”: [

“2*2”,

“2*4”,

“4*4”

],

“updateEnabled”: true,

“updateDuration”: 1

}

。..

FormController 直接調(diào)用 MainAbility 的獲取數(shù)據(jù)方法:

// SsqWidgetImpl.java@Overridepublic void updateFormData(long formId, Object.。. vars) {

HiLog.info(TAG, “======== ssq update form data timing, default 30 minutes”);

((MainAbility)context).loadData(formId,Constants.LOTTERY_ID_SSQ);

}

⑦大樂透和福彩 3D 卡片的實(shí)現(xiàn)

這兩個(gè)卡片的實(shí)現(xiàn)過程和雙色球卡片基本一致,主要是 UI 上有些區(qū)別。大樂透卡片 4X4 樣式中,由于中獎(jiǎng)信息列表較長,引入了 list 和 list-item 組件,讓其可在卡片內(nèi)上下滾動(dòng),具體實(shí)現(xiàn)此處不再贅述,有興趣可閱讀源碼。

⑧歷史開獎(jiǎng)列表的實(shí)現(xiàn)

這個(gè)界面也相對簡單,使用了 swiper 組件,左右滑動(dòng)或點(diǎn)擊頭部標(biāo)簽欄,完成***、福彩 3D 標(biāo)簽頁的切換,每個(gè)標(biāo)簽頁展示對應(yīng)的近 50 期開獎(jiǎng)結(jié)果,使用 list 和 list-item 組件渲染。

由于各列表 item 展示 UI 相近,故將其抽成了組件放置于 */common/component/lottery* 目錄下。

lottery 子組件部分,lottery.js:通過 props 接收外部傳入的 lotteryData 數(shù)據(jù)。

// lottery.jsexport default {

props: {

lotteryData: {}

}

}

lottery.hml 組件布局代碼:

《!--lottery.hml--》《div class=“item”》

《div class=“item-header”》

《text style=“font-weight : bold;”》第{{ lotteryData.lottery_no }}期《/text》

《text class=“remarks”》開獎(jiǎng)日期:{{ lotteryData.lottery_date }}《/text》

《/div》

《div style=“margin-left : 10px;”》

《text for=“{{ lotteryData.ballList }}”

class=“ball”

style=“background-color : {{ $idx 》= lotteryData.redBallCount ? ‘#6666FF’ : ‘#FF0033’ }};”

》{{ $item }}《/text》

《/div》

《div class=“amount-box”》

《div style=“flex-direction : column;”》

《text class=“text-small”》本期全國銷量《/text》

《text class=“text-amount”》{{ lotteryData.lottery_sale_amount }}《/text》

《/div》

《text class=“diver”》《/text》

《div style=“flex-direction : column;”》

《text class=“text-small”》累計(jì)獎(jiǎng)池《/text》

《text class=“text-amount”》{{ lotteryData.lottery_pool_amount || ‘0’ }}《/text》

《/div》

《/div》《/div》

css 比較簡單,這里不再給出。

父組件實(shí)現(xiàn):

《!--home.hml--》《element name=‘lottery’ src=‘。./。./common/component/lottery/lottery.hml’》《/element》《div class=“container”》

《div class=“title-container”》

《text class=“title {{ currentIdx == 0 ? tabSelected : tabUnSelected }}” onclick=“onTabClick(0)”》雙色球《/text》

《text class=“title {{ currentIdx == 1 ? tabSelected : tabUnSelected }}” onclick=“onTabClick(1)”》大樂透《/text》

《text class=“title {{ currentIdx == 2 ? tabSelected : tabUnSelected }}” onclick=“onTabClick(2)”》福彩3D《/text》

《/div》

《swiper class=“swiper” id=“swiper” index=“0” indicator=“false” loop=“true”

digital=“false” on:change=“onChange”》

《div class=“swiperContent”》

《list class=“”》

《list-item for=“{{ ssqResList }}” class=“l(fā)ottery-item”》

《lottery lottery-data = “{{$item}}”》《/lottery》

《/list-item》

《/list》

《/div》

《div class=“swiperContent”》

《list class=“”》

《list-item for=“{{ dltResList }}” class=“l(fā)ottery-item”》

《lottery lottery-data = “{{$item}}”》《/lottery》

《/list-item》

《/list》

《/div》

《div class=“swiperContent”》

《list class=“”》

《list-item for=“{{ fcsdResList }}” class=“l(fā)ottery-item”》

《lottery lottery-data = “{{$item}}”》《/lottery》

《/list-item》

《/list》

《/div》

《/swiper》《/div》

《!--home.js--》

import http from ‘@ohos.net.http’;

const JH_URL = ‘http://apis.juhe.cn’const JH_KEY = ‘4931b786dd99c28e7e9990fb75c39fad’export default {

data: {

currentIdx: 0,

tabSelected: ‘tabSelected’,

tabUnSelected: ‘tabUnSelected’,

ssqResList: null, // 雙色球近期開獎(jiǎng)結(jié)果列表

dltResList: null, // 大樂透近期開獎(jiǎng)結(jié)果列表

fcsdResList: null, // 3D球近期開獎(jiǎng)結(jié)果列表

},

onInit() {

this.querySsqHis();

this.queryDltHis();

this.queryFcsdHis();

},

// 查詢雙色球歷史開獎(jiǎng)

querySsqHis() {

console.info(‘xwg== querySsqHis ----------’);

let _t = this

let httpRequest = http.createHttp();

let url = JH_URL + ‘/history’ + ‘?lottery_id=ssq&page_size=50&page=&key=’ + JH_KEY

httpRequest.request(url, (err, data) =》 {

if (err == null) {

let lotteryResList = JSON.parse(data.result).result.lotteryResList

_t.ssqResList = lotteryResList.map(item =》 {

item.ballList = item.lottery_res.split(“,”)

item.redBallCount = 6

return item

})

console.info(‘xwg== ssqResList:’ + JSON.stringify(_t.ssqResList));

} else {

console.info(‘xwg== error:’ + JSON.stringify(err));

}

});

},

// 查詢大樂透歷史開獎(jiǎng)

queryDltHis() {

let _t = this

let httpRequest = http.createHttp();

let url = JH_URL + ‘/history’ + ‘?lottery_id=ssq&page_size=50&page=&key=’ + JH_KEY

httpRequest.request(url, (err, data) =》 {

if (err == null) {

let dltRes = JSON.parse(data.result).result.lotteryResList

_t.dltResList = dltRes.map(item =》 {

item.ballList = item.lottery_res.split(“,”)

item.redBallCount = 5

return item

})

} else {

console.info(‘xwg== error:’ + JSON.stringify(err));

}

});

},

// 查詢福彩3D歷史開獎(jiǎng)

queryFcsdHis() {

let _t = this

let httpRequest = http.createHttp();

let url = JH_URL + ‘/history’ + ‘?lottery_id=ssq&page_size=50&page=&key=’ + JH_KEY

httpRequest.request(url, (err, data) =》 {

if (err == null) {

let fcsdRes = JSON.parse(data.result).result.lotteryResList

_t.fcsdResList = fcsdRes.map(item =》 {

item.ballList = item.lottery_res.split(“,”)

item.redBallCount = 3

return item

})

} else {

console.info(‘xwg== error:’ + JSON.stringify(err));

}

});

},

// swiper滑動(dòng)監(jiān)聽

onChange(value) {

this.currentIdx = value.index

},

// tab click事件

onTabClick(idx) {

this.currentIdx = idx

this.$element(‘swiper’).swipeTo({

index: idx

});

},

computed: {}

}

尚未解決的問題:這里引入了 http 組件進(jìn)行網(wǎng)絡(luò)請求,但在請求聚合接口時(shí),失敗率很高,但嘗試請求別的網(wǎng)站的 api 時(shí)沒有此現(xiàn)象,目前尚不知原因。

總結(jié)

由于這也是我第一次使用 JS UI 框架進(jìn)行卡片開發(fā)的項(xiàng)目,水平有限,難免會(huì)對官方部分 API 理解不到位甚至理解有誤的地方,希望大家也多多指正,共同進(jìn)步。

這一路上雖然磕磕巴巴,也有很多吐槽,但我們從卡片 JS-UI API 5 到 API 6 功能上逐漸靠攏應(yīng)用 JS-UI 上也能看出來鴻蒙的努力,給它點(diǎn)時(shí)間,相信它功能上會(huì)變得更強(qiáng)大、完善;對于開發(fā)也會(huì)變得更快捷、簡單。

最后附上項(xiàng)目地址:lottery-query,請自行下載資源,歡迎交流學(xué)習(xí)。

https://gitee.com/chinasoft6_ohos/lottery-query

責(zé)任編輯:haq

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報(bào)投訴
  • 鴻蒙系統(tǒng)
    +關(guān)注

    關(guān)注

    183

    文章

    2639

    瀏覽量

    67700
  • HarmonyOS
    +關(guān)注

    關(guān)注

    79

    文章

    2052

    瀏覽量

    32120

原文標(biāo)題:超實(shí)用!鴻蒙彩票查詢卡片

文章出處:【微信號(hào):gh_834c4b3d87fe,微信公眾號(hào):OpenHarmony技術(shù)社區(qū)】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。

收藏 人收藏

    評(píng)論

    相關(guān)推薦
    熱點(diǎn)推薦

    鴻蒙5開發(fā)寶藏案例分享---多開發(fā)實(shí)例(游戲)

    ?【開發(fā)者必看】鴻蒙隱藏寶箱大公開!這些實(shí)戰(zhàn)案例讓你的開發(fā)效率翻倍! 哈嘍各位開發(fā)者小伙伴!今天要和大家分享個(gè)讓我拍大腿的發(fā)現(xiàn)——原來鴻蒙官方早就給我們準(zhǔn)備了超多高質(zhì)量開發(fā)案例!(就
    發(fā)表于 06-03 18:22

    鴻蒙5開發(fā)案例分享揭秘---多開發(fā)實(shí)例(商務(wù)辦公)

    車載系統(tǒng)應(yīng)有盡有。建議大家直接去官網(wǎng)搜【多開發(fā)實(shí)例】,保準(zhǔn)打開新世界的大門! 最后送大家句話: \"讀十篇博客不如精研個(gè)官方案例\"
    發(fā)表于 06-03 16:24

    鴻蒙5開發(fā)寶藏案例分享---多開發(fā)實(shí)例(地圖導(dǎo)航)

    ? 鴻蒙開發(fā)隱藏寶藏大公開!手把手教你玩轉(zhuǎn)\"多\"地圖導(dǎo)航案例 ? 大家好呀!我是你們的老朋友,今天要給大家扒鴻蒙官方文檔里那些\"藏得深\"的實(shí)戰(zhàn)
    發(fā)表于 06-03 16:17

    效率大升!AI賦能鴻蒙萬能卡片開發(fā)

    萬能卡片,作為鴻蒙生態(tài)應(yīng)用和元服務(wù)的重要展示形式,憑借將關(guān)鍵信息和核心操作前置,實(shí)現(xiàn)服務(wù)直達(dá)、減少跳轉(zhuǎn)層級(jí)的體驗(yàn)效果,備受用戶和開發(fā)者青睞。但傳統(tǒng)卡片的設(shè)計(jì)和編碼流程相對繁瑣,影響了萬能卡片
    的頭像 發(fā)表于 01-13 13:44 ?559次閱讀
    效率大升!AI賦能<b class='flag-5'>鴻蒙</b>萬能<b class='flag-5'>卡片</b>開發(fā)

    OpenHarmony源碼編譯后燒錄鏡像教程,RK3566鴻蒙開發(fā)板演示

    本文介紹瑞芯微主板/開發(fā)板編譯OpenHarmony源碼后燒錄鏡像的教程,觸覺智能Purple Pi OH鴻蒙開發(fā)板演示。搭載了瑞芯微RK3566四核處理器,樹莓派卡片電腦設(shè)計(jì),支持開源鴻蒙OpenHarmony3.2-5.0
    的頭像 發(fā)表于 12-30 10:08 ?644次閱讀
    OpenHarmony源碼編譯后燒錄鏡像教程,RK3566<b class='flag-5'>鴻蒙</b>開發(fā)板演示

    鴻蒙原生開發(fā)手記:04-個(gè)完整元服務(wù)案例

    /main_pages.json 中配置,路由名與文件名一一對應(yīng)。 在 main_pages.json 所在地目錄中,可以看到個(gè) form_config.json文件,這個(gè)用來配置服務(wù)卡片,在此按下不表。 頁面中多
    發(fā)表于 12-27 10:35

    何在開源鴻蒙OpenHarmony開啟SELinux模式?RK3566鴻蒙開發(fā)板演示

    本文介紹開源鴻蒙OpenHarmony系統(tǒng)下,開啟/關(guān)閉SELinux權(quán)限的方法,觸覺智能Purple Pi OH鴻蒙開發(fā)板演示,已適配全新OpenHarmony5.0 Release系統(tǒng)
    的頭像 發(fā)表于 11-18 19:03 ?742次閱讀
    如<b class='flag-5'>何在</b>開源<b class='flag-5'>鴻蒙</b>OpenHarmony開啟SELinux模式?RK3566<b class='flag-5'>鴻蒙</b>開發(fā)板演示

    鴻蒙原生開發(fā)手記:02-服務(wù)卡片開發(fā)

    介紹 服務(wù)卡片直桌面小組件,可以放置在桌面上等位置,觸即達(dá)。 服務(wù)卡片分為靜態(tài)卡片和動(dòng)態(tài)卡片
    發(fā)表于 11-14 17:48

    鴻蒙原生開發(fā)手記:01-元服務(wù)開發(fā)

    簡介 元服務(wù)是鴻蒙中的種輕量應(yīng)用形態(tài),無需下載,直接運(yùn)行。類似于微信小程序,但與小程序不同的是,元服務(wù)更加輕量。 元服務(wù)使用原生開發(fā),是系統(tǒng)級(jí)提供的,無論從易用性、性能、體驗(yàn)上,都要比小程序好
    發(fā)表于 11-14 17:28

    鴻蒙系統(tǒng)專用版微信內(nèi)測即將啟動(dòng)

    Next系統(tǒng)的用戶參與內(nèi)測活動(dòng),以進(jìn)步優(yōu)化微信在鴻蒙系統(tǒng)上的表現(xiàn)。內(nèi)測活動(dòng)將為廣大用戶提供個(gè)
    的頭像 發(fā)表于 11-07 10:58 ?1296次閱讀

    原生鴻蒙操作系統(tǒng)正式發(fā)布,誠邁科技與華為起共建鴻蒙新世界

    特性等提升顯著,標(biāo)志著我國在操作系統(tǒng)研發(fā)領(lǐng)域取得了重大突破。 誠邁科技與華為直保持著緊密的伙伴關(guān)系,公司不僅是最早加入鴻蒙生態(tài)的共建者之,也是
    的頭像 發(fā)表于 10-28 09:29 ?1247次閱讀
    原生<b class='flag-5'>鴻蒙</b>操作<b class='flag-5'>系統(tǒng)</b>正式發(fā)布,誠邁科技與華為<b class='flag-5'>一</b>起共建<b class='flag-5'>鴻蒙</b>新世界

    基于鴻蒙Next模擬卡片數(shù)據(jù)數(shù)據(jù)更新

    、介紹 基于鴻蒙Next模擬卡片數(shù)據(jù)數(shù)據(jù)更新二、場景需求 電商平臺(tái)產(chǎn)品信息更新、 客戶關(guān)系管理(CRM)系統(tǒng)、 社交媒體用戶資料更新、 健康管理
    發(fā)表于 08-30 15:32

    國產(chǎn)KylinOS銀河麒麟系統(tǒng)適配OBOO鷗柏觸摸屏查詢體機(jī)完成調(diào)試

    觸摸屏麒麟系統(tǒng)界面“OBOO鷗柏”品牌部分商用液晶顯示產(chǎn)品已接入國產(chǎn)麒麟系統(tǒng)AI人工智能,銀河麒麟(KylinOS),并上架京東商城,液晶廣告機(jī),觸摸屏查詢體機(jī),交互式
    的頭像 發(fā)表于 08-23 18:03 ?1521次閱讀
    國產(chǎn)KylinOS銀河麒麟<b class='flag-5'>系統(tǒng)</b>適配OBOO鷗柏觸摸屏<b class='flag-5'>查詢</b><b class='flag-5'>一</b>體機(jī)完成調(diào)試

    升級(jí)采用鴻蒙HarmonyOS國產(chǎn)系統(tǒng)商用顯示崛起之路上市

    華為鴻蒙HarmonyOS4.0發(fā)布后,中國多行業(yè)客戶群體利于國產(chǎn)系統(tǒng)就在翹首以盼,期盼OBOO鷗柏品牌在室內(nèi)室外商用液晶顯示領(lǐng)域產(chǎn)品的液晶廣告機(jī),觸摸屏查詢體機(jī),交互式
    的頭像 發(fā)表于 08-01 19:53 ?478次閱讀
    升級(jí)采用<b class='flag-5'>鴻蒙</b>HarmonyOS國產(chǎn)<b class='flag-5'>系統(tǒng)</b>商用顯示崛起之路上市

    AIGC系統(tǒng)中聊天小助手卡片小組件嵌套設(shè)計(jì)實(shí)踐

    1.項(xiàng)目描述 領(lǐng)航者卡片樣式較多,有些卡片比較近似;可以用嵌套方案,實(shí)現(xiàn)個(gè)卡片,多個(gè)子單元 可拔插組件式
    的頭像 發(fā)表于 06-12 11:20 ?1053次閱讀
    AIGC<b class='flag-5'>系統(tǒng)</b>中聊天小助手<b class='flag-5'>卡片</b>小組件嵌套設(shè)計(jì)實(shí)踐