來自騰訊十年開發者發自騰訊一線的真實Android資料

現在的市場環境確實不大好,裁員與及在預謀裁員的公司一大把,當然招人的公司也有。就會有一波離職、求職潮。作爲求職者來說,面試是一道坎,很多人會恐懼面試,即使是工作很多年的老鳥,可能仍存在面試的焦慮。

所以今天小編就在這面分享一波福利(評論有驚喜啊~),裏面包含了一些高階Android方面的技術資料,裏面包括有高級UI、性能優化、移動架構師、NDK、混合式開發(ReactNative+Weex)微信小程序、Flutter全方面的Android進階實踐技術講解,不多說直接上乾貨。

以下是本文的知識清單:

  • SparseArray
  • atomic包
  • Android埋點
  • Java基礎之註解
  • 一點小感悟

在這裏由於文字較多,小編總結了一份高階Android技術大綱和學習資料免費分享給大家,文末有領取!

1. SparseArray

當新建一個key爲整型的HashMap時,會出現如下的提示信息,推薦使用SparseArray來替代HashMap:

接下來就來介紹下SparseArray:

a.數據結構:又稱稀疏數組,內部通過兩個數組分別存儲key和value,並用壓縮的方式來存儲數據

b.優點:可替代key爲int、value爲Object的HashMap,相比於HashMap

  • 能更節省存儲空間

  • 由於key指定爲int,能節省int和Integer的裝箱拆箱操作帶來的性能消耗

  • 擴容時只需要數組拷貝工作,而不需重建哈希表

c.適用場景:數據量不大(千以內)、空間比時間重要、需要使用Map且key爲整型;不適合存儲大容量數據,此時性能將退化至少50%

d.使用

添加:public void put(int key, E value)

刪除:

  • public void delete(int key)

  • public void remove(int key)實際上內部會調用delete方法

查找:

  • public E get(int key)

  • public E get(int key, E valueIfKeyNotFound)可設置假設key不存在時默認返回的value

  • public int keyAt(int index)獲取相應的key

  • public E valueAt(int index)獲取相應的value

e.get/put過程:元素會按照key從小到大進行存儲,先使用二分法查詢key對應在數組中的下標index,然後通過該index進行增刪查。源碼分析見SparseArray解析(https://www.jianshu.com/p/30a2bfb202b4

2. atomic包

a.原子操作類:

與採取悲觀鎖策略的synchronized不同,atomic包採用樂觀鎖策略去原子更新數據,並使用CAS技術具體實現

//保證自增線程安全的兩種方式public class Sample { private static Integer count = 0; synchronized public static void increment() {  count++; }}public class Sample { private static AtomicInteger count = new AtomicInteger(0); public static void increment() {  count.getAndIncrement(); }}

基礎知識:Java併發問題--樂觀鎖與悲觀鎖以及樂觀鎖的一種實現方式-CAS(https://www.cnblogs.com/qjjazry/p/6581568.html)

b.類型

原子更新基本類型:

  • AtomicInteger:原子更新Integer

  • AtomicLong:原子更新Long

  • AtomicBoolean:原子更新boolean

以AtomicInteger爲例,常用方法:

  • getAndAdd(int delta):取當前值,再和delta值相加

  • addAndGet(int delta) :先和delta值相加,再取相加後的最終值

  • getAndIncrement():取當前 值,再自增

  • incrementAndGet() :先自增,再取自增後的最終值

  • getAndSet(int newValue):取當前值,再設置爲newValue值

原子更新數組:

  • AtomicIntegerArray:原子更新整型數組中的元素

  • AtomicLongArray:原子更新長整型數組中的元素

  • AtomicReferenceArray:原子更新引用類型數組中的元素

以AtomicIntegerArray爲例,常用方法:

  • addAndGet(int i, int delta):先將數組中索引爲i的元素與delta值相加,再取相加後的最終值

  • getAndIncrement(int i):取數組中索引爲i的元素的值,再自增

  • compareAndSet(int i, int expect, int update):如果數組中索引爲i的元素的值和expect值相等,則更新爲update值

原子更新引用類型:

  • AtomicReference:原子更新引用類型

  • AtomicReferenceFieldUpdater:原子更新引用類型裏的字段

  • AtomicMarkableReference:原子更新帶有標記位的引用類型

//這幾個類提供的方法基本一致,以AtomicReference爲例public class AtomicDemo {private static AtomicReference<User> reference = new AtomicReference<>();public static void main(String[] args) { User user1 = new User("a", 1); reference.set(user1); User user2 = new User("b",2); User user = reference.getAndSet(user2); System.out.println(user);//輸出User{userName='a', age=1} System.out.println(reference.get());//輸出User{userName='b', age=2}}static class User { private String userName; private int age; public User(String userName, int age) {  this.userName = userName;  this.age = age; } @Override public String toString() {  return "User{" +"userName='" + userName + '\'' +", age=" + age + '}'; }}}

原子更新字段:

  • AtomicIntegeFieldUpdater:原子更新整型字段

  • AtomicLongFieldUpdater:原子更新長整型字段

  • AtomicStampedReference:原子更新帶有版本號的引用類型

使用方法:由於原子更新字段類是抽象類,因此需要先通過其靜態方法newUpdater創建一個更新器,並設置想更新的類和屬性
注意:被更新的屬性必須用public volatile修飾

//這幾個類提供的方法基本一致,以AtomicIntegeFieldUpdater爲例public class AtomicDemo {private static AtomicIntegerFieldUpdater updater = AtomicIntegerFieldUpdater.newUpdater(User.class,"age");public static void main(String[] args) { User user = new User("a", 1); int oldValue = updater.getAndAdd(user, 5); System.out.println(oldValue);//輸出1 System.out.println(updater.get(user));//輸出6}static class User { private String userName; public volatile int age; public User(String userName, int age) {  this.userName = userName;  this.age = age; } @Override public String toString() {  return "User{" +"userName='" + userName + '\'' +", age=" + age +'}'; }}}

c.優點:

可以避免多線程的優先級倒置和死鎖情況的發生,提升在高併發處理下的性能,相比於synchronized ,在非激烈競爭的情況下,開銷更小,速度更快

3. Android埋點

a.含義:預先在目標應用採集數據,對特定用戶行爲或事件進行捕獲、處理,並以一定方式上報至服務器,便於後續進行數據分析

b.方式

代碼埋點:在某個事件發生時通過預先寫好的代碼來發送數據

  • 優點:控制精準,採集靈活性強,可自由選擇何時發送自定義數據

  • 缺點:開發、測試成本高,需要等發版才能修改線上埋點、更新代價大

無埋點/全埋點:在端上自動採集並上報儘可能多的數據,在計算時篩選出可用的數據

  • 優點:很大程度上減少開發、測試的重複勞動,數據可回溯且覆蓋全面

  • 缺點:採集信息不夠靈活,數據量大,後端篩選分析工作量大

可視化埋點:通過可視化工具選擇需要收集的埋點數據,下發配置給客戶端,終端點擊時獲取當前點擊的控件根據配置文件進行選擇上報

  • 優點:很大程度上減少開發、測試的重複勞動,數據量可控且相對精確,可在線上動態埋點、而無需等待App發版

  • 缺點:採集信息不夠靈活,無法解決數據回溯的問題

幾個實踐:51信用卡(https://mp.weixin.qq.com/s/svzwQkAy0favp0Ty3NtoLA)、網易(https://mp.weixin.qq.com/s/0dHKu5QIBL_4S7Tum-qW2Q)、58同城(https://mp.weixin.qq.com/s/rP7PiN7lsnUxcY1BAhB_5Q)

4.Java基礎之註解(Annotation)

a.含義:是附加在代碼中的一些元數據,在JDK1.5 版本開始引入,與類、接口、枚舉在同一個層次

b.作用:

聲明在包、類、字段、方法、局部變量、方法參數等前面,用來對這些元素進行說明和註釋

註解不會也不能影響代碼的實際邏輯,僅僅起到輔助性的作用,比如編譯時進行格式檢查、簡化操作進而降低代碼量

c.使用

以下代碼展示了註解的定義、屬性和使用的方法:

//1.註解的定義:通過@interface關鍵字//以下表示創建了一個名爲TestAnnotation的註解public @interface TestAnnotation { //2.註解的屬性://聲明:採用“無形參的方法”形式,方法名錶示屬性名,返回值表示屬性類型//類型:必須是8種基本數據類型,或者類、接口、註解及對應數組//默認值:用default關鍵值,在賦值時可以省略//以下表示註解TestAnnotation中有id和msg兩個屬性,且msg默認值爲hiint id();String msg() default "hi";}//3.註解的使用://對屬性賦值:在註解使用打個括號,以value=""形式,多個屬性之前用逗號隔開;若註解只有一個屬性,則賦值時value=可以省略;如果沒有屬性,括號都可以省略//以下表示對Test類進行標識,並對註解的適兩個屬性進行賦值@TestAnnotation(id=1,msg="hello")public class Test {}

d.類型:

元註解:是一種基本註解,用於解釋註解,注意其描述對象是註解而非代碼,包含類型如下表:

來段代碼感受下這些註釋的使用效果:

//表示TestAnnotation註釋是對類描述的、保留到運行時、被添加到Javadoc、有繼承性值的@Target({ElementType.TYPE})@Retention(RetentionPolicy.RUNTIME)@Documented@Inheritedpublic @interface TestAnnotation {}//由於B類是A類的子類,且B類沒被任何註解應用,則B類繼承了A類的TestAnnotation註解@TestAnnotationpublic class A {}public class B extends A {}

接下來用單獨一個例子來解釋可重複註解

//1.定義一個註解容器(此處指@Persons)://作用:存放其他註解(此處指@Person),其本身也是個註解//注意:需要有個value屬性,類型就是被@Repeatable解釋的註解數組(此處指Person[])@interface Persons { Person[] value();//註解屬性}//2.使用@Repeatable解釋(此處指@Person),括號中是註解容器類(此處指Persons)@Repeatable(Persons.class)@interface Person { String role default "";//註解屬性}//3.使用@Repeatable解釋的註釋時,可以取多個註解值來解釋代碼@Person(role="coder")@Person(role="PM")public class SuperMan {//SuperMan既是程序員又是產品經理}

Java內置註解:下表展示了幾個常用的內部已實現註解

自定義註解:在之前已經介紹了註解的定義、屬性和使用的具體方法,還差一步,註解的提取,需要通過Java的反射技術獲取類方法和字段的註解信息,常用方法:

在之前的Test類裏就可以添加以下代碼,來獲取在類上給@TestAnnotation設置的屬性值了:

boolean hasAnnotation = Test.class.isAnnotationPresent(TestAnnotation.class);if (hasAnnotation) {

最後

總而言之,成功是留給準備好的人的。無論是參加什麼面試,都要做好充足的準備,注意好面試的禮儀和穿着,向面試官表現出自己的熱忱與真誠就好。即使最後沒有過關,也要做好經驗的總結,爲下一次面試做好充足準備。

這裏我爲大家準備了一些我在面試後整理的面試專題資料,除了面試題,還總結出了互聯網公司Android程序員面試涉及到的絕大部分面試題及答案,並整理做成了文檔,以及系統的進階學習視頻資料,免費分享給大家,希望能幫助到你面試前的複習,且找到一個好的工作,也節省大家在網上搜索資料的時間來學習,需要的小夥伴可以在評論區留言~

畢竟不管遇到什麼樣的面試官,去面試首先最主要的就是自己的實力,只要實力夠硬,技術夠強,就不怕面試拿不到offer!

如果你看到了這裏,覺得文章寫得不錯就給個讚唄?如果你覺得那裏值得改進的,請給我留言。一定會認真查詢,修正不足。謝謝。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章