Sunday, 14 June 2015

Using Shared Preferences in your Android Application

Shared Preferences

Shared preferences are like sessions (if you can relate to sessions running in your browser). For eg. when you are shopping on a site like Amazon or Flipkart you don't have to login to browse each item, do you? That's because you are in a session and the session data is stored in cookies in your browser. It will get invalidated when you logout or when the time expires. Shared preferences in Android are something like that. You can save or persist your settings across activities when user navigates across them. One major difference from sessions though is that sessions expire where as shared preference is a persistence storage. We will shortly see the code for it.

NOTE : Shared preference is a persistence storage.

When to use shared preferences?

If you have a relatively small collection of key-values that you'd like to save, you should use the SharedPreferences APIs. A SharedPreferences object points to a file containing key-value pairs and provides simple methods to read and write them. Each SharedPreferences file is managed by the framework and can be private or shared. (Source)

Goal

Lets set our goal first before we begin to write code. We are going to store setting in shared preference which will be used to play music or sound. So User can choose whether he wants to listen to the music or not.

Getting Started with using PreferenceActivity

Lets write our own class that extends PreferenceActivity

public class MyPreferenceActivity extends PreferenceActivity {
    
    private static final String OPT_MUSIC = "music";
    private static final Boolean OPT_SOUND_DEF = true; //default value of the setting

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        addPreferencesFromResource(R.xml.settings);
    }
    
    public static boolean getSound(Context context) {
        return PreferenceManager.getDefaultSharedPreferences(context).getBoolean(OPT_MUSIC, OPT_SOUND_DEF);
    }
}

Note : Notice the getSound() method that returns the boolean ? We will use that to see what setting is currently set. Also note it is static so we can directly call it using the class name. Note the use of PreferenceManager here and how we supply the default value (true in this case).

Loading Settings


As you can see above piece of code gets settings from an xml file named "settings". Inside folder res/xml  create a file named settings.xml and populate it with following content - 

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

    <CheckBoxPreference
        android:defaultValue="true"
        android:key="sound"
        android:summary="@string/music_setting_summary"
        android:title="@string/music_setting_title" />

</PreferenceScreen>

In above xml I am showing a simple check box preference. It will be as simple as user checking and unchecking the checkbox to enable/disable music.

Displaying Settings

Now that we have coded for the music setting lets create a workflow to show it to the user. You can put in anywhere. For simplicity I am assuming it is one of the options in the options menu. Lets call it Settings (see 3rd option in below screenshot).



Now on click of it we should open the shared preference intent that we have created above. Code to do that is as follows - 

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch(item.getItemId()) {
        case R.id.settings:
            Log.i(TAG, "Showing Preference Activity");
            startActivity(new Intent(this, MyPreferenceActivity .class));
            break;
        }
        return true;
    } 

Now on click you should see another activity with a checkbox to enable/disable sound/music (Like below).






Obeying the Setting

That's the code to create and display the setting but we also need to obey our music playing logic according to this setting. So lets go ahead and see how that works.



        if(MyPreferenceActivity .getSound(context)) {
            try {
                final ToneGenerator tg = new ToneGenerator(
                        AudioManager.STREAM_NOTIFICATION, 100);
                tg.startTone(ToneGenerator.TONE_PROP_BEEP);
            } catch (Exception ex) {
                Log.e(TAG, "Could not play notification sound", ex);
            }
        }

What above code does is very simply. Get the sound setting and if it is enabled then play a beep tone else don't. You can easily inject this code in some View's onclicklistener.

Last but not the least

Lastly don't forget to list your preference activity in your applications manifest file :)

        <activity
            android:name=".MyPreferenceActivity "
            android:label="@string/title_activity_prefs" >
        </activity> 


Using shared preferences without PreferenceActivity

Yes you can simply use shared preferences without Preference activity as well. Refer to following syntax.

Setting value in Preference : 

SharedPreferences.Editor editor = getSharedPreferences(PREFERENCE_NAME, MODE_PRIVATE).edit();

editor.putBoolean("music", true);

editor.putString("someStringSetting", "StringSettingValue");

editor.putInt("someIntSetting", 1);

editor.commit();

Retrieving Value from preference :

SharedPreferences prefs = getSharedPreferences(PREFERENCE_NAME, MODE_PRIVATE); 

boolean musicPref = prefs.getBoolean("music", true);

String stringSetting = prefs.getString("someStringSetting", "StringSettingFefaultValue");

String intSetting = prefs.getString("someIntSetting", 1);


NOTE : You can only store primitive type of data like String, integer, boolean etc. You cannot store your custom Objects. To Store your object instances you can convert them in json string (serialize) and then store it. While retrieving convert json string to your object (deserialize) and use it.

Related Links

Saturday, 23 May 2015

Knowing gradle dependency jars download location and copying them to custom location

Background

Whenever you need any dependency in your gradle script, gradle will download it it's cache and use it. By default you should see this cache in .gradle folder under your user directory.

For me it is
  • C:\Users\athakur\.gradle\caches
In this post I will show
  1. how to pinpoint exact location of the downloaded dependency jars and
  2. how to copy these jars to some custom directory you might want the dependencies in
using simple gradle scripts.


Gradle script to show downloaded jars location

Note : Whenever you execute some gradle task using gradle taskName then gradle will by default try finding the task in a file named build.gradle in current directory. 

Put the following code in build.gradle file - 


apply plugin: 'java'

repositories{
  mavenCentral()
}

dependencies{
  compile 'com.google.guava:guava:12.0'
}

task showMeCache << {
  configurations.compile.each { println it }
}

and run the following command
  • gradle showMeCache
You should see the downloaded jar location printed on console. For me it shows as in following screenshot


 Now let's see how we can copy these jar's into some custom directory of your choice.

Gradle script to copy downloaded jars to custom location

 Again append the following code to build.gradle file we created while printing the downloaded jar files location.

task copyDepJars(type: Copy) {
  from configurations.compile
  into 'C:\\Users\\athakur\\Desktop\\lib'
}


Now run following command
  • gradle copyDepJars
All dependent jars should be downloaded to the directory you have specified in "into" attribute of task copyDepJars .


To know more about copy task in gradle refer - Copy - Gradle DSL Version 2.4


Related Links

How to add autocomplete to EditText in Android - AutoCompleteTextView

Background

Everyone must have used EditText to allow use input some text. Ever wondered if such a basic functionality could support autocomplete? Of course it would, it is one of the basic use cases. We will see how to implement it in this post.

AutoCompleteTextView

AutoCompleteTextView is a direct subclass of EditText. We can use this to achieve auto complete feature in Android.

Let's start with the layout. I am going to keep it fairly simple. Just a label denoting what the following text field is for. In this case it would be list of countries. So we are going to provide auto complete for list of countries.

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="${relativePackage}.${activityClass}" >

    <TextView
        android:id="@+id/labelId"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:paddingTop="10dp"
        android:text="@string/autocomplete_label"/>
    
    <AutoCompleteTextView 
        android:id="@+id/autocompleteId"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_below="@id/labelId"/>

</RelativeLayout>

Layout would look something like


 Before we proceed to the Java code/Activity lets quickly define list of countries as string array in string resource file.

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <string name="app_name">AutocompleteDemo</string>
    <string name="title_activity_main">Auto Complete Demo</string>
    <string name="autocomplete_label">List of Countries</string>

    <string-array name="list_of_countries">
        <item>India</item>
        <item>USA</item>
        <item>China</item>
        <item>Canada</item>
        <item>Germany</item>
        <item>France</item>
        <item>Spain</item>
        <item>Japan</item>
    </string-array>

</resources>

Have listed some random country name. That should suffice for this demo. Now lets code the Activity class.

package com.osfg.autocompletedemo;

import android.app.Activity;
import android.os.Bundle;
import android.widget.ArrayAdapter;
import android.widget.AutoCompleteTextView;

/**
 * @author athakur
 */
public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
       
        AutoCompleteTextView acTextView = (AutoCompleteTextView) findViewById(R.id.autocompleteId);
        String[] countriesList = getResources().getStringArray(R.array.list_of_countries);
        ArrayAdapter countryAdapter = new ArrayAdapter(this,android.R.layout.simple_list_item_1,countriesList);
        acTextView.setAdapter(countryAdapter);
    }
}   

And that is it. You should be able to see auto complete now.




Related Links

Sunday, 17 May 2015

Blinking text animation in Android

Background

In last post we saw how to do a simple animation of bouncing ball. In this we will see how to make a text blink using ObjectAnimator. We will make text - "Hello World!" start and stop blinking using buttons.

Creating the Layout

 Create layout file - blinking_text_layout.xml and add following content in it.


<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <Button
        android:id="@+id/startBlinkTextButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:text="Start Blinking Text" />

    <Button
        android:id="@+id/stopBlinkTextButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@id/startBlinkTextButton"
        android:layout_centerHorizontal="true"
        android:text="Stop Blinking Text" />

    <TextView
        android:id="@+id/blinkTextView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@id/stopBlinkTextButton"
        android:layout_centerHorizontal="true"
        android:paddingTop="10dp"
        android:text="Hello World!"
        android:textSize="40sp" />

</RelativeLayout>

The layout should get rendered on your phone as follows -



Now lets write code to animate this text.

Animate Blinking of Text

As you can see from the layout we have two buttons - one to start the blinking animation and other to stop it. Code is as follows - 


package com.osfg.animationdemo;

import android.animation.ArgbEvaluator;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.app.Activity;
import android.graphics.Color;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;

public class AnimationStarter extends Activity {

    private static final String TAG = "AnimationStarter";
    ObjectAnimator textColorAnim;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.blinking_text_layout);

        Button startBlinkTextButton = (Button) findViewById(R.id.startBlinkTextButton);
        Button stopBlinkTextButton = (Button) findViewById(R.id.stopBlinkTextButton);
        final TextView blinkText = (TextView) findViewById(R.id.blinkTextView);

        startBlinkTextButton.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                textColorAnim = ObjectAnimator.ofInt(blinkText, "textColor", Color.BLACK, Color.TRANSPARENT); 
                textColorAnim.setDuration(1000); 
                textColorAnim.setEvaluator(new ArgbEvaluator());     
                textColorAnim.setRepeatCount(ValueAnimator.INFINITE); 
                textColorAnim.setRepeatMode(ValueAnimator.REVERSE); 
                textColorAnim.start();
            }
        });
        
        stopBlinkTextButton.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                if(textColorAnim != null) {
                    textColorAnim.cancel();
                    blinkText.setTextColor(Color.BLACK);
                }
            }
        });

    }

}


Notice on "Stop Blinking Text" button press we are simply cancelling the current animation and setting the color back to black as the transparency of the text can be different as per the state in which the blinking animation was cancelled.

Note :
  • clearAnimation() method of View will have no effect on ObjectAnimator.
  • If you call start() on your ObjectAnimator instance n times then you will have to call cancel() n times for animation to completely stop.

 You can try out the code. Recorded video is as follows - 



Related Links

Creating bouncing ball Animation in Android

Background

In this post I am going to show a very simple animation - Bouncing a ball. As much as Animations are very cool to look at, they are tricky and must be handled carefully.

Animation coding Tip : Just a tip here. Animations are generally started in onResume() method and stopped in onPause() method. You should not do it in onCreate() and onDestroy() methods as these methods are not guaranteed to be invoked every time.


Creating the Layouts

Lets create layouts that we will need to create a animated bouncing ball. To start with lets first create our ball.

For this I am going to create an oval shape in android. This will be in ball_shape.xml file under drawable folder. Contents of it are - 

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="oval" >

    <solid android:color="#8c0000" />

    <stroke
        android:width="2dp"
        android:color="#fff" />
    
    <size
        android:height="80dp"
        android:width="80dp" />

</shape>

This is a simple circular shape with red color fill. We will use this as our ball. Now lets go ahead and create our actual layout with a button to animate this ball and of course the ball itself.

Put following content inside animation_layout.xml file under layout folder.

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <Button
        android:id="@+id/bounceBallButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:text="Bounce Ball" />

    <ImageView
        android:id="@+id/bounceBallImage"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_below="@id/bounceBallButton"
        android:background="@drawable/ball_shape" />

</RelativeLayout>


As you can see we have a button and a ball (essentially ImageView with background set as oval shape) below it. Let's animate this now with our code. Layout will looks as follows -



Animating Bouncing Ball

To animate the ball we fill first set the layout of the Activity with the layout xml we have just created. Then we will get reference to our Button and ball and when user click on the button we will animate the ball so that it appears like bouncing.

Here is the code for it.

package com.osfg.animationdemo;

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.animation.Animation;
import android.view.animation.BounceInterpolator;
import android.view.animation.TranslateAnimation;
import android.view.animation.Animation.AnimationListener;
import android.widget.Button;
import android.widget.ImageView;

public class AnimationStarter extends Activity {

    private static final String TAG = "AnimationStarter";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.animation_layout);

        Button bounceBallButton = (Button) findViewById(R.id.bounceBallButton);
        final ImageView bounceBallImage = (ImageView) findViewById(R.id.bounceBallImage);

        bounceBallButton.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                bounceBallImage.clearAnimation();
                TranslateAnimation transAnim = new TranslateAnimation(0, 0, 0,
                        getDisplayHeight()/2);
                transAnim.setStartOffset(500);
                transAnim.setDuration(3000);
                transAnim.setFillAfter(true);
                transAnim.setInterpolator(new BounceInterpolator());
                transAnim.setAnimationListener(new AnimationListener() {

                    @Override
                    public void onAnimationStart(Animation animation) {
                        Log.i(TAG, "Starting button dropdown animation");

                    }

                    @Override
                    public void onAnimationRepeat(Animation animation) {
                        // TODO Auto-generated method stub

                    }

                    @Override
                    public void onAnimationEnd(Animation animation) {
                        Log.i(TAG,
                                "Ending button dropdown animation. Clearing animation and setting layout");
                        bounceBallImage.clearAnimation();
                        final int left = bounceBallImage.getLeft();
                        final int top = bounceBallImage.getTop();
                        final int right = bounceBallImage.getRight();
                        final int bottom = bounceBallImage.getBottom();
                        bounceBallImage.layout(left, top, right, bottom);

                    }
                });
                bounceBallImage.startAnimation(transAnim);
            }
        });

    }

    private int getDisplayHeight() {
        return this.getResources().getDisplayMetrics().heightPixels;
    }
}


We have simply used Translate Animation with bounce interpolator so that our ball can be viewed as bouncing vertically .You can install and try out this code. You can see the recorded video below -






Related Links


t> UA-39527780-1 back to top