Dynamic String Using String.xml?

When I first saw %1$s and %2$d in the accepted answer, it made no sense. Here is a little more explanation.

String format replacement markers in xml are in the form of

%[parameter index]$[format type]

parameter index: If you had three parts of the string that you wanted to replace, then they would be called %1, %2, and %3. The order you place them in the resource string doesn’t matter, only the order that you supply the parameters in String.format.

format type: There are a lot of ways that you can format things (see the documentation). Here are some common ones:
$s string
$d decimal integer
$f floating point number

Escaping characters

Use %% to get the actual % character.

For more details read the following helpful tutorial.

Android SDK Quick Tip: Formatting Resource Strings

Example

Goal

Create the following formatted string where the gray parts can be replaced programmatically.

12 is an int and Hello is a String.

Solution

MyActivity.java

int myInt = 12;
String myString = “Hello”;
String myFormattedString = String.format(getString(R.string.my_xml_resource_string), myInt, myString);

string.xml

%1$d is an int and %2$s is a String.

Reference: https://stackoverflow.com/questions/3656371/dynamic-string-using-string-xml

Android Adapter Tutorial

In Android, Adapter is a bridge between UI component and data source that helps us to fill data in UI component. It holds the data and send the data to an Adapter view then view can takes the data from the adapter view and shows the data on different views like as ListView, GridView, Spinner etc. For more customization in Views we uses the base adapter or custom adapters.

To fill data in a list or a grid we need to implement Adapter. Adapters acts like a bridge between UI component and data source. Here data source is the source from where we get the data and UI components are list or grid items in which we want to display that data.

Below is a conceptual diagram of Adapter:

Adapter in Android

Adapters In Android:

There are the some commonly used Adapter in Android used to fill the data in the UI components.

  1. BaseAdapter – It is parent adapter for all other adapters
  2. ArrayAdapter – It is used whenever we have a list of single items which is backed by an array
  3. Custom ArrayAdapter – It is used whenever we need to display a custom list
  4. SimpleAdapter – It is an easy adapter to map static data to views defined in your XML file
  5. Custom SimpleAdapter – It is used whenever we need to display a customized list and needed to access the child items of the list or grid

Now we describe each Adapters one by one in detail:

1. BaseAdapter In Android:

BaseAdapter is a common base class of a general implementation of an Adapter that can be used in ListView, GridView, Spinner etc. Whenever we need a customized list in a ListView or customized grids in a GridView we create our own adapter and extend base adapter in that. Base Adapter can be extended to create a custom Adapter for displaying a custom list item.  ArrayAdapter is also an implementation of BaseAdapter.

Custom Adapter code which extends the BaseAdapter in that:

public class CustomAdapter extends BaseAdapter {

@Override
public int getCount() {
return 0;
}

@Override
public Object getItem(int i) {
return null;
}

@Override
public long getItemId(int i) {
return 0;
}

@Override
public View getView(int i, View view, ViewGroup viewGroup) {

return null;
}

In above code snippet we see the overrided functions of BaseAdapter which are used to set the data in a list, grid or a spinner. These functions are described in BaseAdapter tutorial with example.

2. ArrayAdapter In Android:

Whenever we have a list of single items which is backed by an Array, we can use ArrayAdapter. For instance, list of phone contacts, countries or names.

Here is how android ArrayAdapter looks ::

ArrayAdapter(Context context, int resource, int textViewResourceId, T[] objects)

The above function are described in ArrayAdapter tutorial with example.

3. Custom ArrayAdapter In Android:

ArrayAdapter is also an implementation of BaseAdapter, so if we want more customization then we can create a custom adapter and extend ArrayAdapter in that. Since array adapter is an implementation of BaseAdapter, so we can override all the function’s of BaseAdapter in our custom adapter.

Below Custom adapter class MyAdapter extends ArrayAdapter in that:

public class MyAdapter extends ArrayAdapter {

public MyAdapter(Context context, int resource, int textViewResourceId, List objects) {
super(context, resource, textViewResourceId, objects);
}
@Override
public int getCount() {
return super.getCount();
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
return super.getView(position, convertView, parent);
}
}

These functions are described in Custom ArrayAdapter tutorial with example.

4. SimpleAdapter In Android:

In Android  SimpleAdapter is an easy Adapter to map static data to views defined in an XML file(layout). In Android we can specify the data backing to a list as an ArrayList of Maps(i.e. hashmap or other). Each entry in a ArrayList is corresponding to one row of a list.

The Map contains the data for each row. Here we also specify an XML file(custom list items file) that defines the views which is used to display the row, and a mapping from keys in the Map to specific views.

Whenever we have to create a custom list we need to implement custom adapter. As we discuss earlier ArrayAdapter is used when we have a list of single item’s backed by an Array. So if we need more customization in a ListView or a GridView we need to implement simple adapter.

SimpleAdapter code in Android:

SimpleAdapter (Context context, List<? extends Map<String, ?>> data, int resource, String[] from, int[] to)

The above parameters of a simple Adapter is described in SimpleAdapter tutorial with example.

5. Custom SimpleAdapter In Android:

Whenever we have to create a custom list we need to implement custom adapter. As we discuss earlier ArrayAdapter is used when we have a list of single item’s backed by an Array. So if we need customization in a ListView or a GridView we need to implement simple Adapter but when we need more customization in list or grid items where we have many view’s in a list item and then we have to perform any event like click or any other event to a particular view then we need to implement a custom adapter who fulfills our requirement’s and quite easy to be implemented.

BaseAdapter is the parent adapter for all other adapters so if we extends a SimpleAdapter then we can also override the base adapter’s function in that class.

Important Note: We can’t perform events like click and other event on child item of a list or grid but if we have some requirements to do that then we can create our own custom adapter and extends the simple adapter in that.

Custom Adapter extends SimpleAdapter in that:

public class CustomAdapter extends SimpleAdapter {
public CustomAdapter(Context context, List<? extends Map<String, ?>> data, int resource, String[] from, int[] to) {
super(context, data, resource, from, to);

}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
return super.getView(position, convertView, parent);

}

@Override
public int getCount() {
return super.getCount();
}
}

The above overrided functions of simple adapter are already described in Custom SimpleAdapter article.


Adapter Example In Android Studio:

Below is the Android Studio example which show the use of the Adapter in Android. In this example we display a list of fruits names with images by using SimpleAdapter and whenever user click on a list item the fruit’s name displayed in a Toast.

Below you can download complete Android Studio code, see final output and read step by step explanation:

Adapter example in Android Studio

Step 1: Create a new project and name it SimpleAdapterExample.

Step 2: Open res -> layout -> xml (or) main.xml and add following code :

In this step we open an xml file and add the code for displaying a ListView by using its different attributes.

<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=".MainActivity">

<ListView
android:id="@+id/simpleListView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:divider="#000"
android:dividerHeight="2dp"
android:listSelector="#600"/>

</RelativeLayout>

Step 3: Save fruit images in drawable folder with name apple, banana, litchi, mango and pineapple.

Step 4: Open src -> package -> MainActivity.java

In this step we add the code for initiate ListView and set the data in the list. In this firstly we create two arrays first for fruit names and second for fruits images and then set the data in the ListView using SimpleAdapter.

package example.abhiandriod.simpleadapterexample;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ListView;
import android.widget.SimpleAdapter;
import android.widget.Toast;

import java.util.ArrayList;
import java.util.HashMap;

public class MainActivity extends AppCompatActivity {

    //initialize view's
    ListView simpleListView;
    String[] fruitsNames = {"Apple", "Banana", "Litchi", "Mango", "PineApple"};//fruit names array
    int[] fruitsImages = {R.drawable.apple, R.drawable.banana, R.drawable.litchi, R.drawable.mango, R.drawable.pineapple};//fruits images
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        simpleListView=(ListView)findViewById(R.id.simpleListView);

        ArrayList<HashMap<String,String>> arrayList=new ArrayList<>();
        for (int i=0;i<fruitsNames.length;i++)
        {
            HashMap<String,String> hashMap=new HashMap<>();//create a hashmap to store the data in key value pair
            hashMap.put("name",fruitsNames[i]);
            hashMap.put("image",fruitsImages[i]+"");
            arrayList.add(hashMap);//add the hashmap into arrayList
        }
        String[] from={"name","image"};//string array
        int[] to={R.id.textView,R.id.imageView};//int array of views id's
        SimpleAdapter simpleAdapter=new SimpleAdapter(this,arrayList,R.layout.list_view_items,from,to);//Create object and set the parameters for simpleAdapter
        simpleListView.setAdapter(simpleAdapter);//sets the adapter for listView

        //perform listView item click event
        simpleListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
                Toast.makeText(getApplicationContext(),fruitsNames[i],Toast.LENGTH_LONG).show();//show the selected image in toast according to position
            }
        });
    }

    
}

Step 5: Create new layout-> rec-> layout-> list_view_items.xml and add following code:

In this step we create a xml file for displaying ListView items. In this xml we add the code for displaying a ImageView and a TextView.

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#fff">

<ImageView
android:id="@+id/imageView"
android:layout_width="50dp"
android:layout_height="50dp"
android:padding="5dp"
android:layout_alignParentRight="true"
android:layout_marginRight="10dp"
android:src="@drawable/ic_launcher" />

<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="@dimen/activity_horizontal_margin"
android:text="Demo"
android:textColor="#000" />
</RelativeLayout>

 Output:

Now run the App and you will different fruit names listed in ListView. Here we used Simple Adapter to fill data in ListView.

Swipe screen left , right , top , bottom

In This example creating a Swipe screen example .Swipe screen left / right / top / bottom , an alert will show.

 

File : AndroidMainifest.xml

 

<?xml version="1.0" encoding="utf-8"?>
    package="com.android.swipe"
    android:versionCode="1"
    android:versionName="1.0" >
    <uses-sdk android:minSdkVersion="8" />
    <application
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name" >
        <activity
            android:label="@string/app_name"
            android:name="com.androidexample.swipescreen.SwipeScreenExample" >
            <intent-filter >
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
</manifest>

 

File : src/SwipeScreenExample.java

 

Create touch event with the use of SimpleGestureFilter class object

 

import com.android.swipe.R;
import com.androidexample.swipescreen.SimpleGestureFilter.SimpleGestureListener;
import android.app.Activity;
import android.os.Bundle;
import android.view.MotionEvent;
import android.widget.Toast;
public class SwipeScreenExample extends Activity implements SimpleGestureListener{
            private SimpleGestureFilter detector;
         
        @Override
            public void onCreate(Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);
                setContentView(R.layout.swipe_screen);
         
                // Detect touched area
                detector = new SimpleGestureFilter(this,this);
        }
         
    @Override
    public boolean dispatchTouchEvent(MotionEvent me){
        // Call onTouchEvent of SimpleGestureFilter class
         this.detector.onTouchEvent(me);
       return super.dispatchTouchEvent(me);
    }
    @Override
     public void onSwipe(int direction) {
      String str = "";
     
      switch (direction) {
     
      case SimpleGestureFilter.SWIPE_RIGHT : str = "Swipe <a href="#">Right</a>";
                                               break;
      case SimpleGestureFilter.SWIPE_LEFT :  str = "Swipe Left";
                                                     break;
      case SimpleGestureFilter.SWIPE_DOWN :  str = "Swipe Down";
                                                     break;
      case SimpleGestureFilter.SWIPE_UP :    str = "Swipe Up";
                                                     break;
     
      }
       Toast.makeText(this, str, Toast.LENGTH_SHORT).show();
     }
     
     @Override
     public void onDoubleTap() {
        Toast.makeText(this, "Double Tap", Toast.LENGTH_SHORT).show();
     }
         
  }

 

File : src/SimpleGestureFilter.java

 

import android.app.Activity;
import android.view.GestureDetector;
import android.view.GestureDetector.SimpleOnGestureListener;
import android.view.MotionEvent;
public class SimpleGestureFilter extends SimpleOnGestureListener{
     
         public final static int SWIPE_UP    = 1;
         public final static int SWIPE_DOWN  = 2;
         public final static int SWIPE_LEFT  = 3;
         public final static int SWIPE_RIGHT = 4;
         
         public final static int MODE_TRANSPARENT = 0;
         public final static int MODE_SOLID       = 1;
         public final static int MODE_DYNAMIC     = 2;
         
         private final static int ACTION_FAKE = -13; //just an unlikely number
         private int swipe_Min_Distance = 100;
         private int swipe_Max_Distance = 350;
         private int swipe_Min_Velocity = 100;
     
     private int mode             = MODE_DYNAMIC;
     private boolean running      = true;
     private boolean tapIndicator = false;
     
     private Activity context;
     private GestureDetector detector;
     private SimpleGestureListener listener;
     
     public SimpleGestureFilter(Activity context,SimpleGestureListener sgl) {
     
      this.context = context;
      this.detector = new GestureDetector(context, this);
      this.listener = sgl;
     }
     
     public void onTouchEvent(MotionEvent event){
     
       if(!this.running)
      return;
     
       boolean result = this.detector.onTouchEvent(event);
     
       if(this.mode == MODE_SOLID)
        event.setAction(MotionEvent.ACTION_CANCEL);
       else if (this.mode == MODE_DYNAMIC) {
     
         if(event.getAction() == ACTION_FAKE)
           event.setAction(MotionEvent.ACTION_UP);
         else if (result)
           event.setAction(MotionEvent.ACTION_CANCEL);
         else if(this.tapIndicator){
          event.setAction(MotionEvent.ACTION_DOWN);
          this.tapIndicator = false;
         }
     
       }
       //else just do nothing, it's Transparent
     }
     
     public void setMode(int m){
      this.mode = m;
     }
     
     public int getMode(){
      return this.mode;
     }
     
     public void setEnabled(boolean status){
      this.running = status;
     }
     
     public void setSwipeMaxDistance(int distance){
      this.swipe_Max_Distance = distance;
     }
     
     public void setSwipeMinDistance(int distance){
      this.swipe_Min_Distance = distance;
     }
     
     public void setSwipeMinVelocity(int distance){
      this.swipe_Min_Velocity = distance;
     }
     
     public int getSwipeMaxDistance(){
      return this.swipe_Max_Distance;
     }
     
     public int getSwipeMinDistance(){
      return this.swipe_Min_Distance;
     }
     
     public int getSwipeMinVelocity(){
      return this.swipe_Min_Velocity;
     }
     
     @Override
         public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
           float velocityY) {
         
          final float xDistance = Math.abs(e1.getX() - e2.getX());
          final float yDistance = Math.abs(e1.getY() - e2.getY());
         
          if(xDistance > this.swipe_Max_Distance || yDistance > this.swipe_Max_Distance)
           return false;
         
          velocityX = Math.abs(velocityX);
          velocityY = Math.abs(velocityY);
                boolean result = false;
         
          if(velocityX > this.swipe_Min_Velocity && xDistance > this.swipe_Min_Distance){
           if(e1.getX() > e2.getX()) // <a href="#">right</a> to left
            this.listener.onSwipe(SWIPE_LEFT);
           else
            this.listener.onSwipe(SWIPE_RIGHT);
         
           result = true;
          }
          else if(velocityY > this.swipe_Min_Velocity && yDistance > this.swipe_Min_Distance){
           if(e1.getY() > e2.getY()) // <a href="#">bottom</a> to up
            this.listener.onSwipe(SWIPE_UP);
           else
            this.listener.onSwipe(SWIPE_DOWN);
         
           result = true;
          }
         
           return result;
         }
     
     @Override
     public boolean onSingleTapUp(MotionEvent e) {
      this.tapIndicator = true;
      return false;
     }
     
     @Override
     public boolean onDoubleTap(MotionEvent arg) {
      this.listener.onDoubleTap();;
      return true;
     }
     
     @Override
     public boolean onDoubleTapEvent(MotionEvent arg) {
      return true;
     }
     
     @Override
     public boolean onSingleTapConfirmed(MotionEvent arg) {
     
      if(this.mode == MODE_DYNAMIC){        // we owe an ACTION_UP, so we fake an
         arg.setAction(ACTION_FAKE);      //action which will be converted to an ACTION_UP later.
         this.context.dispatchTouchEvent(arg);
      
     
      return false;
     }
     
        static interface SimpleGestureListener{
         void onSwipe(int direction);
         void onDoubleTap();
     }
     
    }

http://androidexample.com/Swipe_screen_left__right__top_bottom/index.php?view=article_discription&aid=95&aaid=118

Create Repeating Alarm Start After Each 2 Minutes

In This example creating a simple repeating alarm system with the use of AlarmManager. Alarm will start after each 2 mins.

 

Steps :

  1. Using AlarmManager class to repeating and called a PendingIntent after each 2 min.
2. Call a media file on PendingIntent and start media file.
  3. So after each 2 min AlarmManager will call PendingIntent a media file start.

Project Structure :

 

create_alarm_alarmmanager_project_sketch

 

File : AndroidMainifest.xml

 

<?xml version="1.0" encoding="utf-8"?>
    package="com.example.alarmmanagerexample"
    android:versionCode="1"
    android:versionName="1.0" >
    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="17" />
    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="com.example.alarmmanagerexample.AlarmManagerExample"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity
            android:name=".RingAlarm"
            android:label="@string/app_name" />
    </application>
</manifest>

 

File : src/AlarmManagerExample.java

 

Create a alarm with the use of AlarmManager which will call a pending indent RingAlarm after each 2 minutes.

 

import android.os.Bundle;
import android.os.SystemClock;
import android.app.Activity;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.Intent;
public class AlarmManagerExample extends Activity {
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_alarm_manager_example);
        
        
        try {
            
            //Create a new PendingIntent and add it to the AlarmManager
            Intent intent = new Intent(this, RingAlarm.class);
            PendingIntent pendingIntent = PendingIntent.getActivity(this,
                12345, intent, PendingIntent.FLAG_CANCEL_CURRENT);
            AlarmManager am =
                (AlarmManager)getSystemService(Activity.ALARM_SERVICE);
            am.setRepeating(AlarmManager.ELAPSED_REALTIME, SystemClock.elapsedRealtime(),
                    2*60*60,pendingIntent);
            
          } catch (Exception e) {}
    }
}

 

File : src/RingAlarm.java

 

RingAlarm class create media player and start a audio file after each 2 minutes.

 

import android.app.Activity;
import android.content.Context;
import android.media.MediaPlayer;
import android.media.RingtoneManager;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.view.Window;
import android.view.WindowManager;
import android.widget.Button;
public class RingAlarm extends Activity {
        
       MediaPlayer mp=null ;
      
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            
                    super.onCreate(savedInstanceState);
                    this.requestWindowFeature(Window.FEATURE_NO_TITLE);
                    this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
                            WindowManager.LayoutParams.FLAG_FULLSCREEN);
                    
                    setContentView(R.layout.alarm);
                    Button stopAlarm = (Button) findViewById(R.id.stopAlarm);
                    
                    mp = MediaPlayer.create(getBaseContext(),R.raw.audio);
                    
                    
                    stopAlarm.setOnTouchListener(new OnTouchListener() {
                        
                        @Override
                        public boolean onTouch(View arg0, MotionEvent arg1) {
                            // TODO Auto-generated method stub
                            mp.stop();
                            finish();
                            return false;
                        }
                    });
             
                    playSound(this, getAlarmUri());
                }
             
                private void playSound(final Context context, Uri alert) {
                     
                    
                    Thread background = new Thread(new Runnable() {
                        public void run() {
                            try {
                                
                               mp.start();
                               
                            } catch (Throwable t) {
                                Log.i("Animation", "Thread  exception "+t);
                            }  
                        }
                 });
                 background.start();
               }
             
                @Override
                protected void onDestroy() {
                    super.onDestroy();
                    mp.stop();
                }               //Get an alarm sound. Try for an alarm. If none set, try notification,
                    //Otherwise, ringtone.
                private Uri getAlarmUri() {
                    
                    Uri alert = RingtoneManager
                            .getDefaultUri(RingtoneManager.TYPE_ALARM);
                    if (alert == null) {
                        alert = RingtoneManager
                                .getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
                        if (alert == null) {
                            alert = RingtoneManager
                                    .getDefaultUri(RingtoneManager.TYPE_RINGTONE);
                        }
                    }
                    return alert;
                }
            
}

http://androidexample.com/Create_Repeating_Alarm_Start_After_Each_2_Minutes/index.php?view=article_discription&aid=93&aaid=116

Nine-patch

Canvas and Drawables

The Android framework APIs provides a set of 2D-drawing APIs that allow you to render your own custom graphics onto a canvas or to modify existing Views to customize their look and feel. When drawing 2D graphics, you’ll typically do so in one of two ways:

  1. Draw your graphics or animations into a View object from your layout. In this manner, the drawing of your graphics is handled by the system’s normal View hierarchy drawing process — you simply define the graphics to go inside the View.
  2. Draw your graphics directly to a Canvas. This way, you personally call the appropriate class’s onDraw()method (passing it your Canvas), or one of the Canvas draw...() methods (like drawPicture()). In doing so, you are also in control of any animation.

Option “a,” drawing to a View, is your best choice when you want to draw simple graphics that do not need to change dynamically and are not part of a performance-intensive game. For example, you should draw your graphics into a View when you want to display a static graphic or predefined animation, within an otherwise static application. Read Drawables for more information.

Option “b,” drawing to a Canvas, is better when your application needs to regularly re-draw itself. Applications such as video games should be drawing to the Canvas on its own. However, there’s more than one way to do this:

  • In the same thread as your UI Activity, wherein you create a custom View component in your layout, call invalidate() and then handle the onDraw()callback.
  • Or, in a separate thread, wherein you manage a SurfaceView and perform draws to the Canvas as fast as your thread is capable (you do not need to request invalidate()).

Draw with a Canvas


When you’re writing an application in which you would like to perform specialized drawing and/or control the animation of graphics, you should do so by drawing through a Canvas. A Canvas works for you as a pretense, or interface, to the actual surface upon which your graphics will be drawn — it holds all of your “draw” calls. Via the Canvas, your drawing is actually performed upon an underlying Bitmap, which is placed into the window.

In the event that you’re drawing within the onDraw() callback method, the Canvas is provided for you and you need only place your drawing calls upon it. You can also acquire a Canvas from SurfaceHolder.lockCanvas(), when dealing with a SurfaceView object. (Both of these scenarios are discussed in the following sections.) However, if you need to create a new Canvas, then you must define the Bitmap upon which drawing will actually be performed. The Bitmap is always required for a Canvas. You can set up a new Canvas like this:

Bitmap b = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(b);

Now your Canvas will draw onto the defined Bitmap. After drawing upon it with the Canvas, you can then carry your Bitmap to another Canvas with one of the Canvas.drawBitmap(Bitmap,...) methods. It’s recommended that you ultimately draw your final graphics through a Canvas offered to you byView.onDraw() or SurfaceHolder.lockCanvas() (see the following sections).

The Canvas class has its own set of drawing methods that you can use, like drawBitmap(...), drawRect(...), drawText(...), and many more. Other classes that you might use also have draw() methods. For example, you’ll probably have some Drawable objects that you want to put on the Canvas. Drawable has its own draw() method that takes your Canvas as an argument.

On a View

If your application does not require a significant amount of processing or frame-rate speed (perhaps for a chess game, a snake game, or another slowly-animated application), then you should consider creating a custom View component and drawing with a Canvas in View.onDraw(). The most convenient aspect of doing so is that the Android framework will provide you with a pre-defined Canvas to which you will place your drawing calls.

To start, extend the View class (or descendant thereof) and define the onDraw() callback method. This method will be called by the Android framework to request that your View draw itself. This is where you will perform all your calls to draw through the Canvas, which is passed to you through theonDraw() callback.

The Android framework will only call onDraw() as necessary. Each time that your application is prepared to be drawn, you must request your View be invalidated by calling invalidate(). This indicates that you’d like your View to be drawn and Android will then call your onDraw() method (though is not guaranteed that the callback will be instantaneous).

Inside your View component’s onDraw(), use the Canvas given to you for all your drawing, using various Canvas.draw...() methods, or other classdraw() methods that take your Canvas as an argument. Once your onDraw() is complete, the Android framework will use your Canvas to draw a Bitmap handled by the system.

Note: In order to request an invalidate from a thread other than your main Activity’s thread, you must call postInvalidate().

For information about extending the View class, read Building Custom Components.

For a sample application, see the Snake game, in the SDK samples folder: <your-sdk-directory>/samples/Snake/.

On a SurfaceView

The SurfaceView is a special subclass of View that offers a dedicated drawing surface within the View hierarchy. The aim is to offer this drawing surface to an application’s secondary thread, so that the application isn’t required to wait until the system’s View hierarchy is ready to draw. Instead, a secondary thread that has reference to a SurfaceView can draw to its own Canvas at its own pace.

To begin, you need to create a new class that extends SurfaceView. The class should also implement SurfaceHolder.Callback. This subclass is an interface that will notify you with information about the underlying Surface, such as when it is created, changed, or destroyed. These events are important so that you know when you can start drawing, whether you need to make adjustments based on new surface properties, and when to stop drawing and potentially kill some tasks. Inside your SurfaceView class is also a good place to define your secondary Thread class, which will perform all the drawing procedures to your Canvas.

Instead of handling the Surface object directly, you should handle it via a SurfaceHolder. So, when your SurfaceView is initialized, get the SurfaceHolder by calling getHolder(). You should then notify the SurfaceHolder that you’d like to receive SurfaceHolder callbacks (from SurfaceHolder.Callback) by calling addCallback() (pass it this). Then override each of the SurfaceHolder.Callback methods inside your SurfaceView class.

In order to draw to the Surface Canvas from within your second thread, you must pass the thread your SurfaceHandler and retrieve the Canvas withlockCanvas(). You can now take the Canvas given to you by the SurfaceHolder and do your necessary drawing upon it. Once you’re done drawing with the Canvas, call unlockCanvasAndPost(), passing it your Canvas object. The Surface will now draw the Canvas as you left it. Perform this sequence of locking and unlocking the canvas each time you want to redraw.

Note: On each pass you retrieve the Canvas from the SurfaceHolder, the previous state of the Canvas will be retained. In order to properly animate your graphics, you must re-paint the entire surface. For example, you can clear the previous state of the Canvas by filling in a color with drawColor()or setting a background image with drawBitmap(). Otherwise, you will see traces of the drawings you previously performed.

For a sample application, see the Lunar Lander game, in the SDK samples folder: <your-sdk-directory>/samples/LunarLander/. Or, browse the source in the Sample Code section.

Drawables


Android offers a custom 2D graphics library for drawing shapes and images. The android.graphics.drawable package is where you’ll find the common classes used for drawing in two-dimensions.

This document discusses the basics of using Drawable objects to draw graphics and how to use a couple subclasses of the Drawable class. For information on using Drawables to do frame-by-frame animation, see Drawable Animation.

A Drawable is a general abstraction for “something that can be drawn.” You’ll discover that the Drawable class extends to define a variety of specific kinds of drawable graphics, including BitmapDrawable, ShapeDrawable, PictureDrawable, LayerDrawable, and several more. Of course, you can also extend these to define your own custom Drawable objects that behave in unique ways.

There are three ways to define and instantiate a Drawable: using an image saved in your project resources; using an XML file that defines the Drawable properties; or using the normal class constructors. Below, we’ll discuss each the first two techniques (using constructors is nothing new for an experienced developer).

Creating from resource images

A simple way to add graphics to your application is by referencing an image file from your project resources. Supported file types are PNG (preferred), JPG (acceptable) and GIF (discouraged). This technique would obviously be preferred for application icons, logos, or other graphics such as those used in a game.

To use an image resource, just add your file to the res/drawable/ directory of your project. From there, you can reference it from your code or your XML layout. Either way, it is referred using a resource ID, which is the file name without the file type extension (E.g., my_image.png is referenced asmy_image).

Note: Image resources placed in res/drawable/ may be automatically optimized with lossless image compression by the aapt tool during the build process. For example, a true-color PNG that does not require more than 256 colors may be converted to an 8-bit PNG with a color palette. This will result in an image of equal quality but which requires less memory. So be aware that the image binaries placed in this directory can change during the build. If you plan on reading an image as a bit stream in order to convert it to a bitmap, put your images in the res/raw/ folder instead, where they will not be optimized.

Example code

The following code snippet demonstrates how to build an ImageView that uses an image from drawable resources and add it to the layout.

LinearLayout mLinearLayout;

protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);

  // Create a LinearLayout in which to add the ImageView
  mLinearLayout = new LinearLayout(this);

  // Instantiate an ImageView and define its properties
  ImageView i = new ImageView(this);
  i.setImageResource(R.drawable.my_image);
  i.setAdjustViewBounds(true); // set the ImageView bounds to match the Drawable's dimensions
  i.setLayoutParams(new Gallery.LayoutParams(LayoutParams.WRAP_CONTENT,
      LayoutParams.WRAP_CONTENT));

  // Add the ImageView to the layout and set the layout as the content view
  mLinearLayout.addView(i);
  setContentView(mLinearLayout);
}

In other cases, you may want to handle your image resource as a Drawable object. To do so, create a Drawable from the resource like so:

Resources res = mContext.getResources();
Drawable myImage = res.getDrawable(R.drawable.my_image);

Note: Each unique resource in your project can maintain only one state, no matter how many different objects you may instantiate for it. For example, if you instantiate two Drawable objects from the same image resource, then change a property (such as the alpha) for one of the Drawables, then it will also affect the other. So when dealing with multiple instances of an image resource, instead of directly transforming the Drawable, you should perform a tween animation.

Example XML

The XML snippet below shows how to add a resource Drawable to an ImageView in the XML layout (with some red tint just for fun).

<ImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:tint="#55ff0000"
        android:src="@drawable/my_image"/>

For more information on using project resources, read about Resources and Assets.

Creating from resource XML

By now, you should be familiar with Android’s principles of developing a User Interface. Hence, you understand the power and flexibility inherent in defining objects in XML. This philosophy caries over from Views to Drawables. If there is a Drawable object that you’d like to create, which is not initially dependent on variables defined by your application code or user interaction, then defining the Drawable in XML is a good option. Even if you expect your Drawable to change its properties during the user’s experience with your application, you should consider defining the object in XML, as you can always modify properties once it is instantiated.

Once you’ve defined your Drawable in XML, save the file in the res/drawable/ directory of your project. Then, retrieve and instantiate the object by calling Resources.getDrawable(), passing it the resource ID of your XML file. (See the example below.)

Any Drawable subclass that supports the inflate() method can be defined in XML and instantiated by your application. Each Drawable that supports XML inflation utilizes specific XML attributes that help define the object properties (see the class reference to see what these are). See the class documentation for each Drawable subclass for information on how to define it in XML.

Example

Here’s some XML that defines a TransitionDrawable:

<transition xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@drawable/image_expand">
    <item android:drawable="@drawable/image_collapse">
</transition>

With this XML saved in the file res/drawable/expand_collapse.xml, the following code will instantiate the TransitionDrawable and set it as the content of an ImageView:

Resources res = mContext.getResources();
TransitionDrawable transition = (TransitionDrawable)
    res.getDrawable(R.drawable.expand_collapse);
ImageView image = (ImageView) findViewById(R.id.toggle_image);
image.setImageDrawable(transition);

Then this transition can be run forward (for 1 second) with:

transition.startTransition(1000);

Refer to the Drawable classes listed above for more information on the XML attributes supported by each.

Shape Drawable


When you want to dynamically draw some two-dimensional graphics, a ShapeDrawable object will probably suit your needs. With a ShapeDrawable, you can programmatically draw primitive shapes and style them in any way imaginable.

A ShapeDrawable is an extension of Drawable, so you can use one wherever a Drawable is expected — perhaps for the background of a View, set withsetBackgroundDrawable(). Of course, you can also draw your shape as its own custom View, to be added to your layout however you please. Because the ShapeDrawable has its own draw() method, you can create a subclass of View that draws the ShapeDrawable during the View.onDraw() method. Here’s a basic extension of the View class that does just this, to draw a ShapeDrawable as a View:

public class CustomDrawableView extends View {
  private ShapeDrawable mDrawable;

  public CustomDrawableView(Context context) {
    super(context);

    int x = 10;
    int y = 10;
    int width = 300;
    int height = 50;

    mDrawable = new ShapeDrawable(new OvalShape());
    mDrawable.getPaint().setColor(0xff74AC23);
    mDrawable.setBounds(x, y, x + width, y + height);
  }

  protected void onDraw(Canvas canvas) {
    mDrawable.draw(canvas);
  }
}

In the constructor, a ShapeDrawable is defines as an OvalShape. It’s then given a color and the bounds of the shape are set. If you do not set the bounds, then the shape will not be drawn, whereas if you don’t set the color, it will default to black.

With the custom View defined, it can be drawn any way you like. With the sample above, we can draw the shape programmatically in an Activity:

CustomDrawableView mCustomDrawableView;

protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  mCustomDrawableView = new CustomDrawableView(this);

  setContentView(mCustomDrawableView);
}

If you’d like to draw this custom drawable from the XML layout instead of from the Activity, then the CustomDrawable class must override theView(Context, AttributeSet) constructor, which is called when instantiating a View via inflation from XML. Then add a CustomDrawable element to the XML, like so:

<com.example.shapedrawable.CustomDrawableView
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        />

The ShapeDrawable class (like many other Drawable types in the android.graphics.drawable package) allows you to define various properties of the drawable with public methods. Some properties you might want to adjust include alpha transparency, color filter, dither, opacity and color.

You can also define primitive drawable shapes using XML. For more information, see the section about Shape Drawables in the Drawable Resourcesdocument.

Nine-patch


A NinePatchDrawable graphic is a stretchable bitmap image, which Android will automatically resize to accommodate the contents of the View in which you have placed it as the background. An example use of a NinePatch is the backgrounds used by standard Android buttons — buttons must stretch to accommodate strings of various lengths. A NinePatch drawable is a standard PNG image that includes an extra 1-pixel-wide border. It must be saved with the extension .9.png, and saved into the res/drawable/ directory of your project.

The border is used to define the stretchable and static areas of the image. You indicate a stretchable section by drawing one (or more) 1-pixel-wide black line(s) in the left and top part of the border (the other border pixels should be fully transparent or white). You can have as many stretchable sections as you want: their relative size stays the same, so the largest sections always remain the largest.

You can also define an optional drawable section of the image (effectively, the padding lines) by drawing a line on the right and bottom lines. If a View object sets the NinePatch as its background and then specifies the View’s text, it will stretch itself so that all the text fits inside only the area designated by the right and bottom lines (if included). If the padding lines are not included, Android uses the left and top lines to define this drawable area.

To clarify the difference between the different lines, the left and top lines define which pixels of the image are allowed to be replicated in order to stretch the image. The bottom and right lines define the relative area within the image that the contents of the View are allowed to lie within.

Here is a sample NinePatch file used to define a button:

This NinePatch defines one stretchable area with the left and top lines and the drawable area with the bottom and right lines. In the top image, the dotted grey lines identify the regions of the image that will be replicated in order to stretch the image. The pink rectangle in the bottom image identifies the region in which the contents of the View are allowed. If the contents don’t fit in this region, then the image will be stretched so that they do.

The Draw 9-patch tool offers an extremely handy way to create your NinePatch images, using a WYSIWYG graphics editor. It even raises warnings if the region you’ve defined for the stretchable area is at risk of producing drawing artifacts as a result of the pixel replication.

Example XML

Here’s some sample layout XML that demonstrates how to add a NinePatch image to a couple of buttons. (The NinePatch image is saved asres/drawable/my_button_background.9.png

<Button id="@+id/tiny"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:layout_centerInParent="true"
        android:text="Tiny"
        android:textSize="8sp"
        android:background="@drawable/my_button_background"/>

<Button id="@+id/big"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_centerInParent="true"
        android:text="Biiiiiiig text!"
        android:textSize="30sp"
        android:background="@drawable/my_button_background"/>

Note that the width and height are set to “wrap_content” to make the button fit neatly around the text.

Below are the two buttons rendered from the XML and NinePatch image shown above. Notice how the width and height of the button varies with the text, and the background image stretches to accommodate it.

9 Nine Patche Guides

Supporting Multiple Screens

Android runs on a variety of devices that offer different screen sizes and densities. For applications, the Android system provides a consistent development environment across devices and handles most of the work to adjust each application’s user interface to the screen on which it is displayed. At the same time, the system provides APIs that allow you to control your application’s UI for specific screen sizes and densities, in order to optimize your UI design for different screen configurations. For example, you might want a UI for tablets that’s different from the UI for handsets.

Although the system performs scaling and resizing to make your application work on different screens, you should make the effort to optimize your application for different screen sizes and densities. In doing so, you maximize the user experience for all devices and your users believe that your application was actually designed for their devices—rather than simply stretched to fit the screen on their devices.

By following the practices described in this document, you can create an application that displays properly and provides an optimized user experience on all supported screen configurations, using a single. apk file.

Note: The information in this document assumes that your application is designed for Android 1.6 (API Level 4) or higher. If your application supports Android 1.5 or lower, please first read Strategies for Android 1.5.

Also, be aware that Android 3.2 has introduced new APIs that allow you to more precisely control the layout resources your application uses for different screen sizes. These new features are especially important if you’re developing an application that’s optimized for tablets. For details, see the section about Declaring Tablet Layouts for Android 3.2.

Overview of Screens Support


This section provides an overview of Android’s support for multiple screens, including: an introduction to the terms and concepts used in this document and in the API, a summary of the screen configurations that the system supports, and an overview of the API and underlying screen-compatibility features.

Terms and concepts

Screen size
Actual physical size, measured as the screen’s diagonal.For simplicity, Android groups all actual screen sizes into four generalized sizes: small, normal, large, and extra-large.
Screen density
The quantity of pixels within a physical area of the screen; usually referred to as dpi (dots per inch). For example, a “low” density screen has fewer pixels within a given physical area, compared to a “normal” or “high” density screen.For simplicity, Android groups all actual screen densities into six generalized densities: low, medium, high, extra-high, extra-extra-high, and extra-extra-extra-high.
Orientation
The orientation of the screen from the user’s point of view. This is either landscape or portrait, meaning that the screen’s aspect ratio is either wide or tall, respectively. Be aware that not only do different devices operate in different orientations by default, but the orientation can change at runtime when the user rotates the device.
Resolution
The total number of physical pixels on a screen. When adding support for multiple screens, applications do not work directly with resolution; applications should be concerned only with screen size and density, as specified by the generalized size and density groups.
Density-independent pixel (dp)
A virtual pixel unit that you should use when defining UI layout, to express layout dimensions or position in a density-independent way.The density-independent pixel is equivalent to one physical pixel on a 160 dpi screen, which is the baseline density assumed by the system for a “medium” density screen. At runtime, the system transparently handles any scaling of the dp units, as necessary, based on the actual density of the screen in use. The conversion of dp units to screen pixels is simple: px = dp * (dpi / 160). For example, on a 240 dpi screen, 1 dp equals 1.5 physical pixels. You should always use dp units when defining your application’s UI, to ensure proper display of your UI on screens with different densities.

Range of screens supported

Starting with Android 1.6 (API Level 4), Android provides support for multiple screen sizes and densities, reflecting the many different screen configurations that a device may have. You can use features of the Android system to optimize your application’s user interface for each screen configuration and ensure that your application not only renders properly, but provides the best user experience possible on each screen.

To simplify the way that you design your user interfaces for multiple screens, Android divides the range of actual screen sizes and densities into:

  • A set of four generalized sizes: small, normal, large, and xlarge

    Note: Beginning with Android 3.2 (API level 13), these size groups are deprecated in favor of a new technique for managing screen sizes based on the available screen width. If you’re developing for Android 3.2 and greater, see Declaring Tablet Layouts for Android 3.2 for more information.

  • A set of six generalized densities:
    • ldpi (low) ~120dpi
    • mdpi (medium) ~160dpi
    • hdpi (high) ~240dpi
    • xhdpi (extra-high) ~320dpi
    • xxhdpi (extra-extra-high) ~480dpi
    • xxxhdpi (extra-extra-extra-high) ~640dpi

The generalized sizes and densities are arranged around a baseline configuration that is a normal size and mdpi (medium) density. This baseline is based upon the screen configuration for the first Android-powered device, the T-Mobile G1, which has an HVGA screen (until Android 1.6, this was the only screen configuration that Android supported).

Each generalized size and density spans a range of actual screen sizes and densities. For example, two devices that both report a screen size of normalmight have actual screen sizes and aspect ratios that are slightly different when measured by hand. Similarly, two devices that report a screen density of hdpi might have real pixel densities that are slightly different. Android makes these differences abstract to applications, so you can provide UI designed for the generalized sizes and densities and let the system handle any final adjustments as necessary. Figure 1 illustrates how different sizes and densities are roughly categorized into the different size and density groups.

Figure 1. Illustration of how Android roughly maps actual sizes and densities to generalized sizes and densities (figures are not exact).

As you design your UI for different screen sizes, you’ll discover that each design requires a minimum amount of space. So, each generalized screen size above has an associated minimum resolution that’s defined by the system. These minimum sizes are in “dp” units—the same units you should use when defining your layouts—which allows the system to avoid worrying about changes in screen density.

  • xlarge screens are at least 960dp x 720dp
  • large screens are at least 640dp x 480dp
  • normal screens are at least 470dp x 320dp
  • small screens are at least 426dp x 320dp

Note: These minimum screen sizes were not as well defined prior to Android 3.0, so you may encounter some devices that are mis-classified between normal and large. These are also based on the physical resolution of the screen, so may vary across devices—for example a 1024×720 tablet with a system bar actually has a bit less space available to the application due to it being used by the system bar.

To optimize your application’s UI for the different screen sizes and densities, you can provide alternative resources for any of the generalized sizes and densities. Typically, you should provide alternative layouts for some of the different screen sizes and alternative bitmap images for different screen densities. At runtime, the system uses the appropriate resources for your application, based on the generalized size or density of the current device screen.

You do not need to provide alternative resources for every combination of screen size and density. The system provides robust compatibility features that can handle most of the work of rendering your application on any device screen, provided that you’ve implemented your UI using techniques that allow it to gracefully resize (as described in the Best Practices, below).

Note: The characteristics that define a device’s generalized screen size and density are independent from each other. For example, a WVGA high-density screen is considered a normal size screen because its physical size is about the same as the T-Mobile G1 (Android’s first device and baseline screen configuration). On the other hand, a WVGA medium-density screen is considered a large size screen. Although it offers the same resolution (the same number of pixels), the WVGA medium-density screen has a lower screen density, meaning that each pixel is physically larger and, thus, the entire screen is larger than the baseline (normal size) screen.

Density independence

Your application achieves “density independence” when it preserves the physical size (from the user’s point of view) of user interface elements when displayed on screens with different densities.

Maintaining density independence is important because, without it, a UI element (such as a button) appears physically larger on a low-density screen and smaller on a high-density screen. Such density-related size changes can cause problems in your application layout and usability. Figures 2 and 3 show the difference between an application when it does not provide density independence and when it does, respectively.

Figure 2. Example application without support for different densities, as shown on low, medium, and high-density screens.

Figure 3. Example application with good support for different densities (it’s density independent), as shown on low, medium, and high density screens.

The Android system helps your application achieve density independence in two ways:

  • The system scales dp units as appropriate for the current screen density
  • The system scales drawable resources to the appropriate size, based on the current screen density, if necessary

In figure 2, the text view and bitmap drawable have dimensions specified in pixels (px units), so the views are physically larger on a low-density screen and smaller on a high-density screen. This is because although the actual screen sizes may be the same, the high-density screen has more pixels per inch (the same amount of pixels fit in a smaller area). In figure 3, the layout dimensions are specified in density-independent pixels (dp units). Because the baseline for density-independent pixels is a medium-density screen, the device with a medium-density screen looks the same as it does in figure 2. For the low-density and high-density screens, however, the system scales the density-independent pixel values down and up, respectively, to fit the screen as appropriate.

In most cases, you can ensure density independence in your application simply by specifying all layout dimension values in density-independent pixels (dp units) or with "wrap_content", as appropriate. The system then scales bitmap drawables as appropriate in order to display at the appropriate size, based on the appropriate scaling factor for the current screen’s density.

However, bitmap scaling can result in blurry or pixelated bitmaps, which you might notice in the above screenshots. To avoid these artifacts, you should provide alternative bitmap resources for different densities. For example, you should provide higher-resolution bitmaps for high-density screens and the system will use those instead of resizing the bitmap designed for medium-density screens. The following section describes more about how to supply alternative resources for different screen configurations.

How to Support Multiple Screens


The foundation of Android’s support for multiple screens is its ability to manage the rendering of an application’s layout and bitmap drawables in an appropriate way for the current screen configuration. The system handles most of the work to render your application properly on each screen configuration by scaling layouts to fit the screen size/density and scaling bitmap drawables for the screen density, as appropriate. To more gracefully handle different screen configurations, however, you should also:

  • Explicitly declare in the manifest which screen sizes your application supportsBy declaring which screen sizes your application supports, you can ensure that only devices with the screens you support can download your application. Declaring support for different screen sizes can also affect how the system draws your application on larger screens—specifically, whether your application runs in screen compatibility mode.

    To declare the screen sizes your application supports, you should include the <supports-screens> element in your manifest file.

  • Provide different layouts for different screen sizesBy default, Android resizes your application layout to fit the current device screen. In most cases, this works fine. In other cases, your UI might not look as good and might need adjustments for different screen sizes. For example, on a larger screen, you might want to adjust the position and size of some elements to take advantage of the additional screen space, or on a smaller screen, you might need to adjust sizes so that everything can fit on the screen.

    The configuration qualifiers you can use to provide size-specific resources are small, normal, large, and xlarge. For example, layouts for an extra-large screen should go in layout-xlarge/.

    Beginning with Android 3.2 (API level 13), the above size groups are deprecated and you should instead use the sw<N>dp configuration qualifier to define the smallest available width required by your layout resources. For example, if your multi-pane tablet layout requires at least 600dp of screen width, you should place it in layout-sw600dp/. Using the new techniques for declaring layout resources is discussed further in the section aboutDeclaring Tablet Layouts for Android 3.2.

  • Provide different bitmap drawables for different screen densitiesBy default, Android scales your bitmap drawables (.png, .jpg, and .gif files) and Nine-Patch drawables (.9.png files) so that they render at the appropriate physical size on each device. For example, if your application provides bitmap drawables only for the baseline, medium screen density (mdpi), then the system scales them up when on a high-density screen, and scales them down when on a low-density screen. This scaling can cause artifacts in the bitmaps. To ensure your bitmaps look their best, you should include alternative versions at different resolutions for different screen densities.

    The configuration qualifiers (described in detail below) that you can use for density-specific resources are ldpi (low), mdpi (medium), hdpi (high),xhdpi extra-high), xxhdpi (extra-extra-high), and xxxhdpi (extra-extra-extra-high). For example, bitmaps for high-density screens should go indrawable-hdpi/.

    Note: The mipmap-xxxhdpi qualifier is necessary only to provide a launcher icon that can appear larger than usual on an xxhdpi device. You do not need to provide xxxhdpi assets for all your app’s images.

    Some devices scale-up the launcher icon by as much as 25%. For example, if your highest density launcher icon image is already extra-extra-high-density, the scaling process will make it appear less crisp. So you should provide a higher density launcher icon in the mipmap-xxxhdpi directory, which the system uses instead of scaling up a smaller version of the icon.

    See Provide an xxx-high-density launcher icon for more information. You should not use the xxxhdpi qualifier for UI elements other than the launcher icon.

Note: Place all your launcher icons in the res/mipmap-[density]/ folders, rather than the res/drawable-[density]/ folders. The Android system retains the resources in these density-specific folders, such as mipmap-xxxhdpi, regardless of the screen resolution of the device where your app is installed. This behavior allows launcher apps to pick the best resolution icon for your app to display on the home screen. For more information about using the mipmap folders, see Managing Projects Overview.

The size and density configuration qualifiers correspond to the generalized sizes and densities described in Range of screens supported, above.

Note: If you’re not familiar with configuration qualifiers and how the system uses them to apply alternative resources, read Providing Alternative Resources for more information.

At runtime, the system ensures the best possible display on the current screen with the following procedure for any given resource:

  1. The system uses the appropriate alternative resourceBased on the size and density of the current screen, the system uses any size- and density-specific resource provided in your application. For example, if the device has a high-density screen and the application requests a drawable resource, the system looks for a drawable resource directory that best matches the device configuration. Depending on the other alternative resources available, a resource directory with the hdpiqualifier (such as drawable-hdpi/) might be the best match, so the system uses the drawable resource from this directory.
  2. If no matching resource is available, the system uses the default resource and scales it up or down as needed to match the current screen size and densityThe “default” resources are those that are not tagged with a configuration qualifier. For example, the resources in drawable/ are the default drawable resources. The system assumes that default resources are designed for the baseline screen size and density, which is a normal screen size and a medium-density. As such, the system scales default density resources up for high-density screens and down for low-density screens, as appropriate.

    However, when the system is looking for a density-specific resource and does not find it in the density-specific directory, it won’t always use the default resources. The system may instead use one of the other density-specific resources in order to provide better results when scaling. For example, when looking for a low-density resource and it is not available, the system prefers to scale-down the high-density version of the resource, because the system can easily scale a high-density resource down to low-density by a factor of 0.5, with fewer artifacts, compared to scaling a medium-density resource by a factor of 0.75.

For more information about how Android selects alternative resources by matching configuration qualifiers to the device configuration, read How Android Finds the Best-matching Resource.

Using configuration qualifiers

Android supports several configuration qualifiers that allow you to control how the system selects your alternative resources based on the characteristics of the current device screen. A configuration qualifier is a string that you can append to a resource directory in your Android project and specifies the configuration for which the resources inside are designed.

To use a configuration qualifier:

  1. Create a new directory in your project’s res/ directory and name it using the format: <resources_name>-<qualifier>
    • <resources_name> is the standard resource name (such as drawable or layout).
    • <qualifier> is a configuration qualifier from table 1, below, specifying the screen configuration for which these resources are to be used (such ashdpi or xlarge).

    You can use more than one <qualifier> at a time—simply separate each qualifier with a dash.

  2. Save the appropriate configuration-specific resources in this new directory. The resource files must be named exactly the same as the default resource files.

For example, xlarge is a configuration qualifier for extra-large screens. When you append this string to a resource directory name (such as layout-xlarge), it indicates to the system that these resources are to be used on devices that have an extra-large screen.

Table 1. Configuration qualifiers that allow you to provide special resources for different screen configurations.

Screen characteristic Qualifier Description
Size small Resources for small size screens.
normal Resources for normal size screens. (This is the baseline size.)
large Resources for large size screens.
xlarge Resources for extra-large size screens.
Density ldpi Resources for low-density (ldpi) screens (~120dpi).
mdpi Resources for medium-density (mdpi) screens (~160dpi). (This is the baseline density.)
hdpi Resources for high-density (hdpi) screens (~240dpi).
xhdpi Resources for extra-high-density (xhdpi) screens (~320dpi).
xxhdpi Resources for extra-extra-high-density (xxhdpi) screens (~480dpi).
xxxhdpi Resources for extra-extra-extra-high-density (xxxhdpi) uses (~640dpi). Use this for the launcher icon only, see noteabove.
nodpi Resources for all densities. These are density-independent resources. The system does not scale resources tagged with this qualifier, regardless of the current screen’s density.
tvdpi Resources for screens somewhere between mdpi and hdpi; approximately 213dpi. This is not considered a “primary” density group. It is mostly intended for televisions and most apps shouldn’t need it—providing mdpi and hdpi resources is sufficient for most apps and the system will scale them as appropriate. If you find it necessary to provide tvdpi resources, you should size them at a factor of 1.33*mdpi. For example, a 100px x 100px image for mdpi screens should be 133px x 133px for tvdpi.
Orientation land Resources for screens in the landscape orientation (wide aspect ratio).
port Resources for screens in the portrait orientation (tall aspect ratio).
Aspect ratio long Resources for screens that have a significantly taller or wider aspect ratio (when in portrait or landscape orientation, respectively) than the baseline screen configuration.
notlong Resources for use screens that have an aspect ratio that is similar to the baseline screen configuration.

Note: If you’re developing your application for Android 3.2 and higher, see the section about Declaring Tablet Layouts for Android 3.2 for information about new configuration qualifiers that you should use when declaring layout resources for specific screen sizes (instead of using the size qualifiers in table 1).

For more information about how these qualifiers roughly correspond to real screen sizes and densities, see Range of Screens Supported, earlier in this document.

For example, the following application resource directories provide different layout designs for different screen sizes and different drawables. Use themipmap/ folders for launcher icons.

res/layout/my_layout.xml              // layout for normal screen size ("default")
res/layout-large/my_layout.xml        // layout for large screen size
res/layout-xlarge/my_layout.xml       // layout for extra-large screen size
res/layout-xlarge-land/my_layout.xml  // layout for extra-large in landscape orientation

res/drawable-mdpi/graphic.png         // bitmap for medium-density
res/drawable-hdpi/graphic.png         // bitmap for high-density
res/drawable-xhdpi/graphic.png        // bitmap for extra-high-density
res/drawable-xxhdpi/graphic.png       // bitmap for extra-extra-high-density

res/mipmap-mdpi/my_icon.png         // launcher icon for medium-density
res/mipmap-hdpi/my_icon.png         // launcher icon for high-density
res/mipmap-xhdpi/my_icon.png        // launcher icon for extra-high-density
res/mipmap-xxhdpi/my_icon.png       // launcher icon for extra-extra-high-density
res/mipmap-xxxhdpi/my_icon.png      // launcher icon for extra-extra-extra-high-density

For more information about how to use alternative resources and a complete list of configuration qualifiers (not just for screen configurations), seeProviding Alternative Resources.

Be aware that, when the Android system picks which resources to use at runtime, it uses certain logic to determine the “best matching” resources. That is, the qualifiers you use don’t have to exactly match the current screen configuration in all cases in order for the system to use them. Specifically, when selecting resources based on the size qualifiers, the system will use resources designed for a screen smaller than the current screen if there are no resources that better match (for example, a large-size screen will use normal-size screen resources if necessary). However, if the only available resources are larger than the current screen, the system will not use them and your application will crash if no other resources match the device configuration (for example, if all layout resources are tagged with the xlarge qualifier, but the device is a normal-size screen). For more information about how the system selects resources, read How Android Finds the Best-matching Resource.

Tip: If you have some drawable resources that the system should never scale (perhaps because you perform some adjustments to the image yourself at runtime), you should place them in a directory with the nodpi configuration qualifier. Resources with this qualifier are considered density-agnostic and the system will not scale them.

Designing alternative layouts and drawables

The types of alternative resources you should create depends on your application’s needs. Usually, you should use the size and orientation qualifiers to provide alternative layout resources and use the density qualifiers to provide alternative bitmap drawable resources.

The following sections summarize how you might want to use the size and density qualifiers to provide alternative layouts and drawables, respectively.

Alternative layouts

Generally, you’ll know whether you need alternative layouts for different screen sizes once you test your application on different screen configurations. For example:

  • When testing on a small screen, you might discover that your layout doesn’t quite fit on the screen. For example, a row of buttons might not fit within the width of the screen on a small screen device. In this case you should provide an alternative layout for small screens that adjusts the size or position of the buttons.
  • When testing on an extra-large screen, you might realize that your layout doesn’t make efficient use of the big screen and is obviously stretched to fill it. In this case, you should provide an alternative layout for extra-large screens that provides a redesigned UI that is optimized for bigger screens such as tablets.Although your application should work fine without an alternative layout on big screens, it’s quite important to users that your application looks as though it’s designed specifically for their devices. If the UI is obviously stretched, users are more likely to be unsatisfied with the application experience.
  • And, when testing in the landscape orientation compared to the portrait orientation, you might notice that UI elements placed at the bottom of the screen for the portrait orientation should instead be on the right side of the screen in landscape orientation.

To summarize, you should be sure that your application layout:

  • Fits on small screens (so users can actually use your application)
  • Is optimized for bigger screens to take advantage of the additional screen space
  • Is optimized for both landscape and portrait orientations

If your UI uses bitmaps that need to fit the size of a view even after the system scales the layout (such as the background image for a button), you should use Nine-Patch bitmap files. A Nine-Patch file is basically a PNG file in which you specify two-dimensional regions that are stretchable. When the system needs to scale the view in which the bitmap is used, the system stretches the Nine-Patch bitmap, but stretches only the specified regions. As such, you don’t need to provide different drawables for different screen sizes, because the Nine-Patch bitmap can adjust to any size. You should, however, provide alternate versions of your Nine-Patch files for different screen densities.

Alternative drawables

Figure 4. Relative sizes for bitmap drawables that support each density.

Almost every application should have alternative drawable resources for different screen densities, because almost every application has a launcher icon and that icon should look good on all screen densities. Likewise, if you include other bitmap drawables in your application (such as for menu icons or other graphics in your application), you should provide alternative versions or each one, for different densities.

Note: You only need to provide density-specific drawables for bitmap files (.png, .jpg, or .gif) and Nine-Patch files (.9.png). If you use XML files to define shapes, colors, or other drawable resources, you should put one copy in the default drawable directory (drawable/).

To create alternative bitmap drawables for different densities, you should follow the 3:4:6:8:12:16 scaling ratiobetween the six generalized densities. For example, if you have a bitmap drawable that’s 48×48 pixels for medium-density screens, all the different sizes should be:

  • 36×36 (0.75x) for low-density
  • 48×48 (1.0x baseline) for medium-density
  • 72×72 (1.5x) for high-density
  • 96×96 (2.0x) for extra-high-density
  • 144×144 (3.0x) for extra-extra-high-density
  • 192×192 (4.0x) for extra-extra-extra-high-density (launcher icon only; see note above)

For more information about designing icons, see the Icon Design Guidelines, which includes size information for various bitmap drawables, such as launcher icons, menu icons, status bar icons, tab icons, and more.

Declaring Tablet Layouts for Android 3.2


For the first generation of tablets running Android 3.0, the proper way to declare tablet layouts was to put them in a directory with the xlargeconfiguration qualifier (for example, res/layout-xlarge/). In order to accommodate other types of tablets and screen sizes—in particular, 7″ tablets—Android 3.2 introduces a new way to specify resources for more discrete screen sizes. The new technique is based on the amount of space your layout needs (such as 600dp of width), rather than trying to make your layout fit the generalized size groups (such as large or xlarge).

The reason designing for 7″ tablets is tricky when using the generalized size groups is that a 7″ tablet is technically in the same group as a 5″ handset (the large group). While these two devices are seemingly close to each other in size, the amount of space for an application’s UI is significantly different, as is the style of user interaction. Thus, a 7″ and 5″ screen should not always use the same layout. To make it possible for you to provide different layouts for these two kinds of screens, Android now allows you to specify your layout resources based on the width and/or height that’s actually available for your application’s layout, specified in dp units.

For example, after you’ve designed the layout you want to use for tablet-style devices, you might determine that the layout stops working well when the screen is less than 600dp wide. This threshold thus becomes the minimum size that you require for your tablet layout. As such, you can now specify that these layout resources should be used only when there is at least 600dp of width available for your application’s UI.

You should either pick a width and design to it as your minimum size, or test what is the smallest width your layout supports once it’s complete.

Note: Remember that all the figures used with these new size APIs are density-independent pixel (dp) values and your layout dimensions should also always be defined using dp units, because what you care about is the amount of screen space available after the system accounts for screen density (as opposed to using raw pixel resolution). For more information about density-independent pixels, read Terms and concepts, earlier in this document.

Using new size qualifiers

The different resource configurations that you can specify based on the space available for your layout are summarized in table 2. These new qualifiers offer you more control over the specific screen sizes your application supports, compared to the traditional screen size groups (small, normal, large, and xlarge).

Note: The sizes that you specify using these qualifiers are not the actual screen sizes. Rather, the sizes are for the width or height in dp units that are available to your activity’s window. The Android system might use some of the screen for system UI (such as the system bar at the bottom of the screen or the status bar at the top), so some of the screen might not be available for your layout. Thus, the sizes you declare should be specifically about the sizes needed by your activity—the system accounts for any space used by system UI when declaring how much space it provides for your layout. Also beware that the Action Bar is considered a part of your application’s window space, although your layout does not declare it, so it reduces the space available for your layout and you must account for it in your design.

Table 2. New configuration qualifiers for screen size (introduced in Android 3.2).

Screen configuration Qualifier values Description
smallestWidth sw<N>dp

Examples:
sw600dp
sw720dp

The fundamental size of a screen, as indicated by the shortest dimension of the available screen area. Specifically, the device’s smallestWidth is the shortest of the screen’s available height and width (you may also think of it as the “smallest possible width” for the screen). You can use this qualifier to ensure that, regardless of the screen’s current orientation, your application’s has at least <N> dps of width available for its UI.

For example, if your layout requires that its smallest dimension of screen area be at least 600 dp at all times, then you can use this qualifier to create the layout resources, res/layout-sw600dp/. The system will use these resources only when the smallest dimension of available screen is at least 600dp, regardless of whether the 600dp side is the user-perceived height or width. The smallestWidth is a fixed screen size characteristic of the device; the device’s smallestWidth does not change when the screen’s orientation changes.

The smallestWidth of a device takes into account screen decorations and system UI. For example, if the device has some persistent UI elements on the screen that account for space along the axis of the smallestWidth, the system declares the smallestWidth to be smaller than the actual screen size, because those are screen pixels not available for your UI.

This is an alternative to the generalized screen size qualifiers (small, normal, large, xlarge) that allows you to define a discrete number for the effective size available for your UI. Using smallestWidth to determine the general screen size is useful because width is often the driving factor in designing a layout. A UI will often scroll vertically, but have fairly hard constraints on the minimum space it needs horizontally. The available width is also the key factor in determining whether to use a one-pane layout for handsets or multi-pane layout for tablets. Thus, you likely care most about what the smallest possible width will be on each device.

Available screen width w<N>dp

Examples:
w720dp
w1024dp

Specifies a minimum available width in dp units at which the resources should be used—defined by the <N> value. The system’s corresponding value for the width changes when the screen’s orientation switches between landscape and portrait to reflect the current actual width that’s available for your UI.

This is often useful to determine whether to use a multi-pane layout, because even on a tablet device, you often won’t want the same multi-pane layout for portrait orientation as you do for landscape. Thus, you can use this to specify the minimum width required for the layout, instead of using both the screen size and orientation qualifiers together.

Available screen height h<N>dp

Examples:
h720dp
h1024dp
etc.

Specifies a minimum screen height in dp units at which the resources should be used—defined by the <N> value. The system’s corresponding value for the height changes when the screen’s orientation switches between landscape and portrait to reflect the current actual height that’s available for your UI.

Using this to define the height required by your layout is useful in the same way as w<N>dp is for defining the required width, instead of using both the screen size and orientation qualifiers. However, most apps won’t need this qualifier, considering that UIs often scroll vertically and are thus more flexible with how much height is available, whereas the width is more rigid.

While using these qualifiers might seem more complicated than using screen size groups, it should actually be simpler once you determine the requirements for your UI. When you design your UI, the main thing you probably care about is the actual size at which your application switches between a handset-style UI and a tablet-style UI that uses multiple panes. The exact point of this switch will depend on your particular design—maybe you need a 720dp width for your tablet layout, maybe 600dp is enough, or 480dp, or some number between these. Using these qualifiers in table 2, you are in control of the precise size at which your layout changes.

For more discussion about these size configuration qualifiers, see the Providing Resources document.

Configuration examples

To help you target some of your designs for different types of devices, here are some numbers for typical screen widths:

  • 320dp: a typical phone screen (240×320 ldpi, 320×480 mdpi, 480×800 hdpi, etc).
  • 480dp: a tweener tablet like the Streak (480×800 mdpi).
  • 600dp: a 7” tablet (600×1024 mdpi).
  • 720dp: a 10” tablet (720×1280 mdpi, 800×1280 mdpi, etc).

Using the size qualifiers from table 2, your application can switch between your different layout resources for handsets and tablets using any number you want for width and/or height. For example, if 600dp is the smallest available width supported by your tablet layout, you can provide these two sets of layouts:

res/layout/main_activity.xml           # For handsets
res/layout-sw600dp/main_activity.xml   # For tablets

In this case, the smallest width of the available screen space must be 600dp in order for the tablet layout to be applied.

For other cases in which you want to further customize your UI to differentiate between sizes such as 7” and 10” tablets, you can define additional smallest width layouts:

res/layout/main_activity.xml           # For handsets (smaller than 600dp available width)
res/layout-sw600dp/main_activity.xml   # For 7” tablets (600dp wide and bigger)
res/layout-sw720dp/main_activity.xml   # For 10” tablets (720dp wide and bigger)

Notice that the previous two sets of example resources use the “smallest width” qualifier, sw<N>dp, which specifies the smallest of the screen’s two sides, regardless of the device’s current orientation. Thus, using sw<N>dp is a simple way to specify the overall screen size available for your layout by ignoring the screen’s orientation.

However, in some cases, what might be important for your layout is exactly how much width or height is currently available. For example, if you have a two-pane layout with two fragments side by side, you might want to use it whenever the screen provides at least 600dp of width, whether the device is in landscape or portrait orientation. In this case, your resources might look like this:

res/layout/main_activity.xml         # For handsets (smaller than 600dp available width)
res/layout-w600dp/main_activity.xml  # Multi-pane (any screen with 600dp available width or more)

Notice that the second set is using the “available width” qualifier, w<N>dp. This way, one device may actually use both layouts, depending on the orientation of the screen (if the available width is at least 600dp in one orientation and less than 600dp in the other orientation).

If the available height is a concern for you, then you can do the same using the h<N>dp qualifier. Or, even combine the w<N>dp and h<N>dp qualifiers if you need to be really specific.

Declaring screen size support

Once you’ve implemented your layouts for different screen sizes, it’s equally important that you declare in your manifest file which screens your application supports.

Along with the new configuration qualifiers for screen size, Android 3.2 introduces new attributes for the <supports-screens> manifest element:

android:requiresSmallestWidthDp
Specifies the minimum smallestWidth required. The smallestWidth is the shortest dimension of the screen space (in dp units) that must be available to your application UI—that is, the shortest of the available screen’s two dimensions. So, in order for a device to be considered compatible with your application, the device’s smallestWidth must be equal to or greater than this value. (Usually, the value you supply for this is the “smallest width” that your layout supports, regardless of the screen’s current orientation.)For example, if your application is only for tablet-style devices with a 600dp smallest available width:

<manifest ... >
    <supports-screens android:requiresSmallestWidthDp="600" />
    ...
</manifest>

However, if your application supports all screen sizes supported by Android (as small as 426dp x 320dp), then you don’t need to declare this attribute, because the smallest width your application requires is the smallest possible on any device.

Caution: The Android system does not pay attention to this attribute, so it does not affect how your application behaves at runtime. Instead, it is used to enable filtering for your application on services such as Google Play. However, Google Play currently does not support this attribute for filtering (on Android 3.2), so you should continue using the other size attributes if your application does not support small screens.

android:compatibleWidthLimitDp
This attribute allows you to enable screen compatibility mode as a user-optional feature by specifying the maximum “smallest width” that your application supports. If the smallest side of a device’s available screen is greater than your value here, users can still install your application, but are offered to run it in screen compatibility mode. By default, screen compatibility mode is disabled and your layout is resized to fit the screen as usual, but a button is available in the system bar that allows users to toggle screen compatibility mode on and off.

Note: If your application’s layout properly resizes for large screens, you do not need to use this attribute. We recommend that you avoid using this attribute and instead ensure your layout resizes for larger screens by following the recommendations in this document.

android:largestWidthLimitDp
This attribute allows you to force-enable screen compatibility mode by specifying the maximum “smallest width” that your application supports. If the smallest side of a device’s available screen is greater than your value here, the application runs in screen compatibility mode with no way for the user to disable it.

Note: If your application’s layout properly resizes for large screens, you do not need to use this attribute. We recommend that you avoid using this attribute and instead ensure your layout resizes for larger screens by following the recommendations in this document.

Caution: When developing for Android 3.2 and higher, you should not use the older screen size attributes in combination with the attributes listed above. Using both the new attributes and the older size attributes might cause unexpected behavior.

For more information about each of these attributes, follow the respective links above.

Best Practices


The objective of supporting multiple screens is to create an application that can function properly and look good on any of the generalized screen configurations supported by Android. The previous sections of this document provide information about how Android adapts your application to screen configurations and how you can customize the look of your application on different screen configurations. This section provides some additional tips and an overview of techniques that help ensure that your application scales properly for different screen configurations.

Here is a quick checklist about how you can ensure that your application displays properly on different screens:

  1. Use wrap_content, match_parent, or dp units when specifying dimensions in an XML layout file
  2. Do not use hard coded pixel values in your application code
  3. Do not use AbsoluteLayout (it’s deprecated)
  4. Supply alternative bitmap drawables for different screen densities

The following sections provide more details.

1. Use wrap_content, match_parent, or the dp unit for layout dimensions

When defining the android:layout_width and android:layout_height for views in an XML layout file, using "wrap_content", "match_parent" or dpunits guarantees that the view is given an appropriate size on the current device screen.

For instance, a view with a layout_width="100dp" measures 100 pixels wide on medium-density screen and the system scales it up to 150 pixels wide on high-density screen, so that the view occupies approximately the same physical space on the screen.

Similarly, you should prefer the sp (scale-independent pixel) to define text sizes. The sp scale factor depends on a user setting and the system scales the size the same as it does for dp.

2. Do not use hard-coded pixel values in your application code

For performance reasons and to keep the code simpler, the Android system uses pixels as the standard unit for expressing dimension or coordinate values. That means that the dimensions of a view are always expressed in the code using pixels, but always based on the current screen density. For instance, if myView.getWidth() returns 10, the view is 10 pixels wide on the current screen, but on a device with a higher density screen, the value returned might be 15. If you use pixel values in your application code to work with bitmaps that are not pre-scaled for the current screen density, you might need to scale the pixel values that you use in your code to match the un-scaled bitmap source.

If your application manipulates bitmaps or deals with pixel values at runtime, see the section below about Additional Density Considerations.

3. Do not use AbsoluteLayout

Unlike the other layouts widgets, AbsoluteLayout enforces the use of fixed positions to lay out its child views, which can easily lead to user interfaces that do not work well on different displays. Because of this, AbsoluteLayout was deprecated in Android 1.5 (API Level 3).

You should instead use RelativeLayout, which uses relative positioning to lay out its child views. For instance, you can specify that a button widget should appear “to the right of” a text widget.

4. Use size and density-specific resources

Although the system scales your layout and drawable resources based on the current screen configuration, you may want to make adjustments to the UI on different screen sizes and provide bitmap drawables that are optimized for different densities. This essentially reiterates the information from earlier in this document.

If you need to control exactly how your application will look on various screen configurations, adjust your layouts and bitmap drawables in configuration-specific resource directories. For example, consider an icon that you want to display on medium and high-density screens. Simply create your icon at two different sizes (for instance 100×100 for medium-density and 150×150 for high-density) and put the two variations in the appropriate directories, using the proper qualifiers:

res/drawable-mdpi/icon.png   //for medium-density screens
res/drawable-hdpi/icon.png   //for high-density screens

Note: If a density qualifier is not defined in a directory name, the system assumes that the resources in that directory are designed for the baseline medium density and will scale for other densities as appropriate.

For more information about valid configuration qualifiers, see Using configuration qualifiers, earlier in this document.

Additional Density Considerations


This section describes more about how Android performs scaling for bitmap drawables on different screen densities and how you can further control how bitmaps are drawn on different densities. The information in this section shouldn’t be important to most applications, unless you have encountered problems in your application when running on different screen densities or your application manipulates graphics.

To better understand how you can support multiple densities when manipulating graphics at runtime, you should understand that the system helps ensure the proper scale for bitmaps in the following ways:

  1. Pre-scaling of resources (such as bitmap drawables)Based on the density of the current screen, the system uses any size- or density-specific resources from your application and displays them without scaling. If resources are not available in the correct density, the system loads the default resources and scales them up or down as needed to match the current screen’s density. The system assumes that default resources (those from a directory without configuration qualifiers) are designed for the baseline screen density (mdpi), unless they are loaded from a density-specific resource directory. Pre-scaling is, thus, what the system does when resizing a bitmap to the appropriate size for the current screen density.

    If you request the dimensions of a pre-scaled resource, the system returns values representing the dimensions after scaling. For example, a bitmap designed at 50×50 pixels for an mdpi screen is scaled to 75×75 pixels on an hdpi screen (if there is no alternative resource for hdpi) and the system reports the size as such.

    There are some situations in which you might not want Android to pre-scale a resource. The easiest way to avoid pre-scaling is to put the resource in a resource directory with the nodpi configuration qualifier. For example:

    res/drawable-nodpi/icon.png

    When the system uses the icon.png bitmap from this folder, it does not scale it based on the current device density.

  2. Auto-scaling of pixel dimensions and coordinatesAn application can disable pre-scaling by setting android:anyDensity to "false" in the manifest or programmatically for a Bitmap by settinginScaled to "false". In this case, the system auto-scales any absolute pixel coordinates and pixel dimension values at draw time. It does this to ensure that pixel-defined screen elements are still displayed at approximately the same physical size as they would be at the baseline screen density (mdpi). The system handles this scaling transparently to the application and reports the scaled pixel dimensions to the application, rather than physical pixel dimensions.

    For instance, suppose a device has a WVGA high-density screen, which is 480×800 and about the same size as a traditional HVGA screen, but it’s running an application that has disabled pre-scaling. In this case, the system will “lie” to the application when it queries for screen dimensions, and report 320×533 (the approximate mdpi translation for the screen density). Then, when the application does drawing operations, such as invalidating the rectangle from (10,10) to (100, 100), the system transforms the coordinates by scaling them the appropriate amount, and actually invalidate the region (15,15) to (150, 150). This discrepancy may cause unexpected behavior if your application directly manipulates the scaled bitmap, but this is considered a reasonable trade-off to keep the performance of applications as good as possible. If you encounter this situation, read the following section about Converting dp units to pixel units.

    Usually, you should not disable pre-scaling. The best way to support multiple screens is to follow the basic techniques described above in How to Support Multiple Screens.

If your application manipulates bitmaps or directly interacts with pixels on the screen in some other way, you might need to take additional steps to support different screen densities. For example, if you respond to touch gestures by counting the number of pixels that a finger crosses, you need to use the appropriate density-independent pixel values, instead of actual pixels.

Scaling Bitmap objects created at runtime

Figure 5. Comparison of pre-scaled and auto-scaled bitmaps.

If your application creates an in-memory bitmap (a Bitmap object), the system assumes that the bitmap is designed for the baseline medium-density screen, by default, and auto-scales the bitmap at draw time. The system applies “auto-scaling” to a Bitmap when the bitmap has unspecified density properties. If you don’t properly account for the current device’s screen density and specify the bitmap’s density properties, the auto-scaling can result in scaling artifacts the same as when you don’t provide alternative resources.

To control whether a Bitmap created at runtime is scaled or not, you can specify the density of the bitmap with setDensity(), passing a density constant from DisplayMetrics, such as DENSITY_HIGHor DENSITY_LOW.

If you’re creating a Bitmap using BitmapFactory, such as from a file or a stream, you can useBitmapFactory.Options to define properties of the bitmap as it already exists, which determine if or how the system will scale it. For example, you can use the inDensity field to define the density for which the bitmap is designed and the inScaled field to specify whether the bitmap should scale to match the current device’s screen density.

If you set the inScaled field to false, then you disable any pre-scaling that the system may apply to the bitmap and the system will then auto-scale it at draw time. Using auto-scaling instead of pre-scaling can be more CPU expensive, but uses less memory.

Figure 5 demonstrates the results of the pre-scale and auto-scale mechanisms when loading low (120), medium (160) and high (240) density bitmaps on a high-density screen. The differences are subtle, because all of the bitmaps are being scaled to match the current screen density, however the scaled bitmaps have slightly different appearances depending on whether they are pre-scaled or auto-scaled at draw time.

Note: In Android 3.0 and above, there should be no perceivable difference between pre-scaled and auto-scaled bitmaps, due to improvements in the graphics framework.

Converting dp units to pixel units

In some cases, you will need to express dimensions in dp and then convert them to pixels. Imagine an application in which a scroll or fling gesture is recognized after the user’s finger has moved by at least 16 pixels. On a baseline screen, a user’s must move by 16 pixels / 160 dpi, which equals 1/10th of an inch (or 2.5 mm) before the gesture is recognized. On a device with a high-density display (240dpi), the user’s must move by 16 pixels / 240 dpi, which equals 1/15th of an inch (or 1.7 mm). The distance is much shorter and the application thus appears more sensitive to the user.

To fix this issue, the gesture threshold must be expressed in code in dp and then converted to actual pixels. For example:

// The gesture threshold expressed in dp
private static final float GESTURE_THRESHOLD_DP = 16.0f;

// Get the screen's density scale
final float scale = getResources().getDisplayMetrics().density;
// Convert the dps to pixels, based on density scale
mGestureThreshold = (int) (GESTURE_THRESHOLD_DP * scale + 0.5f);

// Use mGestureThreshold as a distance in pixels...

The DisplayMetrics.density field specifies the scale factor you must use to convert dp units to pixels, according to the current screen density. On a medium-density screen, DisplayMetrics.density equals 1.0; on a high-density screen it equals 1.5; on an extra-high-density screen, it equals 2.0; and on a low-density screen, it equals 0.75. This figure is the factor by which you should multiply the dp units on order to get the actual pixel count for the current screen. (Then add 0.5f to round the figure up to the nearest whole number, when converting to an integer.) For more information, refer to theDisplayMetrics class.

However, instead of defining an arbitrary threshold for this kind of event, you should use pre-scaled configuration values that are available fromViewConfiguration.

Using pre-scaled configuration values

You can use the ViewConfiguration class to access common distances, speeds, and times used by the Android system. For instance, the distance in pixels used by the framework as the scroll threshold can be obtained with getScaledTouchSlop():

private static final int GESTURE_THRESHOLD_DP = ViewConfiguration.get(myContext).getScaledTouchSlop();

Methods in ViewConfiguration starting with the getScaled prefix are guaranteed to return a value in pixels that will display properly regardless of the current screen density.

How to Test Your Application on Multiple Screens


Figure 6. A set of AVDs for testing screens support.

Before publishing your application, you should thoroughly test it in all of the supported screen sizes and densities. The Android SDK includes emulator skins you can use, which replicate the sizes and densities of common screen configurations on which your application is likely to run. You can also modify the default size, density, and resolution of the emulator skins to replicate the characteristics of any specific screen. Using the emulator skins and additional custom configurations allows you to test any possible screen configuration, so you don’t have to buy various devices just to test your application’s screen support.

To set up an environment for testing your application’s screen support, you should create a series of AVDs (Android Virtual Devices), using emulator skins and screen configurations that emulate the screen sizes and densities you want your application to support. To do so, you can use the AVD Manager to create the AVDs and launch them with a graphical interface.

To launch the Android SDK Manager, execute the SDK Manager.exe from your Android SDK directory (on Windows only) or execute android from the<sdk>/tools/ directory (on all platforms). Figure 6 shows the AVD Manager with a selection of AVDs, for testing various screen configurations.

Table 3 shows the various emulator skins that are available in the Android SDK, which you can use to emulate some of the most common screen configurations.

For more information about creating and using AVDs to test your application, see Managing AVDs with AVD Manager.

Table 3. Various screen configurations available from emulator skins in the Android SDK (indicated in bold) and other representative resolutions.

Low density (120), ldpi Medium density (160), mdpi High density (240), hdpi Extra-high-density (320), xhdpi
Small screen QVGA (240×320) 480×640
Normal screen WQVGA400 (240×400)
WQVGA432 (240×432)
HVGA (320×480) WVGA800 (480×800)
WVGA854 (480×854)
600×1024
640×960
Large screen WVGA800** (480×800)
WVGA854** (480×854)
WVGA800* (480×800)
WVGA854* (480×854)
600×1024
Extra-Large screen 1024×600 WXGA (1280×800)
1024×768
1280×768
1536×1152
1920×1152
1920×1200
2048×1536
2560×1536
2560×1600
* To emulate this configuration, specify a custom density of 160 when creating an AVD that uses a WVGA800 or WVGA854 skin.
** To emulate this configuration, specify a custom density of 120 when creating an AVD that uses a WVGA800 or WVGA854 skin.
† This skin is available with the Android 3.0 platform

To see the relative numbers of active devices that support any given screen configuration, see the Screen Sizes and Densities dashboard.

Figure 7. Size and density options you can set, when starting an AVD from the AVD Manager.

We also recommend that you test your application in an emulator that is set up to run at a physical size that closely matches an actual device. This makes it a lot easier to compare the results at various sizes and densities. To do so you need to know the approximate density, in dpi, of your computer monitor (for instance, a 30″ Dell monitor has a density of about 96 dpi). When you launch an AVD from the AVD Manager, you can specify the screen size for the emulator and your monitor dpi in the Launch Options, as shown in figure 7.

If you would like to test your application on a screen that uses a resolution or density not supported by the built-in skins, you can create an AVD that uses a custom resolution or density. When creating the AVD from the AVD Manager, specify the Resolution, instead of selecting a Built-in Skin.

If you are launching your AVD from the command line, you can specify the scale for the emulator with the -scaleoption. For example:

emulator -avd <avd_name> -scale 96dpi

To refine the size of the emulator, you can instead pass the -scale option a number between 0.1 and 3 that represents the desired scaling factor.

For more information about creating AVDs from the command line, see Managing AVDs from the Command Line.

Creating a Background Service in Android Using IntentService

In this tutorial we will take a look into one of most important and commonly used Android concept called IntentService. This post explains steps involved in creating a background service in Android using IntentService. Before you start with this post, we recommend you to have a glance at below posts

* Checkout Android Service Tutorial

* Android Networking Tutorial

1. What is IntentService?

IntentService is a subclass of android.app.Service class. A stated intent service allows to handle long running tasks without effecting the application UI thread. This is not bound to any activity so, it is not getting effected for any change in activity lifecycle. Once IntentService is started, it handles each Intent using a worker thread and stops itself when it runs out of work.

IntentService would be an best solution, If you have an work queue to process. For example, if your application using analytics you will likely to send event name and related parameter to your tracking server for each user generated event. Although each event means a tiny piece of data, creating networking request on each click will result an overhead to your application. Instead, you can use work queue processor design pattern and process the events in a batch.

2. IntentService Limitations

  1. No easy or direct way to interact with user interface directly from IntentService. Later in this example, we will explain to pass result back from IntentService to
  2. With IntentService, there can only be one request processed at any single point of time. If you request for another task, then the new job will wait until the previous one is completed. This means that IntentService process the request
  3. An tasks stated using IntentService cannot be interrupted

3. Why do we need IntentService?

Android design guidelines strongly suggests to perform all the long running tasks off the UI thread. For example, if you have to periodically download the largest chunk of data from server, you must use IntentService to avoid ANR. ANR (Application not responding) message often occurs, if your main thread is doing too much of work. In this course of this tutorial, we will learn the below concepts

  1. How to create and use IntentService
  2. How to pass data from activity to service as parameter
  3. How to pass result back to activity
  4. Update activity based on the result

Case Study

To make this tutorial easy to understand we will extend our previous tutorial (Android Networking Tutorial) to use Intent Service for downloading the data from server. We suggest you to checkout Android Networking Example to get familiar with downloading data from server using different http clients available in Android.

Feed Url : http://stacktips.com/api/get_category_posts/?dev=1&slug=android

Expected Result Start service to download the data when application is started. Once download is complete, update ListView present in your activity.

Feed Response Object

JSON Feed Response

4. Create an IntentService

In the context of our example, we will create an IntentService to download the data from server. Once download is completed, the response will be sent back to activity. Lets create a new class DownloadService.java and extend it fromandroid.app.IntentService. Now let us override onHandleIntent() method.

When service is started the onHandleIntent() method is called on the worker thread.Unlike Service, IntentService stops itself once it completes its task, so you don’t need to call stopSelf() for stoping the IntentService.

package com.javatechig.intentserviceexample;

import android.app.IntentService;
import android.content.Intent;
import android.os.Bundle;
import android.os.ResultReceiver;
import android.text.TextUtils;
import android.util.Log;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;

public class DownloadService extends IntentService {

    public static final int STATUS_RUNNING = 0;
    public static final int STATUS_FINISHED = 1;
    public static final int STATUS_ERROR = 2;

    private static final String TAG = "DownloadService";

    public DownloadService() {
        super(DownloadService.class.getName());
    }

    @Override
    protected void onHandleIntent(Intent intent) {

        Log.d(TAG, "Service Started!");

        final ResultReceiver receiver = intent.getParcelableExtra("receiver");
        String url = intent.getStringExtra("url");

        Bundle bundle = new Bundle();

        if (!TextUtils.isEmpty(url)) {
            /* Update UI: Download Service is Running */
            receiver.send(STATUS_RUNNING, Bundle.EMPTY);

            try {
                String[] results = downloadData(url);

                /* Sending result back to activity */
                if (null != results && results.length > 0) {
                    bundle.putStringArray("result", results);
                    receiver.send(STATUS_FINISHED, bundle);
                }
            } catch (Exception e) {

                /* Sending error message back to activity */
                bundle.putString(Intent.EXTRA_TEXT, e.toString());
                receiver.send(STATUS_ERROR, bundle);
            }
        }
        Log.d(TAG, "Service Stopping!");
        this.stopSelf();
    }

    private String[] downloadData(String requestUrl) throws IOException, DownloadException {
        InputStream inputStream = null;
        HttpURLConnection urlConnection = null;

        /* forming th java.net.URL object */
        URL url = new URL(requestUrl);
        urlConnection = (HttpURLConnection) url.openConnection();

        /* optional request header */
        urlConnection.setRequestProperty("Content-Type", "application/json");

        /* optional request header */
        urlConnection.setRequestProperty("Accept", "application/json");

        /* for Get request */
        urlConnection.setRequestMethod("GET");
        int statusCode = urlConnection.getResponseCode();

        /* 200 represents HTTP OK */
        if (statusCode == 200) {
            inputStream = new BufferedInputStream(urlConnection.getInputStream());
            String response = convertInputStreamToString(inputStream);
            String[] results = parseResult(response);
            return results;
        } else {
            throw new DownloadException("Failed to fetch data!!");
        }
    }

    private String convertInputStreamToString(InputStream inputStream) throws IOException {

        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
        String line = "";
        String result = "";

        while ((line = bufferedReader.readLine()) != null) {
            result += line;
        }

            /* Close Stream */
        if (null != inputStream) {
            inputStream.close();
        }

        return result;
    }

    private String[] parseResult(String result) {

        String[] blogTitles = null;
        try {
            JSONObject response = new JSONObject(result);
            JSONArray posts = response.optJSONArray("posts");
            blogTitles = new String[posts.length()];

            for (int i = 0; i < posts.length(); i++) {
                JSONObject post = posts.optJSONObject(i);
                String title = post.optString("title");
                blogTitles[i] = title;
            }

        } catch (JSONException e) {
            e.printStackTrace();
        }
        return blogTitles;
    }

    public class DownloadException extends Exception {

        public DownloadException(String message) {
            super(message);
        }

        public DownloadException(String message, Throwable cause) {
            super(message, cause);
        }
    }
}

How it works

  1. DownloadService class extending IntentService and overridingonHandleIntent() method. In onHandleIntent() method we will perform our network request to download data from server
  2. Before it downloads the data from server, the request is being fetched from bundle. Our Activity will send this data as extras while starting the
  3. Once Download is successful we will send the response back to activity viaResultReceiver
  4. For any exceptions or error, we will pass the error response back to activity via ResultReceiver.
  5. We have declared custom exception class DownloadException for handling all our custom error messages. You may do this

5. Declaring Service in the Manifest

Like Service, an IntentService also needs an entry in your application manifest. Provide the element entry and declare all your IntentServices you using. Additionally as we are performing operation to download data from internet, we will request forandroid.permission.INTERNET permission.

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

    <!-- Internet permission, as we are accessing data from server -->
    <uses-permission android:name="android.permission.INTERNET" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme">
        <activity
            android:name=".MyActivity"
            android:label="@string/app_name">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>


        <!-- Declaring Service in Manifest -->
        <service
            android:name=".DownloadService"
            android:exported="false" />

    </application>

</manifest>

6. Sending Work Requests to the IntentService

To start the DownloadService to download data, you must create an explicit Intent and add all the request parameters to it. A service can be started by callingstartService() method. You can start an IntentService either form an Activity or aFragment.

What is the additional DownloadResultReceiver here, huh?. Remember that we have to pass the result of download request from service to activity. This will be done through ResultReceiver.

/* Starting Download Service */
mReceiver = new DownloadResultReceiver(new Handler());
mReceiver.setReceiver(this);
Intent intent = new Intent(Intent.ACTION_SYNC, null, this, DownloadService.class);

/* Send optional extras to Download IntentService */
intent.putExtra("url", url);
intent.putExtra("receiver", mReceiver);
intent.putExtra("requestId", 101);

startService(intent);

7. Report Status From IntentService to Activity

To send the status of a work request in an IntentService to other components, get the instance of ResultReceiver. Send the status by calling send() method.

final ResultReceiver receiver = intent.getParcelableExtra("receiver");
Bundle bundle = new Bundle();

/* Service Started */
receiver.send(STATUS_RUNNING, Bundle.EMPTY);

/* Status Finished */
bundle.putStringArray("result", results);
receiver.send(STATUS_FINISHED, bundle);

/* Sending error message back to activity */
bundle.putString(Intent.EXTRA_TEXT, "Error message here..");
receiver.send(STATUS_ERROR, bundle);

8. Receive Status Broadcasts from an IntentService

To receive results back from IntentService, we can use subclass of ResultReciever. Once results are sent from Service the onReceiveResult() method will be called. Your activity handles this response and fetches the results from the Bundle. Once results are recieved, accordingly the activity instance updates the UI.

DownloadResultReceiver.java

package com.javatechig.intentserviceexample;

import android.os.Bundle;
import android.os.Handler;
import android.os.ResultReceiver;

public class DownloadResultReceiver extends ResultReceiver {
    private Receiver mReceiver;

    public DownloadResultReceiver(Handler handler) {
        super(handler);
    }

    public void setReceiver(Receiver receiver) {
        mReceiver = receiver;
    }

    public interface Receiver {
        public void onReceiveResult(int resultCode, Bundle resultData);
    }

    @Override
    protected void onReceiveResult(int resultCode, Bundle resultData) {
        if (mReceiver != null) {
            mReceiver.onReceiveResult(resultCode, resultData);
        }
    }
}

MainActivity.java

@Override
    public void onReceiveResult(int resultCode, Bundle resultData) {
        switch (resultCode) {
            case DownloadService.STATUS_RUNNING:
                setProgressBarIndeterminateVisibility(true);
                break;
            case DownloadService.STATUS_FINISHED:
                /* Hide progress & extract result from bundle */
                setProgressBarIndeterminateVisibility(false);
                String[] results = resultData.getStringArray("result");

                /* Update ListView with result */
                arrayAdapter = new ArrayAdapter(MyActivity.this, android.R.layout.simple_list_item_2, results);
                listView.setAdapter(arrayAdapter);
                break;
            case DownloadService.STATUS_ERROR:
                /* Handle the error */
                String error = resultData.getString(Intent.EXTRA_TEXT);
                Toast.makeText(this, error, Toast.LENGTH_LONG).show();
                break;
        }
    }

9. Output

Android Networking Example 

11. Download Source Code

Download complete example source code from GitHub

How to add parameters to HttpURLConnection using POST

You can get output stream for the connection and write the parameter query string to it.

URL url = new URL("http://yoururl.com");
HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
conn.setReadTimeout(10000);
conn.setConnectTimeout(15000);
conn.setRequestMethod("POST");
conn.setDoInput(true);
conn.setDoOutput(true);

List<NameValuePair> params = new ArrayList<NameValuePair>();
params.add(new BasicNameValuePair("firstParam", paramValue1));
params.add(new BasicNameValuePair("secondParam", paramValue2));
params.add(new BasicNameValuePair("thirdParam", paramValue3));

OutputStream os = conn.getOutputStream();
BufferedWriter writer = new BufferedWriter(
        new OutputStreamWriter(os, "UTF-8"));
writer.write(getQuery(params));
writer.flush();
writer.close();
os.close();

conn.connect();

private String getQuery(List<NameValuePair> params) throws UnsupportedEncodingException
{
    StringBuilder result = new StringBuilder();
    boolean first = true;

    for (NameValuePair pair : params)
    {
        if (first)
            first = false;
        else
            result.append("&");

        result.append(URLEncoder.encode(pair.getName(), "UTF-8"));
        result.append("=");
        result.append(URLEncoder.encode(pair.getValue(), "UTF-8"));
    }

    return result.toString();
}

Android POST and GET Request using HttpURLConnection Tutorial

Objective

In the tutorial we learn how to send the POST and GET HTTP/HTTPS requests through our android application.

In this tutorial,  we are going to learn about HTTP/HTTPS POST & GET Requests. Http is an underlying protocol used by world wide web. POST and GET are two most commonly used HTTP methods for request and response between the client and the server. GET method basically requests data from specified resource, whereas Post method submits data to be processed to a specified resource.

 

Step 2

Create new project

1. Create a new project in Android Studio. File => New => New Project.

2. Give the application name and then click Next. Select the platform and API and then click Next.

3. Select Empty Activity and click Next. Give the activity name or you can use default name.

4. And finally click Finish.

 

Step 3

Give Permission

You need to provide some permissions to access the internet from your application. So, open your AndroidManifest.xml file and add the following code snippet.

1
<uses-permission android:name="android.permission.INTERNET"/>

 

Step 4

Create layout show response

  1. In activity_main.xml file, add two button named “Send POST Request” and “Send GET Request” and set an on click listener to them. Methods called on onClick() method will be sendPostRequest() and sendGetRequest() respectively.
  2. Add TextView and give it a unique id. So that we can show the response in the textview by calling its id. You can use the code written below:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<Button
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Send POST Request"
    android:id="@+id/sendPost"
    android:layout_alignParentTop="true"
    android:layout_alignParentLeft="true"
    android:layout_alignParentStart="true"
    android:layout_alignRight="@+id/sendGet"
    android:layout_alignEnd="@+id/sendGet"
    android:onClick="sendPostRequest"/>
<Button
    style="?android:attr/buttonStyleSmall"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Send GET Request"
    android:id="@+id/sendGet"
    android:layout_below="@+id/sendPost"
    android:layout_alignParentLeft="true"
    android:layout_alignParentStart="true"
    android:layout_alignParentRight="true"
    android:layout_alignParentEnd="true"
    android:onClick="sendGetRequest"/>
<TextView
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:text="Response..."
    android:id="@+id/showOutput"
    android:layout_below="@+id/sendGet"
    android:layout_alignParentRight="true"
    android:layout_alignParentEnd="true" />

 

screen_1

Step 5

Send Post Request

    1. We have to create a class which sends Post request asynchronously.
      1
      2
      3
      4
      5
      6
      private class PostClass extends AsyncTask<String, Void, Void> {
         @Override
         protected Void doInBackground(String... params) {
             return null;
         }
      }
    2. Get the textview context, then set a url using URL class and parameters in a string.
      1
      2
      3
      final TextView outputView = (TextView) findViewById(R.id.showOutput);
      URL url = new URL("Your URL");</pre>
      <pre>String urlParameters = "fizz=buzz";
    3. Now open the connection using HttpURLConnection and set its properties like method, user_agent and language.
      1
      2
      3
      4
      5
      HttpURLConnection connection = (HttpURLConnection)url.openConnection();
      connection.setRequestMethod("POST");
      connection.setRequestProperty("USER-AGENT", "Mozilla/5.0");
      connection.setRequestProperty("ACCEPT-LANGUAGE", "en-US,en;0.5");
      connection.setDoOutput(true);  // You need to set it to true if you want to send (output) a request body, for example with POST or PUT requests. Sending the request body itself is done via the connection's output stream:
    4. Now, we have to use DataOutPutStream for controlling the output. We can do multiple operation on output stream using DataOutPutStream, It also helps us to write primitive Java data types to an output stream.
      1
      2
      3
      4
      DataOutputStream dStream = new DataOutputStream(connection.getOutputStream());
      dStream.writeBytes(urlParameters); //Writes out the string to the underlying output stream as a sequence of bytes
      dStream.flush(); // Flushes the data output stream.
      dStream.close(); // Closing the output stream.
    5. Next step in the process would be getting the response from server using BufferedReader. It reads text from a character-input stream, buffering characters so as to provide for efficient reading of characters, arrays, and lines.
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      int responseCode = connection.getResponseCode(); // getting the response code
      final StringBuilder output = new StringBuilder("Request URL " + url);
      output.append(System.getProperty("line.separator") + "Request Parameters " + urlParameters);
      output.append(System.getProperty("line.separator")  + "Response Code " + responseCode);
      BufferedReader br = new BufferedReader(new InputStreamReader(connection.getInputStream()));
      String line = "";
      StringBuilder responseOutput = new StringBuilder();
      System.out.println("output===============" + br);
      while((line = br.readLine()) != null ) {
         responseOutput.append(line);
      }
      br.close();
      output.append(System.getProperty("line.separator") + "Response " + System.getProperty("line.separator") + System.getProperty("line.separator") + responseOutput.toString());
    6. Set the response in TextView.
      1
      2
      3
      4
      5
      6
      7
      8
      MainActivity.this.runOnUiThread(new Runnable() {
         @Override
         public void run() {
             outputView.setText(output);;
         }
      });
    7. Execute it by calling its setPostRequest method.
      1
      2
      3
      public void sendPostRequest(View View) {
         new PostClass(this).execute();
      }

Here is the final code for PostClass :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
public void sendPostRequest(View View) {
    new PostClass(this).execute();
}
private class PostClass extends AsyncTask<String, Void, Void> {
    private final Context context;
    public PostClass(Context c){
        this.context = c;
    }
    protected void onPreExecute(){
        progress= new ProgressDialog(this.context);
        progress.setMessage("Loading");
        progress.show();
    }
    @Override
    protected Void doInBackground(String... params) {
        try {
            final TextView outputView = (TextView) findViewById(R.id.showOutput);
            URL url = new URL("Your URL");
            HttpURLConnection connection = (HttpURLConnection)url.openConnection();
            String urlParameters = "fizz=buzz";
            connection.setRequestMethod("POST");
            connection.setRequestProperty("USER-AGENT", "Mozilla/5.0");
            connection.setRequestProperty("ACCEPT-LANGUAGE", "en-US,en;0.5");
            connection.setDoOutput(true);
            DataOutputStream dStream = new DataOutputStream(connection.getOutputStream());
            dStream.writeBytes(urlParameters);
            dStream.flush();
            dStream.close();
            int responseCode = connection.getResponseCode();
            final StringBuilder output = new StringBuilder("Request URL " + url);
            output.append(System.getProperty("line.separator") + "Request Parameters " + urlParameters);
            output.append(System.getProperty("line.separator")  + "Response Code " + responseCode);
            output.append(System.getProperty("line.separator")  + "Type " + "POST");
            BufferedReader br = new BufferedReader(new InputStreamReader(connection.getInputStream()));
            String line = "";
            StringBuilder responseOutput = new StringBuilder();
            System.out.println("output===============" + br);
            while((line = br.readLine()) != null ) {
                responseOutput.append(line);
            }
            br.close();
            output.append(System.getProperty("line.separator") + "Response " + System.getProperty("line.separator") + System.getProperty("line.separator") + responseOutput.toString());
            MainActivity.this.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    outputView.setText(output);
                    progress.dismiss();
                }
            });
        } catch (MalformedURLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return null;
    }
}

screen_2

screen_3

 

Step 6

Send Get Request

Now we are going to send the GET HTTP request. For this, we need to change a few lines in the above code.

  1. Create another class and name it GetClass.
    1
    2
    3
    4
    5
    6
    private class GetClass extends AsyncTask<String, Void, Void> {
         @Override
         protected Void doInBackground(String... params) {
         }
    }
  2. Change the request method from POST to GET
    1
    connection.setRequestMethod("GET");
  3. Remove the DataOutPutStream code because we don’t have to send the parameters for post request.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
        private class GetClass extends AsyncTask<String, Void, Void> {
            private final Context context;
            public GetClass(Context c){
                this.context = c;
            }
            protected void onPreExecute(){
                progress= new ProgressDialog(this.context);
                progress.setMessage("Loading");
                progress.show();
            }
            @Override
            protected Void doInBackground(String... params) {
                try {
                    final TextView outputView = (TextView) findViewById(R.id.showOutput);
                    URL url = new URL("Your URL");</pre>
    <pre>
     HttpURLConnection connection = (HttpURLConnection)url.openConnection();
     String urlParameters = "fizz=buzz";
     connection.setRequestMethod("GET");
     connection.setRequestProperty("USER-AGENT", "Mozilla/5.0");
     connection.setRequestProperty("ACCEPT-LANGUAGE", "en-US,en;0.5");
     int responseCode = connection.getResponseCode();
     final StringBuilder output = new StringBuilder("Request URL " + url);
     output.append(System.getProperty("line.separator") + "Response Code " + responseCode);
     output.append(System.getProperty("line.separator") + "Type " + "GET");
     BufferedReader br = new BufferedReader(new InputStreamReader(connection.getInputStream()));
     String line = "";
     StringBuilder responseOutput = new StringBuilder();
     System.out.println("output===============" + br);
     while((line = br.readLine()) != null ) {
     responseOutput.append(line);
     }
     br.close();
     output.append(System.getProperty("line.separator") + "Response " + System.getProperty("line.separator") + System.getProperty("line.separator") + responseOutput.toString());
     MainActivity.this.runOnUiThread(new Runnable() {
     @Override
     public void run() {
     outputView.setText(output);
     progress.dismiss();
     }
     });
     } catch (MalformedURLException e) {
     // TODO Auto-generated catch block
     e.printStackTrace();
     } catch (IOException e) {
     // TODO Auto-generated catch block
     e.printStackTrace();
     }
     return null;
     }
     }
  4. Execute it by calling sendGetRequest method.
    1
    2
    3
    public void sendGetRequest(View View) {
        new GetClass(this).execute();
    }

screen_5

screen_6

 

Step 7

Final code of MainActivity.java file

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
package com.numetriclabz.sendrequests;
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import javax.net.ssl.HttpsURLConnection;
import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Context;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.view.View;
import android.widget.TextView;
public class MainActivity extends Activity {
    private ProgressDialog progress;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
    public void sendPostRequest(View View) {
        new PostClass(this).execute();
    }
    public void sendGetRequest(View View) {
        new GetClass(this).execute();
    }
    private class PostClass extends AsyncTask<String, Void, Void> {
        private final Context context;
        public PostClass(Context c){
            this.context = c;
        }
        protected void onPreExecute(){
            progress= new ProgressDialog(this.context);
            progress.setMessage("Loading");
            progress.show();
        }
        @Override
        protected Void doInBackground(String... params) {
            try {
                final TextView outputView = (TextView) findViewById(R.id.showOutput);
                URL url = new URL("Your URL");</pre>
<pre>
 HttpURLConnection connection = (HttpURLConnection)url.openConnection();
 String urlParameters = "fizz=buzz";
 connection.setRequestMethod("POST");
 connection.setRequestProperty("USER-AGENT", "Mozilla/5.0");
 connection.setRequestProperty("ACCEPT-LANGUAGE", "en-US,en;0.5");
 connection.setDoOutput(true);
 DataOutputStream dStream = new DataOutputStream(connection.getOutputStream());
 dStream.writeBytes(urlParameters);
 dStream.flush();
 dStream.close();
 int responseCode = connection.getResponseCode();
 System.out.println("\nSending 'POST' request to URL : " + url);
 System.out.println("Post parameters : " + urlParameters);
 System.out.println("Response Code : " + responseCode);
 final StringBuilder output = new StringBuilder("Request URL " + url);
 output.append(System.getProperty("line.separator") + "Request Parameters " + urlParameters);
 output.append(System.getProperty("line.separator") + "Response Code " + responseCode);
 output.append(System.getProperty("line.separator") + "Type " + "POST");
 BufferedReader br = new BufferedReader(new InputStreamReader(connection.getInputStream()));
 String line = "";
 StringBuilder responseOutput = new StringBuilder();
 System.out.println("output===============" + br);
 while((line = br.readLine()) != null ) {
 responseOutput.append(line);
 }
 br.close();
 output.append(System.getProperty("line.separator") + "Response " + System.getProperty("line.separator") + System.getProperty("line.separator") + responseOutput.toString());
 MainActivity.this.runOnUiThread(new Runnable() {
 @Override
 public void run() {
 outputView.setText(output);
 progress.dismiss();
 }
 });
 } catch (MalformedURLException e) {
 // TODO Auto-generated catch block
 e.printStackTrace();
 } catch (IOException e) {
 // TODO Auto-generated catch block
 e.printStackTrace();
 }
 return null;
 }
 protected void onPostExecute() {
 progress.dismiss();
 }
 }
 private class GetClass extends AsyncTask<String, Void, Void> {
 private final Context context;
 public GetClass(Context c){
 this.context = c;
 }
 protected void onPreExecute(){
 progress= new ProgressDialog(this.context);
 progress.setMessage("Loading");
 progress.show();
 }
 @Override
 protected Void doInBackground(String... params) {
 try {
 final TextView outputView = (TextView) findViewById(R.id.showOutput);
 URL url = new URL("Your URL");</pre>
<pre>
 HttpURLConnection connection = (HttpURLConnection)url.openConnection();
 String urlParameters = "fizz=buzz";
 connection.setRequestMethod("GET");
 connection.setRequestProperty("USER-AGENT", "Mozilla/5.0");
 connection.setRequestProperty("ACCEPT-LANGUAGE", "en-US,en;0.5");
 int responseCode = connection.getResponseCode();
 final StringBuilder output = new StringBuilder("Request URL " + url);
 output.append(System.getProperty("line.separator") + "Response Code " + responseCode);
 output.append(System.getProperty("line.separator") + "Type " + "GET");
 BufferedReader br = new BufferedReader(new InputStreamReader(connection.getInputStream()));
 String line = "";
 StringBuilder responseOutput = new StringBuilder();
 System.out.println("output===============" + br);
 while((line = br.readLine()) != null ) {
 responseOutput.append(line);
 }
 br.close();
 output.append(System.getProperty("line.separator") + "Response " + System.getProperty("line.separator") + System.getProperty("line.separator") + responseOutput.toString());
 MainActivity.this.runOnUiThread(new Runnable() {
 @Override
 public void run() {
 outputView.setText(output);
 progress.dismiss();
 }
 });
 } catch (MalformedURLException e) {
 // TODO Auto-generated catch block
 e.printStackTrace();
 } catch (IOException e) {
 // TODO Auto-generated catch block
 e.printStackTrace();
 }
 return null;
 }
 }
}

How to use HttpURLConnection POST data to web server?

Here is one sample.

  ...
  public static String excutePost(String targetURL, String urlParameters)
  {
    URL url;
    HttpURLConnection connection = null;  
    try {
      //Create connection
      url = new URL(targetURL);
      connection = (HttpURLConnection)url.openConnection();
      connection.setRequestMethod("POST");
      connection.setRequestProperty("Content-Type", 
           "application/x-www-form-urlencoded");
			
      connection.setRequestProperty("Content-Length", "" + 
               Integer.toString(urlParameters.getBytes().length));
      connection.setRequestProperty("Content-Language", "en-US");  
			
      connection.setUseCaches (false);
      connection.setDoInput(true);
      connection.setDoOutput(true);

      //Send request
      DataOutputStream wr = new DataOutputStream (
                  connection.getOutputStream ());
      wr.writeBytes (urlParameters);
      wr.flush ();
      wr.close ();

      //Get Response	
      InputStream is = connection.getInputStream();
      BufferedReader rd = new BufferedReader(new InputStreamReader(is));
      String line;
      StringBuffer response = new StringBuffer(); 
      while((line = rd.readLine()) != null) {
        response.append(line);
        response.append('\r');
      }
      rd.close();
      return response.toString();

    } catch (Exception e) {

      e.printStackTrace();
      return null;

    } finally {

      if(connection != null) {
        connection.disconnect(); 
      }
    }
  }
  ...

The urlParameters is a URL encoded string.

 String urlParameters =
        "fName=" + URLEncoder.encode("???", "UTF-8") +
        "&lName=" + URLEncoder.encode("???", "UTF-8")