Build real weather app: JSON, HTTP and Openweathermap

by JFrankie, May 21, 2013
In this post I want to describe how to create a weather app that gives current weather information. This app will use JSON, HTTP connection and AsyncTask to get this information.. As weather provider I will use OpenWeatherMap a free weather service that provides some interesting API really easy to use.I will guide you through the steps necessary to build up a working app. For more information about API, you can visit the OpenWeatherMap web site. I will show to you the final result so you can have an idea about what we will do in this post.




Current weather info – HTTP Request and JSON Response

OpenWeatherMap offers several API to use to get weather information. We want to use the one that gives us the current weather info. The URL to call to get this info is:
http://api.openweathermap.org/data/2.5/weather?q=city,country
Let’s suppose we want to know the weather in Rome, IT. Using our browser we can have:

weather_api_search
As we can see we have JSON response. Formatting the response we have
{
  "coord":{"lon":12.4958,"lat":41.903},
  "sys":{"country":"Italy","sunrise":1369107818,"sunset":1369160979},
  "weather":[{
        "id":802,"main":"Clouds","description":"scattered clouds",
         "icon":"03d"}],
   "base":"global stations",
   "main":{
           "temp":290.38,
           "humidity":68,
           "pressure":1015,
           "temp_min":287.04,
           "temp_max":293.71},
    "wind":{ 
           "speed":1.75,
           "deg":290.002},
    "clouds":{"all":32},
    "dt":1369122932,
    "id":3169070,
    "name":"Rome",
    "cod":200
}
So the first thing we need to do is creating our data model so that we can parse the response and convert it into Java classes. Analyzing the response we have different “main” tags that we can use as class in Java:
  • coord (object)
  • sys (object)
  • weather (array)
  • main (object)
  • wind (object)
  • name: (String)

The response is quite simple and we can convert it manually. The UML class diagram for the model is shown below:



JSON Weather Parser

Once we have created our model we have to parse it. We can create a specific class that handles this task. First we have to create the “root” object that receive as input the entire string containing all the JSON response:
// We create out JSONObject from the data
JSONObject jObj = new JSONObject(data);

Then we start parsing each piece of the response:
// We start extracting the info
Location loc = new Location();

JSONObject coordObj = getObject("coord", jObj);
loc.setLatitude(getFloat("lat", coordObj));
loc.setLongitude(getFloat("lon", coordObj));

JSONObject sysObj = getObject("sys", jObj);
loc.setCountry(getString("country", sysObj));
loc.setSunrise(getInt("sunrise", sysObj));
loc.setSunset(getInt("sunset", sysObj));
loc.setCity(getString("name", jObj));
weather.location = loc;

In the line 4,8 we create two “sub” object (coordObj and sysObj) having as parent the jObj as it clear from the JSON response. As we can see we use some helper methods to get String,int and float values:
private static JSONObject getObject(String tagName, JSONObject jObj)  throws JSONException {
    JSONObject subObj = jObj.getJSONObject(tagName);
    return subObj;
}

private static String getString(String tagName, JSONObject jObj) throws JSONException {
    return jObj.getString(tagName);
}

private static float  getFloat(String tagName, JSONObject jObj) throws JSONException {
    return (float) jObj.getDouble(tagName);
}

private static int  getInt(String tagName, JSONObject jObj) throws JSONException {
    return jObj.getInt(tagName);
}

And then we finally parse the weather information. We have to remember that weather tag is an array so we have to handle it differently
// We get weather info (This is an array)
JSONArray jArr = jObj.getJSONArray("weather");

// We use only the first value
JSONObject JSONWeather = jArr.getJSONObject(0);
weather.currentCondition.setWeatherId(getInt("id", JSONWeather));
weather.currentCondition.setDescr(getString("description", JSONWeather));
weather.currentCondition.setCondition(getString("main", JSONWeather));
weather.currentCondition.setIcon(getString("icon", JSONWeather));

JSONObject mainObj = getObject("main", jObj);
weather.currentCondition.setHumidity(getInt("humidity", mainObj));
weather.currentCondition.setPressure(getInt("pressure", mainObj));
weather.temperature.setMaxTemp(getFloat("temp_max", mainObj));
weather.temperature.setMinTemp(getFloat("temp_min", mainObj));
weather.temperature.setTemp(getFloat("temp", mainObj));

// Wind
JSONObject wObj = getObject("wind", jObj);
weather.wind.setSpeed(getFloat("speed", wObj));
weather.wind.setDeg(getFloat("deg", wObj));

// Clouds
JSONObject cObj = getObject("clouds", jObj);
weather.clouds.setPerc(getInt("all", cObj));

At the end we have our Weather class filled with the data retrieved.

HTTP Request and Response

Now we have to exchange information with the remote server using HTTP protocol. We have to send information and then read the response. We covered this topic in the previous post(Android HTTP Client: GET, POST, Download, Upload, Multipart Request) so we won’t describe it again, we simply show the code:
public class WeatherHttpClient {

    private static String BASE_URL = "http://api.openweathermap.org/data/2.5/weather?q=";
    private static String IMG_URL = "http://openweathermap.org/img/w/";

    
    public String getWeatherData(String location) {
        HttpURLConnection con = null ;
        InputStream is = null;

        try {
            con = (HttpURLConnection) ( new URL(BASE_URL + location)).openConnection();
            con.setRequestMethod("GET");
            con.setDoInput(true);
            con.setDoOutput(true);
            con.connect();
            
            // Let's read the response
            StringBuffer buffer = new StringBuffer();
            is = con.getInputStream();
            BufferedReader br = new BufferedReader(new InputStreamReader(is));
            String line = null;
            while (  (line = br.readLine()) != null )
                buffer.append(line + "\r\n");
            
            is.close();
            con.disconnect();
            return buffer.toString();
        }
        catch(Throwable t) {
            t.printStackTrace();
        }
        finally {
            try { is.close(); } catch(Throwable t) {}
            try { con.disconnect(); } catch(Throwable t) {}
        }

        return null;
                
    }
    
    public byte[] getImage(String code) {
        HttpURLConnection con = null ;
        InputStream is = null;
        try {
            con = (HttpURLConnection) ( new URL(IMG_URL + code)).openConnection();
            con.setRequestMethod("GET");
            con.setDoInput(true);
            con.setDoOutput(true);
            con.connect();
            
            // Let's read the response
            is = con.getInputStream();
            byte[] buffer = new byte[1024];
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            
            while ( is.read(buffer) != -1)
                baos.write(buffer);
            
            return baos.toByteArray();
        }
        catch(Throwable t) {
            t.printStackTrace();
        }
        finally {
            try { is.close(); } catch(Throwable t) {}
            try { con.disconnect(); } catch(Throwable t) {}
        }
        
        return null;
        
    }
}


Weather App


Finally, it is the time for our Activity. The layout is very simple and of course it is just a skeleton you need to improve it if you want to have a production app.
<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"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".MainActivity" >

    <TextView
        android:id="@+id/cityText"
        style="?android:attr/textAppearanceMedium"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true" />

    <ImageView
        android:id="@+id/condIcon"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_below="@id/cityText" />

    <TextView
        android:id="@+id/condDescr"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@id/condIcon"
        android:layout_alignLeft="@id/condIcon" 
       />

    <TextView
        android:id="@+id/temp"
        style="@style/tempStyle"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="12dp"
        android:layout_alignBaseline="@id/condDescr"
        android:layout_toRightOf="@id/condDescr"/>

    <TextView
        android:id="@+id/pressLab"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_below="@id/condDescr"
        android:text="Pressure"
        android:layout_marginTop="15dp" />

    <TextView
        android:id="@+id/press"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignBaseline="@id/pressLab"
        android:layout_toRightOf="@id/pressLab" 
        style="@style/valData"/>

    <TextView
        android:id="@+id/humLab"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_below="@id/pressLab"
        android:text="Humidity" />

    <TextView
        android:id="@+id/hum"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignBaseline="@id/humLab"
        android:layout_toRightOf="@id/humLab" 
        android:layout_marginLeft="4dp"
        style="@style/valData"/>

    <TextView
        android:id="@+id/windLab"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_below="@id/humLab"
        android:text="Wind" />

    <TextView
        android:id="@+id/windSpeed"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignBaseline="@id/windLab"
        android:layout_toRightOf="@id/windLab"
        android:layout_marginLeft="4dp"
        style="@style/valData" />

    <TextView
        android:id="@+id/windDeg"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignBaseline="@id/windLab"
        android:layout_toRightOf="@id/windSpeed"
        android:layout_marginLeft="4dp" 
        style="@style/valData"/>

</RelativeLayout>



In onCreate method we simply get the reference to the Views inside the layout so that we can populate them later after the request is completed.
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    String city = "Rome,IT";
    
    cityText = (TextView) findViewById(R.id.cityText);
    condDescr = (TextView) findViewById(R.id.condDescr);
    temp = (TextView) findViewById(R.id.temp);
    hum = (TextView) findViewById(R.id.hum);
    press = (TextView) findViewById(R.id.press);
    windSpeed = (TextView) findViewById(R.id.windSpeed);
    windDeg = (TextView) findViewById(R.id.windDeg);
    imgView = (ImageView) findViewById(R.id.condIcon);
    
    JSONWeatherTask task = new JSONWeatherTask();
    task.execute(new String[]{city});
}

and we start an AsyncTask, because as we already know network operations are time consuming so we can run them in the main thread otherwise we could have an ANR problem. The JSONWeatherTask is very simply
protected Weather doInBackground(String... params) {
    Weather weather = new Weather();
    String data = ( (new WeatherHttpClient()).getWeatherData(params[0]));

    try {
        weather = JSONWeatherParser.getWeather(data);
        
        // Let's retrieve the icon
        weather.iconData = ( (new WeatherHttpClient()).getImage(weather.currentCondition.getIcon()));
        
    } catch (JSONException e) {                
        e.printStackTrace();
    }
    return weather;

    }

At line 3 we make the HTTP request and then we parse it at line 6.

At line 9 we retrieve the icon that shows the weather condition.
Running the code we have:


The source code available @github.

Android HTTP Client: GET, POST, Download, Upload, Multipart Request

by JFrankie, May 8, 2013
Often Android apps have to exchange information with a remote server. The easiest way is to use the HTTP protocol as base to transfer information. There are several scenarios where the HTTP protocol is very useful like downloading an image from a remote server or uploading some binary data to the server. Android app performs GET or POST request to send data. In this post, we want to analyze how to use HttpURLConnection to communicate with a remote server.
We will cover three main topics:

  • GET and POST requests
  • Download data from the server
  • Upload data to the server using MultipartRequest
As a server we will use three simple Servlet running inside Tomcat 7.0. We won't cover how to create a Servlet using API 3.0 but the source code will be available soon.

GET and POST requests

GET and POST requests are the base blocks in HTTP protocol. To make this kind of requests we need first to open a connection toward the remove server:

HttpURLConnection con = (HttpURLConnection) ( new URL(url)).openConnection();
con.setRequestMethod("POST");
con.setDoInput(true);
con.setDoOutput(true);
con.connect();

In the first line we get the HttpURLConnection, while in the line 2 we set the method and at the end we connect to the server.
Once we have opened the connection we can write on it using the OutputStream.

con.getOutputStream().write( ("name=" + name).getBytes());

As we already know parameters are written using key value pair.
The last step is reading the response, using the InputStream:

InputStream is = con.getInputStream();
byte[] b = new byte[1024];
while ( is.read(b) != -1)
  buffer.append(new String(b));
con.disconnect();

Everything is very simple by now, but we have to remember one thing: making an HTTP connection is a time consuming operation that could require long time sometime so we can't run it in the main thread otherwise we could get a ANR problem. To solve it we can use an AsyncTask.

private class SendHttpRequestTask extends AsyncTask<String, Void, String>{
  
  @Override
  protected String doInBackground(String... params) {
   String url = params[0];
   String name = params[1];
   String data = sendHttpRequest(url, name);
   return data;
  }

  @Override
  protected void onPostExecute(String result) {
   edtResp.setText(result);
   item.setActionView(null);   
  }
}

Running the app we get:


android_httpclient_post_get_1android_httpclient_post_get_2

As we can see we post a name to the server and it responds with the classic ‘Hello….’. On the server side we can check that the server received correctly our post parameter:

android_tomcat_post_log

Download data from server

One of the most common scenario is when an Android App has to download some data from a remote sever. We can suppose that we want to download an image from the server. In this case we have always to use an AsyncTask to complete our operation, the code is shown below:
public byte[] downloadImage(String imgName) {
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    try {
        System.out.println("URL ["+url+"] - Name ["+imgName+"]");
        
        HttpURLConnection con = (HttpURLConnection) ( new URL(url)).openConnection();
        con.setRequestMethod("POST");
        con.setDoInput(true);
        con.setDoOutput(true);
        con.connect();
        con.getOutputStream().write( ("name=" + imgName).getBytes());
        
        InputStream is = con.getInputStream();
        byte[] b = new byte[1024];
        
        while ( is.read(b) != -1)
            baos.write(b);
        
        con.disconnect();
    }
    catch(Throwable t) {
        t.printStackTrace();
    }
    
    return baos.toByteArray();
}

This method is called in this way:
private class SendHttpRequestTask extends AsyncTask<String, Void, byte[]> {

    
    @Override
    protected byte[] doInBackground(String... params) {
        String url = params[0];
        String name = params[1];
        
        HttpClient client = new HttpClient(url);
        byte[] data = client.downloadImage(name);
        
        return data;
    }

    @Override
    protected void onPostExecute(byte[] result) {
        Bitmap img = BitmapFactory.decodeByteArray(result, 0, result.length);
        imgView.setImageBitmap(img);
        item.setActionView(null);
        
    }
   
}

Running the app we have:

android_httpclient_post_download

Upload data to the server using MultipartRequest


This the most complex part in handling http connection. Natively HttpURLConnection doesn’t handle this type of request. It can happen that an Android App has to upload some binary data to the server. It can be that an app has to upload an image for example. In this case the request get more complex, because a “normal” request isn’t enough. We have to create a MultipartRequest.

A MultipartRequest is a request that is made by different parts like parameters and binary data. How can we handle this request?

Well the first step is opening a connection informing the server we wants to send some binary info:
public void connectForMultipart() throws Exception {
    con = (HttpURLConnection) ( new URL(url)).openConnection();
    con.setRequestMethod("POST");
    con.setDoInput(true);
    con.setDoOutput(true);
    con.setRequestProperty("Connection", "Keep-Alive");
    con.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary);
    con.connect();
    os = con.getOutputStream();
}

In the line 6 and 7 we specify the request content-type and another field called boundary. This field is a char sequence used to separate different parts.

For each part we want to add we need to specify if it is text part like post parameter or it is a file (so binary data).
public void addFormPart(String paramName, String value) throws Exception {
  writeParamData(paramName, value);
}

private void writeParamData(String paramName, String value) throws Exception {
    os.write( (delimiter + boundary + "\r\n").getBytes());
    os.write( "Content-Type: text/plain\r\n".getBytes());
    os.write( ("Content-Disposition: form-data; name=\"" + paramName + "\"\r\n").getBytes());;
    os.write( ("\r\n" + value + "\r\n").getBytes());
    
}

where
private String delimiter = "--";
private String boundary =  "SwA"+Long.toString(System.currentTimeMillis())+"SwA";
To add a file part we can use:
public void addFilePart(String paramName, String fileName, byte[] data) throws Exception {
    os.write( (delimiter + boundary + "\r\n").getBytes());
    os.write( ("Content-Disposition: form-data; name=\"" + paramName +  "\"; filename=\"" + fileName + "\"\r\n"  ).getBytes());
    os.write( ("Content-Type: application/octet-stream\r\n"  ).getBytes());
    os.write( ("Content-Transfer-Encoding: binary\r\n"  ).getBytes());
    os.write("\r\n".getBytes());
   
    os.write(data);
    
    os.write("\r\n".getBytes());
}

So in our app we have:
private class SendHttpRequestTask extends AsyncTask<String, Void, String> {

    
    @Override
    protected String doInBackground(String... params) {
        String url = params[0];
        String param1 = params[1];
        String param2 = params[2];
        Bitmap b = BitmapFactory.decodeResource(UploadActivity.this.getResources(), R.drawable.logo);
        
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        b.compress(CompressFormat.PNG, 0, baos);

        try {
            HttpClient client = new HttpClient(url);
            client.connectForMultipart();
            client.addFormPart("param1", param1);
            client.addFormPart("param2", param2);
            client.addFilePart("file", "logo.png", baos.toByteArray());
            client.finishMultipart();
            String data = client.getResponse();
        }
        catch(Throwable t) {
            t.printStackTrace();
        }
        
        return null;
    }

    @Override
    protected void onPostExecute(String data) {            
        item.setActionView(null);
        
    }
    
    
    
}

Running it we have:


android_tomcat_post_upload_logandroid_httpclient_post_upload
Source code @ github.

Android ListView animation

by JFrankie, April 22, 2013
We talked about ListView and Custom Adapter, but an aspect we want to consider is how to animate the ListView. In this example we will show how to animate Listview when we delete items using AnimatorListener.
As example we will use an ArrayAdapter that is populated by a large number of items. In this case we will use android.R.layout.simple_list_item_1 as row layout.
We will focus our attention on the item animation. For example we want that selected item will fade until they disappear.
The first thing we need to do is creating our animation. We will an xml file called fade_anim.xml under res/anim.
The xml file is very simple, we define that we want that our animation moves from fade 1 to fade 0 with a linear interpolator.

<?xml version="1.0" encoding="utf-8"?>
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
       android:fromAlpha="1.0" android:toAlpha="0" 
       android:interpolator="@android:anim/linear_interpolator"
       android:duration="1000"/>
 
Now in the main activity we simply populate our ListView with an ArrayAdapter like:

@Override
protected void onCreate(Bundle savedInstanceState) {
     super.onCreate(savedInstanceState);
     setContentView(R.layout.activity_main);
     ListView lv = (ListView) findViewById(R.id.listView);
     List<ItemDetail> itemList = createItems(50);
     final ArrayAdapter<ItemDetail> aAdpt = 
           new ArrayAdapter<ItemDetail>(this,                  
                  android.R.layout.simple_list_item_1, itemList);

     lv.setAdapter(aAdpt);
..
}

Where createItems method simply create items like item1,item2,...
The first thing we have to load is our animation in the onCreate with:

// Load animation
final Animation anim = AnimationUtils.loadAnimation(this, R.anim.fade_anim);

Now we want to start our animation when user clicks on an item inside the ListView. But we need first run the animation and when the animation ends we have to remove item from the list. We need, then, an AnimationListener to coordinate these phases (line 6).
So we have first create the listener and then start the animation (line 21) like:

lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> adapterView, 
                        final View view, final int position,
   long id) {
   anim.setAnimationListener(new Animation.AnimationListener() {               

                         @Override
                  public void onAnimationStart(Animation animation) {
                  }
       
                         @Override
                  public void onAnimationRepeat(Animation animation) {}
     
                 @Override
                 public void onAnimationEnd(Animation animation) {
      ItemDetail item = aAdpt.getItem(position);
      aAdpt.remove(item);
                }
              });
          view.startAnimation(anim);
 }
});

Let's run the app. If we clicks on an item we will see that it works correctly, first starts the fading animation and then the item is removed.
Come back to xml file and make the animation duration longer  (for example 3sec=3000), and run it again. While we click on an item and it starts fading let's scroll the list.
What is happening?
Well we can notice that other items are fading even if we didn't click them at all!! Why??
This is because OS re-use the view with other items. So we need to find a way to tell the to OS that while the item is fading the corresponding view shouldn't be used.
How can we do it?!
Well in the onAnimationStart (line 10), when the animation is starting, we can flag the view with transient state, that tells to the OS to not re-use the view.
When the animation ends (line 20), we tell to the OS that the view can be re-used and set the transient to the default value while we set the fade value to 1.

lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> adapterView, 
                        final View view, final int position,
   long id) {
   anim.setAnimationListener(new Animation.AnimationListener() {               

                         @Override
                  public void onAnimationStart(Animation animation) {
                            view.setHasTransientState(true);
                  }
       
                         @Override
                  public void onAnimationRepeat(Animation animation) {}
     
                 @Override
                 public void onAnimationEnd(Animation animation) {
                            ItemDetail item = aAdpt.getItem(position);
                            aAdpt.remove(item);
                            view.setHasTransientState(false);
                }
              });
          view.startAnimation(anim);
 }
});

Now everything works correctly even if we scroll the ListView while the item is fading.

Source  @ github

Android ListView context menu: ActionMode.CallBack

by JFrankie, April 15, 2013
In this post we want to analyze the context menu (contextual action bar). This is a menu that is related to a specific item. The contextual menu can be applied to almost all views but it is usually used with ListView. We talk a lot about List view, because it is one of the most important component. We can distinguish two different type of contextual menu:
  • Floating menu
  • Contextual action mode (ActionMode)
The floating menu is used with Android version lower than 3.0 (API level 11). It is essentially a menu that appears when an user long click on an ListView item. You can find an example here. It looks like the image shown below:

The contextual action mode is introduced in Android 3.0 or higher and it is essentially a contextual bar that appears on the top when user long clicks an item. According to Android guides this kind of menu is better than the floating menu. In this post we want to analyze how we can create this menu.



Create contextual action Mode: Define ActionMode.CallBack interface

To create a contextual menu we have first to define a ActionMode.CallBack interface. This interface is called when an user long clicks on an ListView item. The code looks like:

 private ActionMode.Callback modeCallBack = new ActionMode.Callback() {
  
   public boolean onPrepareActionMode(ActionMode mode, Menu menu)    
    return false;
   }
 
  public void onDestroyActionMode(ActionMode mode) {
    mode = null;   
   }
  
   public boolean onCreateActionMode(ActionMode mode, Menu menu) {
     return true;
   }
  
   public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
   }
};
 
We are interested on line 11 and line 15. The first one is where we will create our contextual action bar on the top of the screen and in line 15 is where we handle the logic when user chooses one of our menu item.
The first thing we have to do is creating our menu. For simplicity we can suppose we have just two menu items, then we define a file under res/menu called activity_main.xml:


<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:id="@+id/edit"
          android:icon="@android:drawable/ic_menu_edit"/>
      
    <item android:id="@+id/delete"
          android:icon="@android:drawable/ic_menu_delete"/>
    
</menu>

Now we have our menu and we simply have to "inject" it in the onCreateActionMode method.

public boolean onCreateActionMode(ActionMode mode, Menu menu) {
 mode.setTitle("Options");
 mode.getMenuInflater().inflate(R.menu.activity_main, menu);
 return true;
}

Now we have to show this contextual action bar when user long clicks on an item.

ActionMode and Long Click: onItemLongClickListener

If we want to show this contextual bar when user long clicks we have simply set a listener on our ListView, that we call lv in the source code. So we have:


lv.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
   public boolean onItemLongClick (AdapterView parent, View view, int position, long id) {
     System.out.println("Long click");
     startActionMode(modeCallBack);
     view.setSelected(true);
     return true;
   }
});

In line 4 we simply start the contextual menu using startActionMode method. Now the result is:
As you can see in the top we have our contextual action bar.

Contextual menu item selection


Now let's suppose we an user clicks on a menu item. How do we handle this event? Well if we come back at ActionMode.CallBack we have to implement another method onActionItemClicked. So we have:


public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
   
 int id = item.getItemId();
 switch (id) {
   case R.id.delete: {
     aAdpt.remove( aAdpt.getItem(aAdpt.currentSelection) );
            mode.finish();
     break;
          }
          case R.id.edit: {
     System.out.println(" edit ");
            break;
         }
         default:
            return false;

}

In line 6 we simply remove from our adapter the selected item. To know the position of the selected item inside the ListView we store it in the OnItemLongClickListener method.

aAdpt.currentSelection = position;

When we finish handling user menu item selection we have to dismiss the contextual action bar callig mode.finish (line 7).