Search

Thursday, July 21, 2011

Adding a button to rate your app in the Market

When you publish an application on the Market is usually a great idea to encourge your users to rate it.

The percentage of users who rate applications is usually very low, so putting a button to facilitate the work is one of the best strategies to get a lot of rates.

And it's very simple, basically you must launch an Intent with a url to the market, and it does all the work alone.

public void rate(View view) {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse("market://details?id=com.trackeen.sea"));
startActivity(intent);
}

Obviously you must change the name for the package, to yours.

And for the button you must include something like this in the view:



And that's all.

Note: If you test launching the market in the Android emulator you will get the following error:



ERROR/AndroidRuntime(230): Caused by: android.content.ActivityNotFoundException: No Activity found to handle Intent { act=android.intent.action.VIEW dat=market://details?id=com.trackeen.sea }

Don't worry, the Market doesn't work in emulators, when you try this code in a real device it will work.

Saturday, July 16, 2011

Canceling an AsyncTask using the back button

After the last post about AsyncTask, there is a pending task to complete the example. A task running in background must be canceled if the user demand it. Thus, this is a good practice promoted by Google. Applications must be responsives. As well as canceling a task, we are going to learn how to capture the back button. AsyncTask will be canceled when back button is pressed by the user.

For capturing back button since Android 2.0 (Api level 5), Google has implemented a new method in Activity class which must be overridden. This method is onBackPressed(). In earlier versions, back button is captured with method onKeyDown() and is identified checking if key received as parameter is KeyEvent.KEYCODE_BACK.

So, in ProgressBarExampleActivity class from the last post we need two changes:
  • Add onBackPressed() method.
  • Set ProgressBarAsyncTask class as member of the class to be cancelled from onBackPressed() method.

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ProgressBar;

public class ProgressBarExampleActivity extends Activity {
 
   private static final String LOG_TAG = "PB_EXAMPLE";
   private EditText etNumSecondsM;
   private EditText etSecondsProgressedM;
 
   private Button bExitM;
   private Button bExecuteM;
   private ProgressBar pbDefaultM;
   private ProgressBarAsyncTask pbTaskM = null;
 
   /** Called when the activity is first created. */
   @Override
   public void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.main);
      drawGUI();
   }

   /** Called when user press the back button */
   @Override
   public void onBackPressed()
   {
      Log.d(LOG_TAG, "Cancelling task");

      if( pbTaskM != null)
      {
         pbTaskM.cancel( false);
      }
   }
 
   public void drawGUI()
   {
      Log.d(LOG_TAG, "Creating Graphic Interface");
      setContentView(R.layout.main);
        
      //Text Editors
      etNumSecondsM = (EditText) findViewById(R.id.etNumSeconds);
      etSecondsProgressedM = (EditText) findViewById( R.id.etSecondProgressed);
        
      //Buttons
      bExecuteM = (Button) findViewById(R.id.bExecute); 
      bExitM = (Button) findViewById(R.id.bExit);
        
      //Progress Bar
      pbDefaultM = (ProgressBar) findViewById( R.id.pbDefault);    
        
      // When the execution button is pressed, the AsyncTask is created and
      // executed.
      bExecuteM.setOnClickListener(new View.OnClickListener() {
            public void onClick(View view) {
               pbTaskM = new ProgressBarAsyncTask( pbDefaultM, etSecondsProgressedM);
               pbTaskM.execute( new Integer( etNumSecondsM.getText().toString()));
            }
      });

      bExitM.setOnClickListener(new View.OnClickListener() {
         public void onClick(View view) {
             exit( RESULT_OK);
         }
      });  
    }
    
    public void exit( int theResult)
    {
       setResult( theResult);
       finish();
    }
}

In the ProgressBarAsyncTask class we have to do next things:

  • Override onCancelled() method for resetting controls as we did in onPostExecute() method, because it will not be called after the cancellation.
  • In doInBackground() method call to isCancelled() method at the end of every iteration, to check if the task has been canceled and exit the loop.

import android.os.AsyncTask;
import android.util.Log;
import android.view.View;
import android.widget.EditText;
import android.widget.ProgressBar;

/**
 * ProgressBarAsyncTask extends from AsyncTask class. It is a template that 
 * is defined as follows:
 * 
 *      AsyncTask< InitialTaskParamsType, ProgressType, ResultTaskType>      
 *      
 */
public class ProgressBarAsyncTask extends AsyncTask {

   private static final String LOG_TAG = "PB_ASYNC_TASK";
   private ProgressBar pbM;
   private EditText teSecondsProgressedM;
   
   /**
    * The parameters in the constructor of the class are the controls from the
    * main activity that we will update as the background work is progressing.
    *  
    * @param pb: the progress bar control.
    * @param secondProgressed: an edit text with the percentage of seconds 
    *                          progressed.
    */
    public ProgressBarAsyncTask(ProgressBar pb, EditText secondProgressed) {
      Log.d(LOG_TAG, "Constructor");
  
      pbM = pb;
      teSecondsProgressedM = secondProgressed;
    }

    /**
     * This method will be called before the execution of the task. Here we 
     * are activating the visibility of the progress controls of the main
     * activity.
     */
    @Override
    protected void onPreExecute() {
      Log.d(LOG_TAG, "Pre-Execute");

      super.onPreExecute();
      pbM.setVisibility( View.VISIBLE);
      teSecondsProgressedM.setVisibility( View.VISIBLE);
    }

    /**
     * This method will be called after the invocation of the 
     * publishProgress( progress) method in the background task. Here is where
     * we update the progress controls.
     * 
     * @param progress: the amount of progress of the background task
     */
    @Override
    protected void onProgressUpdate(Integer... progress) {
      Log.d(LOG_TAG, "Progress Update: " + progress[0].toString());

      super.onProgressUpdate( progress[0]);  
      pbM.setProgress( progress[0]);
      teSecondsProgressedM.setText( progress[0].toString());
    }
 
    /**
     * This method is called after the execution of the background task. Here
     * we reset the progress controls and set their visible property to 
     * invisible again, to hide them.
     * 
     * @param result: is the result of the background task, and it is passed to
     *                this method with de result returned in the 
     *                doInBackGroundMethod()
     */
    @Override
    protected void onPostExecute(Boolean result) {
       Log.d(LOG_TAG, "Post-Execute: " + result);
  
       super.onPostUpdate( result);
       pbM.setVisibility( View.INVISIBLE);
       teSecondsProgressedM.setVisibility( View.INVISIBLE);
       teSecondsProgressedM.setText("");
       pbM.setProgress(0);
    }

    /**
     * This method is called when the AsyncTask is canceled. When this method
     * is called, controls are reset to be used again. 
     */
    @Override
    protected void onCancelled(){
      Log.d(LOG_TAG, "onCancelled");
     
      super.onCancelled();   
      pbM.setVisibility( View.INVISIBLE);
      teSecondsProgressedM.setVisibility( View.INVISIBLE);
      teSecondsProgressedM.setText("");
      pbM.setProgress(0);
    }

    /**
     * This method is called for executing the background task in the AsyncTask.
     * For this tutorial we are only sleeping the thread for the number of 
     * seconds passed as parameter of the function.
     * 
     * @param numSeconds: life of the task
     * @return the result of the background task
     */
    @Override
    protected Boolean doInBackground(Integer... numSeconds) {
      Log.d(LOG_TAG, "doInBackground: " + numSeconds[0]);
  
      try {  
        int totalSecs = numSeconds[0].intValue();
        Log.d(LOG_TAG, "Total SECS: " + totalSecs);
   
        for (int i = 1; i <= totalSecs; i++) {
           Log.d(LOG_TAG, "Sleeping " + i);
           Thread.sleep(1000);
    
           float percentage = ((float)i / (float)totalSecs) * 100;
           Log.d(LOG_TAG, "Percentage of progress: " + percentage);
    
           publishProgress( new Float( percentage).intValue());
           if( isCancelled())
           {
              Log.d(LOG_TAG, "doInBackGround. Task cancelled");
              return false;
           }
        }  
      } catch (InterruptedException e) {
          e.printStackTrace();
          return false;
      }

      return true;
   }
}

Thursday, June 16, 2011

Basic AsyncTask with a progress bar widget

After a few days far from this coding corner, today I'm going to show you an example with one important tool for executing tasks in background with Android. In earlier versions of Android, background execution of task was made managing threads and handlers, as you can see in this example. It was not difficult, but threads are always a thorny issue. Google has simplified this mechanism by means of AsyncTask class.

In this AsyncTask tutorial I have implemented a progress bar widget in the main activity. You can set the number of seconds the task will take. It's a very simple example. Let's go!!!!

First we will define the progress bar in the main.xml file, setting it as invisible in the visibility property:

<ProgressBar
    android:id="@+id/pbDefault"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    style="@android:style/Widget.ProgressBar.Horizontal"
    android:visibility="invisible"
 />

After that, we will define ProgressBarAsyncTask, which will be in charge of doing a background work and update its progress in the progress bar widget. Methods are explained with comments over the code:

import android.os.AsyncTask;
import android.util.Log;
import android.view.View;
import android.widget.EditText;
import android.widget.ProgressBar;

/**
 * ProgressBarAsyncTask extends from AsyncTask class. It is a template that 
 * is defined as follows:
 * 
 *      AsyncTask< InitialTaskParamsType, ProgressType, ResultTaskType>      
 *      
 */
public class ProgressBarAsyncTask extends AsyncTask {

   private static final String LOG_TAG = "PB_ASYNC_TASK";
   private ProgressBar pbM;
   private EditText teSecondsProgressedM;
   
   /**
    * The parameters in the constructor of the class are the controls from the
    * main activity that we will update as the background work is progressing.
    *  
    * @param pb: the progress bar control.
    * @param secondProgressed: an edit text with the percentage of seconds 
    *                          progressed.
    */
    public ProgressBarAsyncTask(ProgressBar pb, EditText secondProgressed) {
      Log.d(LOG_TAG, "Constructor");
  
      pbM = pb;
      teSecondsProgressedM = secondProgressed;
    }

    /**
     * This method will be called before the execution of the task. Here we 
     * are activating the visibility of the progress controls of the main
     * activity.
     */
    @Override
    protected void onPreExecute() {
      Log.d(LOG_TAG, "Pre-Execute");

      super.onPreExecute();
      pbM.setVisibility( View.VISIBLE);
      teSecondsProgressedM.setVisibility( View.VISIBLE);
    }

    /**
     * This method will be called after the invocation of the 
     * publishProgress( progress) method in the background task. Here is where
     * we update the progress controls.
     * 
     * @param progress: the amount of progress of the background task
     */
    @Override
    protected void onProgressUpdate(Integer... progress) {
      Log.d(LOG_TAG, "Progress Update: " + progress[0].toString());

      super.onProgressUpdate( progress[0]);  
      pbM.setProgress( progress[0]);
      teSecondsProgressedM.setText( progress[0].toString());
    }
 
    /**
     * This method is called after the execution of the background task. Here
     * we reset the progress controls and set their visible property to 
     * invisible again, to hide them.
     * 
     * @param result: is the result of the background task, and it is passed to
     *                this method with de result returned in the 
     *                doInBackGroundMethod()
     */
    @Override
    protected void onPostExecute(Boolean result) {
       Log.d(LOG_TAG, "Post-Execute: " + result);
  
       super.onPostUpdate( result);
       pbM.setVisibility( View.INVISIBLE);
       teSecondsProgressedM.setVisibility( View.INVISIBLE);
       teSecondsProgressedM.setText("");
       pbM.setProgress(0);
    }

    /**
     * This method is called for executing the background task in the AsyncTask.
     * For this tutorial we are only sleeping the thread for the number of 
     * seconds passed as parameter of the function.
     * 
     * @param numSeconds: life of the task
     * @return the result of the background task
     */
    @Override
    protected Boolean doInBackground(Integer... numSeconds) {
      Log.d(LOG_TAG, "doInBackground: " + numSeconds[0]);
  
      try {  
        int totalSecs = numSeconds[0].intValue();
        Log.d(LOG_TAG, "Total SECS: " + totalSecs);
   
        for (int i = 1; i <= totalSecs; i++) {
           Log.d(LOG_TAG, "Sleeping " + i);
           Thread.sleep(1000);
    
           float percentage = ((float)i / (float)totalSecs) * 100;
           Log.d(LOG_TAG, "Percentage of progress: " + percentage);
    
           publishProgress( new Float( percentage).intValue());
        }  
      } catch (InterruptedException e) {
          e.printStackTrace();
          return false;
      }

      return true;
   }
}
Now its the time for implementing the main activity:
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ProgressBar;

public class ProgressBarExampleActivity extends Activity {
 
   private static final String LOG_TAG = "PB_EXAMPLE";
   private EditText etNumSecondsM;
   private EditText etSecondsProgressedM;
 
   private Button bExitM;
   private Button bExecuteM;
   private ProgressBar pbDefaultM;
    
   /** Called when the activity is first created. */
   @Override
   public void onCreate(Bundle savedInstanceState) {
     super.onCreate(savedInstanceState);
     setContentView(R.layout.main);
     drawGUI();
   }
    
   public void drawGUI()
   {
      Log.d(LOG_TAG, "Creating Graphic Interface");
      setContentView(R.layout.main);
        
      //Text Editors
      etNumSecondsM = (EditText) findViewById(R.id.etNumSeconds);
      etSecondsProgressedM = (EditText) findViewById( R.id.etSecondProgressed);
        
      //Buttons
      bExecuteM = (Button) findViewById(R.id.bExecute); 
      bExitM = (Button) findViewById(R.id.bExit);
        
      //Progress Bar
      pbDefaultM = (ProgressBar) findViewById( R.id.pbDefault);    
        
      // When the execution button is pressed, the AsyncTask is created and
      // executed.
      bExecuteM.setOnClickListener(new View.OnClickListener() {
         public void onClick(View view) {
            ProgressBarAsyncTask pbTask = new ProgressBarAsyncTask( pbDefaultM,
                                                                    etSecondsProgressedM);
            pbTask.execute( new Integer( etNumSecondsM.getText().toString()));
         }
      });

      bExitM.setOnClickListener(new View.OnClickListener() {
         public void onClick(View view) {
             exit( RESULT_OK);
         }
      });  
    }
    
    public void exit( int theResult)
    {
       setResult( theResult);
       finish();
    }
}
Here the clue is the creation of the ProgressBarAsyncTask and its execution with execute() method, when the "Show Progress Bar" button is pressed. I hope this example is interesting for you. I will return soon with a tutorial for canceling the AsyncTask. See you soon.

Coding for Android is available for mobile devices

Google has implemented a new feature in blogspot. Now when you see http://www.codingforandroid.com in your mobile device, you will see a new template lighter than the original one. A great feature for our bandwith.

Sunday, April 17, 2011

Bad practices coding for Android

In the last post I talked about the good practices to follow by an android beginner. Now I'm going to summarize the bad practices collected from Android Dev Helper 2010. This are common mistakes we must avoid always when coding for Android. Google talks of them as "The five deadly sins":

About Sloth:

To avoid sloth we should be fast and responsive. The clues to be fast are the next:
  • Avoid creating objects (minimize it)
  • Use native methods
  • Virtual is better than interface
  • Static is better than virtual
  • Avoid internal getters an setters
  • Declare constants final
  • Avoid float an enums
  • Use package scope with inner classes

The clues for responsiveness are:
  • Avoid modal Dialogues and Activities, informing always the user with the progress and rendering and filling the data as it arrives
  • Respond to the user input within 5 seconds and Broadcast Receiver must complete in 10 seconds
  • Users perceive a lag longer than 100 to 200ms
  • Use Threads and AsyncTask within Services

About Gluttony:

We must use system resources responsabily:
  • Don't over use WakeLocks
  • Don't update Widgets too frequently
  • Don't update your location unnecessarily
  • Don't use Services to try to override users or the system
  • Do share data to minimize duplication
  • Do use Receivers and Alarms not Services and Threads
  • Do let users manage updates
  • Do minimize resource contention

For using Wakelocks correctly:
  • Do you really need to use one?
  • Use the minimum level possible
  • Release as soon as you can
  • Specify a timeout
  • Don't use them in Activities

About Hostility:

Avoid fight with your users. User experience should be your top priority and you should respect user expectations for navigating your app, avoiding hijack the native experience and respecting the user preferences:
  • The back button should always navigate back through previously seen screens
  • Always support trackball navigation
  • Understand your navigation flow when entry point is a notification or a widget
  • Navigating between application elements should be easy and intuitive
  • Don't hide the status bar
  • Use native icons consistently
  • Put menu options behind the menu button
  • Use only enabled location-based services
  • Ask permission before transmitting location data
  • Only transfer data in the background if user enabled

About Arrogance:
  • Avoid fight the system. Take it as it is.
  • Don't use undocumented APIs
  • Make your app behave consistently with the system
  • Respect the application lifecycle model

About Discrimination:

Since there are many devices and many SO versions, you should design and code for everyone.
  • Don't make assumptions about screen size or resolution
  • Never hard-code string values in code (or XML)
  • Use Relative Layouts and device independent pixels
  • Optimize assets for different screen resolutions
  • Use reflection to determine what APIs are available
  • Store values as Resources (colors, dimensions, arrays, images, layouts)

Sunday, February 27, 2011

Good practices for an Android beginner

When I begin to learn some new programming language or framework, I used to search for the good and bad practices I should take into account. In this old post (http://www.codingforandroid.com/2010/12/help-for-developers.html) I recommended you the Google Application Android Dev Helper 2010. In this app, the first entry in Android section is a little guide for beginners, with good an bad practices for Android developers. Here you have a little summary of the good practices:

About beauty:

About generosity:

About ubiquity:

About utility & entertaiment
  • Create an app that solves a problem
  • Present information in the most useful way possible
  • Create games that are ground breaking and compelling

About Epicness
  • Don't be satisfied with good
  • Create unique solutions
  • Invent new paradigms
  • Leverage the hardware

I hope this is of your interest.

Wednesday, February 23, 2011

Protect your code

A short tip to finish the day. Do you know that when you publish your Android Application it's so easy to download and decompile it?. So everyone can use your code or even modify it to break your copy protection or any thing else.

So it is very recommended to compress and obfuscate your code. It is very easy, simply add the following line in your /default.properties file:


proguard.config=proguard.cfg

And if you use the Eclipse option Export Signed Application Package create by hand the /proguard directory.

The only precaution is to add the following line in proguard.cfg for every class you don't want to be obfuscate:


-keep public class 

Why don't obfuscate? Very easy, if the class must be accessed dynamically in runtime you cannot obfuscate it, otherwise you'll get an Classnofound error.

I hope this trick will be useful for you.