生活随笔
收集整理的這篇文章主要介紹了
Android开发面试:架构设计和网络知识答案精解
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
目錄
架構(gòu)設(shè)計
編程思想
六大設(shè)計原則
重構(gòu)-Code Smell
AOP
設(shè)計模式
創(chuàng)建型5個
行為型11個
結(jié)構(gòu)型7個
編程范式
MVC
MVP
MVVM
MVI
模塊化
組件化
插件化、熱修復
Jectpack
網(wǎng)絡(luò)
網(wǎng)絡(luò)基礎(chǔ)
TCP/UDP協(xié)議
Http/Https協(xié)議
Socket通信
架構(gòu)設(shè)計
編程思想
六大設(shè)計原則
SOLID分類:單一職責原則、開閉原則、里氏替換原則、最少知道原則、接口隔離原則、依賴倒置原則 Single Responsibility Principle:不能有多個導致類變更的原因。一個類中應(yīng)該是一組相關(guān)性很高的函數(shù)、數(shù)據(jù)的封裝。一個類只負責一個職責。這個原則不僅僅適用于類,對于接口和方法也適用,而且接口和方法的單一職責更容易實現(xiàn)。實際開發(fā)中,這是一個備受爭議卻又及其重要的原則?!獑我宦氊熢瓌t Open Closed Principle:軟件中的對象(類、模塊、函數(shù)等)應(yīng)該對擴展開放,對修改關(guān)閉(勃蘭特·梅耶認為,類只應(yīng)該因錯誤而被修改)。也就是應(yīng)該通過擴展來實現(xiàn)變化,而不是通過修改已有的代碼來實現(xiàn)改變。例如,現(xiàn)在業(yè)務(wù)需求有改變,所有書均打七折。有三個方法可以解決這個問題:第一種方法:修改接口。增加一個方法getOffPrice專門進行打折處理。第二種方法:修改實現(xiàn)類,在實現(xiàn)類里修改getPrice方法。第三種方法:重新擴展一個類繼承NovelBook,重新復寫getPrice方法。根據(jù)對擴展開放對修改關(guān)閉原則我們應(yīng)該選擇第三種解決方法。但實際開發(fā)中,修改原有代碼、擴展代碼(通過繼承的方式來升級、維護原有系統(tǒng))往往是同時存在的?!_閉原則 Liskov Substitution Principle:就是只要父類出現(xiàn)的地方子類就可以出現(xiàn),且替換成子類也不會出現(xiàn)任何錯誤或者異常;但是反過來,有子類出現(xiàn)的地方,父類不一定可以適用。也就是說,子類可以擴展父類的功能,但不能改變父類原有的功能。①子類可以實現(xiàn)父類的抽象方法,但不能覆蓋父類的非抽象方法。②子類可以有自己的個性,所以子類出現(xiàn)的地方父類就不一定適用。③實現(xiàn)父類的方法時,形參的類型可以被放大。④實現(xiàn)父類的方法時,返回值的類型可以縮小。通過里氏替換來達到對擴展開放,對修改關(guān)閉的效果。——里氏替換原則 Law of Demeter:也叫最少知道原則。一個對象應(yīng)該對其他對象有最少的了解。低耦合、高內(nèi)聚。——迪米特法則 Interface Segregation Principle:客戶端不應(yīng)該依賴它不需要的接口。接口/抽象中的方法盡量少。單一職責原則是按照職責(業(yè)務(wù)邏輯)進行劃分接口的,而接口隔離原則則是按照實現(xiàn)類對方法的使用來劃分的??梢哉f,接口隔離原則更細一些。①接口盡量小。根據(jù)具體業(yè)務(wù)把一個接口按照接口隔離原則細化成更多的接口。但是在此基礎(chǔ)之上必須不能違背單一職責原則。②接口要高內(nèi)聚。就是說,在接口內(nèi)部實現(xiàn)的方法,不管怎么改,都不會影響到接口外的其他接口或是實現(xiàn)類,只能影響它自己。③定制服務(wù)。定制服務(wù)就是單獨為一個個體提供服務(wù),即只提供訪問者需要的方法。④接口設(shè)計是有限度的。接口設(shè)計越小越好,但是結(jié)構(gòu)同時會變得復雜,維護也變得難了。因此就要把握住這個度。——接口隔離原則 Dependence Inversion Principle:面向接口/抽象編程。①模塊間的依賴關(guān)系通過接口和抽象類產(chǎn)生,實體類之間不直接發(fā)生依賴關(guān)系。②接口和抽象類不依賴于實現(xiàn)類。③實現(xiàn)類依賴接口或者抽象類。模塊間的依賴通過抽象發(fā)生,實現(xiàn)類之間不發(fā)生直接的依賴關(guān)系,其依賴關(guān)系是通過接口或抽象類產(chǎn)生的?!蕾嚨怪迷瓌t
重構(gòu)-Code Smell
《重構(gòu):改善既有代碼的設(shè)計》在該書的第3章“代碼的壞味道”中,收錄了Kent Beck關(guān)于重構(gòu)時機的理解——Code Smell,如果尿布臭了,就換掉它。 Code Smell的22種代碼壞味道如下 Duplicated Code。a、同一個class內(nèi)的兩個函數(shù)含有相同的表達式。——需要Extract Method,提煉出重復代碼,然后讓兩個地點都調(diào)用被提煉出來的那一段代碼。b、兩個互為兄弟的subclass內(nèi)含相同的表達式,要避免這種情況——需要兩個class都使用Extract Method,把Extract的Method推入superclass內(nèi)。c、兩個毫不相干的classes內(nèi)出現(xiàn)Duplicate Code,你應(yīng)該考慮對其中一個使用Extract Class,將重復代碼提煉到一個獨立class中,然后在另一個class內(nèi)使用這個新class。——重復代碼 Long Method。應(yīng)該積極地分解函數(shù)。a、每當感覺需要注釋來說明點什么的時候,就把需要說明的東西封裝成一個函數(shù),并以用途(而非實現(xiàn)手法)命名。b、條件表達式和循環(huán)常常也是提煉的信號?!^長函數(shù) Large Class。應(yīng)該重新抽象。大類就是你把太多的責任交給了一個類?!^大的類 Long Parameter List。使用已有對象封裝參數(shù),或者制造一個參數(shù)對象?!^長參數(shù)列 Divergent Change。一個類受到多種變化的影響。將對象拆分成多個對象,這么一來每個對象就可以只因一種變化而需要修改?!l(fā)散式變化 Shotgun Surgery。這正好和上面相反。一種變化引發(fā)多個類相應(yīng)修改。把需要修改的代碼放進同一個類?!睆検叫薷?/li> Feature Envy。如果一個類的方法頻繁用get 方法存取其他類的狀態(tài)進行計算,那么你要考慮把行為移到涉及狀態(tài)數(shù)目最多的那個類。有時候方法中只有一部分受這種依戀之苦,那就封裝那部分把它帶去夢中家園。有時候一個函數(shù)往往會用到幾個類的功能,那就把這個函數(shù)放在擁有最多被此函數(shù)使用的數(shù)據(jù)的類中去。——依戀情節(jié) Data Clumps。將幾個數(shù)據(jù)封裝成對象。某些數(shù)據(jù)通常像孩子一樣成群玩耍,一起出現(xiàn)在很多類的成員變量中,一起出現(xiàn)在許多方法的參數(shù)中,這些數(shù)據(jù)或許應(yīng)該自己獨立形成對象。一旦擁有新對象,就可以著手尋找Feature Envy?!獢?shù)據(jù)泥團 Primitive Obsession。將幾個有關(guān)聯(lián)的基本數(shù)據(jù)封裝成對象。面向?qū)ο蟮男率滞ǔA晳T使用幾個原始類型的數(shù)據(jù)來表示一個概念。譬如對于范圍,他們會使用兩個數(shù)字。對于Money,他們會用一個浮點數(shù)來表示。因為你沒有使用對象來表達問題中存在的概念,這使得代碼變的難以理解,解決問題的難度大大增加。好的習慣是擴充語言所能提供原始類型,用小對象來表示范圍、金額、 轉(zhuǎn)化率、郵政編碼等等。——基本類型偏執(zhí) Switch Statement。使用多態(tài)替換。少用switch語句,從本質(zhì)上說,switch語句的問題在于重復?!猻witch驚悚現(xiàn)身 Parallel Inheritance Hierarchies。可以讓一個繼承體系的實例引用另一個繼承體系的實例。并行的繼承層次是shotgun surgery 的特殊情況。每當你為某個類增加一個子類,必須也為另一個類相應(yīng)增加一個子類?!叫欣^承體系 Lazy Class。刪除。某個類沒有做足夠的工作,請讓這個類莊嚴赴義吧?!哔橆?/li> Speculative Generality。刪除。一個類實現(xiàn)了從未用到的功能和通用性。通常這樣的類或方法唯一的用戶是test case。不要猶豫,刪除它。但如果它們的用途是幫助測試用例檢測正當功能,當然必須刀下留人?!淇淦湔勎磥硇?/li> Temporary Field。抽象成類。一個對象的屬性可能只在某些情況下才有意義。這樣的代碼將難以理解。專門建立一個對象來持有這樣的孤兒屬性,把只和他相關(guān)的行為移到該類。最常見的是一個特定的算法需要某些只有該算法才有用的變量?!钊嗣曰蟮臅簳r字段 Message Chain。提煉函數(shù)、隱藏分派。消息鏈發(fā)生于當一個客戶向一個對象要求另一個對象,然后客戶又向這另一對象要求另一個對象,再向這另一個對象要求另一個對象,如此如此。先觀察消息鏈最終得到的對象是用來干什么的,看看能否以Extract Method把使用該對象的代碼提煉到一個獨立函數(shù)中,再運用Move Method把這個函數(shù)推入消息鏈。如果這條鏈上的某個對象有多位客戶打算航行此航線的剩余部分,就加一個函數(shù)來做這件事?!^度耦合的消息鏈 Middle Man。刪除。對象的基本特性之一就是封裝,而你經(jīng)常會通過分派去實現(xiàn)封裝。但是這一步不能走得太遠,如果你發(fā)現(xiàn)一個類接口的一大半方法都在做分派,你可能需要移去這個中間人?!虚g人 Inappropriate Intimacy。劃清界限,拆散,合并,單向聯(lián)系。某些類相互之間太親密,它們花費了太多的時間去專研別人的私有部分。對人類而言,我們也許不應(yīng)該太假正經(jīng),但我們應(yīng)當讓自己的類嚴格遵守禁欲主義。——狎昵關(guān)系 Alternative Classes with Different Interfaces。重命名,合并。做相同事情的方法有不同的函數(shù)簽名,一致把它們往類層次上移,直至協(xié)議一致。——異曲同工的類 Incomplete Library Class。使用裝飾模式來包裝類。要建立一個好的類庫非常困難。我們大量的程序工作都基于類庫實現(xiàn)。然而,如此廣泛而又相異的目標對庫構(gòu)建者提出了苛刻的要求。庫構(gòu)建者也不是萬能的。有時候我們會發(fā)現(xiàn)庫類無法實現(xiàn)我們需要的功能。而直接對庫類的修改有非常困難。這時候就需要用各種手段進行重構(gòu)?!煌昝赖膸祛?/li> Data Class。將相關(guān)操作封裝進去,減少public成員變量。對象包括狀態(tài)和行為。如果一個類只有狀態(tài)沒有行為,那么肯定有什么地方出問題了?!冎傻臄?shù)據(jù)類 Refused Bequest。用代理替代繼承。超類傳下來很多行為和狀態(tài),而子類只是用了其中的很小一部分。這通常意味著你的類層次有問題?!痪芙^的遺贈 Comments。人們常把注釋當做除臭劑來使用,經(jīng)常覺得要寫很多注釋表示你的代碼難以理解。當你感覺需要撰寫注釋時,請先嘗試重構(gòu)。——過多的注釋 設(shè)計模式是你希望到達的目標,重構(gòu)則是到達之路
AOP
OOP與AOP:OOP(面向?qū)ο缶幊?#xff0c;是一種典型的縱向編程方式,更多關(guān)注的是對象Object本身的功能,對象之間的功能聯(lián)系往往不會考慮那么詳細)、AOP(面向切面編程,切面,也叫橫向,和OOP一樣,是一種程序設(shè)計思想,通過預編譯方式和運行期動態(tài)代理,實現(xiàn)程序功能的統(tǒng)一維護,橫切關(guān)注點是一個抽象的概念,它是指那些在項目中貫穿多個模塊的業(yè)務(wù),AOP在將橫切關(guān)注點與業(yè)務(wù)主體進行分類,從而提高程序代碼模塊化程度,將涉及到眾多模塊的某一類功能進行統(tǒng)一管理) AOP好處:就拿添加調(diào)用日志舉例,AOP的好處在于:a、類更專注于它的職責(核心代碼中不用包含日志調(diào)用代碼);b、修改工作量更小(只需要修改相應(yīng)的配置文件和日志的實現(xiàn));c、解耦(App不依賴于具體日志框架,在處理Log標簽的地方統(tǒng)一Log框架即可;實現(xiàn)AOP的同時需要依賴注入,這又會減少模塊間依賴) AOP實現(xiàn):運行時切入(epic框架、Dexposed)、編譯時切入(APT——Java編譯之前處理注解生成代碼、ApsectJ——Java編譯階段修改Java代碼、Javassist/ASM——Java編譯之后對class字節(jié)碼進行修改) APT:Annotation Processing Tool,注解處理器,是一種處理注解的工具,在編譯時掃描、解析、處理注解,生成.java文件(它會對源代碼文件進行檢測,找出用戶自定義的注解,根據(jù)注解、注解處理器和相應(yīng)的APT工具自動生成代碼——這段代碼是根據(jù)用戶編寫的注解處理邏輯去生成的,最終將生成的新的源文件與原來的源文件共同編譯(注:APT并不能對源文件進行修改操作,只能生成新的文件)) 注解實現(xiàn)AOP:DataBinding、Dagger2、ButterKnife、EventBus3、DBFlow、AndroidAnnotation,為什么這些框架注解實現(xiàn)AOP要使用APT?(Android注解解析框架主要兩種實現(xiàn)方法:a、一種是運行期通過反射去解析當前類,注入相應(yīng)要運行的方法;b、另一種就是APT,在編譯期生成類的代理類,在運行期直接調(diào)用代理類的代理方法)如果不使用APT基于注解動態(tài)生成java代碼,那么就需要在運行時使用反射或者動態(tài)代理,導致App性能下降 ASM與epic:ASM(是一個Java字節(jié)碼層面的代碼分析及修改工具,利用class被打包為dex前的間隙,插入ASM相關(guān)邏輯對class文件進行操縱行操縱,可以實現(xiàn)動態(tài)生成類,或者基于現(xiàn)有的類進行功能擴展)、epic(ART中函數(shù)的調(diào)用約定,去修改函數(shù)的內(nèi)容,將函數(shù)前兩條指令修改為跳轉(zhuǎn)到自定義邏輯,從而實現(xiàn)對任意方法的Hook) hook:反射/動態(tài)代理(作用于Java層,虛擬機提供的標準編程接口,可靠性較高。如:用動態(tài)代理構(gòu)造出一個代理對象,然后用反射API去替換進程中對象,從而達到hook目的,對Java Framework API修改常用這種方法,修改ActivityThread、當前進程的系統(tǒng)調(diào)用)、JNI Hook(Java層與Native之間的函數(shù))、ClassLoader修改(通過修改ClassLoader加載Java class的Path路徑達到目的,常見應(yīng)用場景:一些熱修復技術(shù),穩(wěn)定性高,不過需要提前編譯好修改后的class去替換,靈活性低)、Xposed(這類hook技術(shù)原理都是去修改ART/Dalvik虛擬機,大量的一些自動化測試、動態(tài)調(diào)試都采用這個方法)
設(shè)計模式
創(chuàng)建型5個
分類:單例模式、工廠方法模式、抽象工廠模式、原型模式、建造者模式 單例模式:定義(確保某一個類只有一個實例,而且自行實例化并向整個系統(tǒng)提供這個實例。即:讓整個生命周期內(nèi)只有一個實例)、使用場景(a、一個類專門提供一些公共功能供別人調(diào)用,而本身并不會處理業(yè)務(wù)邏輯,那么創(chuàng)建多個實例,會消耗內(nèi)存,造成不必要的開銷,此時需要單例;b、如果創(chuàng)建一個對象需要消耗的資源過多,如要訪問IO和數(shù)據(jù)庫等資源,這時就要考慮使用單例模式)、實現(xiàn)方式(a、懶漢式-非線程安全,雙重校驗鎖-線程安全,靜態(tài)內(nèi)部類-線程安全,餓漢式-線程安全,枚舉-線程安全,容器實現(xiàn)-非線程安全;b、不管以哪種形式實現(xiàn)單例模式,它們的核心原理都是將構(gòu)造函數(shù)私有化,并且通過靜態(tài)方法獲取一個唯一實例,在這個獲取過程中必須保證線程安全、防止反序列化導致重新生成實例對象的問題)、優(yōu)點(a、減少內(nèi)存開銷;b、減少系統(tǒng)性能開銷;c、避免對資源的重復占用;d、優(yōu)化和共享資源訪問)、缺點(a、不容易擴展,基本只能通過修改代碼去擴展;b、如果持有了context就容易引發(fā)內(nèi)存泄漏,建議使用ApplicationContext) 工廠方法模式:定義(定義一個用于創(chuàng)建對象的接口,讓子類決定實例化哪個類)、使用場景(復雜對象創(chuàng)建可以使用工廠模式,用new就可以完成對象創(chuàng)建就無需使用工廠模式)、小結(jié)(a、降低對象之間耦合性;b、其依賴于抽象架構(gòu),將實例化任務(wù)交給子類去完成,有非常好擴展) 抽象工廠模式:定義(為創(chuàng)建一組相關(guān)或是相互依賴的對象提供一個接口,而不需要指定它們具體類,是圍繞一個超級工廠創(chuàng)建其他工廠)、使用場景(一個對象族有相同約束時可以使用抽象工廠模式,能解決接口選擇問題(比如Android和iOS是不同系統(tǒng)但有相同的電話、短信等軟件;比如Android中的主題修改,多套主題,不同按鈕彈窗樣式))、小結(jié)(很好做到了接口與實現(xiàn)分離,客戶端面向接口接口編程;但類比較多,每增加一個工廠會對應(yīng)增加具體多種產(chǎn)品類;而且擴展性不好,每當增加一個產(chǎn)品類就需要修改抽象工廠,所有具體工廠也要修改) 原型模式:定義(用原型模式指定創(chuàng)建對象的種類,并通過復制這些原型創(chuàng)建新的對象,簡單來說就是對象的克隆,我們稱將要被克隆的對象為原型)、使用場景(a、類初始化或new一個新對象,需要消耗非常多資源時,可以考慮使用原型設(shè)計模式提升對象創(chuàng)建的效率——因為通過原型復制的方式不會執(zhí)行構(gòu)造方法,避免了初始化占有的時間和空間;b、一個對象需要提供給其他對象訪問,并且該對象希望對外是只讀的情況時,可以考慮使用原型模式通過返回一個對象拷貝的形式實現(xiàn)只讀限制——保護性拷貝)、實現(xiàn)方式(new或clone)、深淺拷貝問題(注意對于非基本數(shù)據(jù)類型的引用類型的淺拷貝問題,由于指向的同一堆對象內(nèi)存地址,修改一處后多處引用會存在聯(lián)動問題;一般建議原型模式盡量使用深拷貝,避免對原型對象造成副作用)、小結(jié)(原型設(shè)計模式是在內(nèi)存中二進制流的拷貝,要比直接new一個對象性能好很多;不過這既是它的優(yōu)點亦是它的缺點,因為直接在內(nèi)存中拷貝,構(gòu)造函數(shù)不會執(zhí)行,這是個需要注意的問題) 建造者模式:定義(將一個復雜對象的構(gòu)建與它的表示分離,使得同樣的構(gòu)建過程可以創(chuàng)建不同的表示)、使用場景(a、初始化一個對象特別復雜時(如:參數(shù)較多,且很多參數(shù)都具有默認值);b、相同的方法,不同的執(zhí)行順序,產(chǎn)生不同的事件結(jié)果時;c、產(chǎn)品類非常復雜,或者產(chǎn)品類中的調(diào)用順序不同產(chǎn)生了不同的作用,這個時候使用建造者模式非常合適)、小結(jié)(Builder模式在Android開發(fā)中也較為常用,通常作為配置類的構(gòu)建器將配置的構(gòu)建和表示分離開來,同時也是將配置從目標類中隔離出來,避免過多的setter方法;Builder模式比較常見的實現(xiàn)形式是通過調(diào)用鏈實現(xiàn),這樣使得代碼更簡潔、易懂)、優(yōu)點(良好的封裝性,使用建造者模式可以使客戶端不必知道產(chǎn)品內(nèi)部組成的細節(jié);建造者獨立,容易擴展)、 缺點(會產(chǎn)生多余的Builder對象以及Director對象,消耗內(nèi)存 )
行為型11個
分類:觀察者模式、策略模式、模板方法模式、命令模式、迭代器模式、中介者模式、備忘錄模式、解釋器模式、狀態(tài)模式、責任鏈模式、訪問者模式 策略模式:定義(策略模式定義了一系列的算法,并將每一個算法封裝起來,而且使他們可以互相替換,讓算法獨立于使用它的客戶而獨立變化)、使用場景(a、飛機、火車、汽車等每一種出行方式都是一個策略;b、商場打折,買2送1、買1件打88折等促銷方式;c、總的來說,使用繼承違背常理(狗繼承動物,讓它飛就太天真了)時,使用實現(xiàn)繁瑣(猴雞狗豬都會叫,他們都各自實現(xiàn)叫的方法太累了)時,此時可以考慮組合(也就是策略模式的表現(xiàn)形式))、設(shè)計原則(a、找出應(yīng)用中可能需要變化之處,把它們獨立出來,不要和那些不需要變化的代碼混在一起;b、針對接口編程,而不是針對實現(xiàn)編程;c、開閉原則:對擴展開放、對修改關(guān)閉)、優(yōu)點(a、結(jié)構(gòu)清晰明了、使用簡單直接;b、耦合度相對較低,擴展性好;c、操作封裝也更為徹底,數(shù)據(jù)更為安全)、缺點(策略類會增多,并且所有策略類都需要對外暴露) 狀態(tài)模式:定義(當一個對象的內(nèi)在狀態(tài)改變時允許改變其行為,這個對象看起來好像修改了它的類)、使用場景(a、一個對象的行為取決于它的狀態(tài),并且它必須在運行時根據(jù)狀態(tài)改變它的行為;b、代碼中包含大量與對象狀態(tài)有關(guān)的條件語句,如:一個操作中含有龐大的多分支語句(ifelse或switchcase),且這些分支依賴于該對象的狀態(tài))、小結(jié)(狀態(tài)模式和策略模式結(jié)構(gòu)幾乎完全一樣,但它們目的和本質(zhì)卻完全不一樣)、優(yōu)點(將繁瑣的狀態(tài)判斷轉(zhuǎn)換成結(jié)構(gòu)清晰的狀態(tài)族,在避免代碼膨脹的同時也保證了可擴展性與可維護性)、缺點(增加系統(tǒng)類和對象的個數(shù))
結(jié)構(gòu)型7個
分類:適配器模式、裝飾模式、代理模式、組合模式、橋接模式、外觀模式、享元模式
編程范式
分類:命令式編程(面向過程、面向?qū)ο?、聲明式編程(函數(shù)式編程、邏輯式)、響應(yīng)式編程 理解:a、命令式編程(Imperative):詳細的命令機器怎么(How)去處理一件事情以達到你想要的結(jié)果(What),如C、C++、Java等;b、聲明式編程(Declarative):只告訴你想要的結(jié)果(What),機器自己摸索過程(How),是在命令式編程之上的抽象,如SQL、HTML、正則表達式等,Kotlin支持函數(shù)式編程;c、響應(yīng)式編程(Reactive):是一種通過異步和數(shù)據(jù)流來構(gòu)建事務(wù)關(guān)系的編程模型,基于觀察者模型并提供了非阻塞、異步的特性,RxJava使得Java平臺也有了能夠?qū)崿F(xiàn)響應(yīng)式編程的框架
MVC
缺點:a、XML做為View層,控制能力太差;b、View與Model存在耦和;c、Activity既作為Control也作為View,違背單一職責原則、最少知道原則,當業(yè)務(wù)邏輯復雜時導致Activity臃腫、代碼量龐大 小結(jié):MVC是MVP、MVVM、MVI的爹
MVP
優(yōu)點:a、解耦View與Model,分離View和業(yè)務(wù)邏輯;b、Activity只負責顯示,代碼變得更加簡潔,提高代碼閱讀性;c、方便對業(yè)務(wù)做單測,直接對presenter 缺點:a、presenter復用性不強;b、持有View引用導致內(nèi)存泄漏;c、隨著業(yè)務(wù)邏輯的增加,導致View的接口變得龐大 如何避免內(nèi)存泄漏:在Activity銷毀時釋放presenter,presenter把View置為null,取消網(wǎng)絡(luò)請求等;使用Lifecycle 接口比較多怎么處理:將通用接口抽象出來放在基類,非通用接口采用繼承方式
MVVM
理解:在MVC思想上實現(xiàn)了數(shù)據(jù)驅(qū)動UI。View產(chǎn)生事件,使用ViewModel進行邏輯處理后,通知Model更新數(shù)據(jù),Model把更新的數(shù)據(jù)給ViewModel, ViewModel通過LiveData自動通知View更新界面,實現(xiàn)數(shù)據(jù)驅(qū)動UI,只要LiveData的數(shù)據(jù)修改UI能自動響應(yīng)更新 優(yōu)點:a、解耦更徹底,viewmodel不持有view;b、viewmodel復用性更強;c、沒有內(nèi)存泄漏;d、數(shù)據(jù)驅(qū)動解決MVP接口龐大問題 缺點:a、ViewModel和View通信更困難,可能通過LiveEventBus實現(xiàn);b、為保證對外暴露的LiveData是不可變的,需要添加不少模板代碼并且容易遺忘;c、View層與ViewModel層的交互比較分散零亂,不成體系
MVI
理解:在MVC基礎(chǔ)上實現(xiàn)了響應(yīng)式編程(Reactive)范式。安卓官方的compose框架、微信小程序、Flutter、React、鴻蒙UI的開發(fā)框架,都是使用響應(yīng)式開發(fā)框架。Model:與MVVM中的Model不同的是,MVI的Model主要指UI狀態(tài)(State),例如頁面加載狀態(tài)、控件位置等都是一種UI狀態(tài);View:與其他MVX中的View一致,可能是一個Activity或者任意UI承載單元,MVI中的View通過訂閱Intent的變化實現(xiàn)界面刷新;Intent:此Intent不是Activity的Intent,用戶的任何操作都被包裝成Intent后發(fā)送給Model層進行數(shù)據(jù)請求 優(yōu)點:a、強調(diào)數(shù)據(jù)單向流動,很容易對狀態(tài)變化進行跟蹤和回溯;b、使用ViewState對State集中管理,只需要訂閱一個ViewState便可獲取頁面的所有狀態(tài),相對MVVM減少了不少模板代碼;c、ViewModel通過ViewState與Action通信,通過瀏覽ViewState和Aciton定義就可以理清ViewModel的職責,可以直接拿來作為接口文檔使用 缺點:a、所有的操作最終都會轉(zhuǎn)換成State,所以當復雜頁面的State容易膨脹;b、state是不變的,因此每當state需要更新時都要創(chuàng)建新對象替代老對象,這會帶來一定內(nèi)存開銷
模塊化
原本一個App模塊承載所有功能,而模塊化就是拆分成多個模塊放在不同Module,每個功能的代碼都在自己所屬module中添加 通常還會有一個通用基礎(chǔ)模塊module_common,提供BaseActivity/BaseFragment、圖片加載、網(wǎng)絡(luò)請求等基礎(chǔ)能力,然后每個業(yè)務(wù)模塊都會依賴這個基礎(chǔ)模塊 多個模塊中肯定會有頁面跳轉(zhuǎn)、數(shù)據(jù)傳遞、方法調(diào)用等情況,所以必然存業(yè)務(wù)模塊間的依賴關(guān)系,這樣模塊間高耦合度加上代碼量變大,就會嚴重影響團隊開發(fā)效率及質(zhì)量
組件化
什么是組件化:去除模塊間耦合,使每個業(yè)務(wù)模塊可以獨立當做App存在,對于其他模塊沒有直接依賴關(guān)系,此時業(yè)務(wù)模塊就成為了業(yè)務(wù)組件,除了業(yè)務(wù)組件還有包括功能組件,模塊化到組件化的過程可以看作從業(yè)務(wù)導向到功能導向的過程 組件化優(yōu)點:a、加快編譯速度(每個業(yè)務(wù)功能都是一個單獨工程,可獨立編譯運行,拆分后代碼量較少,編譯速度變快);b、 提高協(xié)作效率(解耦使得組件之間彼此互不打擾,組件內(nèi)部代碼相關(guān)性極高;團隊中每個人有自己的責任組件,不會影響其他組件;降低團隊成員熟悉項目的成本,只需熟悉責任組件即可;對測試來說,只需重點測試改動的組件,而不是全盤回歸測試) 組件化方案:基礎(chǔ)組件層(包含一些基礎(chǔ)庫以及對基礎(chǔ)庫的封裝,如圖片加載、網(wǎng)絡(luò)請求、日志框架、數(shù)據(jù)存儲等)、功能組件層(包含一些簡單的功能組件,如視頻組件、支付組件等)、MiddleWare中間件層、業(yè)務(wù)組件層、App殼工程
插件化、熱修復
什么是插件化:所謂插件化,就是讓應(yīng)用不必再像原來一樣把所有內(nèi)容都放在一個Apk中,可以把一些功能和邏輯單獨抽出來放在插件Apk中,然后主Apk做到按需調(diào)用,主要是一種動態(tài)加載四大組件的技術(shù) 插件化優(yōu)點:a、減少主Apk體積、65535問題(在Dalvik字節(jié)碼規(guī)范里方法個數(shù)超過了65535,但在art虛擬機上已不存在此問題),讓應(yīng)用更輕便;b、讓用戶不用重新安裝Apk就能升級應(yīng)用功能,減少發(fā)版本頻率,增加用戶體驗 插件化框架:a、最早的插件化框架(2012年大眾點評的屠毅敏就推出了AndroidDynamicLoader框架);b、主流的插件化方案(滴滴任玉剛的VirtualApk、 騰訊的Shadow、Small框架、愛奇藝的Qigsaw、Google AAB) 插件化流程:插件化技術(shù)為了解決類加載和資源加載的問題,主要是動態(tài)加載的過程,包括以下幾步:a、把可執(zhí)行文件(.so/dex/jar/apk等)拷貝到應(yīng)用App內(nèi)部;b、加載可執(zhí)行文件,更換靜態(tài)資源;c、調(diào)用具體方法執(zhí)行業(yè)務(wù)邏輯 插件化原理:主要方案就是先在AndroidManifest.xml中注冊一個Activity來進行占坑,用來通過AMS校驗,接著在合適的時機用插件Activity替換占坑Activity。類加載原理、資源加載原理(反射調(diào)用AssetManager的addAssetPath)、Activity加載原理(代理:dynamic-load-apk采用(通過代理的Activity去執(zhí)行插件中的Activity,加載對應(yīng)生命周期);Hook:主流(Hook IActivityManager或Hook Instrumentation))
Jectpack
DataBinding之ViewBinding和DataBinding區(qū)別:a、目的不同(ViewBinding的出現(xiàn)僅僅是為了幫開發(fā)人員省去寫findViewById的步驟;而DataBinding是用于綁定數(shù)據(jù)的,能夠把視圖的數(shù)據(jù)和代碼變量綁定起來,并且實現(xiàn)自動更新。這個特性使得DataBinding能和MVVM框架進行很好的配合);b、 初始化方式不同(ViewBinding通過生成的Binding類的inflate方法來加載布局,然后還需要用Activity的setContentView()方法來綁定;而Databinding則是通過DataBindingUtil.setContentView()來綁定的);c、包含關(guān)系(DataBinding也有ViewBinding的功能,也可以省去findViewById()方法) ViewModel:ViewModel旨在以生命周期方式存儲和管理用戶界面相關(guān)數(shù)據(jù),可以用來管理Activity和Fragment中的數(shù)據(jù),還可以拿來處理Fragment與Fragment之間通信等 LiveData Lifecycle
網(wǎng)絡(luò)
網(wǎng)絡(luò)基礎(chǔ)
計算機網(wǎng)絡(luò)體系結(jié)構(gòu)是什么:計算機網(wǎng)絡(luò)體系結(jié)構(gòu)分為3種,OSI體系結(jié)構(gòu)7層(物理層、鏈路層、網(wǎng)絡(luò)層、傳輸層、會話層、表示層、應(yīng)用層)——概念清楚理念完整但復雜不實用、TCP/IP體系結(jié)構(gòu)4層(網(wǎng)絡(luò)接口層、網(wǎng)際層IP、運輸層TCP/UDP、應(yīng)用層HTTP)——是Internet核心協(xié)議并被廣泛應(yīng)用于局域網(wǎng)和廣域網(wǎng)、五層體系結(jié)構(gòu)(物理層、鏈路層、網(wǎng)絡(luò)層、運輸層、應(yīng)用層)——目的是為了學習和講解計算機原理 在瀏覽器中輸入url地址到顯示主頁過程(一個網(wǎng)頁請求過程):a、瀏覽器DNS獲取域名對應(yīng)IP(DNS查找過程包括瀏覽器緩存、路由器緩存和DNS緩存),并向Web服務(wù)器發(fā)送Http請求(請求會帶上cookie);b、服務(wù)器處理請求,發(fā)回一個HTML響應(yīng);c、瀏覽器開始顯示HTML 一次網(wǎng)絡(luò)請求中的協(xié)議:DNS(獲取域名對應(yīng)IP地址)、TCP(與服務(wù)器建立TCP連接)、IP(建立TCP連接時,需要發(fā)送數(shù)據(jù),發(fā)送數(shù)據(jù)在網(wǎng)絡(luò)層使用IP協(xié)議)、OPSF(IP數(shù)據(jù)包在路由器之間,路由選擇使用OPSF協(xié)議)、ARP(路由器在與服務(wù)器通信時,需要將IP地址轉(zhuǎn)換為MAC地址,需要使用ARP協(xié)議)、HTTP(在TCP建立完成后,使用HTTP協(xié)議訪問網(wǎng)頁) IP地址分類:A類1-126(0+7位網(wǎng)絡(luò)號+24位主機號)、B類128-191(10+14位網(wǎng)絡(luò)號+16位主機號)、C類192-223(110+21位網(wǎng)絡(luò)號+8位主機號)、D類224-239(1110+多播地址)、E類240-255(1111+保留為今后使用),區(qū)別在于網(wǎng)絡(luò)號 & 主機號占的字節(jié)數(shù)不同 特殊IP地址:0.0.0.0(表示網(wǎng)絡(luò)上本機地址)、255.255.255.255(為廣播地址)、127.0.0.0(不會出現(xiàn)在網(wǎng)絡(luò)上的環(huán)路自檢地址,表示任意主機本身)、主機號全為0(本網(wǎng)絡(luò)本身)、主機號全為1(本網(wǎng)絡(luò)廣播地址) ICMP報文:定義(Internet Control Message Protocol,網(wǎng)際控制報文協(xié)議,屬于IP層協(xié)議)、作用(更有效地轉(zhuǎn)發(fā)IP數(shù)據(jù)包,提高交付成功的機會)、分類(ICMP差錯報告報文和ICMP詢問報文)、主要應(yīng)用(PING分組網(wǎng)間探測;Traceroute跟蹤1個分組從源點到終點的路徑,拿到所有路由器IP) PING原理:應(yīng)用層利用IP層的ICMP協(xié)議包來偵測另一個主機是否可達,不經(jīng)過傳輸層,具體過程是:a、用類型碼為0的ICMP發(fā)請求;b、受到請求的主機則用類型碼為8的ICMP回應(yīng);c、ping程序來計算間隔時間,并計算有多少個包被送達,用戶就可以判斷網(wǎng)絡(luò)大致的情況 路由器與交換機區(qū)別:路由器(屬于網(wǎng)絡(luò)層,識別IP地址以及根據(jù)IP地址轉(zhuǎn)發(fā)數(shù)據(jù)包,維護著路由表并基于路由表進行最佳路徑選擇)、交換機(屬于數(shù)據(jù)鏈路層,識別MAC地址以及根據(jù)MAC地址轉(zhuǎn)發(fā)數(shù)據(jù)幀,維護著橋表并根據(jù)橋表上MAC地址和端口的對應(yīng)關(guān)系進行數(shù)據(jù)幀轉(zhuǎn)發(fā)) Cookie與Session區(qū)別:Cookie(是客戶端機制,存儲量少(一個站點最多20個Cookie,單個Cookie數(shù)據(jù)不超過4K),不安全(可分析存放在本地的Cookie和進行Cookie欺騙),損耗低,主要存放設(shè)備配置信息)、Session(是服務(wù)器機制,存儲量多,安全,損耗高(當訪問增多時比較占用服務(wù)器性能),主要存放重要信息)
TCP/UDP協(xié)議
三次握手過程:a、客戶端發(fā)送連接請求報文段;b、服務(wù)端發(fā)送連接確認報文段;c、客戶端發(fā)送連接確認報文段 四次揮手過程:a、客戶端發(fā)送連接釋放報文段;b、服務(wù)端發(fā)送連接釋放確認報文段;c、服務(wù)端發(fā)送釋放連接的報文段;d、客戶端發(fā)送釋放連接確認報文段 全雙工通信:TCP是全雙工通信(通信雙方的應(yīng)用進程在任何時候都能發(fā)送數(shù)據(jù)) 為什么TCP建立連接需三次握手:防止服務(wù)器端因接收了早已失效的連接請求報文,從而一直等待客戶端請求,最終導致形成死鎖、浪費資源 為什么TCP釋放連接需四次揮手:為了保證通信雙方都能通知對方去釋放、斷開連接 為什么客戶端關(guān)閉連接前要等待2MSL時間:MSL(Maximum Segment Lifetime,報文段最大生存時間,它是任何報文段被丟棄前在網(wǎng)絡(luò)內(nèi)最長時間),a、保證TCP協(xié)議的全雙工連接能夠可靠關(guān)閉;b、保證這次連接的重復數(shù)據(jù)段從網(wǎng)絡(luò)中消失(客戶端發(fā)送了最后1個連接釋放請求確認報文后,再經(jīng)過2MSL時間,則可使本連接持續(xù)時間內(nèi)所產(chǎn)生的所有報文段都從網(wǎng)絡(luò)中消失) TCP無差錯傳輸:a、采用一些可靠傳輸協(xié)議,使得出現(xiàn)差錯時,讓發(fā)送方重傳差錯數(shù)據(jù),即出錯重傳(自動重傳協(xié)議);b、當接收方來不及接收收到的數(shù)據(jù)時,可通知發(fā)送方降低發(fā)送數(shù)據(jù)的效率,即速度匹配(流量控制和擁塞控制協(xié)議) TCP/IP協(xié)議通信過程:對應(yīng)著數(shù)據(jù)入棧過程(HTTP-TCP-IP-以太網(wǎng),數(shù)據(jù)發(fā)送方每層不斷地封裝首部與尾部,添加一些傳輸信息,確保能傳輸?shù)侥康牡?#xff09;與數(shù)據(jù)出棧過程(數(shù)據(jù)接收方每層不斷地拆除首部與尾部,得到最終傳輸數(shù)據(jù)) TCP與UDP區(qū)別:TCP(是面向連接的可靠性字節(jié)流傳輸,傳輸效率慢所需資源多,應(yīng)用于要求通信數(shù)據(jù)可靠的場景,如:Http、FTP、SMTP/POP郵件協(xié)議、Telnet遠程終端接入?yún)f(xié)議等)、UDP(是面向無連接的不可靠數(shù)據(jù)報文段傳輸,傳輸效率快所需資源少,應(yīng)用于要求通信速度快的場景,無擁塞控制,如:DNS、SNMP網(wǎng)絡(luò)管理協(xié)議、NFS遠程文件服務(wù)器協(xié)議、TFTP文件傳輸協(xié)議等)
Http/Https協(xié)議
工作方式:a、服務(wù)器不斷監(jiān)聽TCP 80端口;b、客戶端發(fā)起連接請求;c、雙方建立TCP連接;d、客戶端發(fā)送頁面請求(Http請求報文);e、服務(wù)端返回頁面請求的響應(yīng);f、關(guān)閉TCP連接 Http1.1與Http1.0區(qū)別:a、引入持久連接,在同一個TCP連接中可傳送多個HTTP請求和響應(yīng);b、多個請求和響應(yīng)可同時進行、可重疊;c、引入更加多請求頭和響應(yīng)頭 Http與Https區(qū)別:Http在應(yīng)用層,數(shù)據(jù)不加密明文傳輸,不安全,80端口,不需要CA申請證書;Https在傳輸層,對數(shù)據(jù)SSL加密、身份認證,安全,443端口,需要CA申請證書 URL簡介:統(tǒng)一資源定位符,<協(xié)議>://<主機>:<端口>/<路徑>,如:https://blog.csdn.net/Agg_bin 請求報文:請求行(請求方法(定義對請求對象的操作)+資源路徑(URL中請求地址部分)+協(xié)議版本(定義Http版本號),如:GET /Agg_bin HTTPS)、請求頭(聲明報文部分信息)、請求體(存放需發(fā)送給服務(wù)器的信息,GET請求無請求體) 響應(yīng)報文:狀態(tài)行(協(xié)議版本(服務(wù)器Http版本號)+狀態(tài)碼(200/404/500)+狀態(tài)信息(請求成功/Not Found/服務(wù)器內(nèi)部錯誤),如:HTTP/1.1 202 Accepted)、響應(yīng)頭(最后發(fā)送一個空白行表示頭信息發(fā)送結(jié)束)、響應(yīng)體(Content-Type請求頭定義的格式數(shù)據(jù)) 請求方法GET與POST:GET(傳輸參數(shù)直接加在URL后,URL長度受限最長2048字符;瀏覽器中可見,安全性差;應(yīng)用于數(shù)據(jù)小量或不敏感,請求數(shù)據(jù))、POST(傳輸參數(shù)不受限;請求參數(shù)封裝在Http請求數(shù)據(jù)中,且瀏覽器中無緩存,安全性好;應(yīng)用于大量或數(shù)據(jù)敏感,提交數(shù)據(jù)) 常用請求/響應(yīng)頭:Content-Type(請求/響應(yīng)體類型,如application/json)、Content-Length(請求/響應(yīng)體長度,單位字節(jié))、Cache-Control(資源緩存有效期,如no-cache或max-age=XX)、User-Agent(請求頭用戶標識,如OS和瀏覽器的類型和版本)、Host(請求的主機和端口號)、Cookie(請求頭已有的Cookie)、Date(響應(yīng)頭服務(wù)器日期)、Last-Modified(響應(yīng)頭該資源最后被修改時間)、Set-Cookie(響應(yīng)頭設(shè)置Cookie) Http處理長連接方式:Http1.1默認保持長連接,數(shù)據(jù)傳輸完成后TCP連接不斷開,繼續(xù)使用該通道傳輸數(shù)據(jù);如果不是長連接方式,那么服務(wù)端向客戶端發(fā)送完請求數(shù)據(jù)后就要關(guān)閉TCP連接。Http頭部字段Connection(a、Connection:close表示不使用長連接;b、Connection:Keep-Alive Keep-Alive:max=20表示連接失敗次數(shù)超過20則斷開;c、Connection:Keep-Alive Keep-Alive:time=20表示連接失敗超時時間超過20則斷開)、Keep-Alive機制(Keep-Alive開啟后,TCP層將定時發(fā)送相應(yīng)KeepAlive探針檢測連接可用性)、結(jié)束長連接(使用長連接后,客戶端和服務(wù)端可通過如下2種方式知道本次傳輸結(jié)束,a、判斷傳輸數(shù)據(jù)是否達到Content-Length指示大小;b、若chunked編碼數(shù)據(jù)在最后有一個空chunked塊,則表明本次傳輸數(shù)據(jù)結(jié)束)
Socket通信
Socket是什么:Socket不是一種協(xié)議,是應(yīng)用層與TCP/IP 協(xié)議族通信的中間軟件抽象層,表現(xiàn)為一個封裝了 TCP/IP協(xié)議族的編程接口,屬于傳輸層(主要解決數(shù)據(jù)如何在網(wǎng)絡(luò)中傳輸),Socket能讓我們在Andorid平臺上通過TCP/IP協(xié)議進行開發(fā) Socket實現(xiàn)原理: 流套接字(streamsocket,基于TCP協(xié)議,采用流的方式提供可靠字節(jié)流服務(wù))、數(shù)據(jù)報套接字(datagramsocket,基于UDP協(xié)議,采用數(shù)據(jù)報文提供數(shù)據(jù)打包發(fā)送服務(wù)) Socket基于TCP協(xié)議使用步驟:a、創(chuàng)建客戶端和服務(wù)端連接(Socket socket = new Socket("192.168.1.08", 1080); socket.isConnected()));b、接受服務(wù)端數(shù)據(jù)(BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream())); br.readLine());c、發(fā)送數(shù)據(jù)到服務(wù)端(OutputStream os = socket.getOutputStream(); os.write(("Agg"+"\n").getBytes("utf-8")); os.flush())數(shù)據(jù)結(jié)尾加上換行符才可讓服務(wù)器端的readline()停止阻塞;d、斷開客戶端和服務(wù)端連接(os.close(); br.close(); socket.close()) Socket與Http協(xié)議對比:Socket(屬于傳輸層,因為TCP/IP協(xié)議屬于傳輸層,主要解決數(shù)據(jù)如何在網(wǎng)絡(luò)中傳輸;采用服務(wù)器主動通信,有需要就發(fā)送數(shù)據(jù))、Http協(xié)議(屬于應(yīng)用層,解決的是如何包裝數(shù)據(jù);采用客戶端主動通信,請求-響應(yīng)方式)
?架構(gòu)設(shè)計
編程思想
六大設(shè)計原則
重構(gòu)-Code Smell
AOP
設(shè)計模式
創(chuàng)建型5個
行為型11個
結(jié)構(gòu)型7個
編程范式
MVC
MVP
MVVM
MVI
模塊化
組件化
插件化、熱修復
Jectpack
網(wǎng)絡(luò)
網(wǎng)絡(luò)基礎(chǔ)
TCP/UDP協(xié)議
Http/Https協(xié)議
Socket通信
Android開發(fā)面試系列文章:
Android開發(fā)面試:Android知識答案精解 Android開發(fā)面試:Java知識答案精解 Android開發(fā)面試:架構(gòu)設(shè)計和網(wǎng)絡(luò)知識答案精解 Android開發(fā)面試:數(shù)據(jù)結(jié)構(gòu)與算法知識答案精解 Android開發(fā)面試:Kotlin面試知識答案精解
總結(jié)
以上是生活随笔 為你收集整理的Android开发面试:架构设计和网络知识答案精解 的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔 網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔 推薦給好友。