Android Web Servisleri Kullanımı
Android uygulamaları herhangi bir web servisi doğrudan kullanabilmektedir.Android işletim sistemi için genel olarak XML ya da JSON formatı tercih edilebilir. Bir XML verisini ayrıştıran sınıflar genel olarak tüm XML veriyi önce belleğe okuduklarından mobil dünya için genel olarak JSON kullanılır.
JSON(JavaScript Object Notation) formatı javaScript programlama dilinin 1999 Aralık standartlarında belirtilen nesne yapısından hareketle oluşturulmuştur.Bu tip formatlar genel olarak kolay algılanabilir ve oluşturulabilir yazısal kaynaklardır.
JSON formatı genel olarak isim ve değer çiftlerinden oluşmaktadır. Bu anlamda bakıldığında Map Collection sınıflarına benzetilmektedir.Değerlerin peş peşe yazılması açısından dinamik büyüyen dizilere de benzetilmektedir.
JSON ve ya XML gibi veri yapılarının temel amacı okunabilir bir text formatında taşınmaktadır.Verilerin yazı olarak iletilmesi her ortamda ve her teknolojide kullanılmasına olanak sağlar.Şüphesiz programcı başka yazısal formatları kendisi de oluşturabilir.Fakat JSON ve XML formatları veri iletiminde en çok kullanılan ve kabul gören formatlardır.Bu formatların çok kullanımından dolayı hemen hemen her kütüphane ve framework içerisinde bu formatlarla hazır işlem yapan sınıflar ya da metodlar(fonksiyonlar) bulunmaktadır.
Web Servis İstemci Programlarının Yapısı
Web Servisleri kullanmak için (Android 6.0)APILEVEL23
'den önce HttpClient
isimli bir sınıf kullanılmaktaydı fakat bu sınıf depricated ve APILEVEL23
'den sonra silindiği için bunun yerine HttpUrlConnection
isimli bir sınıf kullanılmaktadır.Bu sınıf ile kendisine gönderilen bir servise Url olarak bağlanılır.Bağlantı alındıktan sonra bir stream alınır ve bu stream ile okuma işlemleri yapılır.Bu işlem kısaca download olarak da düşünülebilir.Ayrıca upload yapmak istenirse stream'e yazma yapmak gereklidir.
JSON Formatında Servislerin Kullanılması
[Dropbox]081-SimpleWebServiceJSON
081-SimpleWebServiceJSON Ne yapar?
EditText'e girilen postakodunu butona basıldığında api.geonames.org üzerinden istek gönderir ve json data alır.
Url işlemleri için URL sınıfı kullanılmaktadır.Bu sınıfın başlangıç metodu java.net.MalformedURLException
türünden Exception throw etmektedir.URL sınıfı java.net
paketi içerisindedir.
Herhangi bir urlye bağlantı için URL sınıfının openConnection
metodu kullanılabilir.Bağlantıyı kesmek için ise HttpConnection sınıfının disconnect
metodu çağrılmalıdır.
Web Servis bağlantıları zaman olarak uzama ihtimaline karşı client programın asenkron bir akış ile bu işlemi gerçekleştirmesi gerekmektedir.
Bir connection elde edildiği zaman o connectiona ilişkin inputStream ve outputStream programcı tarafından alınabilir.Bunun için getInputStream
ve getOutputStream
metodlarından faydalanılabilir.
Bu işlemler için INTERNET izni gerekmektedir.
<uses-permission android:name="android.permission.INTERNET"></uses-permission>
Programcı JSON formatındaki veriyi String olarak aldıktan sonra JSONXXX metodlarıyla ayrıştırılır. Bir JSON formatındaki bir yazıyı JSONObject isimli bir sınıf ile sarmalamak gerekir.Herhangi bir Json elemanına ilişkin bilgiyi JsonArraylerle alabiliriz.
JsonArray nesnesine alınan bir data aşağıdaki gibi ele alınabilir.
geoNames Apiden elde edilen JSON'ın parse edilmesi http://api.geonames.org/postalCodeSearchJSON?postalcode=34387&maxRows=1&username=demo
{
"postalCodes":[
{
"adminCode2":"8521538",
"adminCode1":"34",
"adminName2":"Şişli",
"lng":29,
"countryCode":"TR",
"postalCode":"34387",
"adminName1":"İstanbul",
"ISO3166-2":"34",
"placeName":"Mecidiyeköy",
"lat":41.066667
}
]
}
try {
JSONObject object = new JSONObject(result);
JSONArray items = new JSONArray(object.getString("postalCodes"));
String placeNames = "";
for (int i = 0; i < items.length(); ++i) {
JSONObject curObject = items.getJSONObject(i);
if (!placeNames.isEmpty())
placeNames += "-";
placeNames += curObject.getString("placeName");
}
Toast.makeText(MainActivity.this, placeNames, Toast.LENGTH_LONG).show();
}
catch (Exception ex) {
Toast.makeText(MainActivity.this, ex.getMessage(), Toast.LENGTH_SHORT).show();
}
Burada programcının Json formatında gelen datayı isimleriyle birlikte bilmesi gerekir.
Text Formatında Olmayan Dataların Download Edilmesi
BinaryDataDownload Ne Yapar?
Butona basıldığında linki verilen görseli Asynctask ile indirir ve imageView içerisinde gösterir.
Bir Url üzerinden text olmayan formatta veri indirmesi işlemi yine HttpURLConnection
sınıfı kullanılarak yapılabilir.Bunun için indirilecek formatın ne olduğunun bilinmesi gerekir.Örneğin resim formatındaki data şu şekilde indirilir.
connection = Util.openHttpConnection(params[0]);
InputStream in = new BufferedInputStream(connection.getInputStream());
result = BitmapFactory.decodeStream(in);
Burada BitmapFactory sınıfı resim olmayan fakat resmin datalarını içeren datadan resim elde etmek için kullanılan bir sınıftır.
Burada henüz bir save işlemi yapılmamıştır.Yanlızca bitmap formatı ImageView üzerinde resim olarak gösterilmiştir.
XML Formatında Servislerin Kullanılması
JSON formatına benzer olarak XML formatı da yaygın olarak kullanılmaktadır.Java'da aynı zamanda Androidde de bulunan XMLParser
sınıfları ile bu işlem gerçekleştirilebilir.
Anahtar Notlar:Bir XML içerisinde bir eleman açısal parantezler içerisinde <tag>
bildirilir.ve </tag>
şeklinde kapatılabilir.
Bu elemanların herbirine node denilmektedir. XML formatını ayrıştıran sınıflar nodelar üzerinde işlem yapmaktadırlar.Nodelar kendi içerisinde hiyeraşik bir yapıya sahiptir.
Basit bir XML formati aşağıdaki gibi düşünülebilir.
<players>
<player>
<name>Oguz</name>
<notes>100</notes>
</player>
<player>
<name>Kaan</name>
<notes>100</notes>
</player>
<player>
<name>Burak</name>
<notes>100</notes>
</player>
.
.
.
</players>
Burada players
tepe (route) node olarak düşünülebilir.Diğerleri bunların childleri (çocukları)dır.
XML Formatını Ayrıştıran Sınıflar
[Dropbox]083-SimpleWebServiceXML
Android işletim sistemi için XML ayrıştıran sınıflar daha çok Java içerisinden gelen sınıflardır.
XML ayrıştırmak için önce Document isimli sınıftan faydalanılır.Document oluşturmak için öncellikle DocumentBuilder
isimli bir sınıf gerekmektedir.Bu nesne için DocumentBuilderFactory
sınıfının newInstance
metodu gerekmektedir.
Document sınıfı org.w3c.dom
altında bildirilmiştir.
Dökümanın kendisine ilişkin sınıf Document sınıfıdır.XML içerisinde herhangi bir elemana (tag'e) ilişkin düğüm listesi getElementsByTagName
isimli metod ile elde edilebilir.
Bir DocumentBuilder
nesnesi DocumentBuilderFactory
sınıfının newDocumentBuilder
sınıfıyla alınabilir.
DocumentBuilder
sınıfının parseXXX metoduyla bir Document nesnesi alınabilir.
Document sınıfının getElementByTagName
metoduyla bir düğüme ilişkin tüm alt listeler bir liste olarak elde edilebilir.
Anahtar Notlar:
Boşluk ve standart ASCII olmayan karakterler ve bunun gibi özel karakterler için bir url'in ayrıştırılması UrlEncoder
isimli bir sınıfla yapılabilir.Bu sınıfın encode
metodu encode edilecek yazıyı ve hangi tablolama yöntemiyle encode edeceği bilgisini almaktadır.Tek parametreli encode metodu deprecated durumdadır.Default olarak UTF-8 kullanılabilir
str = URLEncoder.encode(str , "UTF-8")
Bu metod encoding parametresi geçersizse UnsportedEncodingException
fırlatır.
WebServis uygulamalarında genel olarak client uygulamanın encode ederek url vermesi iyi bir tekniktir.
Örnek XML service linki:http://services.aonaware.com/dictservice/dictservice.asmx/Define?word=ankara
Örnek XML Kodu
<?xml version="1.0" encoding="UTF-8"?>
<WordDefinition xmlns="http://services.aonaware.com/webservices/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Word>ankara</Word>
<Definitions>
<Definition>
<Word>ankara</Word>
<Dictionary>
<Id>wn</Id>
<Name>WordNet (r) 2.0</Name>
</Dictionary>
<WordDefinition>Ankara
n : the capital of Turkey; located in west-central Turkey;
formerly known as Angora and is the home of Angora goats
[syn: {Turkish capital}, {capital of Turkey}]</WordDefinition>
</Definition>
</Definitions>
</WordDefinition>
public void onFindButtonClicked(View v)
{
String str = m_editTextWord.getText().toString();
try {
str = URLEncoder.encode(str, "UTF-8");
}
catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
new DictionaryTask().execute("http://services.aonaware.com/DictService/DictService.asmx/Define?word=" + str);
}
private class DictionaryTask extends AsyncTask<String, String, String> {
@Override
protected String doInBackground(String... params)
{
String result = "";
HttpURLConnection connection = null;
try {
connection = Utils.openConnection(params[0]);
InputStream in = new BufferedInputStream(connection.getInputStream());
Document doc = null;
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = null;
db = dbf.newDocumentBuilder();
doc = db.parse(in);
NodeList definitionElements = doc.getElementsByTagName("Definition");
for (int i = 0; i < definitionElements.getLength(); ++i) {
Node itemNode = definitionElements.item(i);
if (itemNode.getNodeType() == Node.ELEMENT_NODE) {
Element element = (Element)itemNode;
NodeList wordDefList = element.getElementsByTagName("WordDefinition");
for (int k = 0; k < wordDefList.getLength(); ++k) {
NodeList textNode = wordDefList.item(k).getChildNodes();
result += ((Node)textNode.item(0)).getNodeValue() + "\n";
}
}
}
}
catch (Exception ex) {
publishProgress(ex.getMessage());
}
finally {
if (connection != null)
connection.disconnect();
}
return result;
}
@Override
protected void onPostExecute(String result)
{
//Toast.makeText(MainActivity.this, result, Toast.LENGTH_LONG).show();
m_textViewResult.setText(result.isEmpty() ? "No word in db" : result);
super.onPostExecute(result);
}
@Override
protected void onProgressUpdate(String... values)
{
Toast.makeText(MainActivity.this, "EXCEPTION:" + values[0], Toast.LENGTH_LONG).show();
super.onProgressUpdate(values);
}
}