如何減少dex檔案中生成的access$x00方法
在安卓開發中,我們可能會經常遇到一些線上報錯,顯示access$x00方法報錯,而實際上我們的程式碼中並沒有這個方法。那麼這些方法是怎麼生成的呢?
實際上這些方法是由編譯器幫我們生成的,舉個例子,當我們在匿名內部類中試圖訪問外部類的private欄位或方法時,此時,我們的內部類實際上並沒有這些private欄位或方法的訪問許可權。編譯器此時會幫我們生成一個包訪問許可權的access$x00方法,通過這個方法再去間接訪問類的private欄位或方法
例如:以下java類
import android.widget.TextView; public class ItemsView { private static String displayText(String item) { return ""; // TODO } private class ItemsAdapter { void bindItem(TextView tv, String item) { tv.setText(ItemsView.displayText(item)); } } }
當我們執行
-- javac -bootclasspath %ANDROID_HOME%/platforms/android-24/android.jar ItemsView.java
-- javap -c ItemsView$ItemsAdapter
後,看到生成了如下的位元組碼檔案
class ItemsView$ItemsAdapter {
final ItemsView this$0;
void bindItem(android.widget.TextView, java.lang.String);
Code:
0: aload_1
1: aload_2
2: invokestatic #3 // Method ItemsView.access$000:(Ljava/lang/String;)Ljava/lang/String;
5: invokevirtual #4 // Method android/widget/TextView.setText:(Ljava/lang/CharSequence;)V
8: return
}
其中加黑的一段程式碼即是編譯器幫我們生成的程式碼。
那麼如果我們想要去掉這些方法,該怎麼做呢?
-- 將從內部類中呼叫的外部類的這些private 欄位或方法,去掉private限定符即可。
實際用例
在作者嘗試通過修改限定符,減少access方法的實踐中,發現涉及到一些Context的access引用訪問,一時找不到具體定義。通過反覆檢視程式碼,思考,修改,測試,最終找到相關引用鏈
Context是由基類引入,例如在BaseActivity中,將Context的限定符設定為protected,此時BaseActivity的子類可以直接引用Context。如果此時子類的內部類也想訪問這個Context引用呢,那麼這個Context引用相對於這個子類的內部類,它是protected,還是private?
實際上當我將父類的Context限定符修改為public時,從子類的內部類中訪問該Context引用時,不會生成access$x00方法;而當Context的限定符為protected時,從子類的內部類中訪問該Context引用時,生成了access$x00方法。
所以,關於這個疑問“此時Context引用相對於這個子類的內部類,它是protected,還是private?”,我的答案是private。
關於這個結論暫時沒想到如何驗證,如果有同學有驗證的思路,歡迎告知!