bm yazılım - staj raporu · pdf filebu doğrultuda staj süresi boyunca ... site, 81 il...

39
Trakya Üniversitesi Mühendislik-Mimarlık Fakültesi Bilgisayar Mühendisliği Bölümü BM Yazılım - Staj Raporu Teslim Eden : İsim-Soyisim : Muhammet Umut AKSOY Numara : 1090203045 Kuruluşun İsmi ve Yeri : Trakya Üniversitesi Bilgi İşlem Edirne, Türkiye Staj Tarihleri : 17.06.2013 – 15.07.2013

Upload: dodan

Post on 31-Jan-2018

249 views

Category:

Documents


5 download

TRANSCRIPT

Trakya Üniversitesi

Mühendislik-Mimarlık Fakültesi

Bilgisayar Mühendisliği Bölümü

BM Yazılım - Staj Raporu

Teslim Eden :

İsim-Soyisim : Muhammet Umut AKSOY

Numara : 1090203045

Kuruluşun İsmi ve Yeri : Trakya Üniversitesi Bilgi İşlem

Edirne, Türkiye

Staj Tarihleri : 17.06.2013 – 15.07.2013

GİRİŞ

Trakya Üniversitesi Bilgi İşlem Bölümünde yapacağım yazılım stajı boyunca, Android

işletim sistemli cihazlar için uygulama geliştirme konusunda ve Java Programlama Dili üzerinde

kendimi geliştirme ve tecrübe kazanma amacı taşımaktayım. Bu doğrultuda staj süresi boyunca

Eclipse geliştirme ortamını kullanarak android uygulama geliştirmek istiyorum. Geliştireceğim

mobil uygulama, içinde Jsoup kütüphanesi, AsyncTask metodu ve HashMap uygulamasının yer

aldığı kaynak siteye bağlanan ve bu siteden veri çeken hava durumu uygulaması olacaktır.

1. GÜN

Staj boyunca android programlama üzerine kendimi geliştirmeye karar vermem nedeniyle

proje olarak android cihazlar için hava durumu uygulaması yazmaya karar verdim. Mevcut hava

durumu uygulamalarını incelemekle işe başladım. Meteoroloji Genel Müdürlüğü tarafından

yayınlanmış olan hava durumu uygulamasının yanı sıra birden çok dilde hizmet veren uluslararası

hava durumu uygulamalarının çalışma prensiplerini incelememin sonunda, sadelik ve performansın

ön planda olacağı bir hava durumu uygulaması düşüncesini benimsedim. Bu düşünce doğrultusunda

aldığım bazı notlar;

*Türkiye'nin tüm illerinin hava durumu tahminlerini içinde barındıran bir meteoroloji raporu

sunan herhangi bir siteden hava durumu raporlarına erişim sağlanacak,

*Uygulamayı çalıştıracak cihaz ekranlarının küçüklüğü nedeniyle raporlardaki gereksiz

açıklamalar ayıklanacak ve sadece tarih, gece – gündüz sıcaklıkları ve yağış durumu hakkında

bilgiler sunulacak,

*Yine cihaz ekranlarının küçüklüğü göz önünde bulundurularak hava durumu bilgisine

ulaşılacak ilin kolay ulaşılabilecek durumda olması gerekmektedir. Bu sorunu çözmek için arama

sonuçlarını anında yansıtan bir arama kutusu tasarlanacak ve en üstte yer verilecektir.

Alınan bu notlar proje sonuna kadar temel teşkil edeceğini düşünüyorum. Proje başında

öngörülemeyen durumlar yaşandığı takdirde notlar üzerinde gerekli düzenlemeler yapılacaktır.

Öncelikle hava durumu raporlarının alınabileceği bir site bulmak için araştırmaya başladım

ve stajın ilk günü bitiminde siteyi bulmayı başardım. Yabancı kaynaklardan alınacak raporların

çevirilerinde oluşacak sorunların tamamı ile çözülemeyeceği, wunderground.com, weather-

forecast.com, accuweather.com, weather.com gibi siteler ayrıntılı olarak incelendiğinde

anlaşılmıştır.

Ayrıca yukarıda bahsedilen sitelerdeki verilerin raporlamaya uygun olacak şekilde mobil

uygulamaya aktarılamayacağı sonucuna varılmıştır. Bu noktadan sonra ihtiyacımızı karşılayacak

hava durumu sitesi Türkçe yayın yapan ve hava durumu tahminlerini belirli bir düzende aktaran

alternatifler araştırılmaya başlanmıştır.

Türkiye'de yayın yapan başlıca hava durumu siteleri;

www.mgm.gov.tr

http://www.haberturk.com/havadurumu

http://havadurumu.hurriyet.com.tr/

http://www.havadurumux.com

http://www.havadurumu.org/

http://15gunlukhavadurumu.gen.tr

Yukarıda yer alan sitelerin bir kısmı hava durumu raporlarını görseller içinde verdikleri için

verileri almak, işleyerek mobil uygulamada kullanmak mümkün olmayacaktır. Yani sadece,

mgm.gov.tr, havadurumux.com ve 15gunlukhavadurumu.gen.tr sitelerindeki veriler işlenebilecek ve

mobil uygulamada kullanılabilecek durumdadır. Bu siteler arasındaki tercih ise sayfa boyutu en

küçük olan siteden yana olacaktır. Mobil cihazların internet kullanımında sıkıntılar yaşamaları ve

görece daha yavaş internet bağlantılarına sahip olmaları bu tercihte etkili olmaktadır. Mgm.gov.tr

sitesindeki sayfaların boyutu yaklaşık 11 KB, havadurumux.com sitesindeki sayfaların boyutu

yaklaşık 9 KB, 15gunlukhavadurumu.gen.tr sitesindeki sayfaların boyutu ise yaklaşık 6 KB'dır. Gün

sonunda 15gunlukhavadurumu.gen.tr üzerinden verilerin çekileceğine karar verilmiştir. Stajın 2.

günü bu site detaylıca incelenecektir.

2. GÜN

Dün hava durumu tahminlerinin 15gunlukhavadurumu.gen.tr sitesi üzerinden çekileceğini

kararlaştırmıştım. Bugün ilk olarak sitenin yapısını detaylıca incelemeye başlıyorum.

Site, 81 il ve bu illerin ilçelerine göre 15 günlük hava durumu tahminlerini yayınlamakta.

Sitede yer alan yaklaşık 900 ilçeye ait hava durumu verileri mobil uygulamaya taşındığında

uygulamanın performansını olumsuz olarak etkileyecektir. Bunun nedeni illerin hava durumlarına

ulaşılırken standart bir adres yapısı olmasına rağmen, ilçelerin hava durumlarına ulaşılırken

standarttan uzak farklı adres yapılarının yer almasıdır.

Daha açık bir ifadeyle,

http://www.15gunlukhavadurumu.gen.tr/ankara-hava-durumu-15-gunluk/

http://www.15gunlukhavadurumu.gen.tr/mus-hava-durumu-15-gunluk/

http://www.15gunlukhavadurumu.gen.tr/sinop-hava-durumu-15-gunluk/

görüldüğü gibi illere ait sayfaların standart bir yapısı vardır. İstenen ilin sayfasına

http://www.15gunlukhavadurumu.gen.tr/ + il adı + -hava-durumu-15-gunluk/ gibi bir yapıyla

ulaşılabilinir. Bu standart yapı, bizi, herhangi bir veritabanında illerin adreslerini tutma

zorunluluğundan kurtarmıştır. İl gibi bir değişken ile bütün illere ulaşılabilinir. Fakat ilçeler için

aynı durum söz konusu değildir.

Örneğin Muş ilinin Bulanık ilçesi sayfasına,

http://www.15gunlukhavadurumu.gen.tr/mus-hava-durumu-15-gunluk/mus-bulanik/

adresiyle ulaşılırken, yine Muş ilinin Malazgirt ilçesine ait sayfaya

http://www.15gunlukhavadurumu.gen.tr/mus-hava-durumu-15-gunluk/mus-malazgirt-hava-

durumu-15-gunluk/ şeklinde bir adres yapısıyla ulaşılmaktadır. Bu farklılık nedeniyle bütün ilçeler

için id, ilçe adı, sayfa adresi sütunlarından oluşacak veritabanı oluşturulması gerekliliği ortaya

çıkmaktadır.

Performansı ve kullanışlılığı etkileyecek önemli bir faktör olması nedeniyle bundan

kaçınılacak ve sadece iller bazında hava durumlarının değerleri uygulamada yer alacaktır.

Bu aşamadan sonra istenilen internet adresine bağlanıp adresteki tüm veriyi bir yerde

depolayan ve bu veri içinden sadece istenilen kısımların kullanılacağı bir metod üzerine çalışmalar

yapılacaktır. Girilen sayfanın bütün verilerinin mobil uygulamada gösterilmesinin bir anlamı yoktur.

Önemli olan sadece hava durumu tahminlerinin, sıcaklıkların ve tarihlerin yer aldığı bölümlerin

uygulama içinde yer almasını sağlamaktır.

Günün son saatlerinde bu metod ve algoritma üzerine yoğunlaşılmıştır. Fakat elle tutulur bir

sonuç alınamamıştır. Yarın bu metod üzerine düşünmeye devam edeceğim ayrıca çeşitli yabancı

kaynaklardan da istediğim şekilde bir metod bulabilmek ümidiyle araştırmalar yapacağım...

3. GÜN

İstenilen web sayfasındaki verileri çekebilmek için uzun süre araştırma yaptım. HttpUnit,

JUnit testing, Web Crawling gibi yöntemleri derinlemesine araştırdım. Java programlama diliyle

kullanılabilecek yöntemlerin çoğunluğuna göz gezdirdim ve verilmiş bir çok örneği inceledim.

Sonrasında bu yöntemlerden daha basit ve daha uygun bir yöntemle karşılaştım. Java'da sadece bu

sorunu etkili bir şekilde çözmek için oluşturulmuş proje olan Jsoup, araştırma ve kodlama sırasında

faydalanılabilecek en geniş dökümantasyona sahip. Resmi sitesi olan http://jsoup.org/ üzerindeki

tanım ve örnekleri okumaya ve incelemeye başladım.

Jsoup java için yazılmış bir HTML Parser'dır. Yoğun bir ilgi görmesi nedeniyle farklı

programlama dilleri için de geliştirmeler yapılmıştır. Yapısının DOM (Document Object Model)

olmasından dolayı çok kullanışlıdır. Diğer HTML Parser'lardan en önemli özelliği HTML tag ve

CSS class yapılarına göre filtreleme yapabilmesidir. Hava durumu verilerini çekeceğimiz

15gunlukhavadurumu.gen.tr sitesinin kaynak kodlarına baktığımızda; <tr> <td>18 Haziran 2013<br/>Pazartesi</td> <td><img src="/icons/113_35x35.png" alt="Güneşli" title="Güneşli"

height="35" width="35" /></td> <td style="text-align: left;">Güneşli</td> <td style="text-align: center;">27&deg;</td> <td style="text-align: center;">22&deg;</td> </tr>

<tr> <td>19 Haziran 2013<br/>Salı</td> <td><img src="/icons/113_35x35.png" alt="Güneşli" title="Güneşli"

height="35" width="35" /></td> <td style="text-align: left;">Güneşli</td> <td style="text-align: center;">27&deg;</td> <td style="text-align: center;">23&deg;</td> </tr>

hava durumu tahminlerinin yukarıda da görüldüğü gibi <td> tagleri içinde bulunduğunu

görüyoruz. Jsoup kütüphanesinin HTML tag'lere göre filtreleme yapabilmesinin vereceği bu

esneklik projemize hız kazandıracaktır.

Projemizde siteyle bağlantı kurmamızı sağlayacak yöntemi seçtikten sonra Jsoup

kütüphanesini indirmemiz gerekiyor. Bugün, Jsoup kütüphanesinin Eclipse ortamında geliştirilecek

projeye eklenmesini tamamladıktan sonra yarın Jsoup üzerine araştırmalara devam edeceğim ve

Eclipse ortamında projenin ilk adımlarını atacağım.

Projemize Jsoup kütüphanesini eklemek için Jsoup.org sitesinin indirme bölümünde

jsoup-1.7.2.jar isimli kütüphaneyi indirmemiz gerekiyor. İndirme adresi :

http://jsoup.org/packages/jsoup-1.7.2.jar

İndirdiğimiz jar dosyasını projenin libs klasörü içine kopyaladıktan sonra kullanacağımız

herhangi bir java dosyasında import ederek rahatlıkla kullanabiliyoruz. Artık, projeyeimport org.jsoup.Jsoup;

import org.jsoup.nodes.Document;

import org.jsoup.nodes.Element;

import org.jsoup.select.Elements;

şeklinde temel komutları import edebiliriz.

4. GÜN

Günün önemli kısmını Jsoup kütüphanesinin dökümantasyonlarını okuyarak geçirdim.

Özellikle "select" metodu üzerine bir çok örnek inceledim ve kullanılışı hakkında önemli bilgiler

edindim.

Select metodu, Döküman (Document), Element (Element) ve Elementler (Elements)

üzerinde kullanılabilen bir metod. Select metodu işlem yaptıktan sonra sonuç olarak Elements yani

Element listesi döndürür. Fakat ilk değeri, son değeri ya da filtrelemeye uygun olarak istenen tek

değeri Element olarak döndürdüğü metodlara da sahiptir.

Element.select(String selector) şeklinde bir kullanıma sahiptir. Seçim

yapacak bir String değer alır. Ve yukarıda da belirttiğim gibi Documents, Elements, Element

üzerinde çalışabilir. Buna basit bir örnek vermek gerekirse;File input = new File("/tmp/input.html");Document doc = Jsoup.parse(input, "UTF-8", "http://example.com/");Elements link = doc.select("a[href]"); // döküman içerisinde a href etiketi bulunanları seç ve link Elementlerine

ata.Elements png = doc.select("img[src$=.png]");// img src etiketi bulunan sonu .png ile bitenleri seç ve png

Elementlerine ataElement masthead = doc.select("div.masthead").first();// masthead sınıfı olan divlerin ilkini seç ve masthead elementine ata.Görüldüğü gibi documents olarak tanımlanmış olan doc nesnesinden istenilen özellikteki

kısımları çok rahatlıkla alıp Element ya da Elements olarak tanımlanmış nesnelere aktarmaktadır.

Örnek olarak verdiğim kodlarda görüldüğü gibi select() metodunun first() gibi metodları da

bulunmaktadır. Select() metoduyla kullanılan diğer önemli alt metodları da araştırdım.

Öğrendiklerimden bazıları şunlardır;

Element.Select(String selector).add(Element element) => add içerisindeki elementi ekler.

Element.Select(String selector).after(String arg0) => after içerisindeki stringten sonra gelen

elementi seçer.

Element.Select(String selector).before(String arg0) => before içerisindeki stringten önce

gelen elementi seçer.

Element.Select(String selector).clear() => elementi temizler.

Element.Select(String selector).clone() => başka bir elemente kopyalar (klonlar).

Element.Select(String selector).contains(Object o) => o nesnesi içerip içermediğini kontrol

eder, Boolean değer döndürür.

Element.Select(String selector).equals(Object o) => o nesnesine eşit olup olmadığını kontrol

eder, Boolean değer döndürür.

Element.Select(String selector).first() => ilk elementi seçer.

Element.Select(String selector).get(int index) => verilen index değerindeki elementi alır.

Element.Select(String selector).last() => son elementi alır.

Element.Select(String selector).text() => verileri element olarak değil text olarak alır ve

element değil String değer döndürür.

Jsoup kütüphanesinin çok zengin olması nedeniyle kullanılan metodlara ait yüzlerce farklı

ve çok kullanışlı alt metodlar bulunmaktadır. Select metodunun sahip olduğu burada yer almayan

onlarca farklı alt metod bulunmaktadır.

5. GÜN

Dün Jsoup kütüphanesinin select metoduyla ilgili yaptığım araştırma ve incelemelere

bugünde devam ettim. Select metodunun genel olarak CSS taglere göre seçim yapıldığından

bahsedilse de farklı kullanım yöntemleriyle çok daha fazla seçenek sunabiliyor. Bugün gün boyunca

Select(String seçenek) kısmıyla yani Select metoduna değer olarak verdiğimiz Stringlerin tipleri

hakkında bilgiler edindim. Öğrendiklerimi aktaracak olursam;

• tagname: tag ismine göre elementleri bulur. Örneğin a tagine göre...

• ns|tag: namespace'e göre yani verilen isim uzayındaki bir tag ismine göre

elementleri bulur. Örneğin değer olarak verilenfb|name stringi <fb:name> etiketinde yer

alan elementleri bulur.

• #id: ID'ye göre elementleri bulur. Örneğin #logo yazıldığında logo ID'sine sahip

olan elementleri bulur.

• .class: sınıfına göre elementleri bulur. Örneğin.masthead sınıfındaki

elementleri alabiliriz.

• [attribute]: özelliğine göre elementleri bulur. Örneğin [href] özelliği

bulunan elementleri seçtirebiliriz.

• [attr=value]: yazılan değere eşit olan özelliğin olduğu elementleri bulur.

Örneğin [width=500] yazdığımızda genişliği 500'e eşit olan elementler seçilir.

• [attr^=value], [attr$=value], [attr*=value]: belirtilen özellikle

başlayan, belirtilen özellikle biten ya da belirtilen özelliği içinde barındıran elementler

seçilir.

• [attr~=regex]: düzenli ifadelere göre de seçim yapmak mümkündür. Örneğin

img[src~=(?i)\.(png|jpe?g)] şeklinde bir string yazdığımızda src etiketinin

bulunduğu png, jpg, jpeg formatındaki resimleri seçmemizi sağlar.

• *: bütün elementleri seçmemizi sağlar.

Yukarıdaki gibi yaptığımız seçimlere ek olarak, bu özellikleri birlikte kombinasyonlar

şeklinde kullanarak da seçimler yapabiliriz. Bu konuda öğrendiklerim;

• el#id: element ve ID bir arada. Örneğin div#logo

• el.class: element ve sınıf bir arada. Örneğin div.masthead

• el[attr]: element ve özelliği bir arada a[href]

Bunun gibi birçok özelliği birlikte kullanma esnekliği sayesinde select metodunun gücünü

kat kat artırabiliriyoruz.

Jsoup kütüphanesinin dökümantasyonunu okumaya devam ediyorum. Haftaya

http://try.jsoup.org adresine verileri çekilecek sitenin kaynak kodlarını yükleyerek denemeler

yapmaya başlayacağım.

6. GÜN

İlk hafta yoğun bir araştırma ve öğrenme dönemi oldu. İkinci haftanın daha çok proje

tasarımı ve algoritmalar üzerinde geçmesini temenni ediyorum.

Geçen hafta Jsoup kütüphanesinin dökümanlarının bir kısmını okuduktan sonra şimdi

http://try.jsoup.org adresinden faydalanarak denemeler yapmaya başlayabilirim. Öncelikle hava

durumu verilerini çekeceğim 15gunlukhavadurumu.gen.tr sitesine tekrar dönelim. Her ile ait hava

durumu verilerine http://15gunlukhavadurumu.gen.tr/+"il adı"+-hava-durumu-15-gunluk/

şeklindeki sayfalarla ulaşabiliyorduk. Şimdi de sayfaların kaynak kodlarını inceleyelim ve hava

durumu verilerine ulaşma yollarına bakalım.Jsoup deneme sayfasında Edirne iline ait sayfanın

kaynak kodlarını koyarak denemelere başladım. Öncelikle filtreleme yaptırabileceğim herhangi bir

css tag aradım fakat sadece hava durumlarını ayrıştıracak herhangi bir tag bulamadım. Sonra hava

durumu verilerinin tablo şeklinde gösterildiğini farkettim ve HTML table kodlarında ayıracak

denemeler yapmaya başladım.

<tr> etiketini girdiğimde hava durumu verilerinin günlere göre ayrıldığını fakat her gün

için, gelen verilerin ayrıştırılmasının zor olacağını farkettim. Android projemizde tarih verilerinin

ayrı, hava verilerinin ayrı, sıcaklık verilerinin ayrı olarak gösterilmesi, karmaşıklığı azaltacak

olması nedeniyle seçilmiştir. <tr> etiketi ile istediğim şekilde düzenleme yapamayacak olmamdan

dolayı başka daha özel bir etiket aramaya başladım.

Sonrasında <td> etiketinin sadece hava durumu verilerinde kullanıldığını ve bu verileri

istediğim şekilde, tarih, hava durumu, sıcaklık olacak şekilde farklı farklı listeleyebildiğini gördüm.

http://try.jsoup.org adresinde yaptığım <td> denemesinde, bir string dizisi içinde 0. eleman 1. gün

tarihi, 1. eleman 1. gün hava durumu resmi, 2. eleman 1. gün hava durumu, 3. eleman 1. gün

gündüz sıcaklığı, 4. eleman 1. gün gece sıcaklığı şeklinde tutulabileceğini farkettim. Yani her bir

günün verileri için string dizide 5 hücre tutulacak ve istenen bir günün verilerine 5*İstenen gün

formülüyle ulaşabiliyoruz. 14 günlük verilerin olduğu sitede 60 elemanlı bir dizi üzerinde bütün

verileri ayrıştırılmış olarak saklayabilir ve bu elemanlar üzerinde istediğimiz şekilde işlemler

yapabiliriz.

Verileri çekme ve işleme konusuna bu şekilde bir çözüm bulduktan sonra projenin tasarımı

için algoritmaları üzerine düşünmeye başladım. En az iki farklı ekran olması gerektiği, ilk ekranda

illerin listelendiği ve bu illerden birisinin seçileceği, ikinci ekranda seçilen ilin verilerinin

listeleneceği bir işleyiş olması gerektiğine karar verdim. İlk ekrandan seçilen il bilgisinin ikinci

ekrana gideceği, ikinci ekranda bu bilgi ile gerekli internet sayfasına erişilip hava durumu

tahminlerinin alınarak ikinci sayfa içinde yer alacak ögelerde listeleneceği geliştireceğim

algoritmanın temellerini oluşturacağını gün sonunda bulmuş oldum. Bu temel üstüne diğer detayları

ilerleyen günlerde tamamlamayı planlıyorum.

7. GÜN

Bütün gün algoritma geliştirme üzerine çalıştım. Projede kullanılacak algoritmaları büyük

ölçüde oluşturdum. Kullanacağım algoritmalar;

1.Başla

2.İl adlarını yükle

3.İlleri listele

4.İl arama çubuğuna değer girildiğinde girilen değere göre tekrar illeri listele.

5.İl seçildiğinde seçilen il verisini tut, diğer ekrana geç.

6.İlk ekrandan gelen veriyi al, büyük harfleri küçük harflere çevir, Türkçe karakterleri

dönüştür ve il değişkeni olarak tut.

7.site ismi + il değişkeni + hava-durumu-15-gunluk adres değişkeni oluştur.

8.Jsoup kütüphanesinden faydalanarak adres değişkenindeki adresle bağlantıyı başlat.

9.Başlatılan bağlantıdan gelen verileri bir document nesnesinde tut.

10.Document nesnesindeki veriler içinde "td" etiketine göre filtreleme yap ve filtrelenen

verileri elementler olarak tut.

11.Tutulan elementleri bir string dizisine aktar.

12.Dizinin 0, 5, 10, 15. 20, 25, 30, 35, 40, 45, 50, 55, 60, 65 elemanlarını tarih textview'u

olarak göster.

13.Dizinin 1, 6, 11, 16, 21, 26, 31, 36, 41, 46, 51, 56, 61, 66 elemanlarında bulunan

resimleri, drawable klasöründeki resimlerle eşleştir ve resim imageview'u olarak göster.

14.Dizinin 3, 8, 13, 18, 23, 28, 33, 38, 43, 48, 53, 58, 63, 68 elemanlarındaki gündüz

sıcaklıklarını durum textview'u içinde gündüz sıcaklıkları olarak göster.

15.Dizinin 4, 9, 14, 19, 24, 29, 34, 39, 44, 49, 54, 59, 64, 69 elemanlarındaki gece

sıcaklıklarını durum textview'u içinde gece sıcaklıkları olarak göster.

16.Bitir.

Analiz ve tasarım aşamasındaki kısımları tamamladıktan sonra, projenin kurulumuyla

uygulama daha doğrusu gerçekleştirim aşamasına geçmiş olacağım. Proje Eclipse ortamı üzerinde

gerçekleştirilecek, bu yüzden ilk iş olarak Eclipse ortamında yeni bir proje açmakla başlıyorum

gerçekleştirim aşamasına.

Eclipse ortamını açtıktan sonra File > New > Android Application Project bağlantısına

tıklayarak gelen pencerede gerekli yerleri dolduruyorum. Application Name kısmına Hava Durumu,

Project Name kısmına HavaDurumu ve Package Name kısmına com.umut.havadurumu yazdıktan

sonra Finish butonunu tıklayarak projemizi oluşturmuş oluyorum.

Kurulum olduktan sonra Package Explorer alanında proje klasörüm gelmiş oldu. Hava

Durumu klasöründeki src alt klasöründe, yazacağım java dosyaları, res>layout alt klasöründe xml

dosyaları, res>drawable-hdpi alt klasöründe hava durumu ikonları, libs alt klasöründe ise Jsoup

adresinden indirdiğimiz, jsoup kütüphanesinin jar dosyası yer alacak.

Kurulum tamamlandıktan sonra çalışmamız için MainActivity.java ve ana uygulama ekranı

olarak da activity_main.xml dosyaları hazır olarak geldi. Bu hazır dosyalar bize yetmeyeceği için

mevcut dosyaların yanlarına yenilerini ekleyeceğiz. Hazır olarak gelen MainActivity.java

dosyasında algoritmamın ilk 5 adımını gerçekleştirip oluşturacağımız başka bir dosyada

algoritmanın geri kalan adımlarını tamamlayacağız. activity_main.xml dosyasında ise kullanıcı

arayüzü oluşturup MainActivity.java dosyasında gerçekleştirilen olayların bu dosyada

görüntülenmesini sağlayacağız.

Yarın, projeye activity_main.xml dosyasında tasarım yaparak ve MainActivity.java

dosyasını yazmaya başlayarak devam edeceğim.

8. GÜN

8.güne activty_main.xml dosyasının tasarımında nelerin olması gerektiğini düşünerek

başladım. İllerin listeleneceği bir listview ve listview'den önce edittext koymanın yeterli geleceğini

düşünüyorum. Edittext'e girilecek karakterlere göre listview'daki iller tekrardan listelenecek ve

böylelikle alttaki illere kolay erişim sağlanmış olacaktır. Daha açık bir ifadeyle anlatmak gerekirse,

listview'da Edirne iline ulaşmak isteyen birisi 20'den fazla ili geçtikten sonra Edirne ilini bulmuş

olacaktır. Halbuki edittext üzerine "e" karakterini girebilse Edirne ili ilk 5 sonuç içinde sıralanacağı

için kolaylıkla tıklama imkanına kavuşmuş olacaktır. Bu işlevselliği uygulamaya koymaya karar

verdikten sonra activity_main.xml dosyasının kodları şu şekilde yazılmış oldu;

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

android:layout_width="fill_parent"

android:layout_height="fill_parent"

android:orientation="vertical" >

<EditText android:id="@+id/inputSearch"

android:layout_width="fill_parent"

android:layout_height="wrap_content"

android:hint = "İli arayın.."

android:inputType="textVisiblePassword"/>

<ListView

android:id="@+id/list_view"

android:layout_width="fill_parent"

android:layout_height="wrap_content" />

</LinearLayout>

Burada kullandığımız listview'da gösterilecek illerin başka bir xml dosyasında bir textview

içinde yer alması gerekmektedir. Bunun için activity_main.xml dosyasına ek olarak, list_item.xml

dosyasını oluşturdum. Ve bu dosyada iller id'sine sahip bir textview kullandım. list_item.xml

dosyasında yazdığım kodlar şu şekildedir;

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:orientation="vertical" >

<TextView android:id="@+id/iller"

android:layout_width="fill_parent"

android:layout_height="wrap_content"

android:padding="10dip"

android:textSize = "16dip"

android:textStyle="bold"/>

</LinearLayout>

Kullanacağım xml dosyalarından ikisini yazdıktan sonra, MainActivity.java dosyası

üzerinde çalışmaya başlayabilirim. Bu dosyada yapılacakların ekranda görülmesi için bu dosyayı,

activity_main.xml dosyasıyla birbirine bağlamamız gerekmektedir. public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

onCreate metoduna setContentView ile yazarak birbirlerine bağlamayı gerçekleştirdim.

Böylelikle java dosyaları üzerinde çalışmaya da başlamış oldum. Yarın java dosyalarındaki

çalışmalarıma devam edeceğim.

9. GÜN

Dün MainActivity.java dosyasıyla activity_main.xml dosyasını birbirine bağlayıp çalışmamı

sonlandırmıştım şimdi kaldığım yerden çalışmalarıma devam ediyorum. Yazdığım algoritmayı

hatırlayacak olursak ilk yapacağımız iş il adlarını yüklemek olacak. Bu yüzden dün yazdığım

onCreate metoduna eklemeler yapacağım. OnCreate metodu üzerinde bu kodları yazmamın nedeni

bu işlemlerin sayfa yüklenir yüklenmez gerçekleşmesi gerektiği. Başka bir olayın gerçekleşmesini

beklemeksiniz bu işlemler gerçekleşmeli. Hemen iller ismiyle bir String dizisi oluşturdum ve bütün

illeri bu diziye eleman olarak atadım. Sonrasında list_view id'li listview'u lv değişkenine,

inputSearch id'li edittext'i de inputSearch değişkenine atadım. Bir adapter tanımlayarak lv

listview'una illerin yüklenmesini gerçekleştirdim. Bütün bunlara karşılık gelen yazdığım kodlar şu

şekildedir;String iller[] = {"Adana", "Adıyaman", "Afyonkarahisar", "Ağrı", "Aksaray",

"Amasya", "Ankara", "Antalya", "Ardahan", "Artvin", "Aydın", "Balıkesir", "Bartın",

"Batman", "Bayburt", "Bilecik", "Bingöl", "Bitlis", "Bolu", "Burdur", "Bursa",

"Çanakkale", "Çankırı", "Çorum", "Denizli", "Diyarbakır", "Düzce", "Edirne", "Elazığ",

"Erzincan", "Erzurum", "Eskişehir", "Gaziantep", "Giresun", "Gümüşhane", "Hakkari",

"Hatay", "Iğdır", "Isparta", "İstanbul", "İzmir", "Kahramanmaraş", "Karabük",

"Karaman", "Kars", "Kastamonu", "Kayseri", "Kırıkkale", "Kırklareli", "Kırşehir",

"Kilis", "Kocaeli", "Konya", "Kütahya", "Malatya", "Manisa", "Mardin", "Mersin",

"Muğla", "Muş", "Nevşehir", "Niğde", "Ordu", "Osmaniye", "Rize", "Sakarya", "Samsun",

"Siirt", "Sinop", "Sivas", "Şanlıurfa", "Şırnak","Tekirdağ", "Tokat", "Trabzon",

"Tunceli", "Uşak", "Van", "Yalova", "Yozgat", "Zonguldak"};

lv = (ListView) findViewById(R.id.list_view);

inputSearch = (EditText) findViewById(R.id.inputSearch);

adapter = new ArrayAdapter<String>(this, R.layout.list_item, R.id.iller,

iller);

lv.setAdapter(adapter);

Bu kodları yazdıktan sonra uygulamayı çalıştırdığımda illerin hepsinin listview üzerinde

görüntülenmesini sağladım. Bundan sonra MainActivity.java dosyasında yapmam gereken işler

olarak inputSearch edittext'ine göre listview'daki il sıralamalarının değişmesi ve tıklanan ilin

değerinin saklanarak diğer ekrana geçilip il değerinin diğer ekrana yollanması kaldı. Diğer ekrana

değer gönderme konusunda eksiklerim olduğu için uzunca bir araştırma yapmam gerekecek. Bu

nedenle bu işi yarına bırakıyorum ve bugünlük inputSearch edittext'i ile çalışıyorum.

Yapmak istediğim iş için addTextChangeListener metodunu kullanacağım. Bu metodla text

değiştiği zaman yapılacaklar, text değişmeden önce yapılacaklar ve text değiştikten sonra

yapılacaklar rahatlıkla yapılabilinir. Bu metodu öğrenmek için uzun araştırmalar yaptıktan sonra

text değiştiği zaman yapılacakları onTextChanged metodunda yazabilecek duruma geldim.

Çalışmasını sağladığım en son kodlar şu şekilde oldu;inputSearch.addTextChangedListener(new TextWatcher() {

@Override

public void onTextChanged(CharSequence cs, int arg1, int arg2, int

arg3) {

// Text değiştiği zaman

MainActivity.this.adapter.getFilter().filter(cs);

}

}

Uygulamaya bu fonksiyonu kazandırmak çok vaktimi almış, çok fazla araştırmama neden

olmuş olsa da başarmış olmaktan mutluyum. Yarın, diğer ekrana geçişi ve ekrana geçerken veri

gönderme üzerine araştırmalar yapacağım.

10. GÜN

Dün MainActivity.java dosyası üzerinde yazdığım kodlardan sonra algoritmamdaki 4. adımı

da tamamlamış oldum. Artık yavaş yavaş MainActivity.java dosyasındaki işim bitiyor ve diğer

ekran ve java dosyasıyla çalışmalarım başlıyor. Fakat bundan önce algoritmadaki 5. adımı ve

MainActivity.java dosyasındaki son kısımları yazmam gerekiyor. Son kısımları yazabilmem için

android uygulamalarda bir ekrandan diğer ekrana geçişi ve geçiş esnasında veri aktarımını

öğrenmem gerekiyor. Bu amaçla, bugünü tamamen bu yöntemi araştırmak ve öğrenmekle geçirdim

diyebilirim.

Activity'ler arası veri aktarımı için Bundle yapısı gerektiğini öğrendikten sonra bununla

ilgili araştırmalara başladım. Uygulamamda bir Bundle oluşturup bu Bundle'a putString metoduyla

il ismini String değişken içerisinde verip en sonda da intent.putExtras() koduyla başlayan diğer

Activity'ye veri gönderimini tamamlayacağımı çok uzun bir araştırmayla öğrenmiş oldum. Günün

geri kalanında da bu öğrendiğimi uygulamam üzerinde koda dönüştürmekle uğraştım.

Activity geçişini ve Bundle ile veri gönderimini listview'un setOnClickListener altında

onItemClick metodu içerisinde yazmam gerektiğini farkettim. SetOnClickListener listview'da

herhangi bir ögeye tıklanıp tıklanmadığını "dinleyen" bir metod. Bu metodun altında da dinleme

sonucunda tıklanmanın gerçekleştiği farkedilirse yapılacakları onItemClick metoduna yazmamı

sağlamaktadır. Bu şekilde listview tıklama olmadığı sürece bekleyecek, tıklama olduğunda harekete

geçecek ve bir intent bir Bundle oluşturacaktır. Bundle'a listview'da tıklanan ili yükleyecek, intent

ile diğer ekrana geçiş yapacak ve geçiş yaparken de veri gönderimi sağlanacaktır. Tüm bu işleri

yapacak kod aşağıdaki şekildedir;final ListView listView1 = (ListView)findViewById(R.id. list_view ) ;

listView1.setOnItemClickListener(new OnItemClickListener() {

@Override

public void onItemClick(AdapterView<?> a, View v, int position, long id) {

bundle = new Bundle();

Intent intent = new Intent(getApplicationContext(),

havaliste.class);

String str = "il adı";

str=listView1.getItemAtPosition(position).toString();

bundle.putString("deneme", str);

intent.putExtras(bundle);

startActivity(intent);

}

});

Yukarıda öncelikle listView1 isimli list_view id'li bir ListView tanımladım. Sonrasında

listView1'in setOnItemClickListener ile her hangi bir item'ına tıklanıp tıklanmadığını dinletmeyi

gerçekleştirdim. Tıklama gerçekleştiğinde yapılacakları ise onItemClick metodunda yazdım. Bu

metod içinde bundle isimli yeni Bundle bir tane de havaliste sınıfına gidecek bir intent isimli Intent

oluşturdum. NullPointerException gibi bir hatanın oluşmasını engellemek için oluşturduğum str

değişkenine "il adı" şeklinde başlangıç değeri verdim. Böylece uygulama hata vermeden geçiş

yapabilecek fakat diğer ekranda il adı şeklinde değer döndürdüğünü gördüğüm zaman hatanın

nereden kaynaklandığını anlayabileceğim. Sonrasında str değişkenine listView1'in tıklanan item'ının

position değerine göre seçip bunu stringe çevirerek atama yapıyorum. Burada getItemAtPosition

kullanmamın nedeni inputSearch ile illerin yerleri değiştiğinde hata oluşmasını engellemek içindir.

En son olarak da bundle içerisine str stringini "deneme" anahtar kelimesiyle koyup bu bundle'ı da

intent içine yerleştirmek oldu ve herşey tamamlandığında intenti başlattım.

11. GÜN

2 hafta sonunda algoritmadaki ilk 5 adımı, MainActivity.java dosyasındaki bütün kodları ve

activity_main.xml, list_item.xml dosyalarındaki tasarımın tamamını yapmış oldum. Stajın geri

kalan 2 haftasında ise algoritmadaki son 10 adımı tamamlayıp uygulamayı tamamı ile çalışır

duruma getirmek için çalışmalar yapacağım. İkinci haftanın ilk gününde yeni ekrana geçiş

yaptığımız için bu yeni ekranın tasarımını yapacağım. Yeni ekranımızda da ilk ekrana benzer

şekilde bir adet TextView ve bir adet ListView olacak. Fakat buradaki görevler çok daha farklı

olacak. TextView MainActivity.java dosyasındaki bundle'dan hangi il adının geldiğini görüntülemek

için, ListView ise o ile ait hava durumu verilerini görüntülemek için kullanılacak. Tabi ki, ListView

kullandığımız için ListView içerisinde görüntülenecek değerleri başka bir xml dosyası tasarlayarak

halletmemiz gerekecek.

10.günün son saatlerinde havaliste activity'sine geçiş yapacağımızı yazmıştık. Bu nedenle

bugün tasarlayacağım xml dosyasına ve sonraki günlerde yazacağım java dosyasına da havaliste

ismini vermek istiyorum.

Package Explorer üzerinde layout klasörüne geldikten sonra klasöre sağ tıklayıp New >

Android XML File seçeneğine tıklıyorum. Burada dosya ismi olarak havaliste.xml yazdıktan sonra

Finish butonuna tıklıyorum ve havaliste.xml dosyamı layout klasörü altında oluşturmuş oluyorum.

Her dosyanın uygun olan klasörler altında toplanması proje büyüdüğünde ve ilerlediğinde

karışıklığı engellemek için hayati önemde alınacak bir önlemdir.

Bundan sonra havaliste.xml dosyasının tasarımını şu şekilde tamamlıyorum;<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:orientation="vertical" >

<TextView

android:id="@+id/textView1"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:text="Hava Durumu"

android:textAppearance="?android:attr/textAppearanceLarge" />

<ListView

android:id="@android:id/list"

android:layout_width="match_parent"

android:layout_height="wrap_content" >

</ListView>

</LinearLayout>

Burada textView1 id'li TextView il adını göstermemizi, list id'li ListView ise hava durumu

tahminlerini listelememizi sağlayacak. Havaliste.xml dosyasında kullandığımız ListView içerisinde

gösterilecek verilerin neler olacağını belirlemek için başka bir xml dosyası oluşturmam

gerekecektir. Fakat ben bu işi yarına bırakıyorum. Yarın yeni xml dosyamı tasarlayarak devam

edeceğim.

12. GÜN

Dün geçiş yapacağımız ve hava durumu verilerini gösterilmesini sağlayacağımız

havaliste.xml dosyasını tasarladıktan sonra bugün, list.xml adında ListView'da olacak verilerin

tiplerini belirteceğim bir xml dosyası oluşturdum. Tasarımını yaptığım list.xml dosyasının kodları

şu şekilde;<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:orientation="horizontal" >

<LinearLayout

android:layout_width="wrap_content"

android:layout_height="match_parent"

android:layout_weight="0.79"

android:orientation="vertical" >

<TextView

android:id="@+id/textView1"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:text="Large Text"

android:textAppearance="?android:attr/textAppearanceLarge" />

</LinearLayout>

<ImageView

android:id="@+id/imageView1"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:src="@drawable/ic_launcher" />

<LinearLayout

android:layout_width="wrap_content"

android:layout_height="match_parent"

android:layout_weight="0.79"

android:orientation="vertical" >

<TextView

android:id="@+id/textView2"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:text="Large Text"

android:textAppearance="?android:attr/textAppearanceLarge" />

</LinearLayout>

</LinearLayout>

Bu tasarımda bir yatay, iki dikey toplam üç adet LinearLayout kullandım. İlk kullandığım ve

yatay olan LinearLayout bütün ögeleri toplama işlemini görüyor. Diğer dikey layoutlar ise,

TextView'ların daha hoş ve ekranda kayma yapmadan durmalarını sağlamak için kullanıldı.

Kullanılan 2 TextView'dan ilki tarih verilerinin gösterilmesini, ikincisi ise gündüz ve gece

sıcaklıklarının gösterilmesini sağlayacak. Aynı zamanda bir adet de ImageView kullanarak

uygulamaya görsellik kattım ve hava durumu tahminlerini gösteren ikonların görüntülenmesini

sağladım. Xml dosyalarının tasarımlarını tamamladıktan sonra, 13. gün yeni java dosyasını

yazmaya başlayacağım.

13. GÜN

13.günde havaliste.java dosyasını oluşturdum. MainActivity.java dosyasındaki bundle'dan

gelen veriyi almak için çalışmalar yaptım fakat tam anlamıyla başarılı olamadım. Bu yüzden

bugünün çok büyük bölümü yaptığım hataları araştırmakla geçti ve bu esnada uygulamamda

AsyncTask kullanmam gerektiğini farkettim. Hatalarım hakkında araştırmalardan arta kalan vakitte

AsyncTask üzerine araştırmalar yaptım fakat araştırmalarımı tamamlayamadım. Yarın da AsyncTask

üzerindeki araştırmalarımı yapmaya devam edeceğim.

Bugün kodlama üzerine yaptıklarım şu şekilde;public class havaliste extends Activity{

@Override

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.havaliste);

Bundle veriler = getIntent().getExtras();

String edtgelenilk = veriler.getString("deneme");

2 gün önce oluşturduğum havaliste.xml dosyasıyla havaliste.java dosyasını bağlamayı

gerçekleştirdim. Ayrıca veriler isminde bir Bundle oluşturdum ve intent ile gelen veriyi bu Bundle'a

yüklemesini sağladım. Sonrasında edtgelenilk ismiyle bir String oluşturdum ve bu stringe veriler

bundle'ındaki "deneme" anahtar kelimeli stringi atadım.

Bu kodları yazdıktan sonra AsyncTask yapısını keşfettim ve araştırmalarım sonunda

yazdığım kodların AsyncTask yapısına göre tekrardan düzenlenmesi gerekliliğini farkettim...

Bugünkü araştırmalarım sonucunda AsyncTask yapısı hakkında aktarabileceklerim;

AsyncTask, kullanıcı uygulamayı kullanırken arka planda yapmak istediğimiz işleri

gerçekleştirmemiz için kullanılır. Örnek olarak, kullanıcı menüyü incelerken arka planda menü

bilgilerini indirebiliriz. Bu yapının kullanılma sebebi kullanıcıları sıkmadan uygulamanın

içeriklerine ulaşmalarını sağlamaktır. AsyncTask classından türetilmiş sınıf ve bu sınıf içerisinde

arkaplanda yapmak istediğimiz işlemleri yapabiliriz.

Android uygulamaları geliştirirken; uygulama arayüzünün yüklenmesi veya yenilenmesi

durumlarında, kullanıcıyı bilgilendirmek için AsyncTask kullanımına ihtiyaç vardır. Diğer türlü

arayüz üzerinde işlem yapmak mümkün değildir.

AsyncTask’i hem inner class olarak hem de ayrı bir class olarak kullanmak mümkün. Ben

projemde AsyncTask'i inner class olarak kullanacağım.

Yarın AsyncTask hakkındaki araştırmalarımı bitirip bu yapıyı kullanarak havaliste.java

dosyasını yazmaya devam etmeyi planlıyorum.

14. GÜN

Bugünün büyük çoğunluğunu AsyncTask üzerinde araştırmalar yaparak geçirdim.

Araştırmalarımdan sonra projeme AsyncTask yapısını ekleyebilecek bilgiye ulaştım ve gün boyunca

şu şekilde bir yapı yazdım;public class havaliste extends Activity{

@Override

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.havaliste);

new MyTask().execute();

}

class MyTask extends AsyncTask<Void, Void, String> {

ProgressDialog pd = null;

@Override

protected void onPreExecute(){

pd = new ProgressDialog(havaliste.this);

pd.setMessage("Çalışıyor...");

}

@Override

protected String doInBackground(Void... params) {

Bundle veriler = getIntent().getExtras();

String edtgelenilk = veriler.getString("deneme");

}

@Override

protected void onPostExecute(String result) {

}

}

Uygulama çalıştığında AsyncTask olarak tanımlanmış MyTask çalışacaktır. AsyncTask

oluşturulurken gönderilenler Constructor’a, execute metodu ile gönderilenler ise doInBackground

metoduna gider.

Ayrıca inner class tanımını yaparken kullanılan <Void, Void, String> tanımı sırasıyla

gönderilecek parametre tipi, işlemler yapılırken kullanılacak parametre tipi ve işlemler sonucunda

geri döndürelecek veri tipidir.

AsyncTask içerisine veri gönderilmeyecek ve alınmayacaksa bu parametrelerin her biri Void

olarak belirtilmelidir.

Ayrıca daha önce onCreate metodu altında yazdığım bundle kodları AsyncTask yapısına

geçtiğim için bu yapının doInBackground kısmına alınmıştır.

Projem AsyncTask yapısıyla daha sağlam ve işlenmesi daha kolay bir yapıya kavuştuktan

sonra yarından itibaren algoritmadaki kalan adımları yazmaya devam edebilirim.

15. GÜN

Dün doInBackground metodu altında bundle kodlarını yazmıştım. Diğer metodlar altında

değil de doInBackground altında yazmamın nedeni, uygulamayı çalıştıran cihazların, tüm bu

işlemleri arka planda yapmalarını sağlayabilmektir. DoInBackground kısmında yapacağımız

işlemler tam olarak bitmedi. Yazdığım AsyncTask yapısında doInBackground'un bir string değer

döndürmesi ve bu stringi de onPostExecute tarafının alması gerekmektedir. Fakat ben,

doInBackground tarafından değer döndürülecek herhangi bir string yazmadım. Stajın 15. gününde

bunun üzerine çalışmalar yapacağım. Bundle ile önceki ekrandan gelen il ismini bir stringe atadım,

ama bu stringi return etmemin bir anlamı yok. Bu string değerini kullanarak siteyle bağlantı kurmalı

oradan gelen verileri bir string içine aktarmalı ve bu string değerini değer olarak döndürmeliyim.

Bu mantıkla doInBackground'daki yazdığım kodları şu şekilde geliştirdim;class MyTask extends AsyncTask<Void, Void, String> {

ProgressDialog pd = null;

String title3 ="";

@Override

protected void onPreExecute(){

pd = new ProgressDialog(havaliste.this);

pd.setMessage("Çalışıyor...");

}

@Override

protected String doInBackground(Void... params) {

try {

Bundle veriler = getIntent().getExtras();

String edtgelenilk = veriler.getString("deneme");

String edtgelen = edtgelenilk;

edtgelen=edtgelen.toLowerCase();

edtgelen=edtgelen.replace("ç", "c");

edtgelen=edtgelen.replace("ğ", "g");

edtgelen=edtgelen.replace("ı", "i");

edtgelen=edtgelen.replace("ö", "o");

edtgelen=edtgelen.replace("ş", "s");

edtgelen=edtgelen.replace("ü", "u");

String il = "http://www.15gunlukhavadurumu.gen.tr/" + edtgelen +

"-hava-durumu-15-gunluk/";

} catch (IOException e) {

e.printStackTrace();

}

return title3;

}

Öncelikle doInBackground içindeki kodları try – catch yapısı içine alarak olası durumlarda

oluşabilecek kilitlenmelerin önüne geçmiş oldum. Try – catch blogu çalışmasa dahi title3

değişkenini oluştururken başlangıç değeri verdiğim için, doInBackground hatalı da olsa bir string

değeri döndürmüş olacak. Try – cath bloguna baktığımızda bundle ile önceki ekrandan alınan il

verisinin edtgelen isimli bir string değişkenine aktardığımı göreceğiz. Bu string değişkenini siteye

bağlantı kurarken kullanacağım için, replace metodlarıyla önce büyük harfi küçük harfe döndürdüm

sonrasında da Türkçe karakterlerin dönüşümlerini gerçekleştirdim. Böylece uygun bir web sayfa

adresi yapısı oluşturmuş oldum. Yarın web sayfa adresini, Jsoup kütüphanesiyle kullanarak hava

durumu verilerini almak üzere çalışmalar yapacağım.

16. GÜN

Stajın başında uzun uzun incelediğim Jsoup kütüphanesini projemde kullanacağım zamana

gelmiş bulunmaktayım. Bugün il isimli string değişkenine atadığım web sayfası adresini Jsoup'da

connect metodunda kullanacağım. Connect kodu sonucunda sayfanın tüm kaynak koduna ulaşıp

bunlar bir Document nesnesine aktaracağım. Sonra bu document içinde <td> etiketine uygun olan

bölümleri elementler halinde tutacağım ve bu elementlerden string nesnesine aktaracağım. En sonda

da bu string değerini döndürerek doInBackground'da çalışmalarımı bitirecek ve onPostExecute

kısmında çalışmaya başlayacağım.

Projemde kullanacağım Jsoup kodları için öncelikle bazı import işlemleri yapmam

gerekecek. Libs klasöründeki Jsoup kütüphanesinden metodları çağırabilmemi sağlayacak bu

import kodları şu şekildedir;import org.jsoup.Jsoup;

import org.jsoup.nodes.Document;

import org.jsoup.nodes.Element;

import org.jsoup.select.Elements;

İlk olarak Jsoup kütüphanesini import ediyorum java dosyama. Sonrasında üçünü de

kullanacağım için Document, Elements ve Element nodelarını import ediyorum. İmport işlemini

tamamladığıma göre artık bu Jsoup kütüphanesini kullanmaya başlayabilirim. DoInBackground

metodunun tamamlanmış hali şu şekildedir; @Override

protected String doInBackground(Void... params) {

try {

Bundle veriler = getIntent().getExtras();

String edtgelenilk = veriler.getString("deneme");

String edtgelen = edtgelenilk;

edtgelen=edtgelen.toLowerCase();

edtgelen=edtgelen.replace("ç", "c");

edtgelen=edtgelen.replace("ğ", "g");

edtgelen=edtgelen.replace("ı", "i");

edtgelen=edtgelen.replace("ö", "o");

edtgelen=edtgelen.replace("ş", "s");

edtgelen=edtgelen.replace("ü", "u");

String il = "http://www.15gunlukhavadurumu.gen.tr/" +

edtgelen + "-hava-durumu-15-gunluk/";

Document doc = Jsoup.connect(il).userAgent("Mozilla").get();

Elements els = doc.getElementsByTag("td");

for (Element el : els) {

title3= title3 + el.html()+"xxx";

}

title3= edtgelenilk + "yyy" + title3;

} catch (IOException e) {

e.printStackTrace();

}

return title3;

}

Jsoup.connect ile doc değişkenine sayfanın tüm kaynak kodunu yükledim. ElementsByTag

komutu ile <td> tagi içindeki verileri alıp els Elementleri için aktardım. Sonrasında for döngüsüyle

title3 değişkenine bu elementleri, aralarında xxx ayıracı olacak şekilde atadım. En son, verilerin

hangi ile ait olduğunu belirtmek için yyy ayıracı kullanarak ilin ismini de title3 stringine koydum ve

bu title3 değişkenini return ettim. Yarın döndürdüğüm title3 değişkenin onPostExecute metodunda

kullanacağım.

17. GÜN

Bugün, dün doInBackground'dan dönen title3 stringini onPostExecute üzerinde kullanmaya

çalıştım. Döndürdüğüm bu değeri sağlıklı bir şekilde onPostExecute'ta alabildim fakat verileri tam

anlamıyla ayıramadım.

Yüzlerce deneme yaptım, saatlerce bu ayrıştırma işlemi üzerine düşündüm bir çıkar yolu

bulamadım. Proje bu aşamada tıkandı. Tıkanıklığı bu şekilde çözemeyeceğimi düşününce,

doInBackground'da, title3 değişkenine verileri farklı şekilde yüklemeye çalıştım fakat burada

uğraşmak çok daha fazla sorun ortaya çıkardı.

DoInBackground'daki denemeler sonucunda sıklıkla NullPointerException hatası aldım ve

her hatada kodları tekrardan gözden geçirip iyice kafamın karışmasına sebep oldum. Kafamı

toparlamak için, birkaç saat, tamamı ile kodlardan uzak kağıt üzerinde mantık hatası aradım. Bütün

gün bu şekilde bitti. Kağıda doInBackground ve onPostExecute metodlarının yaptıkları işleri

yazdım.

Kağıttaki analizlerim sonucu doInBackground'da yaptıklarımın belirli mantık dahilinde

olduğuna kanaat getirerek, o kısmı tekrar yazmaktan vazgeçtim. @Override

protected void onPostExecute(String result) {

result = result.replace("xxxxxx", "xxx");

result = result.replace("<br />", " ");

result = result.replace("&deg;", "°C");

result = result.replace("&Ccedil;", "Ç");

String[] sonuc;

String[] sonucilk = {"il","sonuçlar"};

sonucilk = result.split("yyy");

sonuc = sonucilk[1].split("xxx");

TextView baslik = (TextView) findViewById(R.id.textView1);

baslik.setText(sonuc[0] + " Hava Durumu");

}

Buraya kadar yazdığım kodlar doğru olarak çalışmakta fakat bundan sonrasında listview

ekleyip sonuçları listview'de gösterdiğimde NullPointerException hatası almaktayım. Bu hatanın

çözümü için araştırmalara devam ediyorum. Yarın araştırmalarıma devam edeceğim.

18. GÜN

Dün takıldığım sorun üzerine bugün araştırmalara devam ettim. Araştırmalarım sonucunda

ListView kullanarak birbirlerinden farklı tipteki verilerin bir arada gösterilebilmesinin en sağlıklı

yöntemlerinden birinin HashMap yapısı kullanmak olduğunu buldum. Benim sorunumu tam olarak

çözüp çözmeyeceğinden emin olmamakla beraber, araştırmalarımı bu yönde devam ettirdim ve

projemde deneme amaçlı olarak HashMap kullanmaya karar verdim.

HashMap kullanımını tamamlamak için gerekli 7 adım bulunmaktadır;

1. ListView oluştur.

2. HashMap için ArrayList oluştur.

3. HashMap oluştur.

4. HashMap'e veri koy.

5. HashMap'i ArrayList'e ekle.

6. ArrayList'i SimpleDataAdapter ile şarj et.

7. SetAdapter komutu ile tamamla.

Bu 7 adımında uygulandığı örnek bir uygulamayı da inceledim;ListView list = (ListView) findViewById(R.id.SCHEDULE); //1. adım

ArrayList<HashMap<String, String>>mylist=new ArrayList<Hashmap<String,

String>>(); //2.adım

HashMap<String, String> map = new HashMap<String, String>(); //3. adım

map.put("train", "103(x)");

map.put("from", "6:35 AM");

map.put("to", "7:45 AM"); //4. adım

mylist.add(map); //5. adım

mSchedule = new SimpleAdapter(this, mylist, R.layout.row,

new String[] {"train", "from", "to"}, new int[]

{R.id.TRAIN_CELL, R.id.FROM_CELL, R.id.TO_CELL}); //6.adım

list.setAdapter(mSchedule); //7.adım

Bu örnek sayesinde HashMap kullanımını anladığımı düşünüyorum ve projemde bu yöntemi

kullanarak ilerleyeceğim. Bu arada kodları incelerken, dün yazdığım kodlarda String[] olarak

tanımladığım sonuç dizisinin elemanlarına başlangıç değerleri vermediğimi farkettim. İleride yeni

sorunlar çıkarabileceğini düşündüğüm için başlangıç değerleri atadım ve yeni hali şu şekilde oldu; String[] sonuc =

{"yükleniyor","yükleniyor","yükleniyor","yükleniyor","yükleniyor",

"yükleniyor","yükleniyor","yükleniyor","yükleniyor","yükleniyor", "yükleniyor",

"yükleniyor","yükleniyor","yükleniyor","yükleniyor", "yükleniyor", "yükleniyor",

"yükleniyor","yükleniyor","yükleniyor", "yükleniyor", "yükleniyor", "yükleniyor",

"yükleniyor","yükleniyor", "yükleniyor", "yükleniyor","yükleniyor", "yükleniyor",

"yükleniyor", "yükleniyor","yükleniyor","yükleniyor","yükleniyor", "yükleniyor",

"yükleniyor","yükleniyor","yükleniyor","yükleniyor","yükleniyor", "yükleniyor",

"yükleniyor", "yükleniyor","yükleniyor","yükleniyor", "yükleniyor","yükleniyor",

"yükleniyor","yükleniyor","yükleniyor", "yükleniyor","yükleniyor","yükleniyor",

"yükleniyor","yükleniyor", "yükleniyor","yükleniyor","yükleniyor","yükleniyor",

"yükleniyor"};

Yarın HashMap yöntemini uygulamamda oluşturmaya çalışacağım.

19. GÜN

Dünkü araştırmalarım sonucunda öğrendiğim HashMap için çalışmalara başladım. Dün

verdiğim örneğe benzer şekilde projemde HashMap'i kısmen uygulamayı başardım. Kısmen

diyorum, çünkü ImageView üzerinde resimleri göstermeyi şu an başaramadım.

15Gunlukhavadurumu.gen.tr, sitesindeki hava durumunu gösteren resimleri icons adlı bir

klasörde tuttuğunu farkettim ve bu klasördeki bütün .png formatındaki resimleri kopyalayarak,

projenin res klasörünün altında bulunan drawable-hdpi klasörüne yerleştirdim.

Uygulamamda, gelen resim verilerine göre karşılaştırma yaparak aynı resmi ImageView

içerisinde göstermek için çok çaba sarfettim fakat çalışma anında hata vermemesine rağmen

görüntülemede sorun çıkarmaktadır. Bu hatayı stajın son gününe bırakarak, bugün içinde yazdığım

bütün kodları yayınlıyorum; protected void onPostExecute(String result) {

result = result.replace("xxxxxx", "xxx");

result = result.replace("<br />", " ");

result = result.replace("&deg;", "°C");

result = result.replace("&Ccedil;", "Ç");

String[] sonuc =

{"yükleniyor","yükleniyor","yükleniyor","yükleniyor","yükleniyor",

"yükleniyor","yükleniyor","yükleniyor","yükleniyor","yükleniyor", "yükleniyor",

"yükleniyor","yükleniyor","yükleniyor","yükleniyor", "yükleniyor", "yükleniyor",

"yükleniyor","yükleniyor","yükleniyor", "yükleniyor", "yükleniyor", "yükleniyor",

"yükleniyor","yükleniyor", "yükleniyor", "yükleniyor","yükleniyor", "yükleniyor",

"yükleniyor", "yükleniyor","yükleniyor","yükleniyor","yükleniyor", "yükleniyor",

"yükleniyor","yükleniyor","yükleniyor","yükleniyor","yükleniyor", "yükleniyor",

"yükleniyor", "yükleniyor","yükleniyor","yükleniyor", "yükleniyor","yükleniyor",

"yükleniyor"};

String[] sonucilk = {"il","sonuçlar"};

sonucilk = result.split("yyy");

sonuc = sonucilk[1].split("xxx");

TextView baslik = (TextView) findViewById(R.id.textView1);

baslik.setText(sonucilk[0] + " Hava Durumu");

List<HashMap<String, String>> listinfo = new ArrayList<HashMap<String,

String>>();

listinfo.clear();

for(int i=0;i<14;i++){

HashMap<String, String> hm = new HashMap<String,

String>();

hm.put("tarih", sonuc[i*5]);

sonuc[i*5+1] = "i"+sonuc[i*5+1].substring(17, 20);

hm.put("hava", Integer.toString(R.drawable.i113));

//yukarıdaki satırda istediğim resmi görüntüleyemediğim

için //çalışıp çalışmadığını kontrolde default resim görüntüledim.

hm.put("durum", " " + sonuc[i*5+3]+ " / " +

sonuc[i*5+4]);

listinfo.add(hm);

}

String[] from = { "tarih","hava", "durum" };

int[] to = { R.id.tarih,R.id.hava, R.id.durum };

SimpleAdapter adapter = new SimpleAdapter(getBaseContext(),

listinfo,R.layout.list_hava, from, to);

ListView mylist = (ListView) findViewById(android.R.id.list);

mylist.setAdapter(adapter);

Bu şekilde yazıldığında herhangi bir sorun olmaksızın uygulama çalışmakta fakat resim

görüntüleme konusunda istenilen resim değil default olarak belirlediğim bir resim

görüntülenmektedir. Uygulamanın şu ana kadar ki hali, belirttiğim sorun hariç aksaklık olmadan

çalışmaktadır. Yarın bu hatanın çözülmesi için çalışmalar yaptıktan sonra, vakit olduğu müddetçe

test ve hata ayıklama üzerine çalışacağım ve 20 günlük stajımı bitirmiş olacağım.

20. GÜN

Stajın ve hava durumu uygulamasının son gününe nihayet geldim. Bugün gün boyunca

uygulamayı test edeceğim ve sorunsuz olarak çalıştığını gördükten sonra Google Play'e

yükleyeceğim. Ama ondan önce resim sorununu çözmek için yine yoğun araştırmalara

başlayacağım.

Gün boyunca yaptığım denemelerde R.drawable."resim ismi" şeklinde bir değişkene göre

resim görüntülemeye çalıştım fakat her defasında derleyici hata verdi. Böyle bir yapı bulunmadığını

farkettikten sonra, başka çözümler üretmek üzere düşünmeye başladım. Bildiğim kadarıyla

R.drawable.resim komutuyla ulaşılan resim değişkenleri integer değer almakta ve bu integer

değerler R.java dosyasında sistem tarafından otomatik atanmaktadır. Bu integer değerlerinin elle

değiştirmeye kalktığımda R.java dosyasının tanınmadığını gördüm, bu yüzden R.java dosyasında

değişiklik yapmaktan vazgeçtim. Sonrasında bir String dizisi içinde resimlerin isimlerini, bir integer

dizisi içinde resimlerin R.java'daki atanmış değerlerini aynı sırayla tutabileceğimi, böylece

resimlerin isimlerinin bulunduğu dizi içinde, gelen resmin isminin aratılıp bulunduğu hücrenin

index değerini almayı, bu index değeri ile aynı index değerine sahip integer dizi hücresini

hm.put("hava") kodunda kullanmayı düşündüm. Bulduğum çözüm yöntemi geçerli olmakla birlikte

çok fazla sorgu çalışmasına neden olduğu için iyi bir algoritmaya sahip değildi ve bu yüzden de çok

ağır çalışıyordu.

Daha iyi bir algoritma ya da kod bulmak için stajın son gününü de ağırlıklı olarak

araştırmayla geçirdim ve en sonunda istediğim yöntemi buldum.

GetResources().getIdentifier("resim ismi", "drawable", getPackageName) koduyla

belirttiğim resmin R.java'daki integer değerini elde edebiliyordum.

R.java'dan dönen bu integer değerini başka bir integer değişkenine atayıp sonrasında

hm.put() kodu içinde bu integer değerini string değere çevirip görüntülemeyi başardım. Çok farklı

ve çok kullanışlı bu kod sayesinde HashMap'te kullandığım kodlar tamamen doğru olarak

çalışmaktadır.

Yazdığım HashMap'in son ve hatasız çalışan hali;List<HashMap<String, String>> listinfo = new ArrayList<HashMap<String,

String>>();

listinfo.clear();

for(int i=0;i<14;i++){

HashMap<String, String> hm = new HashMap<String,

String>();

hm.put("tarih", sonuc[i*5]);

sonuc[i*5+1] = "i"+sonuc[i*5+1].substring(17, 20);

//sonuc[i*5+1] = sonuc[i*5+1].replace("113",

"0x7f020000");

//r = Integer.parseInt(sonuc[i*5+1]);

int id = getResources().getIdentifier(sonuc[i*5+1],

"drawable", getPackageName());

hm.put("hava", Integer.toString(id));

hm.put("durum", " " + sonuc[i*5+3]+ " / " +

sonuc[i*5+4]);

listinfo.add(hm);

}

Son saatlerde bulduğum bu kod yardımıyla proje istenilen şekilde bitirilmiş ve algoritmada

yazılan bütün adımlar projeye uygulanmıştır...

KAYNAKLAR

[1] Jazz E. "Fill a ListView with HashMap data " Ocak 2012

http://tips4android.blogspot.com/2012/01/fill-listview-with-hashmap-data.html

[2] "Android -AsenkronTask Kullanımı – AsyncTask"

http://ercsoft.net/android-asenkrontask-kullanimi-asynctask/

[3] Ceylan A. "Bundle ile activityler arasında veri aktarma" Haziran 2012

http://www.arifceylan.com/bundle-ile-activityler-arasinda-veri-aktarma/

[4] Davut A. "HTML dosyasından bir makalenin text kısmını otomatik olarak yakalamanın

en iyi yolu nedir?" Ekim 2012

http://www.inploid.com/t/html-dosyasindan-bir-makaleyi-cikarmanin-en-iyi-yolu-nedir/

[5] "jsoup: Java HTML Parser"

http://jsoup.org/