騰訊十年開發者發自騰訊一線的真實Android資料
已經到3月份了,職場的金三銀四跳槽季又來了,不同的是今年比往年「冷」一些,形式更加嚴峻一些,大家多多少少可能都聽到或看到一些資訊,就是好多公司在優化裁員,代表的就是滴滴、京東這種大型網際網路公司,已經官宣了。
即使這種情況下,我相信,3、4月份仍然會有一波離職、求職潮。作為求職這來說,面試是一道坎,很多人會恐懼面試,即使是工作很多年的老鳥,可能仍存在面試的焦慮。
所以今天小編就在這面分享一波福利 (文末有領取方式!) ,裡面包含了一些高階Android方面的技術資料,裡面包括有 高階UI、效能優化、架構師課程、NDK、混合式開發(ReactNative+Weex)微信小程式、Flutter全方面的Android進階實踐技術講解 ,不多說直接上乾貨。
以下是本文的知識清單:
-
SparseArray
-
atomic包
-
Android埋點
-
Java基礎之註解
-
一點小感悟
在這裡由於文字較多,小編總結了一份高階Android技術大綱和學習資料免費分享給大家,文末有領取!
1. SparseArray
當新建一個key為整型的HashMap時,會出現如下的提示資訊,推薦使用SparseArray來替代HashMap:

image
接下來就來介紹下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.型別:
元註解:是一種基本註解,用於解釋註解,注意其描述物件是註解而非程式碼,包含型別如下表:

image
來段程式碼感受下這些註釋的使用效果:
//表示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內建註解:下表展示了幾個常用的內部已實現註解

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

image
在之前的Test類裡就可以新增以下程式碼,來獲取在類上給@TestAnnotation設定的屬性值了:
boolean hasAnnotation = Test.class.isAnnotationPresent(TestAnnotation.class);if (hasAnnotation) { TestAnnotation testAnnotation = Test.class.getAnnotation(TestAnnotation.class); System.out.println("id:"+testAnnotation.id());//輸出1 System.out.println("msg:"+testAnnotation.msg());//輸出hello}
【附】相關架構及資料

Android高階技術大綱

Java語言進階與Android相關技術核心.png