Pazar, Ağustos 14, 2011

RESTful Web Servis Client–Android

Geçen haftaki yazımda Jersey kullanarak JSON üreten oldukça basit bir RESTful Web servis hazırlamıştık. Bu hafta bu web servisi kullanacak Android uygulamasını yazacağız.

Kısaca hatırlamak gerekirse geçen haftaki web servisimiz çıktı olarak aşağıdaki sınıfın JSON karşılığını üretiyordu.

RSOutputDTO.java
package com.blogspot.emrahkocaman.restfulws.json;
public class RSOutputDTO {
	
	private String userName;
	private int userAge;
	
	public void setUserName(String userName) {
		this.userName = userName;
	}
	
	public String getUserName() {
		return userName;
	}
	
	public void setUserAge(int userAge) {
		this.userAge = userAge;
	}
	
	public int getUserAge() {
		return userAge;
	}
	
}

Sadece userName ve userAge alanlarına sahip olan sınıfımızın örnek JSON karşılığı ise aşağıdaki satırdan ibaret.


{"userName":"Kamil","userAge":30}


Projemizin tek amacı bu web servisi çağırmak, dönen JSON string’ini parse ederek ekranda göstermekten ibaret olacak.


İşe önce ADT plugin’i kurulmuş bir Eclipse’te Android projesi oluşturarak başlıyoruz.


File –> New –> Android Project menüsüni kullanarak bir Android projesi oluşturuyoruz.





Daha sonra ADT plugin’i yardımı ile web servisten dönen bilgilerin gösterileceği basit bir arayüz hazırlıyoruz.



main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<RelativeLayout android:id="@+id/relativeLayout1" android:layout_height="fill_parent" android:layout_width="fill_parent" android:layout_marginTop="10dip">
<EditText android:layout_toRightOf="@+id/textView1" android:layout_height="wrap_content" android:layout_width="fill_parent" android:id="@+id/txtUserName">
<requestFocus></requestFocus>
</EditText>
<EditText android:layout_height="wrap_content" android:layout_below="@+id/txtUserName" android:layout_width="wrap_content" android:layout_alignLeft="@+id/txtUserName" android:layout_alignRight="@+id/txtUserName" android:id="@+id/txtUserAge"></EditText>
<Button android:text="WS Çağır" android:id="@+id/btnCall" android:layout_height="wrap_content" android:layout_width="wrap_content" android:layout_below="@+id/txtUserAge" android:layout_alignLeft="@+id/txtUserAge" android:layout_alignRight="@+id/txtUserAge"></Button>
<TextView android:text="Kullanıcı Adı" android:paddingRight="10dip" android:layout_height="wrap_content" android:id="@+id/textView1" android:layout_width="wrap_content" android:layout_alignParentLeft="true" android:paddingTop="10dip" android:paddingBottom="10dip"></TextView>
<TextView android:text="Kullanıcı Yaşı" android:layout_height="wrap_content" android:id="@+id/textView2" android:layout_width="wrap_content" android:layout_below="@+id/textView1" android:layout_alignLeft="@+id/textView1" android:layout_alignRight="@+id/textView1" android:paddingTop="10dip"></TextView>
</RelativeLayout>
</LinearLayout>

Arayüzü hazırladığımıza göre web servis çağırmak için hazırız. RESTful web servislerin HTTP protokolü ile (GET, PUT, POST vb…) çalıştığından bahsetmiştik. Yani RESTful bir web servis çağırmak için ihtiyacımız olan tek şey bir http istemcisi ve bu istemciyi Android kendi bünyesinde barındırıyor (org.apache.http.impl.client.DefaultHttpClient) bu sayede 3.parti bir kütüphaneye gerek kalmadan HTTP istekleri yapmamız mümkün.

Bundan sonrasını kod üzerinde anlatarak devam edeyim.

package com.blogspot.emrahkocaman;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.StatusLine;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.json.JSONException;
import org.json.JSONObject;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.Toast;
public class RestClientActivity extends Activity {
	/** Called when the activity is first created. */
	@Override
	public void onCreate(Bundle savedInstanceState) {
	
super.onCreate(savedInstanceState);
	setContentView(R.layout.main);
	Button btnCallWS = (Button) findViewById(R.id.btnCall);
	btnCallWS.setOnClickListener(new OnClickListener() {
			@Override
	public void onClick(View arg0) {
//HTTP protokolüne ulaşmak için kullanılan sınıf
	 DefaultHttpClient httpclient = new DefaultHttpClient();
	 //Hazırladığımız web srvis GET isteklerine cevap veriyordu
	 HttpGet httpget = new HttpGet(
	 "http://192.168.37.1:8080/restfulwssample/rest/examples/getUserInfo");
	//IP olarak bilgisayarınızın local ip'sini vermeniz gerekiyor. 
//Aksi halde android uygulaması kendi 
	//localhost'una ulaşmaya çalışacaktır.
	HttpResponse response;
	try {
	//İsteği gönder
	  response = httpclient.execute(httpget);
	  StatusLine requestSuccess = response.getStatusLine();
	//İstek başarılı
	if (requestSuccess.getStatusCode() == 200) {
	  HttpEntity entity = response.getEntity();
	  if (entity != null) {
	   InputStream instream = entity.getContent();
	   //Stream olarak dönen cevabı anlaşılır bir hale getirmemiz gerekiyor
String requestResult = convertStreamToString(instream);
try {
	   //Android kendi içerisinde JSON stack'ini barındırıyor.
//Gelen string'i JSON objesine dönüştürüyoruz
	   JSONObject jsonResult = new JSONObject(requestResult);
	   Toast.makeText(RestClientActivity.this, jsonResult.toString(), Toast.LENGTH_LONG).show();
} catch (JSONException e) {
	    Toast.makeText(RestClientActivity.this, "JSON Exception", Toast.LENGTH_SHORT).show();
	   }
instream.close();
	}
	}
	} catch (Exception ex) {
	Log.e("REST_ERR", ex.getMessage());
	Toast.makeText(RestClientActivity.this, "Houston we have a problem", Toast.LENGTH_SHORT).show();
			
	}
	}
});
}
	private static String convertStreamToString(InputStream is) {
		BufferedReader reader = new BufferedReader(new InputStreamReader(is));
		StringBuilder sb = new StringBuilder();
		String line = null;
		try {
			while ((line = reader.readLine()) != null) {
				sb.append(line + "\n");
			}
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				is.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return sb.toString();
	}
}

Uygulamayı çalıştırıp “WS Çağır” butonuna bastığımızda bize ulaşan JSON nesnesini görmeliyiz.



Bize ulaşan JSON nesnesini parse ederek içinde “Kullanıcı Adı” ve “Kullanıcı Yaşı” bilgilerini çıkarmamız gerekiyor. Android içerisinde bulunan JSON stack’i bu işlemi yapmak mümkün.

userName.setText(jsonResult.getString("userName"));
userAge.setText(jsonResult.getString("userAge"));

Örneğimizdeki response’da sadece iki alan olduğu için zorlanmadık ama gerçek hayatta web servisler bu kadar basit değil tabiki. Çok fazla alan içeren JSON nesnelerini bu şekilde parse etmek hem hataya açık hemde çok zahmetli bir hal alacaktır. Bu sebeple JSON nesnelerini bizim içip parse edip istediğimiz nesnelere dönüştürecek kütüphaneler kullanabiliriz. Bu için tavsiyem Jackson ve Gson kütüphaneleri. 

Bunları arasındaki seçim konusunda ise tavsiyem, öncelik hız ise Jackson, öncelik uygulama boyutu ise (mobil uygulamaların boyutları büyük olduğunda fazlaca eleştiriliyorlar) GSON kullanmanız.

Şimdi örneğimize Gson’uda ekleyerek projeyi tamamlayalım.

Öncelik Gson kütüphanesi http://code.google.com/p/google-gson/ adresinden indiriyor ve projemizin classpath’ine ekliyoruz..

Hatırlayacağımız üzere dönen JSON nesnesi server tarafında RSOutputDTO.java sınıfına karşılık geliyor. Aynı sınıfı Android projemizede kopyalarak ilerliyoruz.


Gson sınıfı yardımıyla dönen JSON nesnesini RSOutputDTO nesnesine dönüştürerek örneği tamamlıyoruz.

Gson gson = new GsonBuilder().create();
RSOutputDTO result = gson.fromJson(jsonResult.toString(), RSOutputDTO.class);
userName.setText(result.getUserName());
userAge.setText(Integer.toString(result.getUserAge()));

Herkese kolay gelsin.

Eclipse projesi : http://db.tt/NoHiJ30

9 yorum:

  1. Eline sağlık güzel bir örnek olmuş.

    YanıtlaSil
  2. RestClientActivity cannot be resolved to a type hatası alıyorum neden oluyor?

    YanıtlaSil
    Yanıtlar
    1. Proje düzgün olarak build edilememiş anladığım kadarıyla. Classpath sorunu olabilir. Projenin android versiyonunun pc'inde bulunup bulunmadığını kontrol edebilirsin ilk adım olarak.

      Sil
  3. Çok Güzel Bir Örnek Eline Sağlık Kardeşim

    YanıtlaSil
  4. file upload örneği de verirsen çok dua alırsın :)

    YanıtlaSil
  5. Merhaba hocam bırde bunun kullanıcı tarafından parametre gonderılen halını hazırlarsanız ıhya oluruz

    YanıtlaSil
  6. Böyle güzel türkçe kaynaklar görmek gerçekten güzel.Elinize sağlık.

    YanıtlaSil
  7. hocam teşekkürler gerçekten böyle türkçe kaynaklar bulmak sevindiriyor sen yaz hocam yaz :)

    YanıtlaSil
  8. hocam çalışmıyor kodlarınızı birebir kopyalayıp yapıştırdım ama olmuyor, ip adresinizin bulunduğu yere localhost yazdım wampdan kurdum mysql serveri ve yaptıklarınızın aynısını yaptım veri.json olarak kaydettim chromedan ulaşabiliyorum fakat androidden ulaşamadım bir türlü lütfen yardım edermisiniz lütfen

    YanıtlaSil