Context として以下のように Application Context を渡しているコードを見かけました。
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Button textView = new Button(getApplicationContext());
}
}
これがなぜよくないのか説明します。
View に渡された Context はスタイル属性を取得するのに使われます。
View.java
public View(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
this(context);
final TypedArray a = context.obtainStyledAttributes(
attrs, com.android.internal.R.styleable.View, defStyleAttr, defStyleRes);
...
background = a.getDrawable(attr);
...
View のスタイルは
- 1. XMLタグで指定された値(例 android:background="@drawable/button_bg")
- 2. style で指定された値(例 style="@style/MyButtonStyle)
- 3. テーマで指定された値(例 テーマの中で
- @style/MyButtonStyle
)
このことを踏まえて obtainStyledAttributes() の中身をみると
Context.java
public final TypedArray obtainStyledAttributes(
AttributeSet set, @StyleableRes int[] attrs, @AttrRes int defStyleAttr,
@StyleRes int defStyleRes) {
return getTheme().obtainStyledAttributes(
set, attrs, defStyleAttr, defStyleRes);
}
getTheme() で Theme を取得し、Theme の obtainStyledAttributes() を呼んでいます。つまり、3. では Context が持っているテーマ情報を使っているのです。
Application Context を渡してはいけない理由がわかったでしょうか。
Activity ごとにテーマを指定できるのに、Application Context を渡してしまうと、Activity のテーマが全く利用されません。
実際にやってみましょう。
Application には Theme.AppCompat(黒系)、MainActivity には Theme.AppCompat.Light(白系)を指定します。
<manifest ...>
<application
...
android:theme="@style/Theme.AppCompat">
<activity
android:name=".MainActivity"
android:theme="@style/Theme.AppCompat.Light">
...
</activity>
</application>
</manifest>
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button button1 = new Button(getApplicationContext());
button1.setText("Application Context");
Button button2 = new Button(this);
button1.setText("Activity Context");
LinearLayout ll = (LinearLayout) findViewById(R.id.container);
ll.addView(button1);
ll.addView(button2);
}
}
画面のテーマは Theme.AppCompat.Light (白系)なのに、Application Context を渡した上のボタンは Theme.AppCompat(黒系)の色になってしまっています。
Context が持つテーマが利用されるという仕組みは、v7 AppCompat Support Library でも使われています。 AppCompatTextView を見てみましょう。
public class AppCompatTextView extends TextView implements TintableBackgroundView {
...
public AppCompatTextView(Context context, AttributeSet attrs, int defStyleAttr) {
super(TintContextWrapper.wrap(context), attrs, defStyleAttr);
TintContextWrapper でラップした Context を TextView に渡しています。これにより、colorAccent の指定色によって自動でテキストカーソルなどが tint されます。
0 件のコメント:
コメントを投稿