From 87e5604ad04c0b7aaacf3d52bae85e62d308cb6d Mon Sep 17 00:00:00 2001 From: zuoxiao <lf_zuo@163.com> Date: 星期四, 26 六月 2025 16:41:02 +0800 Subject: [PATCH] refactor(generallibrary):重构开卡成功界面并移除未使用的开卡界面 --- README.md | 1122 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 1,120 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index f276ded..2666be9 100644 --- a/README.md +++ b/README.md @@ -232,6 +232,171 @@ - CardData: 鍗$墖鏁版嵁 - ProjectDataBean: 椤圭洰鏁版嵁 +## 鏁版嵁绫荤鐞嗚鑼� + +### Bean鍖呯粨鏋勭粍缁� + +椤圭洰涓墍鏈夌殑鏁版嵁绫伙紙Data Class锛夐兘搴旇缁熶竴鏀惧湪`bean`鍖呬笅鐨勭浉搴斿瓙鐩綍涓紝鎸夌収鍔熻兘鍜岀敤閫旇繘琛屽垎绫伙細 + +``` +generallibrary/src/main/java/com/dayu/general/bean/ +鈹溾攢鈹� net/ # 缃戠粶鎺ュ彛鐩稿叧鏁版嵁绫� +鈹溾攢鈹� card/ # 鍗$墖鐩稿叧鏁版嵁绫� +鈹溾攢鈹� db/ # 鏁版嵁搴撳疄浣撶被 +鈹斺攢鈹� ... # 鍏朵粬鍔熻兘妯″潡鏁版嵁绫� +``` + +#### 1. 缃戠粶鎺ュ彛鏁版嵁绫� (bean/net/) + +鎵�鏈堿PI鎺ュ彛鐨勮姹傚拰鍝嶅簲鏁版嵁绫婚兘鏀惧湪`net`鐩綍涓嬶細 + +```kotlin +// 璇锋眰鏁版嵁绫荤ず渚� +data class RechargeRequest( + val rechargeType: Int, + val cardNum: String, + val money: String, + // ... 鍏朵粬瀛楁 +) + +// 鍝嶅簲鏁版嵁绫荤ず渚� +data class CardCancelResult( + val projectNo: Int, + val cardNum: String, + val orderNo: String +) +``` + +#### 2. 鍗$墖鐩稿叧鏁版嵁绫� (bean/card/) + +鎵�鏈夊崱鐗囨搷浣滅浉鍏崇殑鏁版嵁绫绘斁鍦╜card`鐩綍涓嬶細 + +```kotlin +data class UserCard( + var cardType: String = "", + var balance: Int = 0, + var userCode: String = "", + // ... 鍏朵粬瀛楁 +) +``` + +#### 3. 鏁版嵁搴撳疄浣撶被 (bean/db/) + +鎵�鏈塕oom鏁版嵁搴撶殑瀹炰綋绫绘斁鍦╜db`鐩綍涓嬶細 + +```kotlin +@Entity(tableName = "card_data") +data class CardData( + @PrimaryKey val id: Long, + val cardNumber: String, + // ... 鍏朵粬瀛楁 +) +``` + +### 鏁版嵁绫诲懡鍚嶈鑼� + +1. **鎺ュ彛鍝嶅簲鏁版嵁绫�**: 浠Result`缁撳熬 + - `CardCancelResult` - 閿�鍗℃帴鍙e搷搴� + - `RechargeResult` - 鍏呭�兼帴鍙e搷搴� + - `WaterPriceResult` - 姘翠环鎺ュ彛鍝嶅簲 + +2. **鎺ュ彛璇锋眰鏁版嵁绫�**: 浠Request`缁撳熬 + - `RechargeRequest` - 鍏呭�兼帴鍙h姹� + - `SearchUserBeanRequest` - 鐢ㄦ埛鎼滅储璇锋眰 + +3. **涓氬姟瀹炰綋鏁版嵁绫�**: 浣跨敤涓氬姟鍚嶇О + - `UserCard` - 鐢ㄦ埛鍗$墖鏁版嵁 + - `ClearCard` - 娓呴浂鍗℃暟鎹� + +4. **鏁版嵁搴撳疄浣撶被**: 浣跨敤琛ㄥ悕瀵瑰簲鐨勫疄浣撳悕 + - `CardData` - 鍗$墖鏁版嵁琛� + - `ProjectDataBean` - 椤圭洰鏁版嵁琛� + +### 鏁版嵁绫诲垱寤烘渶浣冲疄璺� + +#### 1. 鏂囦欢澶存敞閲婅鑼� + +```kotlin +package com.dayu.general.bean.net + +/** + * 閿�鍗$粨鏋滄暟鎹被 + * @author: zuo + * @date: 2025/01/17 + * @description: 閿�鍗℃帴鍙h繑鍥炴暟鎹� + */ +data class CardCancelResult( + val projectNo: Int, // 椤圭洰缂栧彿 + val cardNum: String, // 鍗″彿 + val orderNo: String // 璁㈠崟鍙� +) +``` + +#### 2. 瀛楁娉ㄩ噴瑙勮寖 + +- 姣忎釜瀛楁閮藉簲璇ユ坊鍔犺鍐呮敞閲婅鏄庣敤閫� +- 瀵逛簬鏋氫妇鍊兼垨鐗规畩鍚箟鐨勫瓧娈碉紝璇︾粏璇存槑鍙栧�艰寖鍥� + +#### 3. 瀵煎叆浣跨敤瑙勮寖 + +鍦ˋctivity鎴栧叾浠栫被涓娇鐢ㄦ暟鎹被鏃讹紝搴旇瀵煎叆鍏蜂綋鐨勬暟鎹被锛� + +```kotlin +// 姝g‘鐨勫鍏ユ柟寮� +import com.dayu.general.bean.net.CardCancelResult +import com.dayu.general.bean.net.RechargeResult + +// 鍦ㄤ唬鐮佷腑浣跨敤 +private fun handleCancelResult(result: CardCancelResult) { + // 澶勭悊閿�鍗$粨鏋� +} +``` + +#### 4. 绂佹鍐呰仈瀹氫箟 + +**绂佹**鍦ˋctivity鎴栧叾浠栫被涓唴鑱斿畾涔夋暟鎹被锛� + +```kotlin +// 鉂� 閿欒鍋氭硶 - 涓嶈鍦ˋctivity涓唴鑱斿畾涔夋暟鎹被 +class CardCancelActivity : BaseNfcActivity() { + + // 鉂� 绂佹杩欐牱鍋� + data class CardCancelResult( + val projectNo: Int, + val cardNum: String, + val orderNo: String + ) +} + +// 鉁� 姝g‘鍋氭硶 - 鍦╞ean鍖呬腑瀹氫箟鏁版嵁绫� +// 鏂囦欢: generallibrary/src/main/java/com/dayu/general/bean/net/CardCancelResult.kt +data class CardCancelResult( + val projectNo: Int, + val cardNum: String, + val orderNo: String +) +``` + +### 鏁版嵁绫荤鐞嗕紭鍔� + +1. **缁熶竴绠$悊**: 鎵�鏈夋暟鎹被闆嗕腑鍦╞ean鍖呬笅锛屼究浜庢煡鎵惧拰缁存姢 +2. **鑱岃矗鍒嗙**: 涓氬姟閫昏緫鍜屾暟鎹粨鏋勫垎绂伙紝浠g爜缁撴瀯鏇存竻鏅� +3. **澶嶇敤鎬у己**: 鏁版嵁绫诲彲浠ュ湪澶氫釜妯″潡闂村鐢� +4. **鏄撲簬閲嶆瀯**: 鏁版嵁缁撴瀯鍙樻洿鏃跺彧闇�淇敼涓�涓枃浠� +5. **绫诲瀷瀹夊叏**: 缂栬瘧鏈熺被鍨嬫鏌ワ紝鍑忓皯杩愯鏃堕敊璇� + +### 杩佺Щ鐜版湁浠g爜 + +瀵逛簬宸茬粡瀛樺湪鐨勫唴鑱旀暟鎹被锛屽簲璇ユ寜鐓т互涓嬫楠よ繘琛岃縼绉伙細 + +1. 鍦╞ean鍖呯殑鐩稿簲瀛愮洰褰曚笅鍒涘缓鏁版嵁绫绘枃浠� +2. 绉诲姩鏁版嵁绫诲畾涔夊埌鏂版枃浠� +3. 鍦ㄥ師鏂囦欢涓坊鍔犲鍏ヨ鍙� +4. 娴嬭瘯纭繚鍔熻兘姝e父 +5. 鎻愪氦浠g爜鍙樻洿 + +閫氳繃缁熶竴鐨勬暟鎹被绠$悊瑙勮寖锛屽彲浠ユ彁楂樹唬鐮佺殑鍙淮鎶ゆ�у拰鍙鎬э紝浣块」鐩粨鏋勬洿鍔犳竻鏅拌鑼冦�� + ## 寮�鍙戠幆澧冭姹� - Android Studio Arctic Fox鎴栨洿楂樼増鏈� @@ -317,8 +482,17 @@ 2. 鐐瑰嚮浜嬩欢鐩戝惉 ```kotlin // 鏂瑰紡1锛氫娇鐢ㄧ被鍨嬪父閲忥紙鎺ㄨ崘锛� -titleBar.setOnItemclickListner(TitleBar.ClickType_LEFT_IMAGE) { finish() } -titleBar.setOnItemclickListner(TitleBar.ClickType_RIGHT_TEXT) { showMenu() } +titleBar.setOnItemclickListner(TitleBar.ClickType_LEFT_IMAGE) { + finish() +} +titleBar.setOnItemclickListner(TitleBar.ClickType_RIGHT_TEXT) { + showMenu() +} + +// 鎴栬�呬娇鐢ㄥ畬鏁寸殑OnClickListener +titleBar.setOnItemclickListner(TitleBar.ClickType_LEFT_IMAGE, View.OnClickListener { + finish() +}) // 鏂瑰紡2锛氫娇鐢ㄤ綅缃拰绫诲瀷甯搁噺锛堝凡搴熷純锛� titleBar.setOnItemclickListner(TitleBar.IMAGE, TitleBar.LEFT) { finish() } @@ -352,6 +526,173 @@ 2. 璁剧疆鏂囨湰鎴栧浘鐗囨椂锛屽鏋滀紶鍏ull鎴�0锛屽搴旂殑瑙嗗浘灏嗚闅愯棌 3. 缁勪欢榛樿浣跨敤鍨傜洿绾挎�у竷灞�锛岀‘淇濆湪甯冨眬鏂囦欢涓缃悎閫傜殑楂樺害 +#### 甯歌浣跨敤绀轰緥 +```kotlin +// 鍦ˋctivity鐨刬nitView鏂规硶涓缃� +private fun initView() { + // 璁剧疆杩斿洖鎸夐挳鐐瑰嚮浜嬩欢 + binding.titleBar.setOnItemclickListner(TitleBar.ClickType_LEFT_IMAGE) { + finish() + } + + // 璁剧疆鍙充晶鏂囨湰鎸夐挳鐐瑰嚮浜嬩欢 + binding.titleBar.setOnItemclickListner(TitleBar.ClickType_RIGHT_TEXT) { + // 澶勭悊鍙充晶鎸夐挳鐐瑰嚮閫昏緫 + handleRightButtonClick() + } +} +``` + +## 鏀粯鏂瑰紡鍔ㄦ�佽幏鍙栧姛鑳� + +椤圭洰涓疄鐜颁簡鏀粯鏂瑰紡鐨勫姩鎬佽幏鍙栧拰鏄剧ず鍔熻兘锛屾敮鎸佷粠鏈嶅姟鍣ㄨ幏鍙栨敮浠樻柟寮忓垪琛ㄥ苟鍔ㄦ�佸垱寤篟adioButton銆� + +### 鏁版嵁缁撴瀯 + +```kotlin +// 鏀粯鏂瑰紡鏁版嵁绫� +data class PaymentMethod( + val id: Long, + val name: String, + val remarks: String, + val deleted: Int +) + +// 鏀粯鏂瑰紡鎺ュ彛杩斿洖鏁版嵁绫� +data class PaymentMethodResponse( + val itemTotal: Any?, + val obj: List<PaymentMethod>, + val pageCurr: Any?, + val pageSize: Any?, + val pageTotal: Any? +) +``` + +### 浣跨敤鏂瑰紡 + +#### 1. 鍦ˋctivity涓坊鍔犳敮浠樻柟寮忕浉鍏冲睘鎬� + +```kotlin +class YourActivity : AppCompatActivity() { + // 鏀粯鏂瑰紡鐩稿叧灞炴�� + private var paymentMethod: String = "鐜伴噾" + private var paymentId: Long = 0 + private var paymentMethodList: List<PaymentMethod> = listOf() + + // ... 鍏朵粬浠g爜 +} +``` + +#### 2. 鑾峰彇鏀粯鏂瑰紡鍒楄〃 + +```kotlin +/** + * 鑾峰彇鏀粯鏂瑰紡鍒楄〃 + */ +private fun getPaymentMethods() { + ApiManager.getInstance().requestGetLoading( + this, + "terminal/paymentmethod/get", + PaymentMethodResponse::class.java, + null, + object : SubscriberListener<BaseResponse<PaymentMethodResponse>>() { + override fun onNext(response: BaseResponse<PaymentMethodResponse>) { + if (response.success) { + val paymentMethods = response.content?.obj ?: listOf() + if (paymentMethods.isNotEmpty()) { + paymentMethodList = paymentMethods + updatePaymentMethodRadioGroup() + } + } else { + Toast.makeText(this@YourActivity, "鑾峰彇鏀粯鏂瑰紡澶辫触: ${response.msg}", Toast.LENGTH_SHORT).show() + } + } + + override fun onError(e: Throwable?) { + super.onError(e) + Toast.makeText(this@YourActivity, "鑾峰彇鏀粯鏂瑰紡澶辫触: ${e?.message ?: "缃戠粶寮傚父"}", Toast.LENGTH_SHORT).show() + } + } + ) +} +``` + +#### 3. 鍔ㄦ�佸垱寤篟adioButton + +```kotlin +/** + * 鏇存柊鏀粯鏂瑰紡RadioGroup + */ +private fun updatePaymentMethodRadioGroup() { + // 娓呯┖鍘熸湁RadioButton + binding.paymentMethodRadioGroup.removeAllViews() + + // 鍔ㄦ�佹坊鍔燫adioButton + paymentMethodList.forEachIndexed { index, method -> + val radioButton = RadioButton(this) + radioButton.id = View.generateViewId() + radioButton.layoutParams = LinearLayout.LayoutParams(0, resources.getDimensionPixelSize(R.dimen.dimen_40), 1.0f) + + // 璁剧疆鏍峰紡 + radioButton.text = method.name + radioButton.background = resources.getDrawable(R.drawable.radio_selector) + radioButton.buttonDrawable = null + radioButton.gravity = Gravity.CENTER + radioButton.setTextColor(resources.getColorStateList(R.color.radio_button_text_color)) + radioButton.setTextSize(TypedValue.COMPLEX_UNIT_SP, 14f) + + // 娣诲姞鍒癛adioGroup + binding.paymentMethodRadioGroup.addView(radioButton) + + // 榛樿閫変腑绗竴涓� + if (index == 0) { + radioButton.isChecked = true + paymentMethod = method.name + paymentId = method.id + } + } + + // 璁剧疆閫夋嫨鐩戝惉 + binding.paymentMethodRadioGroup.setOnCheckedChangeListener { group, checkedId -> + for (i in 0 until group.childCount) { + val radioButton = group.getChildAt(i) as RadioButton + if (radioButton.id == checkedId) { + paymentMethod = radioButton.text.toString() + paymentId = paymentMethodList[i].id + break + } + } + } +} +``` + +#### 4. 甯冨眬鏂囦欢閰嶇疆 + +```xml +<RadioGroup + android:id="@+id/paymentMethodRadioGroup" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="horizontal"> + <!-- 鍔ㄦ�佹坊鍔燫adioButton锛屼笉闇�瑕侀瀹氫箟 --> +</RadioGroup> +``` + +### 鍔熻兘鐗圭偣 + +1. **鍔ㄦ�佽幏鍙�**: 浠庢湇鍔″櫒鍔ㄦ�佽幏鍙栨敮浠樻柟寮忓垪琛紝鏀寔鍚庡彴閰嶇疆 +2. **鑷姩甯冨眬**: 鏍规嵁鏀粯鏂瑰紡鏁伴噺鑷姩璋冩暣RadioButton甯冨眬 +3. **鏍峰紡缁熶竴**: 鎵�鏈夊姩鎬佸垱寤虹殑RadioButton浣跨敤缁熶竴鐨勬牱寮� +4. **榛樿閫夋嫨**: 鑷姩閫変腑绗竴涓敮浠樻柟寮忎綔涓洪粯璁ら�夐」 +5. **浜嬩欢澶勭悊**: 鏀寔閫夋嫨鍙樺寲鐩戝惉锛屽疄鏃舵洿鏂板綋鍓嶉�変腑鐨勬敮浠樻柟寮� + +### 娉ㄦ剰浜嬮」 + +1. 纭繚鍦ㄨ皟鐢╜getPaymentMethods()`鍓嶅凡缁忓垵濮嬪寲浜嗙浉鍏崇殑UI缁勪欢 +2. 鍔ㄦ�佸垱寤虹殑RadioButton闇�瑕佽缃敮涓�鐨処D锛屼娇鐢╜View.generateViewId()` +3. 鍦ˋctivity閿�姣佹椂娉ㄦ剰娓呯悊鐩稿叧璧勬簮锛岄伩鍏嶅唴瀛樻硠婕� +4. 缃戠粶璇锋眰澶辫触鏃惰鏈夌浉搴旂殑閿欒澶勭悊鏈哄埗 + ## 娉ㄦ剰浜嬮」 1. 鏁版嵁搴撹縼绉� @@ -371,6 +712,783 @@ - 纭繚寮傚父淇℃伅琚纭褰曞拰涓婃姤 - 閬垮厤寮傚父淇℃伅娉勯湶鏁忔劅鏁版嵁 +5. API寮傚父澶勭悊鏈�浣冲疄璺� + - 閽堝鐗瑰畾閿欒鐮佹彁渚涘弸濂界殑鐢ㄦ埛鎻愮ず + - 鍖哄垎缃戠粶寮傚父銆佷笟鍔″紓甯稿拰绯荤粺寮傚父 + - 寮傚父鍙戠敓鍚庡強鏃堕噸缃甎I鐘舵�侊紝鍏佽鐢ㄦ埛閲嶈瘯 + - 鎻愪緵鏄庣‘鐨勬搷浣滄寚寮曪紝濡�"璇峰厛杩涜寮�鍗℃搷浣�" + +### API寮傚父澶勭悊绀轰緥 + +```kotlin +// 鍦ˋPI鍥炶皟涓鐞嗕笉鍚岀被鍨嬬殑寮傚父 +object : SubscriberListener<BaseResponse<YourDataType>>() { + override fun onNext(response: BaseResponse<YourDataType>) { + if (response.success) { + // 澶勭悊鎴愬姛鎯呭喌 + handleSuccess(response.content) + } else { + // 澶勭悊涓氬姟寮傚父 + handleBusinessError(response.code, response.msg) + } + } + + override fun onError(e: Throwable?) { + super.onError(e) + // 澶勭悊缃戠粶寮傚父 + handleNetworkError(e) + // 閲嶇疆UI鐘舵�� + resetViewState() + } +} + +// 涓氬姟寮傚父澶勭悊鏂规硶 +private fun handleBusinessError(code: String?, msg: String?) { + when (code) { + "1081" -> ToastUtil.show("璇ュ崱鐗囨湭鍦ㄧ郴缁熶腑娉ㄥ唽锛岃鍏堣繘琛屽紑鍗℃搷浣�") + "1001" -> ToastUtil.show("鏉冮檺涓嶈冻锛岃鑱旂郴绠$悊鍛�") + "1002" -> ToastUtil.show("璐︽埛浣欓涓嶈冻") + else -> { + val errorMsg = when { + msg.isNullOrBlank() -> "鎿嶄綔澶辫触锛岃閲嶈瘯" + msg.contains("鏁版嵁涓嶅瓨鍦�") -> "鏁版嵁涓嶅瓨鍦紝璇锋鏌ヨ緭鍏ヤ俊鎭�" + msg.contains("缃戠粶") -> "缃戠粶杩炴帴寮傚父锛岃妫�鏌ョ綉缁滃悗閲嶈瘯" + msg.contains("瓒呮椂") -> "璇锋眰瓒呮椂锛岃閲嶈瘯" + else -> "鎿嶄綔澶辫触: $msg" + } + ToastUtil.show(errorMsg) + } + } + // 閲嶇疆鐣岄潰鐘舵�� + resetViewState() +} + +// 缃戠粶寮傚父澶勭悊鏂规硶 +private fun handleNetworkError(e: Throwable?) { + val errorMsg = when { + e?.message?.contains("timeout") == true -> "缃戠粶璇锋眰瓒呮椂锛岃妫�鏌ョ綉缁滆繛鎺�" + e?.message?.contains("network") == true -> "缃戠粶杩炴帴澶辫触锛岃妫�鏌ョ綉缁滆缃�" + e?.message?.contains("host") == true -> "鏈嶅姟鍣ㄨ繛鎺ュけ璐ワ紝璇风◢鍚庨噸璇�" + else -> "缃戠粶寮傚父: ${e?.message ?: "鏈煡閿欒"}" + } + ToastUtil.show(errorMsg) +} + +### Dialog寮圭獥浣跨敤鏈�浣冲疄璺� + +椤圭洰涓彁渚涗簡澶氱Dialog缁勪欢锛岀敤浜庝笉鍚岀殑浜や簰鍦烘櫙銆傛帹鑽愪娇鐢ㄩ」鐩凡鏈夌殑Dialog缁勪欢鏉ヤ繚鎸乁I椋庢牸鐨勪竴鑷存�с�� + +#### 甯哥敤Dialog缁勪欢 + +1. **ConfirmDialog**: 纭瀵硅瘽妗嗭紝鐢ㄤ簬閲嶈鎿嶄綔鐨勪簩娆$‘璁� +2. **TipDialog**: 鎻愮ず瀵硅瘽妗嗭紝鐢ㄤ簬鏄剧ず鎻愮ず淇℃伅 +3. **EdtDialog**: 杈撳叆瀵硅瘽妗嗭紝鐢ㄤ簬鑾峰彇鐢ㄦ埛杈撳叆 +4. **鑷畾涔塂ialog**: 缁ф壙Dialog绫诲疄鐜扮壒瀹氬姛鑳� + +#### ConfirmDialog浣跨敤绀轰緥 + +```kotlin +// 鍩烘湰鐢ㄦ硶 - 鍙樉绀烘秷鎭� +val dialog = ConfirmDialog(context, "鎿嶄綔鎴愬姛") +dialog.show() + +// 甯︽爣棰樼殑鐢ㄦ硶 +val dialog = ConfirmDialog(context, "鎻愮ず", "纭瑕佸垹闄よ繖鏉¤褰曞悧锛�") { + // 鐐瑰嚮纭鎸夐挳鐨勫洖璋� + deleteRecord() + dialog.dismiss() +} +dialog.show() + +// 鍦ㄥ紓甯稿鐞嗕腑浣跨敤 +private fun handleError(title: String, message: String) { + activity?.let { activity -> + val confirmDialog = ConfirmDialog(activity, title, message) { + // 鐐瑰嚮纭鍚庣殑鎿嶄綔 + resetViewState() + } + confirmDialog.show() + } +} +``` + +#### TipDialog浣跨敤绀轰緥 + +```kotlin +// 绠�鍗曟彁绀� +val tipDialog = TipDialog(context, "鎿嶄綔瀹屾垚") +tipDialog.show() + +// 甯﹀洖璋冪殑鎻愮ず +val tipDialog = TipDialog(context, "纭閫�鍑哄簲鐢紵", object : TipUtil.TipListener { + override fun onCancle() { + // 鍙栨秷鎿嶄綔 + } +}) +tipDialog.show() +``` + +#### 鑷畾涔塂ialog鏈�浣冲疄璺� + +```kotlin +class CustomDialog(context: Context) : Dialog(context, R.style.ws_pay_showSelfDialog) { + + private lateinit var binding: DialogCustomBinding + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + binding = DialogCustomBinding.inflate(layoutInflater) + setContentView(binding.root) + + // 璁剧疆瀵硅瘽妗嗗睘鎬� + setupDialog() + + // 鍒濆鍖栬鍥� + initViews() + } + + private fun setupDialog() { + // 璁剧疆瀵硅瘽妗嗗搴︿负灞忓箷瀹藉害鐨�85% + window?.apply { + val params = attributes + params.width = (context.resources.displayMetrics.widthPixels * 0.85).toInt() + params.height = ViewGroup.LayoutParams.WRAP_CONTENT + params.gravity = Gravity.CENTER + attributes = params + setBackgroundDrawableResource(android.R.color.transparent) + } + + // 璁剧疆鐐瑰嚮澶栭儴涓嶅彇娑� + setCanceledOnTouchOutside(false) + } + + private fun initViews() { + binding.btnConfirm.setOnClickListener { + // 澶勭悊纭閫昏緫 + dismiss() + } + + binding.btnCancel.setOnClickListener { + dismiss() + } + } +} +``` + +#### Dialog浣跨敤娉ㄦ剰浜嬮」 + +1. **鍐呭瓨娉勬紡闃叉姢**: 纭繚鍦ˋctivity閿�姣佹椂鍏抽棴Dialog +```kotlin +override fun onDestroy() { + super.onDestroy() + dialog?.dismiss() +} +``` + +2. **鐢熷懡鍛ㄦ湡绠$悊**: 鍦‵ragment涓娇鐢―ialog鏃舵敞鎰忕敓鍛藉懆鏈� +```kotlin +// 鍦‵ragment涓畨鍏ㄦ樉绀篋ialog +activity?.let { activity -> + if (!activity.isFinishing && !activity.isDestroyed) { + dialog.show() + } +} +``` + +3. **鏍峰紡涓�鑷存��**: 浣跨敤椤圭洰缁熶竴鐨凞ialog鏍峰紡 +```kotlin +// 浣跨敤椤圭洰瀹氫箟鐨凞ialog鏍峰紡 +super(context, R.style.ws_pay_showSelfDialog) +``` + +4. **鐢ㄦ埛浣撻獙浼樺寲**: + - 閲嶈鎿嶄綔浣跨敤ConfirmDialog杩涜浜屾纭 + - 閿欒淇℃伅浣跨敤甯︽爣棰樼殑Dialog锛屾彁渚涙竻鏅扮殑閿欒鍒嗙被 + - 闀挎椂闂存搷浣滄樉绀哄姞杞紻ialog锛岄伩鍏嶇敤鎴疯鎿嶄綔 + +### 閲戦鏍煎紡鍖栨渶浣冲疄璺� + +鍦ㄥ鐞嗛噾棰濈浉鍏崇殑鏁版嵁鏃讹紝搴旇缁熶竴浣跨敤涓や綅灏忔暟鏍煎紡锛岀‘淇濇樉绀虹殑涓�鑷存�у拰鍑嗙‘鎬с�� + +#### 閲戦鏍煎紡鍖栨柟娉� + +```kotlin +// 浣跨敤String.format鏍煎紡鍖栭噾棰濅负涓や綅灏忔暟 +val amount = 123.4 +val formattedAmount = String.format("%.2f", amount) +// 缁撴灉: "123.40" + +// 鍦ㄦ樉绀烘椂娣诲姞璐у竵鍗曚綅 +binding.balanceText.text = "${formattedAmount} 鍏�" +``` + +#### 閲戦杈撳叆楠岃瘉 + +```kotlin +private fun validateAmount(amountStr: String): Double? { + if (amountStr.isEmpty()) { + ToastUtil.show("璇疯緭鍏ラ噾棰�") + return null + } + + val amount = try { + amountStr.toDouble() + } catch (e: NumberFormatException) { + ToastUtil.show("璇疯緭鍏ユ湁鏁堢殑閲戦") + return null + } + + if (amount <= 0) { + ToastUtil.show("閲戦蹇呴』澶т簬0") + return null + } + + // 妫�鏌ュ皬鏁颁綅鏁颁笉瓒呰繃2浣� + val decimalPlaces = amountStr.substringAfter('.', "").length + if (decimalPlaces > 2) { + ToastUtil.show("閲戦鏈�澶氫繚鐣欎袱浣嶅皬鏁�") + return null + } + + return amount +} +``` + +#### 閲戦璁$畻鍜屾樉绀虹ず渚� + +```kotlin +private fun calculateAndDisplayAmounts() { + val rechargeAmount = validateAmount(binding.rechargeAmount.text.toString()) ?: return + val bonusAmount = validateAmount(binding.bonusAmount.text.toString()) ?: 0.0 + + // 璁$畻鎬婚噾棰� + val totalAmount = rechargeAmount + bonusAmount + + // 鏍煎紡鍖栨樉绀� + val formattedRecharge = String.format("%.2f", rechargeAmount) + val formattedBonus = String.format("%.2f", bonusAmount) + val formattedTotal = String.format("%.2f", totalAmount) + + // 鏇存柊UI鏄剧ず + binding.rechargeAmountText.text = "${formattedRecharge} 鍏�" + binding.bonusAmountText.text = "${formattedBonus} 鍏�" + binding.totalAmountText.text = "${formattedTotal} 鍏�" +} +``` + +#### EditText閲戦杈撳叆闄愬埗 + +鍦ㄥ竷灞�鏂囦欢涓缃噾棰濊緭鍏ョ殑闄愬埗锛� + +```xml +<EditText + android:id="@+id/amountEditText" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:inputType="numberDecimal" + android:digits="0123456789." + android:maxLength="10" + android:hint="璇疯緭鍏ラ噾棰�" /> +``` + +#### TextWatcher瀹炵幇灏忔暟浣嶉檺鍒� + +浣跨敤TextWatcher鏉ラ檺鍒剁敤鎴峰彧鑳借緭鍏ユ渶澶氫袱浣嶅皬鏁帮細 + +```kotlin +/** + * 璁剧疆閲戦杈撳叆闄愬埗锛屾渶澶氫繚鐣欎袱浣嶅皬鏁� + */ +private fun setupAmountInputLimit(editText: EditText) { + editText.addTextChangedListener(object : TextWatcher { + override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {} + + override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {} + + override fun afterTextChanged(s: Editable?) { + val text = s.toString() + if (text.isEmpty()) return + + // 妫�鏌ユ槸鍚﹀寘鍚皬鏁扮偣 + if (text.contains(".")) { + val parts = text.split(".") + if (parts.size == 2) { + val decimalPart = parts[1] + // 濡傛灉灏忔暟浣嶈秴杩�2浣嶏紝鎴彇鍓嶄袱浣� + if (decimalPart.length > 2) { + val newText = "${parts[0]}.${decimalPart.substring(0, 2)}" + editText.removeTextChangedListener(this) + editText.setText(newText) + editText.setSelection(newText.length) + editText.addTextChangedListener(this) + } + } + } + + // 闃叉杈撳叆澶氫釜灏忔暟鐐� + val dotCount = text.count { it == '.' } + if (dotCount > 1) { + val newText = text.substring(0, text.lastIndexOf('.')) + editText.removeTextChangedListener(this) + editText.setText(newText) + editText.setSelection(newText.length) + editText.addTextChangedListener(this) + } + + // 闃叉浠ュ皬鏁扮偣寮�澶� + if (text.startsWith(".")) { + editText.removeTextChangedListener(this) + editText.setText("0$text") + editText.setSelection(editText.text.length) + editText.addTextChangedListener(this) + } + } + }) +} + +// 鍦╥nitView涓皟鐢� +setupAmountInputLimit(binding.rechargeAmount) +setupAmountInputLimit(binding.bonusAmount) +``` + +#### 閲戦鏍煎紡鍖栨敞鎰忎簨椤� + +1. **缁熶竴鏍煎紡**: 鎵�鏈夐噾棰濇樉绀洪兘浣跨敤涓や綅灏忔暟鏍煎紡 +2. **杈撳叆楠岃瘉**: 楠岃瘉鐢ㄦ埛杈撳叆鐨勯噾棰濇牸寮忓拰鑼冨洿 +3. **璁$畻绮惧害**: 浣跨敤Double绫诲瀷杩涜閲戦璁$畻锛岄伩鍏嶇簿搴︿涪澶� +4. **鏄剧ず鍗曚綅**: 閲戦鏄剧ず鏃剁粺涓�娣诲姞璐у竵鍗曚綅锛堝"鍏�"锛� +5. **杈圭晫妫�鏌�**: 妫�鏌ラ噾棰濈殑鏈�澶у�煎拰鏈�灏忓�奸檺鍒� + +## 鍏呭�兼帴鍙d娇鐢ㄨ鏄� + +椤圭洰涓疄鐜颁簡瀹屾暣鐨勫厖鍊煎姛鑳斤紝鍖呮嫭鍏呭�兼帴鍙h皟鐢ㄥ拰NFC鍐欏崱鎿嶄綔銆� + +### 鍏呭�兼帴鍙h鎯� + +**鎺ュ彛鍦板潃**: `/terminal/card/termRecharge` +**璇锋眰鏂瑰紡**: POST +**鎺ュ彛鎻忚堪**: 缁堢鍏呭�兼帴鍙o紝鐢ㄤ簬鍒涘缓鍏呭�艰鍗曞苟杩斿洖鍐欏崱鎵�闇�淇℃伅 + +#### 璇锋眰鍙傛暟 + +```kotlin +data class RechargeRequest( + val rechargeType: Int, // 鍏呭�肩被鍨� (鍥哄畾鍊�: 2) + val cardNum: String, // 鍗″彿 + val money: String, // 鍏呭�奸噾棰� (鏍煎紡: "300.0") + val amount: String, // 鍏呭�兼暟閲� + val gift: String, // 璧犻�侀噾棰� + val paymentId: String, // 鏀粯鏂瑰紡ID + val price: String, // 鍗曚环 (鏍煎紡: "0.90") + val remarks: String, // 澶囨敞 (榛樿: "鍏呭��") + val operator: Long // 鎿嶄綔鍛業D +) +``` + +#### 璇锋眰绀轰緥 + +```json +{ + "rechargeType": 2, + "cardNum": "53232810100600001", + "money": "300.0", + "amount": "50", + "gift": "5", + "paymentId": "1838466162264350722", + "price": "0.90", + "remarks": "鍏呭��", + "operator": 2024090516595200300 +} +``` + +#### 杩斿洖鍙傛暟 + +```kotlin +data class RechargeResult( + val projectNo: Int, // 椤圭洰缂栧彿 + val cardNum: String, // 鍗″彿 + val orderNo: String, // 璁㈠崟鍙� + val waterPrice: Double, // 姘翠环 + val time: String // 鏃堕棿 +) +``` + +#### 杩斿洖绀轰緥 + +```json +{ + "code": "0001", + "content": { + "projectNo": 10, + "cardNum": "53232810100600001", + "orderNo": "2506041414250065", + "waterPrice": 0.9, + "time": "2025-05-08 17:31:02" + }, + "msg": "璇锋眰鎴愬姛", + "success": true +} +``` + +### 鍏呭�煎姛鑳藉疄鐜� + +#### 1. 鍦ˋctivity涓皟鐢ㄥ厖鍊兼帴鍙� + +```kotlin +/** + * 璋冪敤鍏呭�兼帴鍙� + */ +private fun callRechargeApi(rechargeAmount: Double, bonusAmount: Double) { + val cardNum = cardInfo?.cardNum ?: cardAddress ?: "" + + // 鏋勫缓鍏呭�艰姹傚弬鏁� + val params = mapOf( + "rechargeType" to 2, + "cardNum" to cardNum, + "money" to String.format("%.1f", rechargeAmount), + "amount" to String.format("%.0f", bonusAmount), + "gift" to String.format("%.0f", bonusAmount), + "paymentId" to paymentId.toString(), + "price" to "0.90", + "remarks" to "鍏呭��", + "operator" to 2024090516595200300L + ) + + ApiManager.getInstance().requestPostLoading( + this, + "terminal/card/termRecharge", + RechargeResult::class.java, + params, + object : SubscriberListener<BaseResponse<RechargeResult>>() { + override fun onNext(response: BaseResponse<RechargeResult>) { + if (response.success && response.code == "0001") { + // 鍏呭�兼垚鍔燂紝璺宠浆鍒板啓鍗$晫闈� + response.content?.let { rechargeResult -> + startWriteCardActivity(rechargeResult, rechargeAmount, bonusAmount) + } + } else { + ToastUtil.show("鍏呭�煎け璐�: ${response.msg ?: "鏈煡閿欒"}") + } + } + + override fun onError(e: Throwable?) { + super.onError(e) + ToastUtil.show("鍏呭�煎け璐�: ${e?.message ?: "缃戠粶寮傚父"}") + } + } + ) +} +``` + +#### 2. 璺宠浆鍒板啓鍗$晫闈� + +```kotlin +/** + * 鍚姩鍐欏崱鐣岄潰 + */ +private fun startWriteCardActivity(rechargeResult: RechargeResult, rechargeAmount: Double, bonusAmount: Double) { + // 鍒涘缓UserCard瀵硅薄鐢ㄤ簬鍐欏崱 + val userCard = UserCard().apply { + cardInfo?.let { info -> + userCode = info.cardNum ?: "" + balance = ((rechargeAmount + bonusAmount) * 100).toInt() // 杞崲涓哄垎 + } + + // 璁剧疆鍏朵粬蹇呰淇℃伅 + projectCode = rechargeResult.projectNo + waterPrice = rechargeResult.waterPrice.toFloat() + rechargeDate = java.util.Calendar.getInstance() + } + + // 鍚姩鍐欏崱Activity + val intent = Intent(this, NfcWreatActivity::class.java).apply { + putExtra("cardType", "USER_CARD") + putExtra("cardAddr", cardAddress) + putExtra("operationTypeCode", CardOperationType.Recharge.code) + putExtra("orderNumber", rechargeResult.orderNo) + putExtra("userCard", userCard) + } + + startActivity(intent) +} +``` + +#### 3. NFC鍐欏崱澶勭悊 + +鍦╜NfcWreatActivity`涓紝鍏呭�兼搷浣滀細琚嚜鍔ㄥ鐞嗭細 + +```kotlin +CardOperationType.Recharge -> { + nfcWreatHelper.writeUserDataAsync(userCard, object : NFCCallBack { + override fun isSusses(flag: Boolean, msg: String?) { + runOnUiThread { + if (flag) { + postCardData(cardType, cardAddr) + ToastUtil.show("鍏呭�煎啓鍗℃垚鍔�!") + } else { + ToastUtil.show("鍏呭�煎啓鍗″け璐�: ${msg ?: "鏈煡閿欒"}") + } + } + } + }) +} +``` + +### 鍏呭�兼祦绋嬭鏄� + +1. **鐢ㄦ埛杈撳叆**: 鐢ㄦ埛鍦ㄥ厖鍊肩晫闈㈣緭鍏ュ厖鍊奸噾棰濆拰璧犻�侀噾棰� +2. **鍙傛暟楠岃瘉**: 楠岃瘉杈撳叆鐨勯噾棰濇牸寮忓拰鏈夋晥鎬� +3. **鎺ュ彛璋冪敤**: 璋冪敤`/terminal/card/termRecharge`鎺ュ彛鍒涘缓鍏呭�艰鍗� +4. **璁㈠崟鍒涘缓**: 鏈嶅姟鍣ㄥ垱寤哄厖鍊艰鍗曞苟杩斿洖璁㈠崟淇℃伅 +5. **璺宠浆鍐欏崱**: 鎴愬姛鍚庤烦杞埌NFC鍐欏崱鐣岄潰 +6. **NFC鍐欏崱**: 鐢ㄦ埛璐村崱杩涜NFC鍐欏崱鎿嶄綔 +7. **鍐欏崱瀹屾垚**: 鍐欏崱鎴愬姛鍚庢洿鏂板崱鐗囦綑棰� + +### 娉ㄦ剰浜嬮」 + +1. **閲戦鏍煎紡**: 鍏呭�奸噾棰濅娇鐢ㄤ竴浣嶅皬鏁版牸寮忥紝濡�"300.0" +2. **鎿嶄綔鍛業D**: 闇�瑕佹牴鎹疄闄呯櫥褰曠敤鎴疯缃纭殑鎿嶄綔鍛業D +3. **鏀粯鏂瑰紡**: 鏀粯鏂瑰紡ID闇�瑕佷粠鏀粯鏂瑰紡鎺ュ彛鑾峰彇 +4. **閿欒澶勭悊**: 鍏呭�煎け璐ユ椂瑕佹彁渚涙槑纭殑閿欒淇℃伅 +5. **鍐欏崱楠岃瘉**: 鍐欏崱鍓嶈楠岃瘉鍗″彿涓�鑷存�� +6. **璁㈠崟璺熻釜**: 淇濆瓨璁㈠崟鍙风敤浜庡悗缁煡璇㈠拰璺熻釜 + +### 鐩稿叧鏁版嵁绫� + +```kotlin +// 鍏呭�艰姹傛暟鎹被 +data class RechargeRequest( + val rechargeType: Int, + val cardNum: String, + val money: String, + val amount: String, + val gift: String, + val paymentId: String, + val price: String, + val remarks: String, + val operator: Long +) + +// 鍏呭�肩粨鏋滄暟鎹被 +data class RechargeResult( + val projectNo: Int, + val cardNum: String, + val orderNo: String, + val waterPrice: Double, + val time: String +) +``` + +## 姘翠环鎺ュ彛浣跨敤璇存槑 + +椤圭洰涓疄鐜颁簡姘翠环鐨勫姩鎬佽幏鍙栧拰绠$悊鍔熻兘锛屾敮鎸佷粠鏈嶅姟鍣ㄨ幏鍙栨渶鏂版按浠峰苟鍦ㄥ叏灞�鑼冨洿鍐呬娇鐢ㄣ�� + +### 姘翠环鎺ュ彛璇︽儏 + +**鎺ュ彛鍦板潃**: `/terminal/client/getWaterPrice` +**璇锋眰鏂瑰紡**: GET +**鎺ュ彛鎻忚堪**: 鑾峰彇褰撳墠绯荤粺姘翠环淇℃伅 + +#### 杩斿洖鍙傛暟 + +```kotlin +data class WaterPriceResult( + val price: Double // 姘翠环 +) +``` + +#### 杩斿洖绀轰緥 + +```json +{ + "code": "0001", + "content": { + "price": 0.9 + }, + "msg": "璇锋眰鎴愬姛", + "success": true +} +``` + +### 姘翠环鍔熻兘瀹炵幇 + +#### 1. BaseApplication涓殑姘翠环瀛樺偍 + +```kotlin +class BaseApplication { + companion object { + // 姘翠环淇℃伅 + var waterPrice: Double = 0.0 + } +} +``` + +#### 2. MainActivity涓欢鏃惰幏鍙栨按浠� + +```kotlin +class MainActivity : BaseNfcActivity() { + private val handler = Handler(Looper.getMainLooper()) + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + // ... 鍏朵粬鍒濆鍖栦唬鐮� ... + + // 寤舵椂20绉掑悗鑾峰彇姘翠环锛岄伩鍏嶅奖鍝嶅惎鍔ㄦ�ц兘 + handler.postDelayed({ + getWaterPrice() + }, 20000) // 20绉掑欢鏃� + } + + /** + * 鑾峰彇姘翠环淇℃伅 + */ + private fun getWaterPrice() { + ApiManager.getInstance().requestGetLoading( + this, + "terminal/client/getWaterPrice", + WaterPriceResult::class.java, + null, + object : SubscriberListener<BaseResponse<WaterPriceResult>>() { + override fun onNext(response: BaseResponse<WaterPriceResult>) { + if (response.success && response.code == "0001") { + // 鑾峰彇姘翠环鎴愬姛锛屼繚瀛樺埌BaseApplication + response.content?.let { waterPriceResult -> + BaseApplication.waterPrice = waterPriceResult.price + } + } + } + + override fun onError(e: Throwable?) { + super.onError(e) + // 缃戠粶寮傚父鏃朵笉鏄剧ず閿欒淇℃伅锛岄伩鍏嶅奖鍝嶇敤鎴蜂綋楠� + } + } + ) + } + + override fun onDestroy() { + super.onDestroy() + // 娓呯悊Handler鍥炶皟锛岄槻姝㈠唴瀛樻硠婕� + handler.removeCallbacksAndMessages(null) + } +} +``` + +#### 3. RechargeDetailActivity涓殑姘翠环妫�鏌ュ拰浣跨敤 + +```kotlin +class RechargeDetailActivity : AppCompatActivity() { + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + // ... 鍏朵粬鍒濆鍖栦唬鐮� ... + + // 妫�鏌ュ苟鑾峰彇姘翠环 + checkAndGetWaterPrice() + } + + /** + * 妫�鏌ュ苟鑾峰彇姘翠环 + */ + private fun checkAndGetWaterPrice() { + // 濡傛灉BaseApplication涓殑姘翠环涓虹┖鎴栦负0锛屽垯閲嶆柊鑾峰彇 + if (BaseApplication.waterPrice <= 0.0) { + getWaterPrice() + } + } + + /** + * 鑾峰彇姘翠环淇℃伅 + */ + private fun getWaterPrice() { + ApiManager.getInstance().requestGetLoading( + this, + "terminal/client/getWaterPrice", + WaterPriceResult::class.java, + null, + object : SubscriberListener<BaseResponse<WaterPriceResult>>() { + override fun onNext(response: BaseResponse<WaterPriceResult>) { + if (response.success && response.code == "0001") { + // 鑾峰彇姘翠环鎴愬姛锛屼繚瀛樺埌BaseApplication + response.content?.let { waterPriceResult -> + BaseApplication.waterPrice = waterPriceResult.price + } + } else { + // 鑾峰彇姘翠环澶辫触锛屼娇鐢ㄩ粯璁ゅ�� + if (BaseApplication.waterPrice <= 0.0) { + BaseApplication.waterPrice = 0.9 // 璁剧疆榛樿姘翠环 + } + } + } + + override fun onError(e: Throwable?) { + super.onError(e) + // 缃戠粶寮傚父锛屼娇鐢ㄩ粯璁ゅ�� + if (BaseApplication.waterPrice <= 0.0) { + BaseApplication.waterPrice = 0.9 // 璁剧疆榛樿姘翠环 + } + } + } + ) + } + + /** + * 鍦ㄥ厖鍊兼帴鍙d腑浣跨敤姘翠环 + */ + private fun callRechargeApi(rechargeAmount: Double, bonusAmount: Double) { + // 鑾峰彇褰撳墠姘翠环锛屽鏋滀负0鍒欎娇鐢ㄩ粯璁ゅ�� + val currentWaterPrice = if (BaseApplication.waterPrice > 0.0) { + BaseApplication.waterPrice + } else { + 0.9 // 榛樿姘翠环 + } + + // 鏋勫缓鍏呭�艰姹傚弬鏁� + val params = mapOf( + // ... 鍏朵粬鍙傛暟 ... + "price" to String.format("%.2f", currentWaterPrice), // 浣跨敤鑾峰彇鍒扮殑姘翠环 + // ... 鍏朵粬鍙傛暟 ... + ) + + // ... 鎺ュ彛璋冪敤浠g爜 ... + } +} +``` + +### 姘翠环绠$悊娴佺▼ + +1. **搴旂敤鍚姩**: MainActivity鍚姩鍚庡欢鏃�20绉掕幏鍙栨按浠凤紝閬垮厤褰卞搷鍚姩鎬ц兘 +2. **鍏ㄥ眬瀛樺偍**: 鑾峰彇鍒扮殑姘翠环瀛樺偍鍦˙aseApplication.waterPrice涓� +3. **鎸夐渶鑾峰彇**: 鍦ㄩ渶瑕佷娇鐢ㄦ按浠风殑鐣岄潰锛堝鍏呭�肩晫闈級妫�鏌ユ按浠锋槸鍚︿负绌� +4. **閲嶆柊鑾峰彇**: 濡傛灉姘翠环涓虹┖鎴栦负0锛屽垯閲嶆柊璋冪敤鎺ュ彛鑾峰彇 +5. **榛樿澶勭悊**: 濡傛灉鑾峰彇澶辫触锛屼娇鐢ㄩ粯璁ゆ按浠�0.9鍏� +6. **瀹炴椂浣跨敤**: 鍦ㄥ厖鍊肩瓑涓氬姟涓娇鐢ㄦ渶鏂扮殑姘翠环淇℃伅 + +### 鎶�鏈壒鐐� + +1. **鎬ц兘浼樺寲**: 寤舵椂鑾峰彇閬垮厤褰卞搷搴旂敤鍚姩閫熷害 +2. **鍏ㄥ眬鍏变韩**: 姘翠环淇℃伅鍦˙aseApplication涓叏灞�鍏变韩 +3. **鎸夐渶鍒锋柊**: 鍦ㄩ渶瑕佹椂妫�鏌ュ苟閲嶆柊鑾峰彇姘翠环 +4. **瀹归敊澶勭悊**: 鑾峰彇澶辫触鏃朵娇鐢ㄩ粯璁ゆ按浠凤紝纭繚涓氬姟姝e父杩涜 +5. **鍐呭瓨绠$悊**: 姝g‘澶勭悊Handler鍥炶皟锛岄槻姝㈠唴瀛樻硠婕� + +### 浣跨敤娉ㄦ剰浜嬮」 + +1. **寤舵椂璁剧疆**: MainActivity涓殑20绉掑欢鏃跺彲鏍规嵁瀹為檯闇�姹傝皟鏁� +2. **榛樿姘翠环**: 榛樿姘翠环0.9鍏冨彲鏍规嵁瀹為檯涓氬姟闇�姹備慨鏀� +3. **閿欒澶勭悊**: 姘翠环鑾峰彇澶辫触鏃朵笉鏄剧ず閿欒淇℃伅锛岄伩鍏嶅奖鍝嶇敤鎴蜂綋楠� +4. **鏁版嵁鏍煎紡**: 姘翠环浣跨敤Double绫诲瀷瀛樺偍锛屼娇鐢ㄦ椂鏍煎紡鍖栦负涓や綅灏忔暟 +5. **鐢熷懡鍛ㄦ湡**: 娉ㄦ剰鍦ˋctivity閿�姣佹椂娓呯悊鐩稿叧璧勬簮 + +### 鐩稿叧鏁版嵁绫� + +```kotlin +// 姘翠环缁撴灉鏁版嵁绫� +data class WaterPriceResult( + val price: Double // 姘翠环 +) +``` + ## 璐$尞鎸囧崡 1. Fork 椤圭洰 -- Gitblit v1.8.0