Tuesday, February 4, 2014

Programming things to remember 2014 Jan

Robolectric + ActionBarCompat v7


  • Robolectric v2.1.1 doesn't support actionbar.
  • Robolectric v2.2 supports ActionBarSherlock and native ActionBar
  • Robolectric v2.3-SNAPSHOT removed the possibility to instantiate an Activity directly from a test. So the dagger pattern we are using can be used with it
  • The main point is, Robolectric doesn't support the ActionBar from the Compatibility library
    Not even with @Config(reportSdk = 10). Different versions throw different exceptions, like: com.android.internal.widget.ActionBarView$HomeView cannot be cast to android.support.v7.internal.widget.ActionBarView$HomeView or java.lang.IllegalStateException: You need to use a Theme.AppCompat theme (or descendant) with this activity. (i used that theme) or java.lang.IllegalStateException: System services not available to Activities before onCreate()
See Corey D's comment on this: http://stackoverflow.com/questions/18790958/cannot-create-actionbaractivity-from-robolectric-2-unit-test


Adding v7 compat to maven project


  • http://stackoverflow.com/a/18796764/1738827
  • My pom file had this:

    <dependency>
            <groupid>com.android.support</groupid>
            <artifactid>appcompat-v7</artifactid>
            <version>18.0.0</version>
            <type>apklib</type>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupid>com.android.support</groupid>
            <artifactid>appcompat-v7</artifactid>
            <version>18.0.0</version>
            <type>jar</type>
            <scope>compile</scope>
        </dependency>
    



SlidingManu JeremyFeinstein


If you don't need actionBarSherlock (and/or don't want to clutter your inheritance hierarchy of the Activity with a lot more layers), it's enough to copy 3 files and resources to your project:
  • SlidingMenu.java
  • CustomViewBehind.java
  • CustomViewAbove.java
And you can use the eg. the 2nd method to create SlidingMenu (https://github.com/jfeinstein10/SlidingMenu).


Tiling background with gradient


<?xml version="1.0" encoding="utf-8"?>
    <bitmap
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:src="@drawable/tile_pattern"
        android:antialias="false"
        android:dither="false"
        android:filter="false"
        android:gravity="center|center_vertical"
        android:tileMode="repeat"
   />

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item>
        <layer-list>

            <item>
                <gradient
                        android:startColor="@color/lobby_tile_background_gradient_start"
                        android:endColor="@color/lobby_tile_background_gradient_end"
                        android:angle="270"
                        />
            </item>

            <item android:drawable="@drawable/lobby_tile_repeat_texture"/>

        </layer-list>
    </item>
</selector>

Ignore git files locally and temporally


With a simple command file can be removed from the git index. So in theory rebasing and moving branch wouldn't cause a problem. However I had conflict problems with this approach trying to rebase.

git update-index --assume-unchanged [<file>...]

And to undo this:

git update-index --no-assume-unchanged [<file>...]

Custom style for buttons in the Android actionBar


It is pretty tricky to have a custom button in the ActionBar. The secret is you have to provide as an ActionView:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" 
    android:clickable="true"
    >
    <ImageButton
        android:id="@+id/imageButton1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/ic_launcher"
        android:clickable="false" 
     />
The clickable is important. This lets the linearLayout handle click events. Though it may interfere with other builtin functionality.

@Override
    public boolean onCreateOptionsMenu(Menu menu) {
    MenuInflater inflater = getMenuInflater();
    inflater.inflate(R.menu.main, menu);

    MenuItem item = menu.findItem(R.id.custom_button);
    item.setActionView(R.layout.menu_overflow);

    final LinearLayout customButton = (LinearLayout) menu.findItem(R.id.action_settings).getActionView();
    customButton.setOnClickListener(new View.OnClickListener() {
        @Override
            public void onClick(View v) {
                // do something here
            }
        });
        return true;
    }

And with this you get the overflow functionality as well. So if the button doesn't fit to the actionBar, it will be placed in the overflow menu. Of course being there you won't get the custom look&feel.

Android onCreateOptionsMenu() call order


This has changed in JellyBean. Whereas it was in ICS (using actionBarSherlock, which states it works the same way the native Activity works):


MainActivity.onCreate()
MainActivity.onResume()
MainActivity.onCreateOptionsMenu()
MainActivity.onPrepareOptionsMenu()
MainActivity.onCreateOptionsMenu()
MainActivity.onPrepareOptionsMenu()
AddedFragment.onStart()
AddedFragment.onResume()


And it became:

MainActivity.onCreate()
MainActivity.onResume()
MainActivity.onCreateOptionsMenu()
MainActivity.onPrepareOptionsMenu()
AddedFragment.onStart()
AddedFragment.onResume()
MainActivity.onCreateOptionsMenu()
MainActivity.onPrepareOptionsMenu()

So the onCreateOptionsMenu() is called once more giving you a chance to alter the actionBar.