【React Native】一款跨平臺籃球APP-為愛好而生

一 前言

我本人是一個籃球迷撕阎,平時很喜歡打籃球也有關(guān)注與籃球相關(guān)的資訊虏束,相信NBA對每個籃球迷來講都是一個再熟悉不過在平臺了镇匀『骨郑籃球是我的愛好晃择,而編程是我的職業(yè)宫屠,我是一名移動開發(fā)者浪蹂。業(yè)余時間想著自己搗鼓個應(yīng)用坤次,思來想去覺得就做個與籃球相關(guān)的吧缰猴,一來是自己對這方面稍微了解一些,二來是完成自己的一個念想隘膘。

二 項目背景

應(yīng)用需要兼容目前最主要的兩大移動平臺:Android和IOS弯菊,而為每端獨立開發(fā)一套代碼管钳,就人力來講耗時太長才漆,工作量也相對較大栽烂,所以就考慮使用跨平臺技術(shù)來開發(fā)腺办,選用由FaceBook開源的React Native怀喉,嘗試一下非原生模式的開發(fā)體驗躬拢。

三 技術(shù)棧選型

React Native

React Native框架旨在使用JavaScript代碼構(gòu)建一個跨平臺APP聊闯,圖3.1是RN底層設(shè)計原理框架圖菱蔬。

圖3.1 RN底層設(shè)計原理架構(gòu)圖

JSX可以說是XML的JavaScript語法拓展,在React框架中可以跟JavaScript相互轉(zhuǎn)換蚪腐。直接操作DOM節(jié)點的效率太低回季,Virtual DOM運用Diff算法更新視圖泡一,它實際上是DOM節(jié)點在內(nèi)存中的一種輕型表達方式瘾杭,不同平臺使用各自的渲染引擎來生成UI粥烁。在iOS上使用了內(nèi)置的JavaScriptCore提供JS運行環(huán)境讨阻,而Android上則是采用Webkit.org官方開源的jsc.so钝吮。

Redux

APP的狀態(tài)維護會隨著功能的增加而變得艱難奇瘦,在React中禁止直接操作DOM節(jié)點耳标,不然會出現(xiàn)狀態(tài)變化和異步結(jié)果混淆在一起,但是更新State仍然是個棘手的問題砸琅。而Redex的集成可以讓應(yīng)用中的數(shù)據(jù)流更加可控症脂。

Redux的工作流程如下:當你想要更新狀態(tài)時摊腋,你需要發(fā)送一個活動(Action)兴蒸,Action里面寫清楚你想要干什么橙凳,當你把事情分清楚之后钓觉,需要寫一個把每個Action和返回的新狀態(tài)聯(lián)系起來的函數(shù)荡灾,這種函數(shù)統(tǒng)我們稱它為Reducer批幌,它負責給應(yīng)用中監(jiān)聽狀態(tài)處返回新的狀態(tài)荧缘。

Typescript

熟悉面向?qū)ο箝_發(fā)的開發(fā)者可以選擇TypeScript作為開發(fā)語言截粗,因為它具備面向?qū)ο笳Z言的特性,React Native提供了插件用于將TypeScript轉(zhuǎn)換成JavaScript从诲。它提供了編譯時的類型檢查系洛,可以盡可能地避免JavaScript語言運行時可能出現(xiàn)的‘undefined’問題描扯。

四 開發(fā)環(huán)境搭建

① 使用 Git 進行代碼管理绽诚;

② 本地開發(fā)環(huán)境搭建恩够,參照 React Natie開發(fā)文檔

③ IDE:Visial Studio Code扑媚、Android Studio(本人在應(yīng)用開發(fā)過程僅在Android環(huán)境下進行了調(diào)試疆股,IOS還沒跑過旬痹,想要跑IOS在同學(xué)需要自己搭建開發(fā)環(huán)境两残,可能會一些兼容問題得處理羡忘。)

五 需求分析

了解了用戶的實際需求之后,結(jié)合需求優(yōu)先級磕昼、現(xiàn)有開發(fā)時間、技術(shù)實現(xiàn)難度等影響因素节猿,我提取了將投入實際開發(fā)的APP的幾大功能需求點票从,分別是:賽況模塊、賽事推送滨嘱、球隊模塊、新聞模塊太雨、社區(qū)模塊吟榴、個人中心模塊。圖5.1是APP的功能模塊圖:

圖5.1 功能模塊圖

六 APP效果圖

  1. 登錄模塊
    登錄操作會有用戶賬號的正則表達式校驗囊扳,賬號和密碼的判空操作吩翻,如有問題會有相應(yīng)的錯誤提示,錯誤提示如圖6.1锥咸,6.2所示狭瞎。
6.1 登錄賬號正則表達式檢查

6.2 登錄賬號正則表達式檢查
  1. 推送模塊
    推送模塊需要前后端合作才能讓推送服務(wù)準確無誤,APP端用戶在個人中心進入“我的主隊”入口搏予,選擇一支自己支持的球隊熊锭,提交保存,后臺接到球隊標簽之后根據(jù)實際賽事情況給用戶推送通知雪侥。
    推送模塊的主要測試點在于:對用戶在“我的主隊”頁面的選擇進行檢驗碗殷,由于目前只支持關(guān)注一支球隊,所以需要對用戶的選擇結(jié)果加以校驗并在有誤操作的情況下給予提示速缨;推送服務(wù)的準確性锌妻,對后臺推送的賽事信息中的球隊進行校驗,看是否符合用戶所預(yù)先選擇的標簽旬牲。推送通知測試情況如圖6.3从祝,6.4所示襟己。
6.3 ‘我的主隊’頁面

6.4 通知中心查看賽事推送
  1. 賽況模塊
    賽況頁面的測試點主要在于賽事信息的準確性、詳情頁加載的穩(wěn)定性牍陌、賽事搜索頁面交互的穩(wěn)定性和數(shù)據(jù)的準確性擎浴。
    賽事主頁的賽事加載采用首次進入全量加載,因為每天的比賽場次基本不會超過15場毒涧,所以沒有分頁加載的必要贮预,賽事搜索頁也同樣采用全量加載模式。不同的是契讲,搜索頁中假設(shè)用戶輸入的日期沒有比賽數(shù)據(jù)仿吞,那應(yīng)該吐司提示“所搜索日期無比賽”,而主頁的比賽數(shù)據(jù)默認加載當前和前一天的數(shù)據(jù)捡偏,假設(shè)這兩天沒有數(shù)據(jù)唤冈,則會一次溯源到離當前日期最近的兩天的比賽數(shù)據(jù)。頁面的實現(xiàn)和測試結(jié)果如圖6.5银伟,6.6你虹,6.7,6.8所示彤避。
6.5 賽況首頁

6.6 賽事詳情頁

6.7 賽事搜索頁

6.8 賽事搜索頁'無賽事’
  1. 球隊模塊
    球隊模塊的測試點主要在于球隊信息和球員信息的準確性傅物,球隊主頁的球隊信息加載同樣采用首次進入全量加載,球隊詳情頁中分Tab加載球隊基本數(shù)據(jù)和球員數(shù)據(jù)琉预,進入詳情頁前的網(wǎng)絡(luò)加載會有Spinner提示董饰,網(wǎng)路加載成功后消失。頁面測試情況如圖6.9圆米,6.10所示卒暂。
6.9 球隊首頁

6.10 球隊詳情頁
  1. 新聞模塊
    新聞模塊的測試點主要在于新聞列表的分頁加載,新聞首頁采用首次進入加載10條新聞娄帖,接下來用戶可以點擊頁面下方的“加載更多”介却,隨即加載第二頁的十條數(shù)據(jù),依此類推块茁,由于接口限制齿坷,分頁數(shù)據(jù)最高可達4頁。另一個測試點則是新聞詳情頁WebView加載網(wǎng)頁的穩(wěn)定性数焊。頁面測試情況如圖6.11永淌,6.12所示。
6.11 新聞首頁

6.12 新聞詳情頁
  1. 社區(qū)模塊
    社區(qū)模塊的主要功能有評論提交佩耳、評論插入遂蛀,出于激勵機制,每當用戶提交一個評論干厚,用戶的個人積分會累積10分李滴。測試點主要在于提交評論后評論傳輸?shù)目煽啃泽χ妗⒃u論列表插入評論的準確性、累積積分數(shù)據(jù)的準確性所坯。頁面測試情況如圖6.13谆扎,6.14所示。
6.13 社區(qū)詳情頁提交評論

6.14 社區(qū)詳細內(nèi)容和熱門評論
  1. 個人中心模塊
    個人中心模塊主要測試點在于修改用戶個人資料芹助、提交意見反饋堂湖、評論APP、退出登錄等二級頁面的穩(wěn)定性和可靠性状土。同時還有一個重要入口:“我的主隊”无蜂,在此頁面中用戶可以選擇自己支持和關(guān)注的一支球隊。頁面測試情況如圖6.15蒙谓,6.16所示斥季。
6.15 個人中心首頁

6.16 意見反饋提交頁面

七 總體設(shè)計原理

客戶端-服務(wù)器交互模式

APP數(shù)據(jù)來源于NBA的官方接口和第三方數(shù)據(jù)平臺,客戶端需要向接口的服務(wù)器發(fā)送請求累驮,服務(wù)器識別請求并返回數(shù)據(jù)酣倾。當客戶端監(jiān)聽到用戶觸發(fā)某個事件時,會發(fā)送出對應(yīng)的Action事件慰照,Action中會有對應(yīng)的網(wǎng)絡(luò)請求,由客戶端發(fā)出一個攜帶URL琉朽、參數(shù)等信息的請求毒租,服務(wù)器接收到請求之后訪問數(shù)據(jù)庫,然后予以響應(yīng)箱叁,請求成果則返回相應(yīng)的JSON數(shù)據(jù)墅垮,失敗則返回錯誤碼「客戶端對返回的數(shù)據(jù)進行解析算色,并在相應(yīng)的UI上給予展示。

基于Redux的客戶端數(shù)據(jù)流

APP架構(gòu)采用客戶端常用設(shè)計模式MVC螟够,基于Redux數(shù)據(jù)流灾梦,其主要流程如圖7.1所示,界面UI與數(shù)據(jù)模型通過中間橋梁Action進行關(guān)聯(lián)妓笙,狀態(tài)的改變導(dǎo)致界面的更新若河,導(dǎo)致狀態(tài)改變的事件由活動(Action)發(fā)起,在Reducer函數(shù)進行處置并返回新的狀態(tài)寞宫。

7.1 基于Redux在客戶端數(shù)據(jù)流圖

推送服務(wù)

推送服務(wù)集成了第三方推送平臺極光推送JPush萧福,它供給可視化的web端控制臺,可以用于發(fā)送推送通知辈赋、統(tǒng)計數(shù)據(jù)鲫忍。本畢業(yè)設(shè)計課題中推送服務(wù)的主要目的是提前通知用戶感興趣的賽事信息膏燕,包括比賽的時間和對陣雙方。

在實現(xiàn)上有兩種方案可供選擇悟民,一個是本地通知坝辫,還有一個是遠程通知。

本地通知的原理是這樣的:用戶在APP內(nèi)選擇了自己的“主隊”之后逾雄,客戶端將主隊的標簽以redux緩存保留在本地阀溶,一天內(nèi)用戶第一次打開APP的時候就會網(wǎng)絡(luò)請求后兩天的比賽數(shù)據(jù),將本地的“主隊”標簽與網(wǎng)絡(luò)請求返回的數(shù)據(jù)集進行比對鸦泳,提取出與“主隊”相關(guān)的賽事信息集合银锻,保存在本地。接著做鹰,需要JS層與Native層的交互击纬,自定義一個NativeModule接口,接口里面實現(xiàn)一個從JS層獲取賽事信息集合的方法钾麸,賽事信息集合以方法參數(shù)的形式傳遞過來更振。最后,使用JPush提供的創(chuàng)建本地通知的API構(gòu)建通知饭尝,設(shè)置通知的標題肯腕、內(nèi)容、觸發(fā)時間钥平。最后实撒,客戶端在監(jiān)聽到通知之后就會彈出系統(tǒng)通知框提醒用戶相關(guān)的賽事信息。

遠程通知的原理是這樣的:使用JPush官網(wǎng)提供的服務(wù)端SDK在本地集成一個推送服務(wù)項目涉瘾,用戶在APP內(nèi)選擇了自己的“主隊”之后知态,客戶端將主隊的標簽以redux緩存保留在本地,與此同時立叛,客戶端調(diào)用react-native-jpush提供的接口JPushModule.setAlias(alias, successCallback)將標簽發(fā)送給服務(wù)器SDK负敏,后臺接收到標簽之后會保存起來。每天凌晨零點秘蛇,推送后臺會發(fā)送一個訪問NBA賽事接口的請求其做,獲取當天的比賽數(shù)據(jù)集合,然后與“主隊”標簽做比對赁还,提取出用戶關(guān)注的球隊的賽事信息存放到集合里面庶柿。接著,服務(wù)器調(diào)用JPush服務(wù)端SDK提供的接口JPushClient.createSingleSchedule(name,time,PushPayload)設(shè)置定時推送通知任務(wù)秽浇,推送的用戶根據(jù)就是客戶端提交上來的別名浮庐,在比賽開始前半個小時會給用戶設(shè)備發(fā)送推送通知,客戶端在監(jiān)聽到通知之后就會彈出系統(tǒng)通知框提醒用戶相關(guān)的賽事信息。

綜合比較兩種方案审残,第二種方案更具可行性梭域。第一種方案受網(wǎng)絡(luò)因素限制較大,請求比賽數(shù)據(jù)集合和推送通知都放在客戶端進行處理搅轿,受用戶使用APP情況的影響較大病涨,比如用戶今天沒有打開APP的話,就無法請求數(shù)據(jù)璧坟,通知推送就無法進行既穆。相比之下,將獲取用戶關(guān)注的球隊的賽事信息和推送通知的實現(xiàn)放在服務(wù)端來做的話雀鹃,就可以不受用戶操作APP情況的影響幻工,客戶端只需要監(jiān)聽通知,這個方案更加準確可靠黎茎。

推送服務(wù)方案二的原理圖如圖7.2所示:

Android系統(tǒng)上囊颅,推送進程會作為服務(wù)在后臺運行,創(chuàng)建并操持與服務(wù)器的長連接傅瞻,服務(wù)端則是調(diào)用JPush REST 提供的API來實現(xiàn)自定制的推送服務(wù)踢代。

7.2 推送服務(wù)方案二原理圖

九 所遇問題匯總

QA集合列舉如下:

  1. 運行Android工程失敗

    Q:
    命令行下運行 react-native run-android 
    ERROR  EPERM: operation not permitted, 
    lstat 'F:\VSCodeWorkSpace\RN\basketballWorkflow\android\app\
    
    A:在AS(已在項目的Android目錄下)運行  gradlew clean ,
    重啟服務(wù)react-native start嗅骄,
    然后重新run胳挎。
    
  2. React Navigaion:導(dǎo)航對象沒有根頁面

    Q:Please specify at last one route when you configuring the navigator
    
    A:新建 TabNavigator / StackNavigator 對象的時候,不可沒有根頁面溺森。
    
  3. 更新Typescript

    Q:每次更改文件之后都需要手動執(zhí)行 tsc慕爬,
    待typescript轉(zhuǎn)成javaScript之后,
    才可以執(zhí)行 react-native run-android
    
    A:開一個終端儿惫,運行 tsc -w澡罚,
    即可自動檢測更改并且轉(zhuǎn)換伸但,
    無需手動執(zhí)行 tsc
    
  4. 開啟Hot Reloading動態(tài)更新布局

    Q:調(diào)試頁面布局的時候肾请,需要手動執(zhí)行 react-native run-android 或者 搖動手機 Reloading,
    麻煩且耗時
    
    A:搖一搖手機更胖,開啟手機的 Enable Hot Reloading
    
  5. React Navigation:如何給React Navigator的headerRight添加監(jiān)聽觸摸事件

    Q:如何給React Navigator的headerRight添加監(jiān)聽觸摸事件
    
    A:代碼例子如下:
    static navigationOptions = ({navigation, screenProps}) => ({  
            headerTitle: '登錄',  
            headerLeft:(  
                <Text  onPress={()=>navigation.state.params.navigatePress()} style={{marginLeft:5, width:30, textAlign:"center"}} >  
                    <Icon  name='ios-arrow-back'size={24} color='white' />  
                </Text>  
            )  
        });  
      
        _onBackAndroid=()=>{  
            alert('點擊headerLeft');  
        }  
          
        componentDidMount(){  
            //在static中使用this方法  
            this.props.navigation.setParams({ navigatePress:this._onBackAndroid })  
        }  
    
  6. 打印日志

    Q:如何在控制臺上打印日志(Windows上)
    
    A:打開終端铛铁,輸入  adb logcat *:S ReactNative:V ReactNativeJS:V
    
  7. 關(guān)閉黃色的WarningBox

    Q:
    Warning: isMounted(...) is deprecated in plain JavaScript React classes.
    Instead, make sure to clean up subscriptions and 
    pending requests in componentWillUnmount to prevent memory leaks.
    
    A:
    在index.js中添加忽略這個warning的代碼:
    YellowBox.ignoreWarnings(['Warning: GiftedListView:  isMounted is deprecated.'])
    

十 React Native開發(fā)心得

  • React Native “Write once,run everywhere”的設(shè)計理念能讓開發(fā)者以比較小的學(xué)習(xí)成本來開發(fā)出一個跨平臺的應(yīng)用軟件却妨,很適合數(shù)據(jù)流式的App饵逐,使用Redux能夠很好地管理數(shù)據(jù)狀態(tài);
  • 對于有比較重的需求的軟件彪标,比如需要大量使用地圖倍权,不建議使用RN開發(fā),一個是性能問題沒有原生的好捞烟,還有就是第三方地圖庫對RN的支持不那么完善薄声,很多時候需要自己填坑当船;
  • 使用RN寫UI時,需要關(guān)注頁面重復(fù)渲染的問題默辨,組件的更新在底層使用了diff算法德频,在Props或者State發(fā)生變化時,就會引起組件的重新渲染缩幸,當然這也可以通過shouldComponentUpdate生命周期來加以控制壹置,或者讓組件繼承PureComponent”硪辏可能在渲染數(shù)據(jù)量較小的時候?qū)π阅艿挠绊懖荒敲疵黠@钞护,但是還是得養(yǎng)成在寫代碼過程中關(guān)注性能的好習(xí)慣;
  • 對于RN能否縮短開發(fā)周期铃肯,提高開發(fā)效率的問題患亿,只能說凡事有利有弊,使用RN開發(fā)UI的效率高了押逼,但是在解決一些特定平臺問題上面花的時間可能會比較多步藕,因為有些問題只能放在Native去解決,也就意味著需要Android和iOS各自開發(fā)一套挑格,然后還要加上Naitve與JS交互的代碼咙冗。

后言
關(guān)于APP的介紹這么多了,有什么不對的地方還望多多指教漂彤,也歡迎大家關(guān)注我(簡書/GitHub
謝謝觀看此文雾消。
歡迎訪問 源代碼地址

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市挫望,隨后出現(xiàn)的幾起案子立润,更是在濱河造成了極大的恐慌,老刑警劉巖媳板,帶你破解...
    沈念sama閱讀 212,816評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件桑腮,死亡現(xiàn)場離奇詭異,居然都是意外死亡蛉幸,警方通過查閱死者的電腦和手機破讨,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,729評論 3 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來奕纫,“玉大人提陶,你說我怎么就攤上這事∑ゲ悖” “怎么了隙笆?”我有些...
    開封第一講書人閱讀 158,300評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我撑柔,道長煤率,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,780評論 1 285
  • 正文 為了忘掉前任乏冀,我火速辦了婚禮蝶糯,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘辆沦。我一直安慰自己昼捍,他們只是感情好,可當我...
    茶點故事閱讀 65,890評論 6 385
  • 文/花漫 我一把揭開白布肢扯。 她就那樣靜靜地躺著妒茬,像睡著了一般。 火紅的嫁衣襯著肌膚如雪蔚晨。 梳的紋絲不亂的頭發(fā)上乍钻,一...
    開封第一講書人閱讀 50,084評論 1 291
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死定枷,一個胖子當著我的面吹牛忆绰,可吹牛的內(nèi)容都是我干的与帆。 我是一名探鬼主播,決...
    沈念sama閱讀 39,151評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了析孽?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,912評論 0 268
  • 序言:老撾萬榮一對情侶失蹤只怎,失蹤者是張志新(化名)和其女友劉穎袜瞬,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體身堡,經(jīng)...
    沈念sama閱讀 44,355評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡邓尤,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,666評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了盾沫。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片裁赠。...
    茶點故事閱讀 38,809評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡殿漠,死狀恐怖赴精,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情绞幌,我是刑警寧澤蕾哟,帶...
    沈念sama閱讀 34,504評論 4 334
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響谭确,放射性物質(zhì)發(fā)生泄漏帘营。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 40,150評論 3 317
  • 文/蒙蒙 一逐哈、第九天 我趴在偏房一處隱蔽的房頂上張望芬迄。 院中可真熱鬧,春花似錦昂秃、人聲如沸禀梳。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,882評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽算途。三九已至,卻和暖如春蚀腿,著一層夾襖步出監(jiān)牢的瞬間嘴瓤,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,121評論 1 267
  • 我被黑心中介騙來泰國打工莉钙, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留廓脆,地道東北人。 一個月前我還...
    沈念sama閱讀 46,628評論 2 362
  • 正文 我出身青樓磁玉,卻偏偏與公主長得像狞贱,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子蜀涨,可洞房花燭夜當晚...
    茶點故事閱讀 43,724評論 2 351

推薦閱讀更多精彩內(nèi)容

  • 用兩張圖告訴你瞎嬉,為什么你的 App 會卡頓? - Android - 掘金 Cover 有什么料? 從這篇文章中你...
    hw1212閱讀 12,704評論 2 59
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 171,867評論 25 707
  • 1厚柳、通過CocoaPods安裝項目名稱項目信息 AFNetworking網(wǎng)絡(luò)請求組件 FMDB本地數(shù)據(jù)庫組件 SD...
    陽明先生_X自主閱讀 15,971評論 3 119
  • 雨别垮,已經(jīng)連續(xù)下了三天便监,時大時小,驟急刻緩碳想,陰云總不見散烧董。我是喜歡下雨的,雨滴一落胧奔,仿佛整個世界都安靜了逊移,喧囂湮沒在...
    芝士夾心閱讀 225評論 0 1
  • 坡道: 今天好友尚錕在群里問大家胳泉,怎樣才能更好的追女生拐叉,如何才能更好的與異性相處 這個問題以前我也不太懂,后來學(xué)習(xí)...
    鄭惠彭閱讀 847評論 0 7