Xamarin Android – Consuming REST API

Pada tulisan bulan Mei (lama kali ya..) saya pernah posting tulisan tentang cara membuat REST Web Service dengan Silex pada tautan berikut. Sejatinya saya berencana membuat tutorial cara mengkonsumsi Web Service tersebut di beberapa jenis platform seperti android dan iOS. Tapi karena keterbatasan waktu, saya baru sempat membuat penggunaannya pada platform android dengan menggunakan Xamarin. Berikut langkah-langkahnya :

  • Buatlah sebuah project android pada Xamarin.
  • Tambahkan package “Newtonsoft.Json” dan “Xamarin.Android.Support.v4” melalui nuget
  • Buatlah sebuah model dengan nama “FoodMenu.cs” yang akan mendefinisikan class data dari FoodMenu, masukkan code berikut :
using System;

namespace SilexSample
{
	public class FoodMenu
	{
		private int id;
		private string name;
		private double price;

		public FoodMenu (string name, double price)
		{
			this.name = name;
			this.price = price;
		}

		public FoodMenu (int id, string name, double price)
		{
			this.id = id;
			this.name = name;
			this.price = price;
		}

		public int Id{get{ return this.id; }}

		public string Name{get{ return this.name; }}
		public double Price{get{ return this.price; }}
	}
}
  • Tambahkan sebuah file yang digunakan untuk melakukan komunikasi dengan REST Server, beri nama dengan “FoodLoader.cs”. Pada file ini akan mendefinisikan fungsi untuk mengambil data, melakukan insert update serta menghapus data. Masukkan code berikut pada class FoodLoader :

 

using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Net;
using Newtonsoft.Json.Linq;

namespace SilexSample
{
	public class FoodLoader
	{
		private static readonly string serverLink = "url_anda/web/index.php/";

		public FoodLoader ()
		{}

		public static List LoadData()
		{
			string link = serverLink + "daftar";
			List datas = new List ();
			try {
				HttpWebRequest request = (HttpWebRequest)WebRequest.Create(link);
				request.Method="GET";
				request.ContentType = "application/json";

				HttpWebResponse response = (HttpWebResponse)request.GetResponse();

				if (response.StatusCode == HttpStatusCode.OK) {
					Stream receiveStream = response.GetResponseStream();
					StreamReader readStream = new StreamReader(receiveStream, Encoding.UTF8);
					string outputString = readStream.ReadToEnd();

					response.Close();
					readStream.Close();

					outputString = outputString.Trim().Replace("// ", "");
					var resultArray = JArray.Parse(outputString);

					for (int i=0; i < resultArray.Count; i++) {
						var jstock = (JObject)resultArray[i];

						FoodMenu temp_data=new FoodMenu(
							int.Parse((string)jstock["id"]),
							(string)jstock["name"],
							double.Parse((string)jstock["price"])
						);

						datas.Add(temp_data);
					}
				}
			}
			catch (Exception e) {
				throw;
			}
			return datas;
		}

		public static String InsertData(FoodMenu data)
		{
			string link = serverLink + "insert";
			String result = "";
			try {
				HttpWebRequest request = (HttpWebRequest)WebRequest.Create(link);

				StringBuilder postData = new StringBuilder();
				postData.Append("name="+data.Name+"&");
				postData.Append("price="+data.Price.ToString());
				var data_encode = Encoding.ASCII.GetBytes(postData.ToString());

				request.Method = "POST";
				request.ContentType = "application/x-www-form-urlencoded";
				request.ContentLength = data_encode.Length;

				using (var stream = request.GetRequestStream())
				{
					stream.Write(data_encode, 0, data_encode.Length);
				}

				var response = (HttpWebResponse)request.GetResponse();

				if (response.StatusCode == HttpStatusCode.OK) {
					Stream receiveStream = response.GetResponseStream();
					StreamReader readStream = new StreamReader(receiveStream, Encoding.UTF8);
					result = readStream.ReadToEnd();

					response.Close();
					readStream.Close();
				}
			}
			catch (Exception) {
				throw;
			}
			return result;
		}

		public static String UpdateData(FoodMenu data, int id)
		{
			string link = serverLink + "update/" + id.ToString ();
			String result = "";
			try {
				HttpWebRequest request = (HttpWebRequest)WebRequest.Create(link);

				StringBuilder postData = new StringBuilder();
				postData.Append("name="+data.Name+"&");
				postData.Append("price="+data.Price.ToString());
				var data_encode = Encoding.ASCII.GetBytes(postData.ToString());

				request.Method = "PUT";
				request.ContentType = "application/x-www-form-urlencoded";
				request.ContentLength = data_encode.Length;

				using (var stream = request.GetRequestStream())
				{
					stream.Write(data_encode, 0, data_encode.Length);
				}

				var response = (HttpWebResponse)request.GetResponse();

				if (response.StatusCode == HttpStatusCode.OK) {
					Stream receiveStream = response.GetResponseStream();
					StreamReader readStream = new StreamReader(receiveStream, Encoding.UTF8);
					result = readStream.ReadToEnd();

					response.Close();
					readStream.Close();
				}
			}
			catch (Exception) {
				throw;
			}
			return result;
		}

		public static String DeleteData(int id)
		{
			string link = serverLink + "delete/" + id.ToString ();
			String result = "";
			try {
				HttpWebRequest request = (HttpWebRequest)WebRequest.Create(link);
				request.Method = "DELETE";
				var response = (HttpWebResponse)request.GetResponse();

				if (response.StatusCode == HttpStatusCode.OK) {
					Stream receiveStream = response.GetResponseStream();
					StreamReader readStream = new StreamReader(receiveStream, Encoding.UTF8);
					result = readStream.ReadToEnd();

					response.Close();
					readStream.Close();
				}
			}
			catch (Exception) {
				throw;
			}
			return result;
		}
	}
}
  • Sekarang kita akan membuat beberapa UI yang ditampilkan pada aplikasi android. UI yang akan dibuat antara lain UI main activity yang terdiri dari sebuah listview dan text, UI form melakukan input/update data, UI untuk menu pada bar, dan untuk row masing-masing data pada listview. Pertama buatlah UI untuk tampilan main pada Main.xml dengan memasukkan code berikut :

<?xml version=1.0 encoding=utf8?>
<LinearLayout xmlns:android=http://schemas.android.com/apk/res/android
    android:orientation=vertical
    android:layout_width=match_parent
    android:layout_height=match_parent>
    <TextView
        android:text=List of Food
        android:layout_width=wrap_content
        android:layout_height=wrap_content
        android:id=@+id/title
        android:layout_gravity=center
        android:textSize=18dp
        android:paddingBottom=8dp />
    <ListView
        android:id=@+id/my_list
        android:layout_width=match_parent
        android:layout_height=match_parent
        android:paddingLeft=5dip
        android:paddingRight=5dip
        android:layout_margin=0dip
        android:padding=0dip
        android:divider=#00000000 />
</LinearLayout>

  • Setelah itu buat layout “form_food.xml” untuk form input data :

<?xml version=1.0 encoding=utf8?>
<LinearLayout xmlns:android=http://schemas.android.com/apk/res/android
    android:orientation=vertical
    android:layout_width=match_parent
    android:layout_height=match_parent>
    <TextView
        android:text=List of Food
        android:layout_width=wrap_content
        android:layout_height=wrap_content
        android:id=@+id/title
        android:layout_gravity=center
        android:textSize=18dp
        android:paddingBottom=8dp />
    <ListView
        android:id=@+id/my_list
        android:layout_width=match_parent
        android:layout_height=match_parent
        android:paddingLeft=5dip
        android:paddingRight=5dip
        android:layout_margin=0dip
        android:padding=0dip
        android:divider=#00000000 />
</LinearLayout>

  • Lalu UI untuk tampilan row masing-masing data pada “row_food.xml :

<?xml version=1.0 encoding=utf8?>
<LinearLayout xmlns:android=http://schemas.android.com/apk/res/android
    android:layout_width=match_parent
    android:layout_height=40dp
    android:orientation=horizontal>
    <TextView
        android:text=Name 
        android:layout_width=wrap_content
        android:layout_height=wrap_content
        android:id=@+id/name
        android:paddingLeft=5dp
        android:layout_gravity=center
        android:width=250dp
        android:textSize=18dp />
    <TextView
        android:id=@+id/price
        android:layout_width=wrap_content
        android:layout_height=wrap_content
        android:gravity=right
        android:text=Price
        android:layout_gravity=center
        android:textSize=18dp />
</LinearLayout>

  • Terakhir UI untuk tampilan top bar pada aplikasi yang terdiri dari tombol Add dan Refresh data pada “bar_menu.xml”

<?xml version=1.0 encoding=utf8?>
<RelativeLayout xmlns:android=http://schemas.android.com/apk/res/android
    xmlns:tools=http://schemas.android.com/tools
    android:layout_width=fill_parent
    android:layout_height=wrap_content>
    <ImageButton
        android:id=@+id/add
        android:layout_width=50dip
        android:layout_height=fill_parent
        android:src=@mipmap/add
        style=?android:attr/borderlessButtonStyle
        android:layout_alignParentRight=true />
    <ImageButton
        android:id=@+id/refresh
        android:layout_width=50dip
        android:layout_height=fill_parent
        android:src=@mipmap/refresh
        style=?android:attr/borderlessButtonStyle
        android:layout_toLeftOf=@id/add />
</RelativeLayout>

  • Setelah membuat UI yang dibutuhkan, sekarang raciklah MainActivity pada aplikasi anda. Berikut code lengkap dari MainActivity :

 

using System;
using System.Collections.Generic;

using Android.App;
using Android.Widget;
using Android.OS;
using Android.Content;
using Android.Views;

namespace SilexSample
{
	[Activity (Label = "SilexSample", MainLauncher = true, Icon = "@mipmap/icon")]
	public class MainActivity : Activity
	{
		AlertDialog.Builder builder;
		private ListView my_list;
		private TextView title;
		private ImageButton btn_add;
		private ImageButton btn_refresh;

		private LoadTask asyncTask;  
		private Handler mHandler = new Handler();
		Runnable mUpdateTimeTask;

		List datas = new List ();
		private FoodAdapter adapter;
		private int current_position = 0;

		protected override void OnCreate (Bundle savedInstanceState)
		{
			base.OnCreate (savedInstanceState);

			SetContentView (Resource.Layout.Main);

			my_list = FindViewById (Resource.Id.my_list);
			title = FindViewById (Resource.Id.title);

			adapter = new FoodAdapter (this, this.datas);
			my_list.Adapter = adapter;
			ListEvent ();
			SetActionBar();

			mUpdateTimeTask = new Runnable(Run);
			mHandler.RemoveCallbacks(mUpdateTimeTask);
			mHandler.Post(mUpdateTimeTask);
		}

		private void RefreshData()
		{
			mUpdateTimeTask = new Runnable(Run);
			mHandler.RemoveCallbacks(mUpdateTimeTask);
			mHandler.Post(mUpdateTimeTask);
		}

		private void SetActionBar()
		{
			Context context = ActionBar.ThemedContext;

			ActionBar.DisplayOptions = ActionBarDisplayOptions.ShowCustom;
			ActionBar.SetCustomView(Resource.Layout.bar_menu);

			btn_add = FindViewById(Resource.Id.add);
			this.btn_add.Click += (o, e) =>
			{
				builder = new AlertDialog.Builder(this);
				builder.SetTitle("Add Data");

				View view_layout = LayoutInflater.From(this).Inflate(Resource.Layout.form_food, null);
				EditText name = view_layout.FindViewById(Resource.Id.name);
				EditText price = view_layout.FindViewById(Resource.Id.price);

				builder.SetView(view_layout);
				builder.SetPositiveButton("Ok", (os, es) =>
				{
					FoodMenu temp = new FoodMenu(name.Text, double.Parse(price.Text));
					FoodLoader.InsertData(temp);
					mHandler.RemoveCallbacks(mUpdateTimeTask);
					mHandler.Post(mUpdateTimeTask);
					((Dialog)os).Dismiss();
				});

				builder.SetNegativeButton("Cancel", (os, es) =>
				{
					((Dialog)os).Dismiss();
				});
				builder.Show();
			};

			btn_refresh = FindViewById(Resource.Id.refresh);
			btn_refresh.Click += (o, e) =>
			{
				RefreshData();
			};
		}

		private void ListEvent(){
			my_list.ItemClick += (o, e) => {
				this.current_position=e.Position;
				builder = new AlertDialog.Builder (this);
				builder.SetMessage("Select an action");
				builder.SetNegativeButton ("Delete", DeleteClicked);
				builder.SetPositiveButton("Update",UpdateClicked);
				builder.Show();
			};
		}

		private void DeleteClicked (object sender, DialogClickEventArgs e)
		{
			FoodLoader.DeleteData (datas [current_position].Id);
			mHandler.RemoveCallbacks(mUpdateTimeTask);
			mHandler.Post(mUpdateTimeTask);
			((Dialog)sender).Dismiss ();
		}
			
		private void UpdateClicked (object sender, DialogClickEventArgs e)
		{
			((Dialog)sender).Dismiss ();

			builder = new AlertDialog.Builder (this);
			builder.SetTitle ("Update Data");
			//
			View view_layout = LayoutInflater.From (this).Inflate (Resource.Layout.form_food, null);

			EditText name = view_layout.FindViewById (Resource.Id.name);
			EditText price = view_layout.FindViewById (Resource.Id.price);

			name.Text = datas [current_position].Name;
			price.Text = datas [current_position].Price.ToString ();

			//
			builder.SetView (view_layout);
			builder.SetPositiveButton ("Ok", (os, es) => {
				FoodMenu temp=new FoodMenu(name.Text,double.Parse(price.Text));
				FoodLoader.UpdateData(temp,datas[current_position].Id);
				mHandler.RemoveCallbacks(mUpdateTimeTask);
				mHandler.Post(mUpdateTimeTask);
				((Dialog)os).Dismiss ();
			});

			builder.SetNegativeButton ("Cancel", (os, es) => {
				((Dialog)os).Dismiss();
			});
			builder.Show();
		}

		public void Run(){
			if (asyncTask != null)
			if (asyncTask.GetStatus() == AsyncTask.Status.Running)
				asyncTask.Cancel(true);   		

			asyncTask = (LoadTask)new LoadTask (this).Execute ();
		}

		private class MyResult {
			public Boolean success;
			public Exception exception;
		}

		private class LoadTask : AsyncTask< Java.Lang.Void , Java.Lang.Void , MyResult>{
			MainActivity parent;
			public LoadTask(MainActivity parent){
				this.parent=parent;
			}

			protected override void OnPreExecute() {
				parent.title.Text = "Loading...";
				base.OnPreExecute();
			}

			protected override void OnPostExecute(MyResult result){
				if (result.exception != null && result.success == false)
					Toast.MakeText (parent, result.exception.Message, ToastLength.Long).Show ();

				parent.title.Text = "List of Food";
				base.OnPostExecute (result);
			}

			protected override MyResult RunInBackground(params Java.Lang.Void[] @params){			
				MyResult result = new MyResult();
				result.exception = null;
				result.success = true;

				try {
					parent.RunOnUiThread(() => {
						parent.LoadData();
					});
				}
				catch (Exception e) {
					result.exception = e;
					result.success = false;
				}
				return result;
			}
		}

		public void LoadData(){
			try {
				this.datas=FoodLoader.LoadData();
				adapter = new FoodAdapter (this, this.datas);
				my_list.Adapter = adapter;
			} 
			catch (Exception) {
				Toast.MakeText (this, "Something error on the server or your connection", ToastLength.Long).Show ();
			}
		}
	}
}

Setelah itu jalankan aplikasi anda untuk melihat hasilnya..

Anda juga dapat mengunduh aplikasi yang telah saya buat di https://github.com/sabithuraira/tutor_silex (aplikasi android yang dibuat saya letakkan pada folder “SilexAndroid”..

Happy coding..

Advertisements

One Response to Xamarin Android – Consuming REST API

  1. Pingback: [Xamarin iOS] Consuming REST API | Sabitlabscode

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: