概要
Support Library 24.1.1を利用しようとしてクラッシュしたのでちょっとメモしておきます。
何が起こるのか?
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final TextView text = (TextView) findViewById(R.id.text);
final Activity activity = (Activity)text.getContext();
}
}
ClassCastExceptionでクラッシュする模様
java.lang.ClassCastException: android.support.v7.widget.TintContextWrapper cannot be cast to android.app.Activity
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2646)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2707)
at android.app.ActivityThread.-wrap12(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1460)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6077)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:865)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:755)
Caused by: java.lang.ClassCastException: android.support.v7.widget.TintContextWrapper cannot be cast to android.app.Activity
at com.github.takahirom.myapplication.MainActivity.onCreate(MainActivity.java:16)
at android.app.Activity.performCreate(Activity.java:6664)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1118)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2599)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2707)
at android.app.ActivityThread.-wrap12(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1460)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6077)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:865)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:755)
なぜ起こるのか?
レイアウト内のTextViewなどはAppCompatActivityによって、AppCompatTextViewに置き換えがされます。(https://github.com/android/platform_frameworks_support/blob/66698bb15ba0f873aa1c2290cc50d6bb839a474a/v7/appcompat/src/android/support/v7/app/AppCompatViewInflater.java#L91 )
以下はAppCompatTextViewのコンストラクタです。
こんな風にActivityをそのまま渡すのではなくTintContextWrapperとしてwrapしてViewクラスなどにContextを渡すためです。
このように行うViewが多くなっているようです
public class AppCompatTextView extends TextView implements TintableBackgroundView {
...
public AppCompatTextView(Context context, AttributeSet attrs, int defStyleAttr) {
super(TintContextWrapper.wrap(context), attrs, defStyleAttr);
どうしてもViewのContextからActivityを取りたい
wrapしてしまっているだけなので、以下のようにwrapを解除してあげれば取得できるようです。
final Activity activity = (Activity) ((ContextWrapper) text.getContext()).getBaseContext();
ただSupport Libraryの実装に依存してしまうので良くないと思います。
できるだけActivityから普通に渡してあげたり、何か他の仕組みを使いましょう。