Saturday, December 26, 2015

How to fix httpcomponents library in Android Studio


I had a project in eclipse which uses httpcomponents. The jars used in eclipse did not work in Android studio and I am using compileSdkVersion 23 with buildToolsVersion '23.0.2'. I have tried out several solutions and wasted 3 hours figuring out how import the httpcomponents libraries.

To avoid wasting your time, here is how I fixed the issue:

Changes in Module specific build.gradle i.e. /app/build.gradle Add following under android {...}

useLibrary 'org.apache.http.legacy'
packagingOptions {
 exclude 'META-INF/DEPENDENCIES'
 exclude 'META-INF/NOTICE'
 exclude 'META-INF/LICENSE'
 exclude 'META-INF/LICENSE.txt'
 exclude 'META-INF/NOTICE.txt'
}
Add following under dependencies {..}
compile ('org.apache.httpcomponents:httpmime:4.3'){
 exclude group: 'org.apache.httpcomponents', module: 'httpclient'
}
compile ('org.apache.httpcomponents:httpcore:4.4.1'){
 exclude group: 'org.apache.httpcomponents', module: 'httpclient'
}
compile 'commons-io:commons-io:1.3.2'

In Top level build.gradle - /build.gradle add the following by replacing earlier statement:

buildscript {
    ...
    dependencies {
        classpath 'com.android.tools.build:gradle:1.3.1'
    }
}

Now gradle sync your project and its done.

Friday, November 13, 2015

Configuring Gradle

Android studio uses new build system called Gradle. We can use it to build project and configure server urls, settings or replace assets.
1. Following example shows build.gradle file to change server url depending upon the build flavor.
I am using two flavors
1. devel
2. prod.
For simplicity I shall keep it simple without configuring it for signing. Both flavors define a config variable "HOST" with different value to be used, when apk is built. If developer chooses, to have "devel" build, it will come with "http://192.168.1.34:3000" as HOST.

productFlavors {
        devel {
            buildConfigField 'String', 'HOST', '"http://192.168.1.34:3000"'
        }

        prod {
            buildConfigField 'String', 'HOST', '"http://api.zuul.com"'

        }
    }

To access the config constant use following code.

String string = BuildConfig.HOST;


2. Following example shows how to replace java or asset files depending upon the product flavor.
As mentioned earlier, project uses two flavors namely "devel" and "prod". Our objective is to replace Constants.java and "ic_launcher.png". Each flavor will have different files. Prepare folder structure as shown:

Copy "ic_launcher.png" file in "devel.res.drawable". Put Constants.java file mentioned below in "devel.java.com.poc.gradleconfiguration".


package com.poc.gradleconfiguration;

public class Constants {

    public static String NAME = "This is development.";
}

Copy "ic_launcher.png" file in "prod.res.drawable". Put Constants.java file mentioned below in "prod.java.com.poc.gradleconfiguration".
package com.poc.gradleconfiguration;

public class Constants {

    public static String NAME = "This is prod.";
}
Don't put Constants.java file mentioned below in "main.java.com.poc.gradleconfiguration", as gradle will copy one of the above files here.
To use the constant use the following code.
String name = Constants.NAME;
Now simply select type build you want to make from build variants view and gradle will make sure you have correct copy of the Constants.java.

Tuesday, April 21, 2015

Restoring activity state after changing configuration

Following are the techniques to save data so that activity can resume from where it had destroyed.

1. onSaveInstanceState()
You can save your serializable data in a bundle and android will save this bundle for you. The same bundle will be returned to you on on in onCreate() and onRestoreInstanceState() callback methods. onRestoreInstanceState() is called after onStart(), whereas onCreate() is called before onStart(). These methods are only called when needed, that is when an activity has been destroyed (because of lack of resources) and needs to be recreated by the system. Because the onCreate() method is called whether the system is creating a new instance of your activity or recreating a previous one, you must check whether the state Bundle is null before you attempt to read it. If it is null, then the system is creating a new instance of the activity, instead of restoring a previous one that was destroyed. e.g.
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    // Check whether we're recreating a previously destroyed instance
    if (savedInstanceState != null) {
        // Restore value of members from saved state
        mUser = savedInstanceState.getString("TEXT");
    } else {
        // Probably initialize members with default values for a new instance
        mUser = "NewUser";
    }
}
@Override
protected void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    outState.putString("TEXT", user);
}
2. onRetainNonConfigurationInstance()
The above approach is good for saving serializable things like String, int, custom objects implementing serializable interface, et al. It has can not save objects like Socket. Solution is to override onRetainNonConfigurationInstance. This method was deprecated in API level 13. e.g. declare the following in your activity
 public Object onRetainNonConfigurationInstance() {
   return this;
}

public void onCreate(Bundle savedState)
{
   YourActivity prevActivity = (YourActivity)getLastNonConfigurationInstance();
   if(prevActivity!= null) { 
       // So the orientation did change
       // Restore some field for example
       this.myValue = prevActivity.myValue;
   }
}
3. android:configChanges
Put an android:configChanges entry in our AndroidManifest.xml file, listing the configuration changes we want to handle ourselves without allowing Android to handle for us. Now we can bypass the activity destruction process at any configuration change, and we simply get a callback letting us know of the change. To handle the configuration change implement onConfiguratuionChanged() in activity. However this is a bad practice. Handling configuration changes requires you to take many additional steps to ensure that each and every string, layout, drawable, dimension, etc. remains in sync with the device's current configuration, and if you aren't careful, your application can easily have a whole series of resource-specific bugs as a result.
4. setRetainInstance() for Fragment
Fragments are destroyed and recreated along with their parent Activities when a configuration change occurs. Calling Fragment#setRetainInstance(true) allows us to bypass this destroy-and-recreate cycle, signalling the system to retain the current instance of the fragment when the activity is recreated. This can only be used with fragments not in the back stack.
5. Using onSaveInstanceState in Fragment
In the fragment, save instance state by override onSaveInstanceState and restore on onActivityCreated:
@Override
public void onActivityCreated(Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);
        ...
    if (savedInstanceState != null) {
        //Restore the fragment's state here
    }
}

@Override
public void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    //Save the fragment's state here
}
And important point, in the activity, you have to save fragment's instance on onSaveInstanceState and restore on onCreate.
@Override
public void onCreate(Bundle savedInstanceState) {
        ...
    if (savedInstanceState != null) {
        //Restore the fragment's instance
        mContent = getSupportFragmentManager().getFragment(
            savedInstanceState, "mContent");
            ...
    }
        ...
}

@Override
protected void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);

    //Save the fragment's instance
    getSupportFragmentManager().putFragment(outState, "mContent", mContent);
}
Reference
1. http://stackoverflow.com/questions/4096169/onsaveinstancestate-and-onrestoreinstancestate 2. http://stackoverflow.com/questions/16769654/how-to-use-onsaveinstancestate-and-onrestoreinstancestate 3. http://stackoverflow.com/questions/4285877/which-one-to-use-onsaveinstancestate-vs-onretainnonconfigurationinstance 4. http://www.bogotobogo.com/Android/android15Rotation.php 5. http://www.androiddesignpatterns.com/2013/04/retaining-objects-across-config-changes.html 6. http://stackoverflow.com/questions/15313598/once-for-all-how-to-correctly-save-instance-state-of-fragments-in-back-stack

Saturday, February 14, 2015

Test Android app by installing app wirelessly on device.

I wanted to try out installing the app wirelessly on device. I followed some links given below:
1. http://developer.android.com/tools/help/adb.html
2. http://stackoverflow.com/questions/2604727/how-can-i-connect-to-android-with-adb-over-tcp
3. https://docs.google.com/document/d/1-wMYWpljgHolnVHCsV2VGeMmBcc29Id9rMbHrZoCelE/edit#

All of thes mentioned similar steps however none worked for me. Problem arised when following command was executed.

d:\sdk\platform-tools>adb tcpip 5555
restarting in TCP mode port: 5555


The command seemed to be stuck and did not finish executing. It took 4-6 hours to figure out the correct procedure by trial and error. Here's the correct procedure.
1. Connect your phone to PC.
2. Open command prompt and go to /sdk/platform-tools/ directory.
3. Now type the following command " adb tcpip 5555".
4. Once you see "restarting ..." message, remove device from PC. This will finish execution of above command.

D:\sdkForEclipseDoNotUpdate\sdk\platform-tools>adb tcpip 5555
restarting in TCP mode port: 5555


5. Now simply run the following command where replace "192.168.0.100 " with ip address of your device.

D:\sdkForEclipseDoNotUpdate\sdk\platform-tools>adb connect 192.168.0.100
connected to 192.168.0.100:5555

6. Check the attached devices.

D:\sdkForEclipseDoNotUpdate\sdk\platform-tools>adb devices
List of devices attached
192.168.0.100:5555      device

Android aar deployment in Maven - 2022

Introduction If you are working on android library project, you might be wondering how to publish it on Maven like this . Earl...