Android中通過view.getContext獲取Activity時得到TintContextWrapper的問題及解決

       這篇博客主要介紹Android在使用AppCompatActivity時遇到的一些出乎意料的問題,下面將問題及解決方案記錄如下,便於查詢。

問題

       在使用Androidstudio開發中,默認創建的activity都繼承自AppCompatActivity,如下圖所示,然後在佈局中使用也使用很簡單的一個佈局如下圖所示。

public class MainActivity extends AppCompatActivity implementsView.OnClickListener{}

       然後我想在別的工具類中(該工具類中有該view的引用)通過view.getContext 獲得view所在activity的實例對象。於是乎有了如下的簡單代碼。

(1)MainActivity 中

Button button = (Button) findViewById(R.id.btn);
button.setOnClickListener(MainActivity.this);

if(button instanceof AppCompatButton){
  Log.d("HHHHH","====button is appCompatButton====");
}

(2)工具類中

public static void getActivityInfo(View view){
    Context context=view.getContext();
    Log.d("HHHHH","getActivityInfo-getContext="+context);
    if(context instanceof Activity){
        Activity activity= (Activity) context;
        Log.d("HHHHH","getActivityInfo-name="+activity.getClass().getSimpleName());
    }
}

結果日誌是這樣的。。。


what??? 

(1)我的Button怎麼成了 AppCompatButton ???  (2)我的view.getContext得到的是TintContextWrapper,而不是Activity??這又是什麼鬼.......

於是乎。。。查源碼發現,我們的activity繼承自AppCompatActivity時,也就是引用的是v7包時,我們的button就自動轉爲AppCompatButton 了(具體的可以參見AppCompatButton 源碼註釋)。同時在AppCompatButton 中我們的Context就變成了圖中第二個框中的TintContextWrapper了。。。。


解決方案

       原來在繼承自AppCompatActivity時,Android底層會將我們應用的控件轉爲v7包中對應的控件,Context就被替換成了TintContextWrapper(他也繼承自ContextWrapper)。所以我們可以通過如下代碼獲取想要的activity。

public static Activity getActivityFromView(View view) {
  if (null != view) {
    Context context = view.getContext();
    while (context instanceof ContextWrapper) {
      if (context instanceof Activity) {
        return (Activity) context;
      }
      context = ((ContextWrapper) context).getBaseContext();
    }
  }
  return null;
}


其他和AppCompatActivity相關的問題可以參考如下文章。

AppCompatActivity

Android 從 View 中獲取 Activity 時遇到 TintContextWrapper cannot be cast to 的問題

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