Android Basic Training Course: Communicating via the Internet

    Most Android devices are preset to access the Internet. It can be Wi-Fi, mobile data services (EDGE, 3G, etc.), or may be something else entirely. Regardless, most people, or at least those who have a data plan or Wi-Fi access will have access to the Internet from their Android phone.
    Not surprisingly,  Android platform for developing a variety of ways to make use of Internet access. Some provide high-level access, such as components integrated WebKit browser. If you want, you can skip all the way and use sockets. In between, you can make use of the API-both on the phone and from a third party offers you access to specific protocols: HTTP, XMPP, SMTP, ...
    The emphasis of this program is to form a higher level of access - WebKit components, discussed in previous chapter, and the Internet access API, discussed in this chapter. Because of the active programmers, we should try to reuse existing components wherever possible considering taking over our own protocol.

Internet permission

    As you can see at some my previous posts, when an application would like to request online data, I always note that we must provide the INTERNET permission in AndroidManifest.xml. So, you must always remember to add this line above <application> tag before start working with Internet:
<uses-permission android:name="android.permission.INTERNET"/>

HTTP Operations via HttpURLConnection 

    Android 6.0 release removes support for the Apache HTTP client (see this post on Google Developer site). If your app is using this client and targets Android 2.3 (API level 9) or higher, use the HttpURLConnection class instead. This API is more efficient because it reduces network use through transparent compression and response caching, and minimizes power consumption. That mean, the package help us to connecting to Internet is still java.net that available in JDK.
    When using it, we can setup a HttpURLConnection from an URL object, get an InputStream which on Internet and parsing it based on it's datatype (Bitmap, JSON, XML, ...).
    Moreover, interacting with Internet process are always declared and done in a background thread (see "Dealing with Threads" post to see more details), unless, you will be crashed with NetworkOnMainThreadException error.
    In next part, I will present the way to get Bitmaps or JSON formatted strings from an URL.

Getting Image from URL on Internet

    From an "image" link (end with .jpg, .png,...), after completed request, we would like to parsing the data response to Bitmap type by using BitmapFactory to decode it. This whole process is done in an AsyncTask as follows:
GetImageTask.java
package info.devexchanges.internet;

import android.app.ProgressDialog;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.widget.Toast;

import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;

public class GetImageTask extends AsyncTask<Void, Void, Bitmap> {

    private final String IMAGE_URL = "http://i.imgur.com/ur4Ye8R.jpg";
    private MainActivity activity;
    private ProgressDialog progressDialog;
    private HttpURLConnection connection;

    public GetImageTask(MainActivity activity) {
        this.activity = activity;
        progressDialog = ProgressDialog.show(activity, "Connecting...", "Downloading Image...", true);
    }

    @Override
    protected Bitmap doInBackground(Void... params) {
        try {
            //get Image from URL by URLConnection
            URL url = new URL(IMAGE_URL);
            connection = (HttpURLConnection) url.openConnection();
            connection.setDoInput(true);
            connection.connect();

            //InputStream and decode to Bitmap
            InputStream input = connection.getInputStream();
            Bitmap bmp = BitmapFactory.decodeStream(input);

            return bmp;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        } finally {
            connection.disconnect();
        }
    }

    @Override
    protected void onPostExecute(Bitmap bitmap) {
        super.onPostExecute(bitmap);
        progressDialog.dismiss(); //dismiss progress bar when task finished!
        if (bitmap == null) {
            Toast.makeText(activity, "Wrong Link!", Toast.LENGTH_SHORT).show();
        } else {
            //call back data to UI thread
            activity.getBackBitmap(bitmap);
        }
    }
}
    As you see in the AsyncTask code, after it finish this work, calling back data to UI thread in onPostExecute() by invoke getBackBitmap() method. So, go to your Activity code and add this:
public void getBackBitmap(Bitmap bitmap) {
        ImageView imageView = (ImageView) findViewById(R.id.image);
        imageView.setImageBitmap(bitmap);
    }
    Of course, through execute(), we can invoke an AsyncTask instance:
new GetImageTask(MainActivity.this).execute();
Note: With downloading images from Internet, there are many external libraries to make your work easier. See this post to learning about Picasso and UniversalImageLoader.

Get JSON from an URL

    Likely with the case above, but now the InputStream response is a string with JSON format. So, we must use a BufferedReader object to read all lines. This AsyncTask will be similar:
GetJSONTask.java
package info.devexchanges.internet;

import android.app.ProgressDialog;
import android.os.AsyncTask;

import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;

public class GetJSONTask extends AsyncTask<Void, Void, String> {

    private HttpURLConnection urlConnection;
    private final String JSON_URL = "http://api.openweathermap.org/data/2.5/weather?q=hanoi,vn&appid=2de143494c0b295cca9337e1e96b00e0";
    private MainActivity activity;
    private ProgressDialog progressDialog;

    public GetJSONTask(MainActivity activity) {
        this.activity = activity;
        progressDialog = ProgressDialog.show(activity, "Connecting...", "Downloading JSON...", true);
    }
    @Override
    protected String doInBackground(Void... params) {

        StringBuilder result = new StringBuilder();

        try {
            URL url = new URL(JSON_URL);
            urlConnection = (HttpURLConnection) url.openConnection();
            InputStream in = new BufferedInputStream(urlConnection.getInputStream());

            BufferedReader reader = new BufferedReader(new InputStreamReader(in));

            String line;
            while ((line = reader.readLine()) != null) {
                result.append(line);
            }
        }catch( Exception e) {
            e.printStackTrace();
        }
        finally {
            urlConnection.disconnect();
        }

        return result.toString();
    }

    @Override
    protected void onPostExecute(String result) {
        progressDialog.dismiss(); //dismiss dialog
        activity.parsingJSONResponse(result); //call back data to UI thread
    }
}
    With JSON_URL link above, the response JSON data will be like this:
{
  "coord": {
    "lon": 105.85,
    "lat": 21.03
  },
  "weather": [
    {
      "id": 803,
      "main": "Clouds",
      "description": "broken clouds",
      "icon": "04d"
    }
  ],
  "main": {
    "temp": 287.85,
    "pressure": 1024.05,
    "humidity": 89,
    "temp_min": 287.85,
    "temp_max": 287.85
  },
  "sys": {
    "message": 0.0082,
    "country": "VN",
    "sunrise": 1453160172,
    "sunset": 1453199888
  },
  "id": 1561096,
  "name": "Xóm Pho",
  "cod": 200
}
    So, we can get JSONObjects, JSONArrays based on each element name:
        // parsing json and set the custom dialog components - text, image and button
        try {
            JSONObject jsonObject = new JSONObject(jsonString);

            //get location
            JSONObject locationObject = jsonObject.getJSONObject("coord");
            location.setText("[ " + locationObject.getString("lon") + ", " + locationObject.getString("lat") + " ]");

            //get temperature, humidity and pressure
            JSONObject tempObject = jsonObject.getJSONObject("main");
            temperature.setText(tempObject.getString("temp") + " Kelvin");
            humidity.setText(tempObject.getString("humidity") + "%");
            pressure.setText(tempObject.getString("pressure") + "Pa");

            //get city name
            city.setText(jsonObject.getString("name"));
        } catch (JSONException e) {
            e.printStackTrace();
        }
    And finally, we have full code for the main activity:
MainActivity.java
package info.devexchanges.internet;

import android.app.Dialog;
import android.graphics.Bitmap;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;

import org.json.JSONException;
import org.json.JSONObject;

public class MainActivity extends AppCompatActivity {

    private View btnGetJSON;
    private View btnGetImage;
    private ImageView imageView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        btnGetImage = findViewById(R.id.btn_img);
        btnGetJSON = findViewById(R.id.btn_json);
        imageView = (ImageView) findViewById(R.id.image);

        btnGetImage.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                new GetImageTask(MainActivity.this).execute();
            }
        });

        btnGetJSON.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                new GetJSONTask(MainActivity.this).execute();
            }
        });
    }

    public void getBackBitmap(Bitmap bitmap) {
        imageView.setImageBitmap(bitmap);
    }

    public void parsingJSONResponse(String jsonString) {
        final Dialog dialog = new Dialog(this);
        dialog.setContentView(R.layout.dialog_weather);
        dialog.setTitle(getString(R.string.notice));
        dialog.setCancelable(true);

        TextView temperature = (TextView) dialog.findViewById(R.id.temperature);
        TextView humidity = (TextView) dialog.findViewById(R.id.humidity);
        TextView pressure = (TextView) dialog.findViewById(R.id.pressure);
        TextView location = (TextView) dialog.findViewById(R.id.location);
        TextView city = (TextView) dialog.findViewById(R.id.city);

        // parsing json and set the custom dialog components - text, image and button
        try {
            JSONObject jsonObject = new JSONObject(jsonString);

            //get location
            JSONObject locationObject = jsonObject.getJSONObject("coord");
            location.setText("[ " + locationObject.getString("lon") + ", " + locationObject.getString("lat") + " ]");

            //get temperature, humidity and pressure
            JSONObject tempObject = jsonObject.getJSONObject("main");
            temperature.setText(tempObject.getString("temp") + " Kelvin");
            humidity.setText(tempObject.getString("humidity") + "%");
            pressure.setText(tempObject.getString("pressure") + "Pa");

            //get city name
            city.setText(jsonObject.getString("name"));
        } catch (JSONException e) {
            e.printStackTrace();
        }

        //showing dialog
        dialog.show();
    }
}
    And it's layout:
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin">
 
    <Button
        android:id="@+id/btn_img"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="@string/get_image" />
 
    <Button
        android:id="@+id/btn_json"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="@string/get_json" />
 
    <ImageView
        android:id="@+id/image"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:layout_marginTop="@dimen/activity_horizontal_margin"
        android:contentDescription="@string/app_name" />
 
</LinearLayout>
    The dialog layout (display when parsing JSON complete):
dialog_weather.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_margin="10dp"
    android:orientation="vertical">
 
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="10dp"
        android:orientation="horizontal">
 
        <TextView
            android:id="@+id/textView2"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="0.35"
            android:text="@string/country" />
 
        <TextView
            android:id="@+id/city"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="0.65"
            android:textColor="@android:color/holo_green_light" />
    </LinearLayout>
 
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="10dp"
        android:orientation="horizontal">
 
        <TextView
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="0.35"
            android:text="@string/location" />
 
        <TextView
            android:id="@+id/location"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="0.65"
            android:textColor="@android:color/holo_blue_dark" />
    </LinearLayout>
 
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="10dp"
        android:orientation="horizontal">
 
        <TextView
            android:id="@+id/textView3"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="0.35"
            android:text="@string/temperature"
            android:textAppearance="?android:attr/textAppearanceSmall" />
 
        <TextView
            android:id="@+id/temperature"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="0.65"
            android:textColor="@android:color/holo_orange_dark" />
    </LinearLayout>
 
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="10dp"
        android:orientation="horizontal">
 
        <TextView
            android:id="@+id/textView4"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="0.35"
            android:text="@string/humidity"
            android:textAppearance="?android:attr/textAppearanceSmall" />
 
        <TextView
            android:id="@+id/humidity"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="0.65"
            android:textColor="@android:color/holo_purple" />
    </LinearLayout>
 
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="10dp"
        android:orientation="horizontal">
 
        <TextView
            android:id="@+id/textView5"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="0.35"
            android:text="@string/pressure" />
 
        <TextView
            android:id="@+id/pressure"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="0.65"
            android:textColor="@android:color/holo_red_dark" />
    </LinearLayout>
 
</LinearLayout>
    After running, we can see this screen:
   When an AsyncTask is running:
   After downloading image finished:
    After downloading/parsing JSON:
    NOTE: Source code of this project now available on @Github.

Parsing XML data?

    Another common datatype is XML. You can also get it from Internet with HttpURLConnection and parsing data response by XMLPullParser, DOM or SAX. The data can be like this:
<current>
    <city id="1561096" name="Xóm Pho">
        <coord lon="105.85" lat="21.03"/>
        <country>VN</country>
        <sun rise="2016-01-18T23:36:12" set="2016-01-19T10:38:09"/>
    </city>
    <temperature value="289.006" min="289.006" max="289.006" unit="kelvin"/>
    <humidity value="88" unit="%"/>
    <pressure value="1025.91" unit="hPa"/>
    <wind>
        <speed value="2.67" name="Light breeze"/>
        <gusts/>
        <direction value="37.001" code="NE" name="NorthEast"/>
    </wind>
    <clouds value="88" name="overcast clouds"/>
    <visibility/>
    <precipitation mode="no"/>
    <weather number="804" value="overcast clouds" icon="04d"/>
    <lastupdate value="2016-01-19T01:50:51"/>
</current>
    I have had a post about this problem (using XMLPullParser), read it HERE to learn about xml parsing.

Web service in Android

    Most of Android application interact with database through SOAP or REST web service. This is more complex type in communicating online data which user can make POST or GET requests with some parameters. Further, user also add, update, delete data in database by these requests through web service.
    By default SDK, Android is not preinstalled SOAP or XML-RPC client API. SOAP web service can be connecting through k-soap2 library. and connecting to REST web service by using Volley. (See my previous post about Volley to deep understand it).
    You can read a simple example of web service consuming at this POST. Moreover, usually, the responding data is much complicated, so, you can read "Parsing Soap Object response" post to learn how to consuming the SOAP web service.

Conclusions

    Like other platforms, communicating with Internet data is an important problem. Through my post, I hope that you can be learned about this with many levels (easy to hard). Moreover, the REST web service is very popular in Android programming, you can study yourself about it by searching on Internet. Thanks for reading and download full example code above by click the button below.




Share


Previous post
« Prev Post
Next post
Next Post »