Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android Holo Light styling changes depending on chosen context

I have been trying to find the cause of weird formatting style inconsistencies for my Views throughout my application and I think I have narrowed it down with this example.

I set up two equivalent layouts of various Viewss with exactly the same procedure and only varying the Context supplied in creation. In the first set, each View is created with the application's context through Activity.getApplicationContext(), whereas in the second set the Views are fed the activity's context through this.

The result is vastly different:

enter image description here

Any suggestions on why using the application context causes the garbage (and inconsistent - colours are white as well as grey) formatting seen in the screenshot?

Activity code:

import android.os.Bundle;
import android.app.Activity;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.Spinner;
import android.widget.TextView;

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // TextViews
        TextView tv1 = new TextView(getApplicationContext());
        tv1.setText("With Application  context");
        TextView tv2 = new TextView(this);
        tv2.setText("With Activity  context");      

        // Spinners
        Spinner sp1 = new Spinner(getApplicationContext());
        sp1.setAdapter(new ArrayAdapter<String>(getApplicationContext(), android.R.layout.simple_spinner_item, new String[] {"App context 1", "App context 2", "App context 3"}));
        Spinner sp2 = new Spinner(this);
        sp2.setAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item, new String[] {"Act context 1", "Act context 2", "Act context 3"}));

        // Edittexts
        EditText et1 = new EditText(getApplicationContext());
        et1.setText("Application Context");
        EditText et2 = new EditText(this);
        et2.setText("Activity Context");        

        // Buttons
        Button b1 = new Button(getApplicationContext());
        b1.setText("Application Context");
        Button b2 = new Button(this);
        b2.setText("Activity Context");     

        // Layout structure
        LinearLayout ll = new LinearLayout(this);
        ll.setOrientation(LinearLayout.VERTICAL);

        ll.addView(tv1);
        ll.addView(sp1);
        ll.addView(et1);
        ll.addView(b1);
        ll.addView(tv2);
        ll.addView(sp2);
        ll.addView(et2);
        ll.addView(b2);

        setContentView(ll);
    }

}

Manifest:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.test.test"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="11"
        android:targetSdkVersion="17" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name" 
        android:theme="@android:style/Theme.Holo.Light" >
        <activity
            android:name="com.test.test.MainActivity"
            android:label="@string/app_name" 
            android:theme="@android:style/Theme.Holo.Light" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>
like image 349
btalb Avatar asked Feb 12 '13 02:02

btalb


1 Answers

In Android sources getApplicationContext() returns Application object which extends ContextWrapper, so using getApplicationContext() you are passing ContextWrapper subclass, but when you pass this, you are passing an Activity object which extends ContextThemeWrapper so you are passing ContextThemeWrapper subclass. Now the difference between ContextWrapper and ContextThemeWrapper is that ContextWrapper simply delegates all of its calls to another Context and ContextThemeWrapper allows you to modify the theme from what is in the wrapped context.

Although, the question was more about why exactly this is happening (as opposed to the cause which was clear), here are also some helpful posts which explain the perils of incorrectly using application context and how to choose a context correctly:

  • When to call activity context OR application context?
  • Using Application context everywhere?

Most importantly from @CommonsWare: "getApplicationContext() is not a complete Context and consequently does not support everything that Activity does."

Awesome post about Context that should clarify everything:

  • http://www.doubleencore.com/2013/06/context/
like image 135
Michał Z. Avatar answered Nov 18 '22 19:11

Michał Z.