Friday, July 17, 2015

How to use an external project as a library project in Android Studio

We have 2 Android projects:
MyApplication is the project that produces apk and to be run on mobile devices;
Dependency is a library project that contains useful classes such as Fragments, Services, Util classes to be used by MyApplication.

The structure of these 2 projects are like this:
MyApplication
  |--build.gradle
  |--settings.gradle
  |--app
  |    |--build.gradle
Dependency
  |--build.gradle
  |--settings.gradle
  |--app
  |    |--build.gradle

First of all, we need to make sure that the gradle plugin of Dependency/app/build.gradle is library instead of application. The first line of the build.gradle file should be this:


apply plugin: 'com.android.library'

Then we go back to the MyApplication project, find the settings.gradle file under the project directory(MyApplication/settings.gradle), edit it to include our Dependency project by adding the lines like this:


include ':library-project-name'
project(':library-project-name').projectDir = new File(settingsDir, '../Dependency/app/')

the second parameter of File(.., ..) is a directory path pointing to the build.gradle file of the app module of the library project.


The last step is to configure the build.gradle file of the app module of the MyApplication project in order to add the library project to its dependencies.

We go to MyApplication/app/build.gradle file and add a line to the dependencies block.


dependencies{
   ........
   compile project(':library-project-name')
}

All done, feel free to use any classes in the Dependency library project in your MyApplication project from this point on.

Wednesday, July 8, 2015

Useful commands for Android Developers on Mac

Check jdk path

/usr/libexec/java_home -v 1.7

Add JDK path to environment variables

export JAVA_HOME=/Library/Java/JavaVirtualMachines/jdk1.7.0_79.jdk/Contents/Home

Add gradle to path

GRADLE_HOME=/Users/ericliu/Developer/Android/gradle-2.5;
export GRADLE_HOME
export PATH=$PATH:$GRADLE_HOME/bin

Add adb to path

export PATH=$PATH:/Users/ericliu/Library/Android/sdk/platform-tools



Open a file with an Application

open Application.app

Or:


open -a Application filename


Close an Application from Terminal

osascript -e 'quit app "APPLICATIONNAME"'

For example, to quit Calendar from the command line, replace APPLICATIONNAME with “Calendar”
osascript -e 'quit app "Calendar"'



Enable Git auto-completion and add the current branch, and the status of the working directory info to the  prompt
First, download some script files from github and rename them to start with "." so they will become hidden files.

curl -OL https://raw.githubusercontent.com/git/git/master/contrib/completion/git-completion.bash

mv git-completion.bash .git-completion.bash

curl -OL https://raw.githubusercontent.com/git/git/master/contrib/completion/git-prompt.sh

mv git-prompt.sh .git-prompt.sh 



Then edit the .bash_profile file or .profile or .bashrc

# Git config: add the current branch, and the status of the working directory info to the # prompt
. ~/.git-prompt.sh
export GIT_PS1_SHOWDIRTYSTATE=1
export PS1='\w$(__git_ps1 " (%s)")\$ '


# Git config: load the .git-completion.bash file if it exists
if [ -f ~/.git-completion.bash ]; then
    source ~/.git-completion.bash
fi



Now the auto-completion for git is enabled and the prompt line will now display the current branch name. If you go to a git repository directory, the prompt line will now look like this:

~/Developer/Work/MyApplication (master)$ 


View Android Task Stack from command line

adb shell dumpsys activity

To be more concise:

adb shell dumpsys activity activities | sed -En -e '/Stack #/p' -e '/Running activities/,/Run #0/p'

In addition, if you only want to see the activities' name in the stack you can do this:

adb shell <enter> dumpsys activity | grep -i run


Compile a C program file.

gcc HelloWorld.c

And run the compiled result.

./a.out




References:

http://osxdaily.com/2014/09/05/gracefully-quit-application-command-line/

http://stackoverflow.com/questions/2442713/view-the-tasks-activity-stack

Tuesday, June 23, 2015

Why the Outer Class has access to inner Class instances' private fields

Consider a class like this




public class Subclass extends Superclass {
 int subMember;
 

 private void interestingMethod(){
  System.out.println("Subclass is interesting");
 }
 
 @Override
 protected void notSoInteresting() {
  super.notSoInteresting();
  System.out.println("Subclass is not so interesting.");
 }
 
 
 public void accessInnerClassFields(){
  Innerclass innerClass = new Innerclass();
  innerClass.innerClassId = 3;
 }
 
 public class Innerclass{
  private long innerClassId = 32L;
  
  void changeOuterMember(){
   subMember = 3;
  }
 }
 
 public void accessInnerStaticClassFields(){
  EricLiu eric = new EricLiu();
  long copyEricId = eric.ericId;
 }
 
 
 public static class EricLiu{
  private long ericId = 123L;
  
 } 
}


Let's look at the methods accessInnerStaticClassFields() and accessInnerClassFields(). They both access the private fields of an inner class, either a static one or non-static one. How does that happen?
The Java Virtual Machine has no idea that they are inner classes so it should prevent another class from accessing the EricLiu and InnerClass's private class members.

Let's dive into the bytecode. call javap -v -p -s -sysinfo -constants Subclass.class
to dissect the outer class first.



 public void accessInnerClassFields();
    Signature: ()V
    flags: ACC_PUBLIC
    Code:
      stack=3, locals=2, args_size=1
         0: new           #37                 // class Subclass$Innerclass
         3: dup           
         4: aload_0       
         5: invokespecial #39                 // Method Subclass$Innerclass."<init>":(LSubclass;)V
         8: astore_1      
         9: aload_1       
        10: ldc2_w        #42                 // long 3l
        13: invokestatic  #44                 // Method Subclass$Innerclass.access$0:(LSubclass$Innerclass;J)V
        16: return        
      LineNumberTable:
        line 23: 0
        line 24: 9
        line 25: 16
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
               0      17     0  this   LSubclass;
               9       8     1 innerClass   LSubclass$Innerclass;

  public void accessInnerStaticClassFields();
    Signature: ()V
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=4, args_size=1
         0: new           #51                 // class Subclass$EricLiu
         3: dup           
         4: invokespecial #53                 // Method Subclass$EricLiu."<init>":()V
         7: astore_1      
         8: aload_1       
         9: invokestatic  #54                 // Method Subclass$EricLiu.access$0:(LSubclass$EricLiu;)J
        12: lstore_2      
        13: return        
      LineNumberTable:
        line 36: 0
        line 37: 8
        line 38: 13
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
               0      14     0  this   LSubclass;
               8       6     1  eric   LSubclass$EricLiu;
              13       1     2 copyEricId   J




Apparently the accessInnerClassFields() method has called an method named:
Subclass$Innerclass.access$0

to access the inner class instance's private field.
and the accessInnerStaticClassFields() method calls the method named:
Subclass$EricLiu.access$0

to access the inner static class instance's private field. So what are these access$0 methods?


Now let's take a look at the bytecode of the inner classes.
We found that the compiler has automatically created a static method inside of both inner classes for the outer class to access the fields. No matter the inner class is a static class or non-static.

Notice at bytecode level, static methods can access non-static fields

 static void access$0(Subclass$Innerclass, long);
    Signature: (LSubclass$Innerclass;J)V
    flags: ACC_STATIC, ACC_SYNTHETIC
    Code:
      stack=3, locals=3, args_size=2
         0: aload_0       
         1: lload_1       
         2: putfield      #19                 // Field innerClassId:J
         5: return        
      LineNumberTable:
        line 28: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature


static long access$0(Subclass$EricLiu);
    Signature: (LSubclass$EricLiu;)J
    flags: ACC_STATIC, ACC_SYNTHETIC
    Code:
      stack=2, locals=1, args_size=1
         0: aload_0       
         1: getfield      #14                 // Field ericId:J
         4: lreturn       
      LineNumberTable:
        line 35: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature

That is the reason why outer class can access inner class instances' private fields.




Thursday, June 11, 2015

Never call setRetainInstance(true) for a Fragment backed by Loaders

Never call setRetainInstance(true) when there is a List inside the Fragment which is backed by a Loader.

Loaders handle configuration changes itself, it will conflict with the saved Fragment instances.

I have run into the following errors a couple of times. By putting breakpoints inside the Android FragmentManager class, I've figured out that it is caused by Loaders calling onLoadFinished(..) while the reference to the Activity is null.

I don't have time to look into the FragmentManager class to figure out what the exact reason is that the mActivity is null right now so I just point it out. Will look into it in the future.


Process: com.ericliudeveloper.sharedbillhelper, PID: 11784 java.lang.NullPointerException at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:950) at android.app.FragmentManagerImpl.performPendingDeferredStart(FragmentManager.java:785) at android.app.FragmentManagerImpl.startPendingDeferredFragments(FragmentManager.java:1086) at android.app.LoaderManagerImpl$LoaderInfo.onLoadComplete(LoaderManager.java:469) at android.content.Loader.deliverResult(Loader.java:144) at android.content.CursorLoader.deliverResult(CursorLoader.java:110) at android.content.CursorLoader.deliverResult(CursorLoader.java:43) at android.content.AsyncTaskLoader.dispatchOnLoadComplete(AsyncTaskLoader.java:265) at android.content.AsyncTaskLoader$LoadTask.onPostExecute(AsyncTaskLoader.java:92) at android.os.AsyncTask.finish(AsyncTask.java:632) at android.os.AsyncTask.access$600(AsyncTask.java:177) at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:645) at android.os.Handler.dispatchMessage(Handler.java:102) at android.os.Looper.loop(Looper.java:146) at android.app.ActivityThread.main(ActivityThread.java:5748) at java.lang.reflect.Method.invokeNative(Native Method) at java.lang.reflect.Method.invoke(Method.java:515) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1291) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1107) at dalvik.system.NativeStart.main(Native Method)

Saturday, June 6, 2015

UnsupportedOperationException when testing Android ContentProvider

I was using ProviderTestCase2 to test my ContentProvider in an Android Application but always getting the UnsupportedOperationException when I tried to do any CRUD operation with my
MockContentResolver, the error message is as follow:


java.lang.UnsupportedOperationException
at android.test.mock.MockContext.openOrCreateDatabase(MockContext.java:222)
at android.database.sqlite.SQLiteOpenHelper.getDatabaseLocked(SQLiteOpenHelper.java:223)
at android.database.sqlite.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java:163)

Eventually I figured out it's all because of this line in my onCreate method of my Provider:

dbHelper = new BillDatabaseHelper(getContext().getApplicationContext());

Because the Context I gave to the Provider is the Application Context so during a test, it's looking for the Application Context instead of the MockContext that is given by the system during testing.

After changing my onCreate method of the Provider to the following, everything works like a charm.

@Overridepublic boolean onCreate() {
   dbHelper = new BillDatabaseHelper(getContext());   return (dbHelper == null) ? false : true;}

Thursday, June 4, 2015

Fixing the Toolbar or Actionbar being overlapped by the Android System Status bar problem.


When I was trying out the new Design Support Library (compile 'com.android.support:design:22.2.0')
and using the Toolbar to replace the Actionbar.

A problem occurs on Android 5.0 devices where the Toolbar goes under the system Status Bar and leaves a empty space on top of the main layout as the following picture shows.


To fix this, we add an attribute to the Layout of this activity:
android:fitsSystemWindows="true"

This attribute is boolean internal attribute to adjust view layout based on system windows such as the status bar. If true, adjusts the padding of this view to leave space for the system windows. Will only take effect if this view is in a non-embedded activity.

The fitsSystemWindows attribute makes your Layout View fit to the edges of the action bar and navigation bar (instead of going under them).

Then the problem is fixed and the display is exactly what we want it to be.


Tuesday, June 2, 2015

Android selector important fact

Note: Remember that Android applies the first item in the state list that matches the current state of the object. So, if the first item in the list contains none of the state attributes above, then it is applied every time, which is why your default value should always be last.



The following snippet will never show the checked state because when the system compares the state against the first item, it always matches as there is no specific state of it.



<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android" android:enterFadeDuration="@android:integer/config_shortAnimTime">


    <item>
        <bitmap android:src="@android:drawable/ic_input_add" />
    </item>


    <item android:state_checked="true">
        <bitmap android:src="@android:drawable/star_big_on" />
    </item>


</selector>

Change the order of items and it works.

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android"
    android:enterFadeDuration="@android:integer/config_shortAnimTime"
    >


    <item android:state_checked="true">
        <bitmap android:src="@android:drawable/star_big_on"/>
    </item>

    <item>
        <bitmap android:src="@android:drawable/ic_input_add"/>
    </item>



</selector>