LoginSignup
22
9

More than 5 years have passed since last update.

最近のSupport Libraryで(Activity)view.getContext()するとクラッシュするので注意

Posted at

概要

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から普通に渡してあげたり、何か他の仕組みを使いましょう。

22
9
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
22
9