Networking - Membuat Koneksi HTTP

Pada latihan sebelumnya (sms) kita sudah mempelajari tentang bagaimana app kita bisa berkomunikasi dengan dunia luar melalui SMS dan email. Cara lain untuk berkomunikasi dengan dunia luar adalah melalui jaringan wireless yang ada dalam perangkat Android. Jadi latihan ini akan mempelajari bagaimana menggunakan protokol HTTP untuk berkomunikasi dengan web servers sehingga kita bisa men-download teks dan data binary. Kita akan mempelajari bagaimana mem-parse file-file XML untuk mengekstrak bagian-bagian dokumen XML yang relevan dimana teknik ini sangat bermanfaat bila kita mengakses web services. Selain XML web services, latihan dalam topik-topik ini juga akan membahas tentang JSON (JavaScript Object Notation), yang merupakan alternatif ringan dari XML. Kita akan menggunakan class-class yang ada di Android SDK untuk memanipulasi isi JSON.

Berkomunikasi Menggunakan HTTP

Salah satu cara yang umum digunakan untuk berkomunikasi dengan dunia luar adalah melalui HTTP. HTTP tidaklah asing bagi kita; ini adalah protokol yang membuat web sangat populer. Dengan menggunakan protokol HTTP, kita bisa melakukan berbagai macam tugas, misalnya men-download laman-laman web dari web sercer, men-download data binary, dan lain-lain.


Latihan Menggunakan Koneksi HTTP:

1. Tambahkan permission pada file 'AndroidManifest.xml' seperti berikut:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.networking">

<uses-permission android:name="android.permission.INTERNET" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

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

</manifest>
2. Buat method 'OpenHttpConnection()' dalam file 'MainActivity.java' seperti berikut:
public class MainActivity extends AppCompatActivity {

private InputStream OpenHttpConnection(String urlString) throws IOException
{
InputStream in = null;
int response = -1;

URL url = new URL(urlString);
URLConnection conn = url.openConnection();

if (!(conn instanceof HttpURLConnection))
throw new IOException("Not an HTTP connection");
try {
HttpURLConnection httpConn = (HttpURLConnection) conn;
httpConn.setAllowUserInteraction(false);
httpConn.setInstanceFollowRedirects(true);
httpConn.setRequestMethod("GET");
httpConn.connect();
response = httpConn.getResponseCode();
if (response == HttpURLConnection.HTTP_OK) {
in = httpConn.getInputStream();
}
}
catch (Exception ex)
{
Log.d("Networking", ex.getLocalizedMessage());
throw new IOException("Error connecting");
}
return in;
}

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

Penjelasan

Karena kita menggunakan protokol HTTP untuk terkoneksi dengan web, maka app kita perlu permission INTERNET; karena itu, terlebih dahulu kita tambahkan adalah permission dalam file 'AndroidManifest.xml'.

Berikutnya kita kemudian membuat method 'OpenHttpConnection()' yang mengambil string URL dan mengembalikan object 'InputStream'. Dengan menggunakan object 'InputStream', kita bisa mendownload data dengan membaca byte-byte dari object stream. Dalam method ini, kita memanfaatkan object 'HttpURLConnection' untuk membuka koneksi HTTP ke suatu URL. Kemudian kita men-set berbagai macam properti koneksi seperti berikut:
HttpURLConnection httpConn = (HttpURLConnection) conn;
httpConn.setAllowUserInteraction(false);
httpConn.setInstanceFollowRedirects(true);
httpConn.setRequestMethod("GET");
httpConn.connect();
response = httpConn.getResponseCode();
if (response == HttpURLConnection.HTTP_OK) {
in = httpConn.getInputStream();
Setelah mencoba membuat koneksi ke server, kode response HTTP dikembalikan. Bila koneksi berhasil dibuat (dengan kode response HTTP_OK), maka kita akan mendapat object 'InputStream' seperti berikut:
httpConn.connect();
response = httpConn.getResponseCode();
if (response == HttpURLConnection.HTTP_OK) {
in = httpConn.getInputStream();


Mendownload File Binary

Hal umum yang sering kita lakukan adalah men-download file binary dari suatu web. Misalnya, kita mungkin ingin mendownload gambar dari suatu server sehingga kita bisa menampilkannya di app kita, seperti dalam latihan berikut ini:

Kita masih menggunakan project yang sama dengan yang sudah kita buat di atas dan kita teruskan disini:

1. Kita modifikasi file layout xml 'activity_main.xml' seperti berikut di bawah ini:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
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"
android:orientation="vertical"
tools:context="com.example.networking.MainActivity">

<ImageView
android:id="@+id/img"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center" />
</LinearLayout>
2. Tambahkan dalam file MainActivity.java menjadi seperti berikut:
package com.example.networking;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.widget.ImageView;

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

public class MainActivity extends AppCompatActivity {

ImageView img;

private InputStream OpenHttpConnection(String urlString) throws IOException
{
InputStream in = null;
int response = -1;

URL url = new URL(urlString);
URLConnection conn = url.openConnection();

if (!(conn instanceof HttpURLConnection))
throw new IOException("Not an HTTP connection");
try {
HttpURLConnection httpConn = (HttpURLConnection) conn;
httpConn.setAllowUserInteraction(false);
httpConn.setInstanceFollowRedirects(true);
httpConn.setRequestMethod("GET");
httpConn.connect();
response = httpConn.getResponseCode();
if (response == HttpURLConnection.HTTP_OK) {
in = httpConn.getInputStream();
}
}
catch (Exception ex)
{
Log.d("Networking", ex.getLocalizedMessage());
throw new IOException("Error connecting");
}
return in;
}

private Bitmap DownloadImage(String URL)
{
Bitmap bitmap = null;
InputStream in = null;

try {
in = OpenHttpConnection(URL);
bitmap = BitmapFactory.decodeStream(in);
in.close();
} catch (IOException e1) {
Log.d("NetworkingActivity", e1.getLocalizedMessage());
}

return bitmap;
}

private class DownloadImageTask extends AsyncTask {
protected Bitmap doInBackground(String...urls) {
return DownloadImage(urls[0]);
}

protected void onPostExecute(Bitmap result) {
ImageView img = (ImageView) findViewById(R.id.img);
img.setImageBitmap(result);
}
}

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
new DownloadImageTask().execute("https://4.bp.blogspot.com/" +
"_eJ6DUueNBrU/TFK-Newa7rI/AAAAAAAAA3A/M4ts1oK8m9k/s1600/learning+from+trees.jpg");
}
}

Penjelasan:

Method 'DonwlowadImage()' mengambil URL gambar untuk di-download dan kemudian membuka koneksi ke server dengan menggunakan method 'OpenHttpConnection()' yang sudah kita buat sebelumnya. Dengan menggunakan object 'InputStream' yang dikembalikan oleh koneksi tersebut, maka method 'decodeStream()' dari class 'BitmapFactory' digunakan untuk men-download dan men-decode data menjadi object 'Bitmap'. Method 'DownloadImage()' kemudian mengembalikan object 'Bitmap'.

Untuk men-download gambar dan menampilkannya di 'activity', kita perlu memanggil method 'DownloadImage()'. Tetapi, mulai Android 3.0, cara synchronous tidak bisa diterapkan lagi. Karena apabila kita langsung memanggil method 'DownloadImage()' langsung di dalam method 'onCreate()' seperti ditunjukkan dalam potongan kode berikut di bawah ini, app kita akan crash ketika dijalankan pada perangkat Android 3.0 ke atas:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
/*men-download gambar secara langsung, tetapi kode ini tidak bisa jalan pada Android 3.0 ke atas*/
Bitmap bitmap = DownloadImage("https://4.bp.blogspot.com/" +
"_eJ6DUueNBrU/TFK-Newa7rI/AAAAAAAAA3A/M4ts1oK8m9k/s1600/learning+from+trees.jpg");
img = (ImageView) findViewById(R.id.img);
img.setImageBitmap(bitmap);
}
Karena method 'DownloadImage()' adalah synchronous, yang artinya, tidak akan mengembalikan nilai apapun sampai gambar selesai di-download, jadi method ini akan memblokir 'activity' app kita. Ini tidak lagi diperbolehkan pada Android 3.0 ke atas, semua kode synchronous harus dibungkus dengan menggunakan class 'AsyncTask'. Dengan menggunakan class 'AsyncTask', memungkinkan kita melakukan hal-hal lain di background dalam thread yang lain. Dengan begitu kita masih bisa melakukan berbagai hal di background tanpa menangani hal-hal berkaitan threading.

Untuk memanggil method 'DownloadImage()' secara asynchrounous, kta perlu membungks kode tersebut dalam suatu subclass dar class 'AsyncTask', seperti berikut:
private class DownloadImageTask extends AsyncTask {
protected Bitmap doInBackground(String...urls) {
return DownloadImage(urls[0]);
}

protected void onPostExecute(Bitmap result) {
ImageView img = (ImageView) findViewById(R.id.img);
img.setImageBitmap(result);
}
}
Pada dasarnya kita membuat satu class (DownloadImageTask) yang menerapkan 'extends' class 'AsyncTask'. Dalam hal ini, ada dua method di dalam class 'DownloadImageTask' yaitu: 'doInBackground()' dan 'onPostExecute()'.

Kita bisa menaruh semua kode yang perlu dijalankan secara asynchronous dalam method 'doInBackground()'. Ketika pekerjaan tersebut selesai, hasilnya akan dilewatkan melalui method 'onPostExecute()'. Dalam hal ini, kita menggunakan 'ImageView' untuk menampilkan gambar yang di-download.

Untuk memanggil class 'DownloadImageTask', kita perlu membuat instans class tersebut dan kemudian memanggil method 'execute()' nya dan kemudian melewatkan URL dari gambar tersebut untuk di-download.

Jalankan di Android emulator dan hasilnya adalah seperti berikut:
Hasil gambar yang di download dari suatu web


No comments: