Archive for April, 2009
Android’le Adım Adım Uygulama Geliştirme – I
Posted by Serkan Doğantekin in Android, Genel on April 27th, 2009
Artık hepimizin çok iyi bildiği gibi herhangibir platformu öğrenmenin en iyi ve kolay yolu konu hakkında örnek bir çalışma yapmaktan geçiyor. Bende bu yazı serisi boyunca basit bir Android uygulamasını, platformun sağladığı çeşitli özellikleri kullanarak geliştirip sizlerle paylaşmaya çalışacağım.
Bu konuda 4 adımlık bir seri içerisinde döviz kur değerlerini gösterecek bir uygulama üzerinde çalışmayı planladım. Bölümlerin içeriklerini özetlemek gerekirse:
1. activity – xml tabanlı ui tanımı – intent kullanımı
2. görsel bileşenler – veritabanını kullanma
3. service ve notification yapıları
4. yeni bir ui kontrol geliştirme
Geliştirme ortamının hazırlanması konusunda çeşitli kaynaklar bulunduğundan bu yazı içerisinde değinmeyeceğim, ama kendim geliştirme ortamı olarak Eclipse ve üzerinde Android plugin’i kullanıyorum.Android platformunda uygulama geliştirmek için bu toollara bağlı olmak zorunluluğu olmasada uygulama geliştirmede oldukça faydalı olduklarını belirtmek isterim. Bu dokuman boyunca anlattığım işlemleride bu konfigürasyonu baz alarak yapıyor olacağım.
Android uygulamalarında genelde ekran olarak kullanıcıya yansıtılan parçaların her birisi “Activity” olarak tanımlanmaktadır (ekran=Activity tanımlamasını kullanabiliriz). Bizde uygulamamızın ilk parçası olarak döviz kurlarını kullanıcıya bir liste halinde sunan Activity tanımımızı yapacagız.
Bunun için ilk başta “CurrencyConverter” adlı yeni bir Android projesi ve bunun içerisinde de CurrencyExchangeActivity adlı bir Activity oluşturalım.

Sonra Activity tanımımızın tasarlamaya başlayalım. Android platformunda Activity kapsamındaki UI tanımlarını iki türlü yapılabilmektedir:
1- kod içerisinde
2- xml tabanlı layout tanımları kullanılarak
Ancak UI ve Activity üzerindeki işlemleri düzgün bir şekilde decouple edebilmek için çoğunlukla XML tabanlı tanımlama kullanılmaktadır. Bizde uygulamamızda benzer bir yaklaşım kullanacağız.
Android projelerinde layout dosyaları “/res/layout” dizini altında tutulmaktadır. Bu dizin altında döviz kur bilgilerini listelemek için “currency_list.xml” isimli bir dosya oluşturalım.

Bu dosyanın içerisinde doviz kurlarını göstermek için kullanacağımız görsel yapıyı tasarlayalım. Şimdilik basit bir liste yapısı içerisinde bilgileri listeleyeceğimizden. bir layout içerisindeki bir list view tanımı ihtiyacımızı karşılayacaktır:
<?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" > <ListView android:id="@+id/currencyList" android:layout_width="fill_parent" android:layout_height="wrap_content" /> </LinearLayout>
Görsel tasarım kısmını bitirdiğimize göre yarattığımız Activity’nin bu layout dosyasını kullanmasını sağlamalıyız. Bunun için Activity’nin kodu içerisinde Activity’nin içeriği olarak bu layout’u göstermemiz gerekecek, bunun içinde Activity’nin “onCreate” metodu içinde “setContentView” metodunu çağırmamız yeterli olacaktır:
public class CurrenyExchangeActivity extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.currency_list); } }
Android içerisindeki “/res” dizini altına uygun şekilde yerleştirilen herşey, R (Resource) sınıfı içerisinde int olarak tanımlanmış id değerleri tarafından refere edilmektedir. “/res” dizini altında olabilecek bazı kaynakları incelersek:
1- /res/values –> basit değerler için
<resources> <string name="...">value</string> <color name="blue">#00F</color> <dimen name="...">value</dimen> <array name="..."> <item>...</item> </array> </resources>
2- /res/drawables –> imaj dosyaları
3-/res/layouts –> layout dosyaları
4-/res/anim –> animasyon dosyları
Bizde “R.layout.currency_list” ile tanımladığımız layout dosyasını ilgili yerlerde refere edebiliriz. R sınıfı kullanımı sadece bizim yarattığımız resource dosyalarına bağlı değildir, ayrıca Android içerisinde default olarak gelen resource itemlarıda “android.R” ile uygulamalarımızda kullanabiliriz.
Şimdi yapmamız gereken döviz kur değerlerini alıp, bunu list view’a uygun şekilde aktarmak olacaktır.
Döviz kur değerlerine ulaşmak için Restfull olarak tanımlanabilecek bir servis sunan “http://xml.altinkaynak.com.tr/doviz.xml” adresini kullanıcağız. Bu adresten doviz kur bilgilerini xml formatında alabiliyoruz:
<altinkaynak> <DOVIZ> <ADI>Tarih</ADI> <ALIS>23.04.2009 11:12:25</ALIS> <SATIS /> </DOVIZ> <!-- there can be more than one --> <DOVIZ> <ADI>USD</ADI> <ALIS>1.6300</ALIS> <SATIS>1.6470</SATIS> </DOVIZ> </altinkaynak>
ListView’a bu değerleri aktarabilmek için ise ListView sınıfındaki “setAdaptor” metodunu kullanacağız. Bu metod, parametre olarak “ListAdaptor” interface’inı implement eden sınıfların instancelarını kullanmaktadır. Uygulamamız için bir ArrayAdaptor yaratıp bunun içine aktarmayı düşündüğümüz değerleri String[] formatında yerleştirmemiz yeterli olacaktır.
Öncelikle yukarıda belirlen URL’den değerleri okuyup String[] olarak hazırlayan bir yapı hazırlayalım:
public String[] getExchange() throws IOException, SAXException, ParserConfigurationException { Vector<String> currencyVector = new Vector<String>(); SAXParserFactory saxParserFactory = SAXParserFactory.newInstance(); SAXParser saxParser = saxParserFactory.newSAXParser(); saxParser.parse(getResources().getString(R.string.currency_url), new CurrencyExchangeHandler(currencyVector)); return currencyVector.toArray(new String[currencyVector.size()]); } private class CurrencyExchangeHandler extends DefaultHandler { private final int STATE_DUMMY = 0; private final int STATE_DOVIZ = 1; private final int STATE_ALIS = 2; private final int STATE_SATIS = 3; private StringBuilder stringBuilder; private Vector<String> stringVector; private int state; private String delimeter = "-"; public CurrencyExchangeHandler(Vector<String> stringVector) { stringBuilder = new StringBuilder(); this.stringVector = stringVector; this.state = STATE_DUMMY; } @Override public void endElement(String uri, String localName, String name) throws SAXException { if("DOVIZ".equalsIgnoreCase(localName)) { stringVector.add(stringBuilder.toString()); stringBuilder.delete(0, stringBuilder.length()); } state = STATE_DUMMY; } @Override public void startElement(String uri, String localName, String name,Attributes attributes) throws SAXException { if("DOVIZ".equalsIgnoreCase(localName)) { state = STATE_DOVIZ; } else if("ALIS".equalsIgnoreCase(localName)) { state = STATE_ALIS; } else if("SATIS".equalsIgnoreCase(localName)) { state = STATE_SATIS; } } @Override public void characters(char[] ch, int start, int length) throws SAXException { switch (state) { case STATE_DOVIZ: stringBuilder.append(ch, start, length); break; case STATE_ALIS: stringBuilder.append(delimeter); stringBuilder.append(ch, start, length); break; case STATE_SATIS: if(length > 0) { stringBuilder.append(delimeter); } stringBuilder.append(ch, start, length); break; } } }
Yukarıdaki SAX parsing işlemi yazının konusunun dışında olduğu için değinmek istemiyorum, ihtiyaç duyarsanız Internet üzerinde oldukça fazla miktarda kaynak bulanilirsiniz.
Yapı içerisindeki şu kullanım dikkatinizi çekmiş olmalı:
saxParser.parse(getResources().getString(R.string.currency_url), new CurrencyExchangeHandler(currencyVector));
Daha önce belirttiğim gibi Android uygulamalarında uygulama içinde kullanılan çeşitli değerleri “/res” dizini altındaki çeşitli dizinlerdeki dosyalarda belirtebilmemiz ve bunlara R sınıfı içindeki id değerlerini kullanarak ulaşmanız mümkündür. Bende kullanacağımız URL’i “/res/values/strings.xml” dosyasında tanımlamayı uygun buldum:
<?xml version="1.0" encoding="utf-8"?> <resources> <string name="app_name">Currency Exchange</string> <string name="currency_url">http://xml.altinkaynak.com.tr/doviz.xml</string> </resources>
Sonrasında bu resource’un değerine ulaşmak için Activity içerisindeki “getResources().getString()” metodunu R sınıfı içerisindeki uygun id değeri ile birlikte kullanabiliriz.
Şimdi elde ettiğimiz bu String[] nesnesini ListView ile ilişkilendirelim:
ListView listView = (ListView) findViewById(R.id.currencyList); String[] content = getExchange(); ArrayAdapter<String> currencyAdaptor = new ArrayAdapter<String>(this,android.R.layout.simple_list_item_1,content); listView.setAdapter(currencyAdaptor);
Burada ArrayAdapter tanımında “android.R.layout.simple_list_item_1″ kısmı dikkatinizi çekebilir. Burada ListView içerisindeki itemların list içerisinde nasıl display edileceği belirtilir. Bu konuda kendimizde bir layout hazırlayıp kullanabileceğimiz gibi bu örnekte olduğu gibi Android içerisinde tanımlı olan layout tanımlarından da faydalanabiliriz.
Tüm bu işlemleri bitirdiğimizde Activity sınıfı aşağıdaki gibi olacaktır:
public class CurrenyExchangeActivity extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.currency_list); try { setExchange(); } catch (Exception e) { e.printStackTrace(); } } public void setExchange() throws IOException, SAXException, ParserConfigurationException { ListView listView = (ListView) findViewById(R.id.currencyList); String[] content = getExchange(); ArrayAdapter<String> currencyAdaptor = new ArrayAdapter<String>(this,android.R.layout.simple_list_item_1,content); listView.setAdapter(currencyAdaptor); } public String[] getExchange() throws IOException, SAXException, ParserConfigurationException { Vector<String> currencyVector = new Vector<String>(); SAXParserFactory saxParserFactory = SAXParserFactory.newInstance(); SAXParser saxParser = saxParserFactory.newSAXParser(); saxParser.parse(getResources().getString(R.string.currency_url), new CurrencyExchangeHandler(currencyVector)); return currencyVector.toArray(new String[currencyVector.size()]); } private class CurrencyExchangeHandler extends DefaultHandler { private final int STATE_DUMMY = 0; private final int STATE_DOVIZ = 1; private final int STATE_ALIS = 2; private final int STATE_SATIS = 3; private StringBuilder stringBuilder; private Vector<String> stringVector; private int state; private String delimeter = "-"; public CurrencyExchangeHandler(Vector<String> stringVector) { stringBuilder = new StringBuilder(); this.stringVector = stringVector; this.state = STATE_DUMMY; } @Override public void endElement(String uri, String localName, String name) throws SAXException { if("DOVIZ".equalsIgnoreCase(localName)) { stringVector.add(stringBuilder.toString()); stringBuilder.delete(0, stringBuilder.length()); } state = STATE_DUMMY; } @Override public void startElement(String uri, String localName, String name,Attributes attributes) throws SAXException { if("DOVIZ".equalsIgnoreCase(localName)) { state = STATE_DOVIZ; } else if("ALIS".equalsIgnoreCase(localName)) { state = STATE_ALIS; } else if("SATIS".equalsIgnoreCase(localName)) { state = STATE_SATIS; } } @Override public void characters(char[] ch, int start, int length) throws SAXException { switch (state) { case STATE_DOVIZ: stringBuilder.append(ch, start, length); break; case STATE_ALIS: stringBuilder.append(delimeter); stringBuilder.append(ch, start, length); break; case STATE_SATIS: if(length > 0) { stringBuilder.append(delimeter); } stringBuilder.append(ch, start, length); break; } } } }
Artık uygulamamızı çalıştırıp deneyebiliriz:

Eğer Eclipse üzerinde Android plugin’ni kullanıyorsanız, plugin Android platformu çalıştırdıktan sonra uygulamayı yükleyecek ve çalıştıracaktır.
Uygulamayı çalıştırdığınızda kullanıdığınız Android SDK’ya göre:
1- Boş bir ekran
yada
2-”java.net.SocketException: unknown error” hatası
Panik olmaya gerek yok :)
Internet erişimi gibi kaynak kullanımları Android platformunun güvenlik yapısında ekstra olarak belirtilmesi gereken izin kuralları kapsamında yapılmaktadır. Bu gibi durumlarda uygulamanın ihtiyaç duyduğu izinler “AndroidManifest.xml” dosyasının içerisinde “
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.yazarbozar.currentexchange" android:versionCode="1" android:versionName="1.0.0"> <application android:icon="@drawable/icon" android:label="@string/app_name"> <activity android:name=".CurrenyExchangeActivity" android:label="@string/app_name"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> <uses-permission android:name="android.permission.INTERNET"/> </manifest>
Şimdi uygulamamızı tekrar çalıştıralım:

Döviz kur değerleri artık elimizde :)
Bu tarz bir uygulamanın olmazsa olmaz bir noktasıda verinin güncellenebilmesidir, bu konuda da uygulamamıza bir menu adımı ekleyerek kullanıcının isteği zaman döviz kur değerlerini güncellemesini sağlayalım.
Android uygulamalarında iki tür menu vardır:
1- Activity tabanlı menüler –> Activity tanımlarına atanan menu adımları
2- Context tabanlı menüler –> Activity içerisinde kullanılan View tanımlarına atanan menu adımları
Örnek uygulamamızda “Activity Menu” tipinde bir menu yaratacağız. Bunun için Activity’nin “onCreateOptionsMenu” metodunu override ederek, metoda parametre olarak gelen Menu nesnesi içerisine kendi menu adımımızı ekleyeceğiz.
Öncelikle menu tanımında ekranda görenecek text değerini “/res/values/strings.xml” dosyasında tanımlayalım:
<?xml version="1.0" encoding="utf-8"?> <resources> <string name="app_name">Currency Exchange</string> <string name="currency_url">http://xml.altinkaynak.com.tr/doviz.xml</string> <string name="menu_item_refresh">Refresh</string> </resources>
Sonrasında Activity sınıfımızda gerekli işlemleri yapalım:
private int MENU_REFRESH = 1; @Override public boolean onCreateOptionsMenu(Menu menu) { super.onCreateOptionsMenu(menu); menu.add(0, MENU_REFRESH, 0, R.string.menu_item_refresh); return true; }
Menu adımı seçimlerinde yapılacak işlemleri kontrol altına almak için ise Activity’nin “onOptionsItemSelected” metodunu override edip, ilgili işlemlerimizi gerçekleştireceğiz:
@Override public boolean onOptionsItemSelected(MenuItem item) { if(item.getItemId() == MENU_REFRESH) { // what to do when MENU_REFRESH is selected try { setExchange(); } catch (Exception e) { e.printStackTrace(); } } return super.onOptionsItemSelected(item); }
Uygulamamızı tekrar çalıştırdığımızda “Menu” tuşuna basarak yarattığımız menuye ulaşabiliriz (kullandığımız servis gün içerisinde bir kaç dakikada bir içerik güncellemektedir):

Şimdi isterseniz uygulamadan çıkmak için bir menu adımı daha ekleyelim.
Öncelikle “/res/values/strings.xml” dosyasına yeni tanımımızı ekleyelim:
<?xml version="1.0" encoding="utf-8"?> <resources> <string name="app_name">Currency Exchange</string> <string name="currency_url">http://xml.altinkaynak.com.tr/doviz.xml</string> <string name="menu_item_refresh">Refresh</string> <string name="menu_item_exit">Exit</string> </resources>
Sonrasında Activity classında kullandığımız “onCreateOptionsMenu” ve “onOptionsItemSelected” metodlarını bu yeni isteğe göre güncelleyelim:
private int MENU_REFRESH = 1; private int MENU_EXIT = 2; @Override public boolean onCreateOptionsMenu(Menu menu) { super.onCreateOptionsMenu(menu); menu.add(0, MENU_REFRESH, 0, R.string.menu_item_refresh); menu.add(0, MENU_EXIT, 0, R.string.menu_item_exit); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { if(item.getItemId() == MENU_REFRESH) { // what to do when MENU_REFRESH is selected try { setExchange(); } catch (Exception e) { e.printStackTrace(); } } if(item.getItemId() == MENU_EXIT) { // what to do when MENU_EXIT is selected this.finish(); //Call this when your activity is done and should be closed } return super.onOptionsItemSelected(item); }
Uygulamamızı tekrar çalıştırıp menu yapısını incelersek:

Uygulamamızı görsel anlamda biraz zenginleştirmek için logomuzu gösteren bir açılış ekranı hazırlayıp, uygulamanın açılışında bu ekranın ilk olarak görüntülenmesini, belli bir süre sonrada yukarıda hazırladığımız döviz kur değerlerini gösteren ekranın gösterilmesini sağlamaya çalışalım.
Bunun için ilk önce açılışta görüntüleyeceğimiz ve uygulamamızın logosunu gösteren Activity’i hazırlayalım:
Öncelikle logomuzu hazırlayıp “/res/drawable/cover.jpg” olarak yerleştirelim.
Sonrasında layout dosyamızı “/res/layout/openning.xml” olarak hazırlayalım:
<?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" > <ImageView android:id="@+id/coverimage" android:layout_width="fill_parent" android:layout_height="fill_parent" android:src="@drawable/cover" /> </LinearLayout>
Burada dikkatimizi çekebilecek bölümlerden bir taneside aşağıdaki kullanım olabilir:
android:src="@drawable/cover"
tanım dosyalarında resource tanımlarına ulaşabilmek için aşağıdaki pattern kullanılır:
@[package_name:]resource_type/resource_identifier
Biz “/res/drawable/cover.jpg” dosyasına erişmeye çalıştığımızdan, yukarıdaki pattern’a göre tanım dosyasında “@drawable/cover” ile dosya erişimini sağlayabiliriz.
Son olarakta bu layout kullanacak Activity sınıfımızı hazırlayalım:
public class CurrencyExchangeCover extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.opening); } }
Bundan sonra ise bu Activity’i uygulamanın açılış Activity tanımı olarak belirtmemiz gerekiyor. Bu gibi tanımlamalar için “AndroidManifest.xml” dosyasını kullanacağız, bu dosya içerisinde hem uygulama (Application) hem de Activity bazında konfigurasyon tanımları yapılmaktadır.
AndroidManifest.xml dosyasını aşağıdaki şekilde hazırlayalım:
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.yazarbozar.currentexchange" android:versionCode="1" android:versionName="1.0.0"> <application android:icon="@drawable/icon" android:label="@string/app_name"> <activity android:name=".CurrencyExchangeCover" android:label="@string/app_name"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:name=".CurrencyExchangeActivity" android:label="@string/app_name"> </activity> </application> <uses-permission android:name="android.permission.INTERNET"/> </manifest>
Bir Activity tanımı içerisinde aşağıdaki tanımlamayı yaparsak, uygulama çalıştığında ilk olarak o Activity tanımı devreye girer:
<intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter>
Ayrıca ekrana getirilecek her Activity tanımı “AndroidManifest.xml” içerisinde tanımlanmak zorundadır.
Şu anda herşey tamamlanmış gibi görünsede, unuttuğumuz bir şey kaldı, oda açılış sayfasından döviz kur bilgileri sayfasına yönlendirmeyi sağlamaktır.
Android platformunda “Intent” adı verilen bir mesaj transfer sistemi bulunmaktadır. Intentler yardımıyla yapmak istediğiniz işi platforma tarif ederek, platformun bu iş için en uygun yapıyı devreye alması sağlanmaktadır (Yukarıdaki örneğimizde de aslında “intent-filter” tanımlaması ile sistemdeki hangi tarz intentlerde Activity’in devreye girmesini istediğimizi belirtmiştik).
Intent yapısı en çok şu iki alanda kullanılır:
1- Yeni bir Activity başlatmak
2- Sistem genelinde mesaj yayınlamak
Biz örnek uygulamamızda başka bir Activity’e yönlendirme yapmayı istediğimizden 1. maddede bahsedilen alan kapsamında kullanacağız.
Bunun için diğer Activity tanımına gitmek istediğimizi belirten bir intent tanımlayıp, sonrasında bunu “startActivity” metoduna girdi olarak vererek platformun istediğimiz Activity’i devreye almasını sağlayacağız:
protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.opening); final Intent intent = new Intent(this,CurrencyExchange.class); // in this example the target Activity is directly declared Runnable runnable = new Runnable() { @Override public void run() { try { Thread.sleep(5000); // wait for 5 seconds startActivity(intent); // jump to the Activity declared in the intent } catch (Exception e) { e.printStackTrace(); } } }; Thread thread = new Thread(runnable); thread.start(); }
Uygulamamızı tekrar çalıştırırsak:

Herşey doğru gibi görünsede uygulamamızın hala bir problemi var. Doviz kur bilgilerini gosterdiğimiz ekranda tanımladığımız “Exit” menu adımını seçersek uygulamadan çıkmak yerine açılış sayfasına geri döndüğümüzü görebiliriz. Bunun nedeni Android platformunda Activity instancelarının bir stack yapısı içinde tutulması yatmaktadır, “CurrenyExchangeActivity” instance’ında “finish” metodunu çalıştırdığımızda platform bizi bu Activity’e çağıran Activity’e yönlendirmektedir, ki bu bizim uygulamamızda açılış ekranı olarak kullandığımız “CurrencyExchangeCover” instance’sıdır.
Bu durumun aşmak için “CurrencyExchangeCover” sınıfında başka bir Activity başlattığımızda, başlattığımız Activity kapanırken bize sonuç dönmesini istediğimizi belirtelim. Bunun için Activity içindeki “startActivityOnResult” metodunu kullanmamız gerekmektedir. Başlattığımız Activity kapanırken, “onActivityResult” metodu -başlatırken kullandığımız parametre değerini geri dönüş değeri olarak kullanarak- çalıştırılacaktır.
private final int REQUEST_CODE = 1; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.opening); final Intent intent = new Intent(this,CurrencyExchangeActivity.class); Runnable runnable = new Runnable() { @Override public void run() { try { Thread.sleep(5000); startActivityForResult(intent,REQUEST_CODE); } catch (Exception e) { e.printStackTrace(); } } }; Thread thread = new Thread(runnable); thread.start(); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if(requestCode == REQUEST_CODE) { this.finish(); } }
Yukarıdaki gibi bir yapı tasarladığımızda “CurrencyExchangeActivity” instance’ı “finish” metodunu çalıştırdığında “CurrencyExchangeCover” instance’ındaki “onActivityResult” metodu çağrılacak, geri dönüş değeri kontrol edilerek uygun durumda “finish” durumu çalıştırılarak bizi stack’de bir geriye yönlendirecektir.
Uygulamamızın 1. adımını bu şekilde bitirmiş olduk, umarım sizler için faydalı bir dokuman olmuştur. 2. bolumde tekrar buluşmak üzere.
iPhone 3.0 için yazılan projeyi 2.2.1 veya daha eski versiyonda derlemek
Açıkcası bu bir konu değil. Sadece bir bug ve çözüm yöntemi hakkında.
Hepimiz Apple tarafındaki yeni güncellemeleri günü gününe takip ediyoruz. Dolayısı ile iPhone için development yapan herkes şu an Xcode ve iPhone SDK’nın son versiyonunu (bugün için beta3) kullanıyordur. Sorunumuzda bu beta versiyon ile ilgili. Eğer projenizi bu beta versiyon ile geliştiriyorsanız ve yanlışlıkla active sdk seçeneğinden simulator veya device versiyonunu 3.0 seçtiyseniz artık önceki versiyonlarda derleyemediğinizi göreceksiniz.
Bu bir bug. Yani en azından ben çözüm yöntemini buldum :) Adım adım şu şekilde yapıyoruz:
- - Önce uygulamamızdan, Xcode’dan ve Simulator’dan çıkıyoruz.
- - Finder ile uygulamamızı geliştirdiğimiz klasörün içerisine giriyoruz.

Xcode 3.0 'da sadece 3.0 seçilmiş uygulama
- - Klasör içerisinde uygulamanın .xodeproj uzantılı klasörünün üzerine geliyoruz (evet klasör ama dosya gibi davranır)
- - Üzerine sağ mouse tuşu ile yada mac tabiri apple + mouse tuşu ile tıklıyoruz.

Uygulamanın bulunduğu klasör...
- - Karşımıza çıkan seçeneklerden Show Package Content seçeneğini seçiyoruz.
- - Yeni bir finder penceresi ile karşılaşıyoruz. İçinde 3 dosya olan.
- - project.pbxproj ve isimli dosyanın üzerine sağ mouse ile tıklıyoruz.

Uygulamanın proje bilgisinin kaydedildiği yer
- - Open With… menüsü içinde Other seçeneğinden Textedit.app uygulaması ile açıyoruz.
- - Apple + F ile (find) dosya içinde 3.0 rakamını aratıyoruz.
- - Uygulmaya göre tek veya bir kaç alanda bulacağı bu rakamın yerine 2.0 yada 2.2.1 yazıyoruz.

3.0 ibaresini 2.0 yada 2.2.1 ile değiştirdiğimiz yer...
- - Dosyayı kaydedip çıkıyoruz. Aynı işlemi username.pbxproj üzerindeki dosyadada yapıyoruz tabi…
Artık uygulamamızda tekrar 2.0 veya üstündeki sürümler için derleme ve debug seçeneklerinin geri geldiğini görebilirsiniz…
//A.i.
iPhone ile Web Service Kullanımı
Posted by Kayhan Bölükbaş in Genel, iPhone on April 14th, 2009
iPhone uygulaması yazarken “Web Service” leri kullanmak isterseniz giriş niteliğinde kabul edilebilecek bu belgeyi kullanabilirsiniz.
Önce çalışan bir “Web Service” örneğine ihtiyacımız var. Asıl amaç “Web Service” yazmak olmadığından, elinizin altında da olmaması durumunda, birde bununla uğraşmamak için aşağıdaki örneği kullabilirsiniz. Bu dokümanın devamında bu örnek üzerinden anlatım yapılacaktır.
http://www.w3schools.com/webservices/tempconvert.asmx?op=CelsiusToFahrenheit
Bu adresi web tarayıcınıza yazdığınızda gelecek sayfada XML mesajlarını(sırasıyla request & response) görebilirsiniz. Öncelikle buradan “request” mesajını alıp koda yerleştirmekle işe başlayabilirsiniz.

NSString *soapMessage = @"<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" "<soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">\n" "<soap:Body >\n" "<CelsiusToFahrenheit xmlns=\"http://tempuri.org/\">\n" "<Celsius>25</Celsius>\n" "</CelsiusToFahrenheit>\n" "</soap:Body>\n" "</soap:Envelope>\n";
XML datayı oluşturduktan sonra “Web Service URL” i ile bir URL objesi ve “request” oluşturmak gerekecek. Bu request için “HTTP Header” alanlarını tanımlayabilirsiniz.
“Content-Type”
“SOAPAction”
“Content-Length”
Bunları XML mesajının üzerinde bulabilirsiniz. “HTTP Method” ve “HTTP Body” yi de tanımladıtan sonra “request” i kullanarak bağlantıyı oluşturmaya başlayabilirsiniz.

NSURL *url = [NSURL URLWithString:@"http://www.w3schools.com/webservices/tempconvert.asmx?op=CelsiusToFahrenheit"]; NSMutableURLRequest *theRequest = [NSMutableURLRequest requestWithURL:url]; NSString *msgLength = [NSString stringWithFormat:@"%d", [soapMessage length]]; [theRequest addValue: @"text/xml; charset=utf-8" forHTTPHeaderField:@"Content-Type"]; [theRequest addValue: @"http://tempuri.org/CelsiusToFahrenheit" forHTTPHeaderField:@"SOAPAction"]; [theRequest addValue: msgLength forHTTPHeaderField:@"Content-Length"]; [theRequest setHTTPMethod:@"POST"]; [theRequest setHTTPBody: [soapMessage dataUsingEncoding:NSUTF8StringEncoding]]; NSURLConnection *theConnection = [[NSURLConnection alloc] initWithRequest:theRequest delegate:self];
Artık yapılması gereken bir bağlantı kurup, dönen XML cevabı parse etmek. Bağlantıyı “NSURLConnection” ile sağlıyoruz. Bağlantı sağladığında “NSURLConnection” in bazı methodlarını düzenlemek gerekmektedir. Dönen veriyi alabilmek için bu methodlar kullanılabilir. Cevabı “NSMutableData” objesine alarak, içinden istediğimiz değeri alabilirsiniz.
“NSURLConnection” methodları:
- “didReceiveResponse” bağlantı kurulabiliyorsa çalışır. Bağlantı kurulabildiğini anladığımızda bizde Data’mızı sıfırlıyoruz.
- “didReceiveData” herhangi bir data alınabildiğinde çalışır. Burada dönen datayı objenize alabilirsiniz.
- “didFailWithError” ile herhangi bir hata durumunda “connection” ve “data” objelerini release etmek için uygun yer olacaktır.
- Son method ise “connectionDidFinishLoading” bağlantı sona erdiğinde çalışacaktır. Burada dönen datadan bir xml metin oluşturabilir ve bu xml metni parse edebilirsiniz.
// Bağlantı kurulabiliyor mu? -(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response { [webData setLength: 0]; } // Dönen datayı alabileceğimiz method. -(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data { [webData appendData:data]; } // Bağlantıda herhangi bir hata olursa çalışacak method. -(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error { NSLog(@"ERROR with theConnection"); [connection release]; [webData release]; } // Bağlantı cevabı döndüğünde çalışan method. XML parse işlemini burada gerçekleştiriyoruz. -(void)connectionDidFinishLoading:(NSURLConnection *)connection { NSLog(@"DONE. Received Bytes: %d", [webData length]); NSString *theXML = [[NSString alloc] initWithBytes: [webData mutableBytes] length:[webData length] encoding:NSUTF8StringEncoding]; NSLog(theXML); [theXML release]; if( xmlParser ) { [xmlParser release]; } xmlParser = [[NSXMLParser alloc] initWithData: webData]; [xmlParser setDelegate: self]; [xmlParser setShouldResolveExternalEntities: YES]; [xmlParser parse]; [connection release]; [webData release]; }
“connectiondidFinishLoading” methodunda görebileceğiniz gibi dönüş değeri olan XML datayı NSXMLParser ile ayrıştırabilirsiniz. Bunu yapmak içinde NSXMLParser’ın methodlarını çağırmanız gerekmektedir:
- “didStartElement” ile XML içindeki elementlerin başlangıcına bakıyoruz. Burada “CelsiusToFahrenheitResult” elementini arıyoruz. (recordResults = TRUE;)
- “foundCharacters” elementin içindeki değeri eğer doğru element ise alacak method.
- Son method elementin bitişine bakıyor. Burada aldğımız değeri ekrana yerleştirecek kod parçasını yazabilirsiniz.
// XML Element başlangıcı. -(void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *) namespaceURI qualifiedName:(NSString *)qName attributes: (NSDictionary *)attributeDict { if( [elementName isEqualToString:@"CelsiusToFahrenheitResult"]) { if(!results) { results = [[NSMutableString alloc] init]; } recordResults = TRUE; } } // Elementin içinde yazılı değer aldığımız method. -(void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string { if( recordResults ) { [results appendString: string]; } } // XML içinde .... ile Element bittiğinde aldığımız değeri ekranda bir component(Label, TextField vb.) içinde // gösteriyoruz. -(void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName { if( [elementName isEqualToString:@"CelsiusToFahrenheitResult"]) { recordResults = FALSE; myLabel.text = results; [results release]; results = nil; } }
“Web Service” örneğimiz dönüş değerini XML metni içinde isimli “Tag” ile vermekte. Bu değeri XML içinde alabilmek için yukarıda görüdüğümüz “didStartElement” ve “didEndElement” methodlarını yazdık. Start methodunda elementini gördüğümüz yerde bir “result” objesi oluşturuyor ve doğru elementi bulduğumuzu belirten bir sonuç değişkenine “TRUE” değerini atıyoruz. Sonra doğru elementte ise o elementin değerini “results(NSMutableString)” içine alıyoruz. En sonda ise “myLabel(UILabel)” üstüne yazdırıyoruz.
Bu yazıda geçen kavramlar ile ilgili ayrıntılı bilgi için aşağıdaki bağlantıları kullanabilirsiniz:
http://developer.apple.com/documentation/Cocoa/Conceptual/URLLoadingSystem/Tasks/UsingNSURLConnection.html
http://developer.apple.com/documentation/Cocoa/Conceptual/XMLParsing/XMLParsing.html
http://www.w3schools.com/soap/default.asp
Güncel Yorumlar