自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

一種Android客戶端架構(gòu)設計分享

移動開發(fā) Android
技術(shù)發(fā)展日新月異,業(yè)界各種Android客戶端架構(gòu)設計,五花八門,但我們不能簡單地說哪種架構(gòu)更好,因為脫離業(yè)務談架構(gòu)是沒有任何意義的,適合業(yè)務的才是好架構(gòu)。而架構(gòu)也不是一成不變的,隨著業(yè)務的發(fā)展,也許當初設計的架構(gòu)已不足以支撐目前的業(yè)務,那么就需要改變之前的架構(gòu)。

前言:技術(shù)發(fā)展日新月異,業(yè)界各種Android客戶端架構(gòu)設計,五花八門,但我們不能簡單地說哪種架構(gòu)更好,因為脫離業(yè)務談架構(gòu)是沒有任何意義的,適合業(yè)務的才是好架構(gòu)。而架構(gòu)也不是一成不變的,隨著業(yè)務的發(fā)展,也許當初設計的架構(gòu)已不足以支撐目前的業(yè)務,那么就需要改變之前的架構(gòu)。接下來將分享下我們Android客戶端的架構(gòu)設計,在App的某個業(yè)務發(fā)展階段或許有一些參考意義。

分層化與模塊化

分層化與模塊化應該是任何軟件開發(fā)的共識。

分層化

在Android應用開發(fā)中通??梢苑譃槿缦聨讓樱?nbsp; 

 

  • SDK層:主要是Android SDK及第三方的SDK(可能基于Android SDK或為獨立的SDK),這些SDK為上層框架提供核心功能的支持。
  • 基礎框架層:這里所謂的基礎框架,指多數(shù)App都必需的基礎功能,是具體業(yè)務邏輯實現(xiàn)的基礎。主要有網(wǎng)絡請求功能、圖片加載與緩存功能、SQLite數(shù)據(jù)庫管理功能、Log管理功能等,當然根據(jù)對業(yè)務邏輯支持的不同,基礎框架層的功能支持也不一定相同,上述幾個應該是大部分App都要支持的,當然Crash監(jiān)控與常用工具類也可歸為該層次。

具體到每個基礎框架的實現(xiàn)則沒有任何限制,如網(wǎng)絡功能可以使用Volley、OkHttp或者自己封裝實現(xiàn)網(wǎng)絡請求邏輯;對于圖片管理功能則可以使用Glide、Fresco、Picasso,亦或自己實現(xiàn)……總之每個基礎框架都要遵循一定的實現(xiàn)原則,保持功能模塊的獨立性,與具體業(yè)務解耦并對外提供良好的交互接口。

  • 業(yè)務邏輯層:如果把App架構(gòu)比作高層建筑,那么上述兩層就是地基。地基打好之后,就可以在上面任意發(fā)揮了,至于如何發(fā)揮,那就必須結(jié)合實際的業(yè)務需求,不同的應用往往有不同的業(yè)務功能模塊。

另一方面,業(yè)務功能模塊也并非完全是并列的級別,有一些業(yè)務邏輯也是可以抽象出來的,作為通用的功能模塊,比如登錄、分享、掃描、統(tǒng)計等,其他的業(yè)務模塊可能會調(diào)用到這些功能。

這里需要注意的是SDK層與基礎框架層并不是一成不變的,但它們的變化周期往往是比較長的,一般來說當基礎功能不能滿足最上層的業(yè)務邏輯時,就需要對其做擴展。由于基礎框架層的功能模塊已經(jīng)是功能級別的粒度劃分,因此擴展往往是模塊級別的擴展,通常是新增基礎功能框架而不是修改原有基礎功能框架,這也符合“開放-閉合”原則。

模塊化

至于模塊化,對于分層化來說則是更細粒度的劃分,即將每一層細分為不同的模塊,各功能模塊盡可能遵循“高內(nèi)聚、低耦合”的原則,功能模塊之間僅提供必要的交互接口。

對于基礎框架層,由上圖可見,往往是根據(jù)功能來劃分。這里的基礎框架層細分為網(wǎng)絡支持功能、圖片庫、日志系統(tǒng)、數(shù)據(jù)庫支持等模塊,如果不足以支撐業(yè)務發(fā)展,可能會新增其他基礎功能模塊。

而業(yè)務邏輯層則主要由業(yè)務需求來決定,如分為掃描功能、電商、快遞查詢等模塊。業(yè)務邏輯層的模塊化還有一種驅(qū)動因素,那就是通用功能的封裝,這一點大家應該都有體會,隨著App業(yè)務邏輯的增加,不同業(yè)務功能之間可能會用到相同的功能,如用戶登錄、分享功能等,我們不希望在每個需要的地方都復寫一遍相關(guān)代碼,于是就需要把通用功能抽取成獨立于具體業(yè)務需求的模塊,如登錄模塊、分享模塊,在模塊內(nèi)部實現(xiàn)通用的業(yè)務邏輯,同時對外暴露調(diào)用接口,不同的業(yè)務只需調(diào)用通用模塊即可。

業(yè)務數(shù)據(jù)流程設計

由于業(yè)務邏輯、數(shù)據(jù)處理邏輯或網(wǎng)絡框架的不同,相信各家應用都有自己的一套數(shù)據(jù)請求流程。最直接的就是從Activity或Fragment中調(diào)用網(wǎng)絡請求的方法,然后通過回調(diào)將結(jié)果返回到Activity或Fragment中,雖然流程最清晰,但這種方式存在幾個嚴重的問題:

  • 網(wǎng)絡數(shù)據(jù)直接返回到Activity或Fragment中,后續(xù)需要對數(shù)據(jù)進行解析、過濾、轉(zhuǎn)換、緩存等操作,這些工作將會大大加重Activity或Fragment的負擔。
  • Activity或Fragment的代碼量猛增,邏輯繁雜(不僅包含了View的邏輯還包含了數(shù)據(jù)處理的邏輯)
  • 從整個應用的角度來看,每個頁面甚至每個接口都需要重復上述相同的冗余工作,完全可以抽象出來。

上述設計思路是需要摒棄的,結(jié)合自身業(yè)務及架構(gòu)演化,我們沒有跟風MVP、MVVM,而是設計了下面一套業(yè)務數(shù)據(jù)請求流程: 

 

 

業(yè)務數(shù)據(jù)請求流程 

首先,視圖層通常表現(xiàn)為Activity或Fragment,并由視圖層發(fā)起數(shù)據(jù)請求,與上述不同,視圖層并不直接跟網(wǎng)絡框架打交道,而是先將數(shù)據(jù)請求發(fā)送到數(shù)據(jù)代理層DataAgent。需要注意到是,視圖層與數(shù)據(jù)代理層之間沒有采用直接通信的方式,而是插入了一個消息調(diào)度器MessageScheduler中轉(zhuǎn)。這樣做的好處是將視圖層與數(shù)據(jù)代理層解耦,視圖層無需關(guān)注數(shù)據(jù)代理層的具體實現(xiàn),有了MessageScheduler,視圖層所要做的就是發(fā)出一個數(shù)據(jù)請求的消息而已,然后就可以靜靜等待一個回復消息,該回復消息會附帶最終需要的數(shù)據(jù)對象,這樣在視圖層就免除了數(shù)據(jù)處理的邏輯,拿到結(jié)果直接展示到UI上即可。使用這種方式,一般來講Activity或Fragment三五百行代碼即可搞定,UI邏輯或接口邏輯(如一個頁面有多個接口)比較復雜的代碼量基本也能控制在1000行左右,邏輯非常清爽。

消息調(diào)度器將視圖層的請求消息轉(zhuǎn)發(fā)到數(shù)據(jù)代理層后,DataAgent解析出數(shù)據(jù)請求類型DataType(該類型對應著具體數(shù)據(jù)對象模型)、必要參數(shù)(接口參數(shù)、是否需要緩存結(jié)果、分頁頁碼等),然后再執(zhí)行具體的操作:

  • 如果要取緩存的數(shù)據(jù),則DataAgent直接向緩存模塊發(fā)送請求。緩存的數(shù)據(jù)可以是初始JSON數(shù)據(jù),也可以是解析處理后得到的數(shù)據(jù)對象Model,可根據(jù)具體需求配置。如果從緩存中取到的是JSON,則DataAgent先要解析處理得到對應Model;如果從緩存中取到的是Model,則不做處理,然后將Model封裝發(fā)回到消息調(diào)度器,再由MessageScheduler分發(fā)給具體的請求者,如Activity或Fragment。
  • 由于Android的數(shù)據(jù)來源有多種,如果數(shù)據(jù)來自持久化存儲,如SQLite或File等,仍然統(tǒng)一由DataAgent來跟它們通信,獲取數(shù)據(jù)并加工后通過MessageScheduler發(fā)回視圖層。
  • 最常見的是從服務器獲取數(shù)據(jù),此種場景下,DataAgent將與網(wǎng)絡框架交互,將從MessageScheduler中獲取的參數(shù)提供給網(wǎng)絡框架構(gòu)造請求url。至于網(wǎng)絡框架使用Volley或OkHttp或者其他都沒關(guān)系,網(wǎng)絡框架負責向Server請求數(shù)據(jù),數(shù)據(jù)通常以JSON格式返回。DataAgent收到返回的JSON數(shù)據(jù)后,根據(jù)DataType將JSON數(shù)據(jù)校驗后拋給解析器,解析器會將JSON解析為視圖層需要的Model。當然數(shù)據(jù)解析過程可能伴隨數(shù)據(jù)的過濾、轉(zhuǎn)換等邏輯。另外需要注意的是,還需要根據(jù)視圖層需求對數(shù)據(jù)進行是否緩存的操作,可選擇緩存JSON還是Model。經(jīng)過一系列操作,得到最終Model后,DataAgent將其通過MessageScheduler發(fā)回視圖層。

當然,由于數(shù)據(jù)請求流程是耗時的,因此上述步驟都是走的線程池,這點上圖中并未注明。

數(shù)據(jù)代理層

DataAgent在上文中已簡單提及,它的主要作用是對數(shù)據(jù)的一系列操作,包括實際的數(shù)據(jù)請求、數(shù)據(jù)解析處理、數(shù)據(jù)緩存等邏輯。下圖為從服務端接口獲取JSON數(shù)據(jù)并處理的流程: 

 

 

從服務端接口獲取JSON數(shù)據(jù)并處理的流程 

從上圖可知,DataAgent的大致工作流程為:

  • DataAgent將真正的數(shù)據(jù)請求發(fā)送給各數(shù)據(jù)源,數(shù)據(jù)源可能為緩存、SQLite或文件,但通常是從服務端獲取數(shù)據(jù),因此DataAgent會將數(shù)據(jù)請求發(fā)到網(wǎng)絡框架層,然后等待數(shù)據(jù)返回。
  • 由于數(shù)據(jù)源不同,返回數(shù)據(jù)也可能不同,這里簡化為兩種:原始JSON或Model。
  • DataAgent拿到數(shù)據(jù)后,則開始數(shù)據(jù)處理流程。以從網(wǎng)絡請求的JSON數(shù)據(jù)為例,先對返回的JSON進行數(shù)據(jù)校驗,檢查數(shù)據(jù)的有效性與正確性,如果數(shù)據(jù)校驗通過,接下來根據(jù)需求來決定要不要寫入緩存,然后再進行數(shù)據(jù)加工(如精度處理、數(shù)據(jù)拼接、數(shù)據(jù)裁剪等),***進行數(shù)據(jù)解析得到視圖層需要的Model。如果數(shù)據(jù)校驗沒有通過,則嘗試從緩存中讀取,從緩存中讀取后也需要校驗(檢查數(shù)據(jù)的時效性、有效性、正確性),校驗通過后同樣進行數(shù)據(jù)處理、解析等流程。如果緩存中讀取得到的就是Model,那么則可以省略數(shù)據(jù)處理和解析的流程。得到最終的Model后,DataAgent將其包裝發(fā)送給MessageScheduler。另外DataAgent還要具有一定的容錯功能,因為任何數(shù)據(jù)源都無法保證能夠返回合法的數(shù)據(jù),如果不對數(shù)據(jù)錯誤進行容錯處理,那么就可能無法解析為對應的Model,從而導致視圖層無數(shù)據(jù)甚至異常。如果接口及緩存都無法返回正確的數(shù)據(jù),DataAgent需要做特殊處理,以保證視圖層能給用戶以反饋。

業(yè)務視圖邏輯

雖然不同的業(yè)務頁面有不同的視圖邏輯,這里以一個應用中最常見的頁面為例來說明,假設該頁面有一個列表。大家都知道ListView(此處為泛指,可能大家都在用RecyclerView了)的工作方式,它需要ViewHolder來填充視圖,需要Adapter來填充數(shù)據(jù),如果每個需要ListView的界面都維護各自的一套ViewHolder及Adapter,那么頁面邏輯又將變得臃腫。

我們在實踐中是這樣做的:

  • 封裝一個Adapter公共處理類,提供多種構(gòu)造函數(shù),其中有一個type參數(shù),用來標明需要使用哪個ViewHolder。
  • 封裝一個ViewHolder抽象類,定義數(shù)據(jù)設置的邏輯,并交由具體的ViewHolder實現(xiàn)。
  • 構(gòu)建一個叫做ViewHolderFactory的類,顧名思義該類主要作用是用來構(gòu)建ViewHolder,它主要提供兩個方法createViewHolder()與createConvertView(),其中createConvertView()是個中間方法,用于生成ViewHolder。
  • 在Adapter的getView方法中,根據(jù)上述type參數(shù),獲取具體的ViewHolder實現(xiàn),調(diào)用設置數(shù)據(jù)的邏輯。

經(jīng)過上述封裝之后,視圖層只需要向Adapter公共處理類傳入一個type參數(shù)即可得到對應的Adapter;等數(shù)據(jù)返回到視圖層后,再將數(shù)據(jù)傳給Adapter公共處理類,其他什么都不用管,就可以展示列表數(shù)據(jù)了。原本需要很多代碼實現(xiàn)的邏輯從視圖層抽離之后,視圖層只需要幾行代碼就能夠完成一個列表展示了。

Hybrid框架

自Android誕生以來,就有Native App與Web App之爭,這兩種開發(fā)方式雖然各有優(yōu)缺點,但Native App一直占據(jù)上風。近一兩年來,移動應用中的Web頁面越來越多,而純Native的應用則相對越來越少。但是純Web App由于其渲染效率、性能問題、對硬件的調(diào)用限制導致其也并未廣泛地應用。于是一種折中的方案成為主流,即Hybrid App。

所謂Hybrid App,即混合開發(fā)方式,部分功能使用Native開發(fā),部分功能使用H5開發(fā)。為了充分利用Web開發(fā)的優(yōu)點并避開其缺點,并非所有業(yè)務功能都適合使用Web方式來開發(fā)。在我們的應用中,主要將H5用于以下方面:

  • 節(jié)日活動或游戲頁、秒殺或團購頁等具有時效性的頁面。
  • 使用說明、公告等偏展示、少交互的頁面。
  • 經(jīng)常更新、交互較少且不涉及硬件調(diào)用的頁面或模塊,如電商商品首頁展示、積分兌換模塊。

截止到目前,我們App中的Web頁所占比重是上升的,大概占到所有功能的25%左右。使用Web開發(fā)的優(yōu)勢非常明顯,可以支持多變的UI視圖效果、節(jié)省開發(fā)人力(Android、iOS共用)、Bug的在線修復而不用App發(fā)版等。

為了滿足App的Web頁面需求,于是我們在基礎框架層擴展了一個Hybrid功能模塊。該框架主要是自行封裝了Android原生的WebView控件,且分為不同層級的封裝,可根據(jù)需要靈活使用,核心功能及特性如下:

  • 支持完整的Web頁面,即整個頁面的內(nèi)容全部是H5實現(xiàn),外部容器為Activity或Fragment。
  • 支持局部的Web頁面,即部分頁面的內(nèi)容是H5實現(xiàn),可單獨使用自定義的WebView或者嵌入Fragment使用。
  • 定義了一套較為完整的交互協(xié)議,支持Native與JS的互相調(diào)用,典型的場景如H5頁面點擊跳轉(zhuǎn)Native功能頁面(支持傳參)、JS喚起Native對話框或Toast等,同時Java也能調(diào)用JS函數(shù)。基于此套交互協(xié)議,基本能夠滿足日常App中Web開發(fā)需求。
  • 避免了JS注入漏洞。
  • 支持同一個Web頁面中Http與Https混合的場景。
  • 向業(yè)務邏輯層暴露接口,可根據(jù)需求定制WebViewClient與WebChromeClient。
  • 對外提供接口,可根據(jù)需求控制縮放、Cookie管理、緩存管理、硬件加速等。
  • 經(jīng)過試驗與摸索,兼容多種Android設備及版本。

雖然后來出現(xiàn)了React Native,但由于學習成本及其Android版本的局限性,結(jié)合我們自己團隊的人力資源原因,我們尚未在應用中正式使用。目前仍然以Hybrid開發(fā)為主,且其在整個應用中的比重越來越大,因此Hybrid框架是我們架構(gòu)中重要的一個組成部分。

消息調(diào)度中心

前面業(yè)務數(shù)據(jù)流程的設計中,在視圖層與數(shù)據(jù)代理層之間插入了一個消息調(diào)度器——MessageScheduler,MessageScheduler主要功能就是管理消息及消息調(diào)度。

MessageScheduler核心原理是維護了一個哈希表,當收到視圖層的數(shù)據(jù)請求時就使用唯一的key將發(fā)起者保存到哈希表中,以便稍后收到DataAgent的返回數(shù)據(jù)后,能夠找到發(fā)起者。存儲好消息發(fā)起者的信息后,即向DataAgent發(fā)送數(shù)據(jù)請求,多個數(shù)據(jù)請求是可以并行的,主要在于線程池的線程數(shù)控制機制。DataAgent返回數(shù)據(jù)之后,MessageScheduler根據(jù)唯一key找到初始的請求者,同樣利用消息機制將請求結(jié)果返回給視圖層,同時在哈希表中清除該元素。其示意圖如下: 

 

 

 

消息分發(fā)器

既然有了消息調(diào)度機制,就需要消息分發(fā)器MessageDispatcher,來負責發(fā)送消息。

MessageDispatcher本質(zhì)上是利用了Android的消息機制來對業(yè)務需求進行封裝和擴展??催^Android Framework層源碼就會發(fā)現(xiàn)其實Android框架本身就有很多地方使用了消息機制來進行通信,Android消息機制可以在模塊頁面間、線程間通信,甚至可以在進程間使用Messenger通信(Messenger方式是利用了消息機制,當然還有其他進程間通信方式)。

MessageDispatcher功能比較簡單,支持兩種方式:

  • 點對點的通信,如兩個頁面之間,通信目標唯一,如上文提到的從視圖層發(fā)送數(shù)據(jù)請求消息到消息調(diào)度器。
  • 點對面的通信,類似于廣播,也有點像EventBus,一條消息發(fā)出,凡是注冊(或叫訂閱)過的頁面都能收到通知;也可以進一步通過Tag控制達到一對一發(fā)送。

其示意圖如下: 

 

 

 

模塊路由中心

一個完整的應用中,免不了模塊之間、功能頁面之間的跳轉(zhuǎn)。當然在需要的地方通過Intent可以實現(xiàn)跳轉(zhuǎn),但這不是一個好的方案,很明顯不同模塊或頁面之間的耦合度增加了。而我們的原則是模塊和頁面之間盡可能解耦,于是設計了一個模塊路由(Module Routing)中心,App中所有的頁面跳轉(zhuǎn)均由其控制。

模塊路由的核心原理是給功能頁面進行唯一編碼,編碼的邏輯可以跟隨產(chǎn)品版本定義到應用中,并保證兼容之前版本。這樣就可以在應用的任何地方只需要向模塊路由中心發(fā)送對應模塊頁面的編碼即可,由模塊路由負責打開目標頁面。

以下幾點需要注意:

  • 整個應用中的功能頁編碼都必須保證唯一
  • 如打開某些功能頁面除了具體編碼外,還可能需要額外參數(shù)。如打開商品詳情頁,除了知道商品詳情頁的編碼外,還需要商品ID,模塊路由需要對附加參數(shù)提供支持。
  • 模塊路由支持打開Web頁面,即Hybrid頁面也支持上述特定編碼,所以在Web頁面上點擊跳轉(zhuǎn)Native頁面使用的協(xié)議也是由模塊路由支持的。

使用模塊路由的好處有:

  • 大量減少應用中的跳轉(zhuǎn)Intent
  • 模塊之間、頁面之間解耦
  • 適配變化,統(tǒng)一管理,修改方便

其他

日志系統(tǒng)

在開發(fā)過程中,甚至運行過程中,日志都是很重要的一部分。當然Android提供了Log相關(guān)的API,但不建議這一行那一行地零星使用,否則如果想統(tǒng)一控制Tag或關(guān)閉Log時非常麻煩。建議對Log API進行簡單封裝或者使用現(xiàn)有第三方Log庫,將Log功能獨立出來,提供統(tǒng)一的調(diào)用接口、級別控制、開關(guān)控制,這樣既方便調(diào)試也方便管理,同時也能為整個應用代碼的清晰做出一點貢獻。

線上崩潰監(jiān)控

對線上應用的Crash監(jiān)控是提高應用穩(wěn)定性、優(yōu)化應用性能的一個重要方法。我們構(gòu)建了一個小型的全局監(jiān)控系統(tǒng),主要由以下功能特性:

  • 對用戶不可見,用戶無感知
  • 全局注冊即可開啟監(jiān)控
  • 捕捉線上崩潰,保存到本地文件
  • 線上崩潰信息按一定策略上傳服務器,上傳后同時刪除本地文件
  • 崩潰信息主要包括Android設備信息(如手機型號、系統(tǒng)版本等)、App版本號、異常信息等

服務器收到上傳的線上崩潰信息后,也按一定策略通過郵件方式通知到開發(fā)者,以便開發(fā)者及時修復異常。線上崩潰監(jiān)測系統(tǒng)雖然小而簡單,但作用非常重要,利用線上崩潰反饋可以有效地提高應用的穩(wěn)定性,建議在應用設計中務必給它留出一個位置。

統(tǒng)計系統(tǒng)

相信大部分應用都有統(tǒng)計分析后臺,可以統(tǒng)計應用的日活、PV、UV或其他用戶行為,也可能有一部分應用是使用的第三方統(tǒng)計功能,如友盟等。結(jié)合公司BI部門的統(tǒng)計需求,我們客戶端自行設計了一套統(tǒng)計方案,用于Android與iOS兩個客戶端。之所以不用第三方統(tǒng)計,主要是因為我們無法根據(jù)需求自由定制且數(shù)據(jù)不在自家服務器,另一方面也有些許數(shù)據(jù)泄露的風險。

基于客戶端的統(tǒng)計系統(tǒng)主要包括三個方面的功能:

  • 數(shù)據(jù)采集
  • 數(shù)據(jù)存儲
  • 數(shù)據(jù)上傳

對于數(shù)據(jù)采集,主要針對統(tǒng)計部門的需求,如采集設備信息、定位信息、App啟動時間次數(shù)、PV、UV、甚至用戶行為,如點擊、切換Tab、頁面流向跟蹤等。

為了避免每次采集完數(shù)據(jù)后就即時上傳,因此需要數(shù)據(jù)存儲,將采集的統(tǒng)計數(shù)據(jù)暫存到本地,一般使用SQLite。然后采用一定策略進行上傳,如數(shù)據(jù)累積到50條或者應用切換到后臺時進行上傳。

對于數(shù)據(jù)上傳,除了上傳時機的選擇策略外,還要遵循一定的結(jié)構(gòu)字段,該結(jié)構(gòu)可以根據(jù)數(shù)據(jù)統(tǒng)計部門的需求來定義。數(shù)據(jù)上傳的流程同樣可以使用之前的數(shù)據(jù)請求框架,只不過返回值可能為一個成功提示而已。

基于上述功能,我們自定義的統(tǒng)計功能模塊提供了方便的調(diào)用接口,并支持靈活擴展,目前可以***支持日常的統(tǒng)計需求,調(diào)用也非常簡單,只需要在需要統(tǒng)計的地方插入一行代碼即可。

域名劫持應對策略

最近遇到域名劫持的問題,真是頭疼,另一方面也說明我們的流量引起運營商注意了。目前主流的有幾下幾種方案:

  • 向運營商投訴。此方法非常被動且效果不佳,完全掌控在運營商手中。
  • 使用httpDNS。此方法使用http的方式直接獲取***IP,繞過localDNS的解析,可謂徹底解決了域名劫持。
  • 先使用域名嘗試,域名失敗后再使用IP嘗試。此方案屬于容災方案,并不能避免域名劫持。

理論上講第二種是***方案,但由于httpDNS為第三方服務,也無法保證效果,外加上付費及接入成本等因素,我們暫時采用了第三種容災方案,主要實施邏輯如下:

  • 應用預先內(nèi)置IP。
  • 每次啟動應用時獲取***IP,并保存到應用本地。
  • 請求數(shù)據(jù)時,先使用域名走正常的邏輯,一旦遇到疑似劫持的問題后,使用本地的IP進行直連嘗試。

上述步驟其實是有漏洞的,比如啟動時獲取***IP的接口如果被劫持了,那么就無法獲取***IP,假如剛好同時服務器IP也改變了,因此預先內(nèi)置的IP已經(jīng)失效,此時就徹底沒辦法了。不過上述兩個條件同時滿足的概率比較小,因此可以使用該方案解決很大一部分域名劫持問題。另外從服務端獲取的IP,如果有多個的話,還需要增加一些策略,即考慮到負載均衡、訪問速度、穩(wěn)定性、網(wǎng)絡運營商等因素,如何確定客戶端拿到的哪一個是***IP,當然這點可以優(yōu)化,但首先能保證用戶看到頁面數(shù)據(jù)或許更加重要。

上述應對域名劫持的策略本身并不能獨立成一個模塊,我們把它集成為網(wǎng)絡框架的擴展。

總結(jié)

上文提到的是我們Android應用架構(gòu)中的核心部分,可能你發(fā)現(xiàn)并沒有什么花哨的、潮流的玩意兒,沒有MVP,沒有RxAndroid,沒有插件化,也沒有熱修復……但就是這樣它仍然支撐起了上億的用戶量。世上沒有***的架構(gòu),只有符合自身業(yè)務的架構(gòu),上述架構(gòu)還有很多缺點,我們也在有選擇、有步驟地重構(gòu),而隨著業(yè)務需求的擴展,架構(gòu)也會不斷演化,***希望本文能給大家?guī)硪稽c參考意義。 

責任編輯:龐桂玉 來源: Android開發(fā)中文站
相關(guān)推薦

2023-03-31 13:31:45

2016-05-09 09:26:06

架構(gòu)ios網(wǎng)絡層

2013-09-04 12:38:56

架構(gòu)設計架構(gòu)設計構(gòu)思

2017-07-05 14:09:04

系統(tǒng)設計與架構(gòu)java云計算

2023-12-26 08:16:56

Kafka緩存架構(gòu)客戶端

2014-09-02 10:54:20

架構(gòu)設計權(quán)限系統(tǒng)

2009-12-22 18:18:11

WCF客戶端編程

2010-02-22 11:10:17

WCF獲取客戶端IP

2011-07-01 10:00:11

Ubuntu OneAndroid

2011-03-07 13:50:20

2020-11-22 08:10:05

架構(gòu)運維技術(shù)

2009-01-15 09:43:51

Web架構(gòu)設計緩存

2013-03-20 11:01:37

Redis客戶端連接

2012-05-24 10:19:42

QQ瀏覽器Android設計分享

2020-05-14 14:48:15

架構(gòu)模式單庫

2011-08-17 10:10:59

2019-07-22 15:59:21

2021-09-22 15:46:29

虛擬桌面瘦客戶端胖客戶端

2020-10-19 13:05:32

架構(gòu)模式

2016-03-25 09:57:09

統(tǒng)一監(jiān)控報警平臺運維
點贊
收藏

51CTO技術(shù)棧公眾號