1枝冀、Android的Handler運行機制
1. Message
Message消息,理解為線程間交流的信息聂儒,處理數(shù)據(jù)后臺線程需要更新UI嫉入,則發(fā)送Message內(nèi)含一些數(shù)據(jù)給UI線程。
2. Handler
Handler處理者觉至,是Message的主要處理者剔应,負責(zé)Message的發(fā)送,Message內(nèi)容的執(zhí)行處理语御。后臺線程就是通過傳進來的 Handler對象引用來sendMessage(Message)峻贮。而使用Handler,需要implement 該類的 handleMessage(Message)方法应闯,它是處理這些Message的操作內(nèi)容纤控,例如Update UI。通常需要子類化Handler來實現(xiàn)handleMessage方法碉纺。
3. Message Queue
Message Queue消息隊列船万,用來存放通過Handler發(fā)布的消息刻撒,按照先進先出執(zhí)行。
在單線程模型下耿导,為了線程通信問題声怔,Android設(shè)計了一個Message Queue(消息隊列), 線程間可以通過該Message Queue并結(jié)合Handler和Looper組件進行信息交換碎节。
每個message queue都會有一個對應(yīng)的Handler。Handler會向message queue通過兩種方法發(fā)送消息:sendMessage或post抵卫。這兩種消息都會插在message queue隊尾并按先進先出執(zhí)行狮荔。但通過這兩種方法發(fā)送的消息執(zhí)行的方式略有不同:通過sendMessage發(fā)送的是一個message對象,會被 Handler的handleMessage()函數(shù)處理;而通過post方法發(fā)送的是一個runnable對象介粘,則會自己執(zhí)行殖氏。
4. Looper
Looper是每條線程里的Message Queue的管家。Android沒有Global的Message Queue姻采,而Android會自動替主線程(UI線程)建立Message Queue雅采,但在子線程里并沒有建立Message Queue。所以調(diào)用Looper.getMainLooper()得到的主線程的Looper不為NULL慨亲,但調(diào)用Looper.myLooper() 得到當(dāng)前線程的Looper就有可能為NULL。
2、面向?qū)ο蟮奶卣?/b>
⑴對象唯一性和媳。
每個對象都有自身唯一的標識涵紊,通過這種標識,可找到相應(yīng)的對象蛉签。在對象的整個生命期中胡陪,它的標識都不改變,不同的對象不能有相同的標識碍舍。?[2]
⑵抽象性柠座。
抽象性是指將具有一致的數(shù)據(jù)結(jié)構(gòu)(屬性)和行為(操作)的對象抽象成類。一個類就是這樣一種抽象片橡,它反映了與應(yīng)用有關(guān)的重要性質(zhì)妈经,而忽略其他一些無關(guān)內(nèi)容。任何類的劃分都是主觀的捧书,但必須與具體的應(yīng)用有關(guān)狂塘。?[2]
⑶繼承性。
繼承性是子類自動共享父類數(shù)據(jù)結(jié)構(gòu)和方法的機制鳄厌,這是類之間的一種關(guān)系荞胡。在定義和實現(xiàn)一個類的時候,可以在一個已經(jīng)存在的類的基礎(chǔ)之上來進行了嚎,把這個已經(jīng)存在的類所定義的內(nèi)容作為自己的內(nèi)容泪漂,并加入若干新的內(nèi)容廊营。?[2]
繼承性是面向?qū)ο蟪绦蛟O(shè)計語言不同于其它語言的最重要的特點,是其他語言所沒有的萝勤。
在類層次中露筒,子類只繼承一個父類的數(shù)據(jù)結(jié)構(gòu)和方法,則稱為單重繼承敌卓。
在類層次中慎式,子類繼承了多個父類的數(shù)據(jù)結(jié)構(gòu)和方法,則稱為多重繼承趟径。
多重繼承瘪吏,JAVA、VB蜗巧、NET掌眠、Objective-C均僅支持單繼承,注意在C++多重繼承時幕屹,需小心二義性蓝丙。
在軟件開發(fā)中,類的繼承性使所建立的軟件具有開放性望拖、可擴充性渺尘,這是信息組織與分類的行之有效的方法,它簡化了對象说敏、類的創(chuàng)建工作量沧烈,增加了代碼的可重用性。
采用繼承性像云,提供了類的規(guī)范的等級結(jié)構(gòu)锌雀。通過類的繼承關(guān)系,使公共的特性能夠共享迅诬,提高了軟件的重用性腋逆。?[2]
⑷多態(tài)性(多形性)
多態(tài)性是指相同的操作或函數(shù)、過程可作用于多種類型的對象上并獲得不同的結(jié)果侈贷。不同的對象惩歉,收到同一消息可以產(chǎn)生不同的結(jié)果,這種現(xiàn)象稱為多態(tài)性俏蛮。
多態(tài)性允許每個對象以適合自身的方式去響應(yīng)共同的消息撑蚌。
多態(tài)性增強了軟件的靈活性和重用性。
3搏屑、性能優(yōu)化總結(jié)2:leakcanary的使用(li)
1争涌、引入庫
2、操作APP辣恋,分析結(jié)果
3亮垫、如果是復(fù)雜的問題可以導(dǎo)出hprof文件到android studio 中繼續(xù)分析
我們啟動app模软,當(dāng)檢測到內(nèi)存泄漏的時候,會出現(xiàn)一個彈窗饮潦,然后手機桌面會出現(xiàn)一個Leaks的圖標
點擊即可看到內(nèi)存泄漏的原因:
4燃异、Serializable和Parcelable的區(qū)別
在使用內(nèi)存的時候,Parcelable 類比Serializable性能高继蜡,所以推薦使用Parcelable類回俐。
1.Serializable在序列化的時候會產(chǎn)生大量的臨時變量,從而引起頻繁的GC稀并。
2.Parcelable不能使用在要將數(shù)據(jù)存儲在磁盤上的情況仅颇。盡管Serializable效率低點,但在這種情況下稻轨,還是建議你用Serializable 灵莲。
實現(xiàn):
1.Serializable 的實現(xiàn)雕凹,只需要繼承 Serializable 即可殴俱。這只是給對象打了一個標記,系統(tǒng)會自動將其序列化枚抵。
2.Parcelabel 的實現(xiàn)线欲,需要在類中添加一個靜態(tài)成員變量 CREATOR,這個變量需要繼承Parcelable.Creator 接口汽摹。
public class MyParcelable implements Parcelable {
? ? private int mData;
? ? public int describeContents() {
? ? ? ? return 0;
? ? }
? ? public void writeToParcel(Parcel out, int flags) {
? ? ? ? out.writeInt(mData);
? ? }
? ? public static final Parcelable.Creator<MyParcelable> CREATOR = new Parcelable.Creator<MyParcelable>() {
? ? ? ? public MyParcelable createFromParcel(Parcel in) {
? ? ? ? ? ? return new MyParcelable(in);
? ? ? ? }
? ? ? ? public MyParcelable[] newArray(int size) {
? ? ? ? ? ? return new MyParcelable[size];
? ? ? ? }
? ? };
? ? private MyParcelable(Parcel in) {
? ? ? ? mData = in.readInt();
? ? }
}
5李丰,什么是內(nèi)存泄漏,android在什么情況下容易產(chǎn)生內(nèi)存泄漏
說到內(nèi)存泄漏就不得不提內(nèi)存溢出逼泣。
內(nèi)存溢出 out of memory趴泌,是指程序在申請內(nèi)存時,沒有足夠的內(nèi)存空間供其使用拉庶,出現(xiàn)out of memory嗜憔;比如申請了一個integer,但給它存了long才能存下的數(shù),那就是內(nèi)存溢出氏仗。
內(nèi)存泄露 memory leak吉捶,是指程序在申請內(nèi)存后,無法釋放已申請的內(nèi)存空間皆尔,一次內(nèi)存泄露危害可以忽略呐舔,但內(nèi)存泄露堆積后果很嚴重。內(nèi)存溢出導(dǎo)致了內(nèi)存泄漏慷蠕。
在Android中常見的內(nèi)存泄漏原因:
1. 資源釋放問題
程序代碼的問題珊拼,長期保持某些資源,如Context流炕、Cursor杆麸、IO流的引用搁进,資源得不到釋放造成內(nèi)存泄露。
2. 對象內(nèi)存過大問題
保存了多個耗用內(nèi)存過大的對象(如Bitmap昔头、XML文件)饼问,造成內(nèi)存超出限制。
3. static關(guān)鍵字的使用問題
static是Java中的一個關(guān)鍵字揭斧,當(dāng)用它來修飾成員變量時莱革,那么該變量就屬于該類,而不是該類的實例讹开。所以用static修飾的變量盅视,它的生命周期是很長的,如果用它來引用一些資源耗費過多的實例(Context的情況最多)旦万,這時就要謹慎對待了闹击。
4. 線程導(dǎo)致內(nèi)存溢出
線程產(chǎn)生內(nèi)存泄露的主要原因在于線程生命周期的不可控。
5成艘,數(shù)據(jù)庫游標忘記回收等
那么針對上面的問題我們怎么避免呢
1)圖片過大導(dǎo)致OOM
Android 中用bitmap時很容易內(nèi)存溢出赏半,比如報如下錯誤:Java.lang.OutOfMemoryError :
bitmap size exceeds VM budget。
解決方法:
方法1: 等比例縮小圖片
方法2:對圖片采用軟引用淆两,及時地進行recyle()操作
SoftReference<Bitmap> bitmap = new SoftReference<Bitmap>(pBitmap);
2)查詢數(shù)據(jù)庫沒有關(guān)閉游標
程序中經(jīng)常會進行查詢數(shù)據(jù)庫的操作断箫,但是經(jīng)常會有使用完畢Cursor后沒有關(guān)閉的情況。如果我們的查詢結(jié)果集比較小秋冰,對內(nèi)存的消耗不容易被發(fā)現(xiàn)仲义,只有在常時間大量操作的情況下才會出現(xiàn)內(nèi)
存問題,這樣就會給以后的測試和問題排查帶來困難和風(fēng)險剑勾。
3)構(gòu)造Adapter時埃撵,沒有使用緩存的 convertView
在使用ListView的時候通常會使用Adapter,那么我們應(yīng)該盡可能的使用ConvertView虽另。為什么要使用convertView?(con what)
當(dāng)convertView為空時暂刘,用setTag()方法為每個View綁定一個存放控件的ViewHolder對象。當(dāng) convertView 不為空洲赵,重復(fù)利用已經(jīng)創(chuàng)建的 view 的時候鸳惯,使用 getTag()方法獲取綁定的ViewHolder對象,這樣就避免了findViewById對控件的層層查詢叠萍,而是快速定位到控件芝发。
4)Bitmap對象不再使用時調(diào)用recycle()釋放內(nèi)存
有時我們會手工的操作Bitmap對象,如果一個Bitmap對象比較占內(nèi)存苛谷,當(dāng)它不再被使用的時
候辅鲸,可以調(diào)用Bitmap.recycle()方法回收此對象的像素所占用的內(nèi)存,但這不是必須的腹殿,視情況而定独悴。
6例书、 簡述下Android JNI調(diào)用過程
1)安裝和下載Cygwin,下載AndroidNDK
2)在ndk項目中JNI接口的設(shè)計
3)使用C/C++實現(xiàn)本地方法
4)JNI生成動態(tài)鏈接庫.so文件
5)將動態(tài)鏈接庫復(fù)制到j(luò)ava工程刻炒,在java工程中調(diào)用决采,運行java工程即可
7、插件化坟奥、熱修復(fù) 树瞭、熱更新的理解
插件化 – apk 分為宿主和插件部分,插件在需要的時候才加載進來
熱修復(fù) – 更新的類或者插件粒度較小的時候爱谁,我們會稱之為熱修復(fù)晒喷,一般用于修復(fù)bug
熱更新 – 2016 Google 的 Android Studio 推出了Instant Run 功能 同時提出了3個名詞
“ 熱部署” – 方法內(nèi)的簡單修改,無需重啟app和Activity访敌。
“暖部署” – app無需重啟凉敲,但是activity需要重啟,比如資源的修改寺旺。
“冷部署” – app需要重啟爷抓,比如繼承關(guān)系的改變或方法的簽名變化等。
站在app開發(fā)者角度的“熱”是指在不發(fā)版的情況來實現(xiàn)更新
而Google提出的“熱”是指值是否需要重新啟動迅涮。 - 同時在開發(fā)插件化的時候也有兩種情景
一種是插件與宿主apk沒有交互废赞,只是在用戶使用到的時候進行一次吊起
還有一種是與宿主有很多的交互
你認為android熱更新框架哪個好:
1.阿里的熱更新框架已經(jīng)開源 了徽龟。但已經(jīng)很久沒有更新過新版本了叮姑。當(dāng)前的版本只支持到了 Android 4.4。由于 5.0 起新的 ART 虛擬機据悔、更嚴格的 SELinux 策略以及對 64 位的支持之類的事传透,使得 Xposed 都在開發(fā)上做了很多調(diào)整。我不知道 Dexposed 現(xiàn)在是否支持极颓,但至少阿里沒有開源朱盐。
2.在本地動態(tài)執(zhí)行遠端下發(fā)的代碼是極度危險的行為。利用此方法執(zhí)行非法代碼等或用于繞過 Google Play 等市場的審查是違反相關(guān)協(xié)議的菠隆,也是對用戶極度不負責(zé)任的行為兵琳。
3.在一些訪問非常密集的地方使用熱更新可能會對效率產(chǎn)生相對比較大的影響,應(yīng)該避免使用.
4.我們可以對 Java 的 ScriptEngine 進行一些封裝成為一個 HotPatch 類使得它更適合做熱更新的工作骇径。
5.首先,檢查熱更新補丁的管道一定要建立在 https 上躯肌,因為下發(fā)代碼是極其危險的,如果被劫持破衔,后果是無法想象的清女。其次,請求時最好自動帶上 Android 版本、手機型號晰筛、地區(qū)嫡丙、版本號等信息拴袭,以方便更精確地下發(fā),千萬不能下發(fā)錯曙博。
6.Java在運行時加載對應(yīng)的類是通過ClassLoader來實現(xiàn)的拥刻,ClassLoader本身是一個抽象來,Android中使用PathClassLoader類作為Android的默認的類加載器
7.我們的如果想做hotpatch父泳,一定要保證我們的hotpacth dex文件出現(xiàn)在dexElements列表的前面泰佳。
二.常用的熱更新技術(shù)框架:
基于QQ空間的HotFix →→ 要使用到android dex分包方案→拆分dex的項目的話,可以參考一下谷歌的multidex方案實現(xiàn).
大眾點評的NuWa←項目補丁自動化做的很完整
alibaba/AndFix
阿里巴巴的DexPosed
dalvik_patch實現(xiàn)multidex
使用React-Native實現(xiàn)app熱部署的一次實踐
alibaba/AndFix
7尘吗、activity生命周期圖解
鎖定屏與解鎖屏幕 只會調(diào)用onPause()逝她,而不會調(diào)用onStop方法,開屏后則調(diào)用onResume()睬捶。在實際操作中會有所出入黔宛,比如在三星手機測試的時候鎖定手機調(diào)用了onPause()和onStop()方法,解鎖時候調(diào)用的是:onRestart()擒贸,onStart()和 onResume()方法臀晃。
介紹不同場景下Activity生命周期的變化過程
啟動Activity:
onCreate()—>onStart()—>onResume(),Activity進入運行狀態(tài)介劫。
Activity退居后臺:
當(dāng)前Activity轉(zhuǎn)到新的Activity界面或按Home鍵回到主屏: onPause()—>onStop()徽惋,進入停滯狀態(tài)。
Activity返回前臺:
onRestart()—>onStart()—>onResume()座韵,再次回到運行狀態(tài)险绘。
Activity退居后臺,且系統(tǒng)內(nèi)存不足誉碴,
系統(tǒng)會殺死這個后臺狀態(tài)的Activity宦棺,若再次回到這個Activity,則會走onCreate()–>onStart()—>onResume()
鎖定屏與解鎖屏幕
只會調(diào)用onPause(),而不會調(diào)用onStop方法黔帕,開屏后則調(diào)用onResume()
Activity銷毀但Task如果沒有銷毀掉代咸,當(dāng)Activity重啟時這個AsyncTask該如何解決?
比如屏幕旋轉(zhuǎn)這個例子成黄,在重建Activity的時候呐芥,會回調(diào)
Activity.onRetainNonConfigurationInstance()
重新傳遞一個新的對象給AsyncTask,完成引用的更新
若Activity已經(jīng)銷毀,此時AsynTask執(zhí)行完并返回結(jié)果,會報異常么?
當(dāng)一個App旋轉(zhuǎn)時奋岁,整個Activity會被銷毀和重建思瘟。
當(dāng)Activity重啟時,AsyncTask中對該Activity的引用是無效的厦取,因此onPostExecute()就不會起作用
若AsynTask正在執(zhí)行潮太,折會報 view not attached to window manager 異常
同樣也是生命周期的問題,在 Activity 的onDestory()方法中調(diào)用Asyntask.cancal方法,讓二者的生命周期同步
內(nèi)存不足時,系統(tǒng)會殺死后臺的Activity,如果需要進行一些臨時狀態(tài)的保存,在哪個方法進行
Activity的 onSaveInstanceState() 和 onRestoreInstanceState()并不是生命周期方法,不同于 onCreate()铡买、onPause()等生命周期方法更鲁,它們并不一定會被觸發(fā)。
當(dāng)應(yīng)用遇到意外情況(如:內(nèi)存不足奇钞、用戶直接按Home鍵)由系統(tǒng)銷毀一個Activity澡为,onSaveInstanceState() 會被調(diào)用。
但是當(dāng)用戶主動去銷毀一個Activity時景埃,例如在應(yīng)用中按返回鍵媒至,onSaveInstanceState()就不會被調(diào)用。除非該activity是被用戶主動銷毀的
通常onSaveInstanceState()只適合用于保存一些臨時性的狀態(tài)谷徙,而onPause()適合用于數(shù)據(jù)的持久化保存拒啰。
8、介紹Activity 四中l(wèi)aunchMode:
我們可以在AndroidManifest.xml配置的android:launchMode屬性為以下四種之一完慧。
1谋旦、standard
standard模式是默認的啟動模式,不用為配置android:launchMode屬性即可屈尼,當(dāng)然也可以指定值為standard册着。standard啟動模式,不管有沒有已存在的實例脾歧,都生成新的實例甲捏。
2、 singleTop
我們在上面的基礎(chǔ)上為指定屬性android:launchMode=”singleTop”鞭执,系統(tǒng)就會按照singleTop啟動模式處理跳轉(zhuǎn)行為司顿。跳轉(zhuǎn)時系統(tǒng)會先在棧結(jié)構(gòu)中尋找是否有一個Activity實例正位于棧頂,如果有則不再生成新的蚕冬,而是直接使用免猾。如果系統(tǒng)發(fā)現(xiàn)存在有Activity實例,但不是位于棧頂是辕,重新生成一個實例囤热。 這就是singleTop啟動模式,如果發(fā)現(xiàn)有對應(yīng)的Activity實例正位于棧頂获三,則重復(fù)利用旁蔼,不再生成新的實例。
3疙教、 singleTask
如果發(fā)現(xiàn)有對應(yīng)的Activity實例棺聊,則使此Activity實例之上的其他Activity實例統(tǒng)統(tǒng)出棧,使此Activity實例成為棧頂對象贞谓,顯示到幕前限佩。
4、singleInstance
這種啟動模式比較特殊,因為它會啟用一個新的棧結(jié)構(gòu)祟同,將Acitvity放置于這個新的棧結(jié)構(gòu)中作喘,并保證不再有其他Activity實例進入。
LaunchMode使用場景
singleTop適合接收通知啟動的內(nèi)容顯示頁面晕城。
例如泞坦,某個新聞客戶端的新聞內(nèi)容頁面,如果收到10個新聞推送砖顷,每次都打開一個新聞內(nèi)容頁面是很煩人的贰锁。
singleTask適合作為程序入口點。
例如瀏覽器的主界面滤蝠。不管從多少個應(yīng)用啟動瀏覽器豌熄,只會啟動主界面一次,其余情況都會走onNewIntent物咳,并且會清空主界面上面的其他頁面房轿。
singleInstance應(yīng)用場景:
鬧鈴的響鈴界面。 你以前設(shè)置了一個鬧鈴:上午6點所森。在上午5點58分囱持,你啟動了鬧鈴設(shè)置界面,并按 Home 鍵回桌面焕济;在上午5點59分時纷妆,你在微信和朋友聊天;在6點時晴弃,鬧鈴響了掩幢,并且彈出了一個對話框形式的 Activity(名為 AlarmAlertActivity) 提示你到6點了(這個 Activity 就是以
SingleInstance
加載模式打開的),你按返回鍵上鞠,回到的是微信的聊天界面际邻,這是因為 AlarmAlertActivity 所在的 Task 的棧只有他一個元素, 因此退出之后這個 Task 的椛盅郑空了世曾。如果是以 SingleTask 打開 AlarmAlertActivity,那么當(dāng)鬧鈴響了的時候谴咸,按返回鍵應(yīng)該進入鬧鈴設(shè)置界面轮听。
9、Activity啟動Service的兩種方式
startService:生命周期和調(diào)用者不同.啟動后若調(diào)用者未調(diào)用stopService而直接退出,Service仍會運行
bindService:生命周期與調(diào)用者綁定,調(diào)用者一旦退出,Service就會調(diào)用unBind->onDestory
10岭佳、Fragment是什么?你曾經(jīng)遇到哪些有關(guān)Fragment的問題?
Fragment可以作為Activity界面的一部分組成出現(xiàn)
其作用是:碎片整理血巍,局部刷新。
一個Activity中可以同時出現(xiàn)多個Fragment,并一個Fragment也可以在多個Activity中使用.在Activity中可以添加,刪除,替換Fragment.Fragment可以響應(yīng)自己的輸入時間,并且有自己的生命周期,但其生命周期受Activity影響.
Fragment生命周期
onAttach():執(zhí)行該方法時珊随,F(xiàn)ragment與Activity已經(jīng)完成綁定述寡,該方法有一個Activity類型的參數(shù)柿隙,代表綁定的Activity,這時候你可以執(zhí)行諸如mActivity = activity的操作鲫凶。
onCreate():初始化Fragment优俘。可通過參數(shù)savedInstanceState獲取之前保存的值掀序。
onCreateView():初始化Fragment的布局帆焕。加載布局和findViewById的操作通常在此函數(shù)內(nèi)完成,但是不建議執(zhí)行耗時的操作不恭,比如讀取數(shù)據(jù)庫數(shù)據(jù)列表叶雹。
onActivityCreated():執(zhí)行該方法時,與Fragment綁定的Activity的onCreate方法已經(jīng)執(zhí)行完成并返回换吧,在該方法內(nèi)可以進行與Activity交互的UI操作折晦,所以在該方法之前Activity的onCreate方法并未執(zhí)行完成,如果提前進行交互操作沾瓦,會引發(fā)空指針異常满着。
onStart():執(zhí)行該方法時,F(xiàn)ragment由不可見變?yōu)榭梢姞顟B(tài)贯莺。
onResume():執(zhí)行該方法時风喇,F(xiàn)ragment處于活動狀態(tài),用戶可與之交互缕探。
onPause():執(zhí)行該方法時魂莫,F(xiàn)ragment處于暫停狀態(tài),但依然可見爹耗,用戶不能與之交互耙考。
onSaveInstanceState():保存當(dāng)前Fragment的狀態(tài)。該方法會自動保存Fragment的狀態(tài)潭兽,比如EditText鍵入的文本倦始,即使Fragment被回收又重新創(chuàng)建,一樣能恢復(fù)EditText之前鍵入的文本山卦。
onStop():執(zhí)行該方法時鞋邑,F(xiàn)ragment完全不可見。
onDestroyView():銷毀與Fragment有關(guān)的視圖怒坯,但未與Activity解除綁定炫狱,依然可以通過onCreateView方法重新創(chuàng)建視圖。通常在ViewPager+Fragment的方式下會調(diào)用此方法剔猿。
onDestroy():銷毀Fragment。通常按Back鍵退出或者Fragment被回收時調(diào)用此方法嬉荆。
onDetach():解除與Activity的綁定归敬。在onDestroy方法之后調(diào)用。
11、是否使用過本地廣播,和全局廣播有什么區(qū)別?
本地廣播在本應(yīng)用范圍內(nèi)傳播,不用擔(dān)心隱私數(shù)據(jù)泄露,不用擔(dān)心別的應(yīng)用偽造廣播.相比全局廣播,本地廣播更高效.
注冊廣播的幾種方法?
1.靜態(tài)注冊:在清單文件中注冊汪茧, 常見的有監(jiān)聽設(shè)備啟動椅亚,常駐注冊不會隨程序生命周期改變
2.動態(tài)注冊:在代碼中注冊,隨著程序的結(jié)束舱污,也就停止接受廣播了
補充一點:有些廣播只能通過動態(tài)方式注冊呀舔,比如時間變化事件、屏幕亮滅事件扩灯、電量變更事件媚赖,因為這些事件觸發(fā)頻率通常很高,如果允許后臺監(jiān)聽珠插,會導(dǎo)致進程頻繁創(chuàng)建和銷毀惧磺,從而影響系統(tǒng)整體性能
為什么Android引入廣播機制?
a:從MVC的角度考慮(應(yīng)用程序內(nèi)) 其實回答這個問題的時候還可以這樣問,android為什么要有那4大組件捻撑,現(xiàn)在的移動開發(fā)模型基本上也是照搬的web那一套MVC架構(gòu)磨隘,只不過是改了點嫁妝而已。
android的四大組件本質(zhì)上就是為了實現(xiàn)移動或者說嵌入式設(shè)備上的MVC架構(gòu)
它們之間有時候是一種相互依存的關(guān)系顾患,有時候又是一種補充關(guān)系番捂,引入廣播機制可以方便幾大組件的信息和數(shù)據(jù)交互。
b:程序間互通消息(例如在自己的應(yīng)用程序內(nèi)監(jiān)聽系統(tǒng)來電)
c:效率上(參考UDP的廣播協(xié)議在局域網(wǎng)的方便性)
d:設(shè)計模式上(反轉(zhuǎn)控制的一種應(yīng)用江解,類似監(jiān)聽者模式)
12白嘁、了解IntentServices嗎?
IntentService是Service的子類,是一個異步的膘流,會自動停止的服務(wù)絮缅,很好解決了傳統(tǒng)的Service中處理完耗時操作忘記停止并銷毀Service的問題
生成一個默認的且與線程相互獨立的工作線程執(zhí)行所有發(fā)送到onStartCommand()方法的Intent,可以在onHandleIntent()中處理.
串行隊列,每次只運行一個任務(wù),不存在線程安全問題,所有任務(wù)執(zhí)行完后自動停止服務(wù),不需要自己手動調(diào)用stopSelf()來停止.
13、如何提升Service進程優(yōu)先級
在AndroidManifest.xml文件中對于intent-filter可以通過android:priority = “1000”這個屬性設(shè)置最高優(yōu)先級呼股,1000是最高值耕魄,如果數(shù)字越小則優(yōu)先級越低,同時適用于廣播彭谁。
14吸奴、數(shù)據(jù)存儲相關(guān)
ContentProvider的主要還是用于數(shù)據(jù)共享,其可以對Sqlite缠局,SharePreferences则奥,F(xiàn)ile等進行數(shù)據(jù)操作用來共享數(shù)據(jù)。而sql的可以理解為數(shù)據(jù)庫的一門語言狭园,可以使用它完成CRUD等一系列的操作
文件存儲:
通過Java.io.FileInputStream和java.io.FileOutputStream這兩個類來實現(xiàn)對文件的讀寫读处,java.io.File類則用來構(gòu)造一個具體指向某個文件或者文件夾的對象。
SharedPreferences:
SharedPreferences是一種輕量級的數(shù)據(jù)存儲機制唱矛,他將一些簡單的數(shù)據(jù)類型的數(shù)據(jù)罚舱,包括boolean類型井辜,int類型,float類型管闷,long類型以及String類型的數(shù)據(jù)粥脚,以鍵值對的形式存儲在應(yīng)用程序的私有Preferences目錄(/data/data/<包名>/shared_prefs/)中,這種Preferences機制廣泛應(yīng)用于存儲應(yīng)用程序中的配置信息包个。
SQLite數(shù)據(jù)庫:
當(dāng)應(yīng)用程序需要處理的數(shù)據(jù)量比較大時刷允,為了更加合理地存儲、管理碧囊、查詢數(shù)據(jù)树灶,我們往往使用關(guān)系數(shù)據(jù)庫來存儲數(shù)據(jù)。Android系統(tǒng)的很多用戶數(shù)據(jù)呕臂,如聯(lián)系人信息鸳吸,通話記錄斤寂,短信息等,都是存儲在SQLite數(shù)據(jù)庫當(dāng)中的,所以利用操作SQLite數(shù)據(jù)庫的API可以同樣方便的訪問和修改這些數(shù)據(jù)张遭。
ContentProvider:
主要用于在不同的應(yīng)用程序之間實現(xiàn)數(shù)據(jù)共享的功能锨阿,不同于sharepreference和文件存儲中的兩種全局可讀寫操作模式恳不,內(nèi)容提供其可以選擇只對哪一部分數(shù)據(jù)進行共享望忆,從而保證我們程序中的隱私數(shù)據(jù)不會有泄漏的風(fēng)險
如何將打開res aw目錄中的數(shù)據(jù)庫文件?
復(fù)制的基本方法是使用getResources().openRawResource方法獲得res aw目錄中資源的 InputStream對象,然后將該InputStream對象中的數(shù)據(jù)寫入其他的目錄中相應(yīng)文件中阐虚。
在Android SDK中可以使用SQLiteDatabase.openOrCreateDatabase方法來打開任意目錄中的SQLite數(shù)據(jù)庫文件序臂。
15、如何將SQLite數(shù)據(jù)庫(dictionary.db文件)與apk文件一起發(fā)布?
可以將dictionary.db文件復(fù)制到Eclipse Android工程中的res aw目錄中实束。所有在res aw目錄中的文件不會被壓縮奥秆,這樣可以直接提取該目錄中的文件∠滩樱可以將dictionary.db文件復(fù)制到res -> raw目錄中
16构订、如何保證Service在后臺不被kill
Service設(shè)置成START_STICKY kill 后會被重啟(等待5秒左右),重傳Intent避矢,保持與重啟前一樣
通過 startForeground將進程設(shè)置為前臺進程悼瘾, 做前臺服務(wù),優(yōu)先級和前臺應(yīng)用一個級別?审胸,除非在系統(tǒng)內(nèi)存非常缺亥宿,否則此進程不會被 kill
雙進程Service: 讓2個進程互相保護**,其中一個Service被清理后砂沛,另外沒被清理的進程可以立即重啟進程
QQ黑科技: 在應(yīng)用退到后臺后烫扼,另起一個只有 1 像素的頁面停留在桌面上,讓自己保持前臺狀態(tài)尺上,保護自己不被后臺清理工具殺死
在已經(jīng)root的設(shè)備下材蛛,修改相應(yīng)的權(quán)限文件,將App偽裝成系統(tǒng)級的應(yīng)用 Android4.0系列的一個漏洞圆到,已經(jīng)確認可行
用C編寫守護進程(即子進程) : Android系統(tǒng)中當(dāng)前進程(Process)fork出來的子進程怎抛,被系統(tǒng)認為是兩個不同的進程卑吭。當(dāng)父進程被殺死的時候,子進程仍然可以存活马绝,并不受影響豆赏。*鑒于目前提到的在Android->- Service層做雙守護都會失敗*,我們可以fork出c進程富稻,多進程守護掷邦。死循環(huán)在那檢查是否還存在,具體的思路如下(Android5.0以上的版本不可行)
用C編寫守護進程(即子進程)椭赋,守護進程做的事情就是循環(huán)檢查目標進程是否存在抚岗,不存在則啟動它。
在NDK環(huán)境中將1中編寫的C代碼編譯打包成可執(zhí)行文件(BUILD_EXECUTABLE)哪怔。主進程啟動時將守護進程放入私有目錄下宣蔚,賦予可執(zhí)行權(quán)限,啟動它即可认境。
聯(lián)系廠商胚委,加入白名單
17、mipmap文件夾和drawable文件夾的區(qū)別
它只是用來放啟動圖標的,好處就是叉信,你只用放一個mipmap圖標亩冬,它就會給你各種版本(比如平板,手機)的apk自動生成相應(yīng)分辨率的圖標硼身,以節(jié)約空間硅急。
18、ListView卡頓的原因以及優(yōu)化策略
重用converView: 通過復(fù)用converview來減少不必要的view的創(chuàng)建佳遂,另外Infalte操作會把xml文件實例化成相應(yīng)的View實例营袜,屬于IO操作,是耗時操作讶迁。
減少findViewById()操作: 將xml文件中的元素封裝成viewholder靜態(tài)類连茧,通過converview的setTag和getTag方法將view與相應(yīng)的holder對象綁定在一起,避免不必要的findviewbyid操作
避免在 getView 方法中做耗時的操作: 例如加載本地 Image 需要載入內(nèi)存以及解析 Bitmap 巍糯,都是比較耗時的操作啸驯,如果用戶快速滑動listview,會因為getview邏輯過于復(fù)雜耗時而造成滑動卡頓現(xiàn)象祟峦。用戶滑動時候不要加載圖片罚斗,待滑動完成再加載,可以使用這個第三方庫glide
Item的布局層次結(jié)構(gòu)盡量簡單宅楞,避免布局太深或者不必要的重繪
盡量能保證 Adapter 的 hasStableIds() 返回 true 這樣在 notifyDataSetChanged() 的時候针姿,如果item內(nèi)容并沒有變化袱吆,ListView 將不會重新繪制這個 View,達到優(yōu)化的目的
在一些場景中距淫,ScollView內(nèi)會包含多個ListView绞绒,可以把listview的高度寫死固定下來。 由于ScollView在快速滑動過程中需要大量計算每一個listview的高度榕暇,阻塞了UI線程導(dǎo)致卡頓現(xiàn)象出現(xiàn)蓬衡,如果我們每一個item的高度都是均勻的,可以通過計算把listview的高度確定下來彤枢,避免卡頓現(xiàn)象出現(xiàn)
使用 RecycleView 代替listview: 每個item內(nèi)容的變動狰晚,listview都需要去調(diào)用notifyDataSetChanged來更新全部的item,太浪費性能了缴啡。RecycleView可以實現(xiàn)當(dāng)個item的局部刷新壁晒,并且引入了增加和刪除的動態(tài)效果,在性能上和定制上都有很大的改善
ListView 中元素避免半透明: 半透明繪制需要大量乘法計算业栅,在滑動時不停重繪會造成大量的計算秒咐,在比較差的機子上會比較卡。 在設(shè)計上能不半透明就不不半透明式镐。實在要弄就把在滑動的時候把半透明設(shè)置成不透明反镇,滑動完再重新設(shè)置成半透明。
盡量開啟硬件加速: 硬件加速提升巨大娘汞,避免使用一些不支持的函數(shù)導(dǎo)致含淚關(guān)閉某個地方的硬件加速歹茶。當(dāng)然這一條不只是對 ListView。
ViewHolder為什么要被聲明成靜態(tài)內(nèi)部類
這個是考靜態(tài)內(nèi)部類和非靜態(tài)內(nèi)部類的主要區(qū)別之一你弦。非靜態(tài)內(nèi)部類會隱式持有外部類的引用惊豺,就像大家經(jīng)常將自定義的adapter在Activity類里,然后在adapter類里面是可以隨意調(diào)用外部activity的方法的禽作。
當(dāng)你將內(nèi)部類定義為static時尸昧,你就調(diào)用不了外部類的實例方法了,因為這時候靜態(tài)內(nèi)部類是不持有外部類的引用的旷偿。聲明ViewHolder靜態(tài)內(nèi)部類烹俗,可以將ViewHolder和外部類解引用。
大家會說一般ViewHolder都很簡單萍程,不定義為static也沒事吧幢妄。確實如此,但是如果你將它定義為static的茫负,說明你懂這些含義蕉鸳。萬一有一天你在這個ViewHolder加入一些復(fù)雜邏輯,做了一些耗時工作,那么如果ViewHolder是非靜態(tài)內(nèi)部類的話潮尝,就很容易出現(xiàn)內(nèi)存泄露榕吼。
如果是靜態(tài)的話,你就不能直接引用外部類勉失,迫使你關(guān)注如何避免相互引用羹蚣。 所以將 ViewHolder內(nèi)部類 定義為靜態(tài)的,是一種好習(xí)慣
19戴质、Android中的動畫有哪些?
逐幀動畫(Drawable Animation):
加載一系列Drawable資源來創(chuàng)建動畫度宦,簡單來說就是播放一系列的圖片來實現(xiàn)動畫效果踢匣,可以自定義每張圖片的持續(xù)時間
補間動畫(Tween Animation):
Tween可以對View對象實現(xiàn)一系列簡單的動畫效果告匠,比如位移,縮放离唬,旋轉(zhuǎn)后专,透明度等等。但是它并不會改變View屬性的值输莺,只是改變了View的繪制的位置戚哎,比如,一個按鈕在動畫過后嫂用,不在原來的位置型凳,但是觸發(fā)點擊事件的仍然是原來的坐標。
屬性動畫(Property Animation):
動畫的對象除了傳統(tǒng)的View對象嘱函,還可以是Object對象甘畅,動畫結(jié)束后,Object對象的屬性值被實實在在的改變了
Android動畫原理
Animation框架定義了透明度往弓,旋轉(zhuǎn)疏唾,縮放和位移幾種常見的動畫,而且控制的是整個View
實現(xiàn)原理是每次繪制視圖時View所在的ViewGroup中的drawChild函數(shù)獲取該View的Animation的Transformation值
然后調(diào)用canvas.concat(transformToApply.getMatrix())函似,通過矩陣運算完成動畫幀槐脏,如果動畫沒有完成,繼續(xù)調(diào)用invalidate()函數(shù)撇寞,啟動下次繪制來驅(qū)動動畫
動畫過程中的幀之間間隙時間是繪制函數(shù)所消耗的時間顿天,可能會導(dǎo)致動畫消耗比較多的CPU資源,最重要的是蔑担,動畫改變的只是顯示牌废,并不能相應(yīng)事件
20、View繪制相關(guān)
SurfaceView和View的區(qū)別
SurfaceView中采用了雙緩存技術(shù)钟沛,在單獨的線程中更新界面
View在UI線程中更新界面
介紹下自定義view的基本流程
1畔规、 明確需求,確定你想實現(xiàn)的效果
2恨统、確定是使用組合控件的形式還是全新自定義的形式叁扫,組合控件即使用多個系統(tǒng)控件來合成一個新控件三妈,你比如titilebar,這種形式相對簡單莫绣,參考
3畴蒲、如果是完全自定義一個view的話,你首先需要考慮繼承哪個類对室,是View呢模燥,還是ImageView等子類。
4掩宜、根據(jù)需要去復(fù)寫View#onDraw蔫骂、View#onMeasure、View#onLayout方法
5.根據(jù)需要去復(fù)寫dispatchTouchEvent牺汤、onTouchEvent方法
6辽旋、根據(jù)需要為你的自定義view提供自定義屬性,即編寫attr.xml,然后在代碼中通過TypedArray等類獲取到自定義屬性值
7檐迟、需要處理滑動沖突补胚、像素轉(zhuǎn)換等問題
21、談?wù)刅iew的繪制流程
measure()方法追迟,layout()溶其,draw()三個方法主要存放了一些標識符,來判斷每個View是否需要再重新測量敦间,布局或者繪制瓶逃,主要的繪制過程還是在onMeasure,onLayout每瞒,onDraw這個三個方法中
1.onMesarue() 為整個View樹計算實際的大小金闽,即設(shè)置實際的高(對應(yīng)屬性:mMeasuredHeight)和寬(對應(yīng)屬性: mMeasureWidth),每個View的控件的實際寬高都是由父視圖和本身視圖決定的剿骨。
2.onLayout() 為將整個根據(jù)子視圖的大小以及布局參數(shù)將View樹放到合適的位置上代芜。
3.onDraw() 開始繪制圖像,繪制的流程如下
首先繪制該View的背景
調(diào)用onDraw()方法繪制視圖本身 (每個View都需要重載該方法浓利,ViewGroup不需要實現(xiàn)該方法)
如果該View是ViewGroup挤庇,調(diào)用dispatchDraw ()方法繪制子視圖
繪制滾動條
自定義View執(zhí)行invalidate()方法,為什么有時候不會回調(diào)onDraw()
自定義一個view時,重寫onDraw贷掖。調(diào)用view.invalidate(),會觸發(fā)onDraw和computeScroll()嫡秕。前提是該view被附加在當(dāng)前窗口.
view.postInvalidate(); //是在非UI線程上調(diào)用的
自定義一個ViewGroup,重寫onDraw苹威。onDraw可能不會被調(diào)用昆咽,原因是需要先設(shè)置一個背景(顏色或圖)。表示這個group有東西需要繪制了,才會觸發(fā)draw掷酗,之后是onDraw调违。因此,一般直接重寫dispatchDraw來繪制viewGroup.自定義一個ViewGroup,dispatchDraw會調(diào)用drawChild.
22泻轰、事件傳遞機制
談?wù)則ouch事件的傳遞流程
所有Touch事件都被封裝成了MotionEvent對象技肩,包括Touch的位置、時間浮声、歷史記錄以及第幾個手指(多指觸摸)等虚婿。
事件類型分為ACTION_DOWN, ACTION_UP, ACTION_MOVE, ACTION_POINTER_DOWN, ACTION_POINTER_UP, ACTION_CANCEL,每個事件都是以ACTION_DOWN開始ACTION_UP結(jié)束泳挥。
對事件的處理包括三類然痊,分別為傳遞——dispatchTouchEvent()函數(shù)、攔截——onInterceptTouchEvent()函數(shù)羡洁、消費——onTouchEvent()函數(shù)和OnTouchListener()
簡單來說:
事件從Activity.dispatchTouchEvent()開始傳遞玷过,只要沒有被停止或攔截,從最上層的View(ViewGroup)開始一直往下(子View)傳遞筑煮。子View可以通過onTouchEvent()對事件進行處理。
事件由父View(ViewGroup)傳遞給子View粤蝎,ViewGroup可以通過onInterceptTouchEvent()對事件做攔截真仲,停止其往下傳遞。
如果事件從上往下傳遞過程中一直沒有被停止初澎,且最底層子View沒有消費事件秸应,事件會反向往上傳遞,這時父View(ViewGroup)可以進行消費碑宴,如果還是沒有被消費的話软啼,最后會到Activity的onTouchEvent()函數(shù)。
如果View沒有對ACTION_DOWN進行消費延柠,之后的其他事件不會傳遞過來祸挪。
= OnTouchListener優(yōu)先于onTouchEvent()對事件進行消費。
上面的消費即表示相應(yīng)函數(shù)返回值為true贞间。
View中setOnTouchListener中的onTouch,onTouchEvent,onClick的執(zhí)行順序
onTouch優(yōu)于onTouchEvent,onTouchEvent優(yōu)于onClick
23贿条、什么是Dalvik虛擬機
Dalvik虛擬機是Android平臺的核心。
它可以支持.dex格式的程序的運行
.dex格式是專為Dalvik設(shè)計的一種壓縮格式
可以減少整體文件尺寸
提高I/O操作的速度
適合內(nèi)存和處理器速度有限的系統(tǒng)
Dalvik虛擬機和JVM有什么區(qū)別
Dalvik 基于寄存器增热,而 JVM 基于棧整以。基于寄存器的虛擬機對于更大的程序來說峻仇,在它們編譯的時候公黑,花費的時間更短。
Dalvik執(zhí)行.dex格式的字節(jié)碼,而JVM執(zhí)行.class格式的字節(jié)碼
Android為每個應(yīng)用程序分配的內(nèi)存大小是多少
一般是16m或者24m,但是可以通過android:largeHeap申請更多內(nèi)存
Dalvik?
Android4.4及以前使用的都是Dalvik虛擬機凡蚜,我們知道Apk在打包的過程中會先將java等源碼通過javac編譯成.class文件奠骄,但是我們的Dalvik虛擬機只會執(zhí)行.dex文件,這個時候dx會將.class文件轉(zhuǎn)換成Dalvik虛擬機執(zhí)行的.dex文件番刊。Dalvik虛擬機在啟動的時候會先將.dex文件轉(zhuǎn)換成快速運行的機器碼含鳞,又因為65535這個問題,導(dǎo)致我們在應(yīng)用冷啟動的時候有一個合包的過程芹务,最后導(dǎo)致的一個結(jié)果就是我們的app啟動慢蝉绷,這就是Dalvik虛擬機的JIT特性(Just In Time)。
ART?
ART虛擬機是在Android5.0才開始使用的Android虛擬機枣抱,ART虛擬機必須要兼容Dalvik虛擬機的特性熔吗,但是ART有一個很好的特性AOT(ahead of time),這個特性就是我們在安裝APK的時候就將dex直接處理成可直接供ART虛擬機使用的機器碼佳晶,ART虛擬機將.dex文件轉(zhuǎn)換成可直接運行的.oat文件桅狠,ART虛擬機天生支持多dex,所以也不會有一個合包的過程轿秧,所以ART虛擬機會很大的提升APP冷啟動速度中跌。
3.總結(jié)
Dalvik虛擬機執(zhí)行的是dex字節(jié)碼,ART虛擬機執(zhí)行的是本地機器碼
ART優(yōu)點:
加快APP冷啟動速度
提升GC速度
提供功能全面的Debug特性
ART缺點:
APP安裝速度慢菇篡,因為在APK安裝的時候要生成可運行.oat文件
APK占用空間大漩符,因為在APK安裝的時候要生成可運行.oat文件
24、如何解決方法數(shù)65k問題?
使用Android Studio 的gradle 可以構(gòu)建MutilDex
25驱还、Android Binder機制原理
Binder是Android系統(tǒng)進程間通信(IPC)方式之一嗜暴,Binder框架定義了四個角色:Server,Client议蟆,ServiceManager(以后簡稱SMgr)以及Binder驅(qū)動闷沥。
其中Server,Client咐容,SMgr運行于用戶空間舆逃,驅(qū)動運行于內(nèi)核空間。這四個角色的關(guān)系和互聯(lián)網(wǎng)類似:Server是服務(wù)器疟丙,Client是客戶終端颖侄,SMgr是域名服務(wù)器(DNS),驅(qū)動是路由器享郊。
26览祖、AMS與WMS
Android的framework層主要是由WMS、AMS還有View所構(gòu)成炊琉,AMS和WMS都屬于Android中的系統(tǒng)服務(wù)
AMS統(tǒng)一調(diào)度所有應(yīng)用程序的Activity
WMS控制所有Window的顯示與隱藏以及要顯示的位置
AMS
基礎(chǔ)了解
作用
統(tǒng)一調(diào)度所有應(yīng)用程序的Activity的生命周期
啟動或殺死應(yīng)用程序的進程
啟動并調(diào)度Service的生命周期
注冊BroadcastReceiver展蒂,并接收和分發(fā)Broadcast
啟動并發(fā)布ContentProvider
調(diào)度task
處理應(yīng)用程序的Crash
查詢系統(tǒng)當(dāng)前運行狀態(tài)
WMS
基礎(chǔ)了解
WindowManagerService服務(wù)的實現(xiàn)是相當(dāng)復(fù)雜的又活,畢竟它要管理的整個系統(tǒng)所有窗口的UI,而在任何一個系統(tǒng)中锰悼,窗口管理子系統(tǒng)都是極其復(fù)雜的柳骄。
作用
為所有窗口分配Surface』悖客戶端向WMS添加一個窗口的過程耐薯,其實就是WMS為其分配一塊Suiface的過程,一塊塊Surface在WMS的管理下有序的排布在屏幕上丝里。Window的本質(zhì)就是Surface曲初。
管理Surface的顯示順序、尺寸杯聚、位置
管理窗口動畫
輸入系統(tǒng)相關(guān):WMS是派發(fā)系統(tǒng)按鍵和觸摸消息的最佳人選臼婆,當(dāng)接收到一個觸摸事件,它需要尋找一個最合適的窗口來處理消息幌绍,而WMS是窗口的管理者颁褂,系統(tǒng)中所有的窗口狀態(tài)和信息都在其掌握之中,完成這一工作不在話下傀广。
27颁独、ProGuard簡介
因為Java代碼是非常容易反編碼的,況且Android開發(fā)的應(yīng)用程序是用Java代碼寫的主儡,為了很好的保護Java源代碼奖唯,我們需要對編譯好后的class文件進行混淆。
ProGuard是一個混淆代碼的開源項目糜值,它的主要作用是混淆代碼,殊不知ProGuard還包括以下4個功能坯墨。
壓縮(Shrink):檢測并移除代碼中無用的類寂汇、字段、方法和特性(Attribute)捣染。
優(yōu)化(Optimize):對字節(jié)碼進行優(yōu)化骄瓣,移除無用的指令。
混淆(Obfuscate):使用a耍攘,b榕栏,c,d這樣簡短而無意義的名稱蕾各,對類扒磁、字段和方法進行重命名。
預(yù)檢(Preveirfy):在Java平臺上對處理后的代碼進行預(yù)檢式曲,確保加載的class文件是可執(zhí)行的妨托。
總而言之缸榛,根據(jù)官網(wǎng)的翻譯:Proguard是一個Java類文件壓縮器、優(yōu)化器兰伤、混淆器内颗、預(yù)校驗器。壓縮環(huán)節(jié)會檢測以及移除沒有用到的類敦腔、字段均澳、方法以及屬性。優(yōu)化環(huán)節(jié)會分析以及優(yōu)化方法的字節(jié)碼符衔≌仪埃混淆環(huán)節(jié)會用無意義的短變量去重命名類、變量柏腻、方法纸厉。這些步驟讓代碼更精簡,更高效五嫂,也更難被逆向(破解)颗品。