1. GÜN Staj boyunca android programlama

Transkript

1. GÜN Staj boyunca android programlama
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-havadurumu-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 jsoup1.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, projeye
import
import
import
import
org.jsoup.Jsoup;
org.jsoup.nodes.Document;
org.jsoup.nodes.Element;
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 ata
Element 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 + "-havadurumu-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
import
import
import
org.jsoup.Jsoup;
org.jsoup.nodes.Document;
org.jsoup.nodes.Element;
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 =
result =
result =
String[]
result.replace("xxxxxx", "xxx");
result.replace("<br />", " ");
result.replace("&deg;", "°C");
result.replace("&Ccedil;", "Ç");
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...

Benzer belgeler

Rapor

Rapor Ayrıca yine bazı kelimeler Göktürkçede günümüz Türkçesinde yazıldığı gibi yazılmaz. Örneğin komşu kelimesi Göktürkçede konşu olarak yazılmaktadır. Aynı şekilde omurga kelimesi de onurga olarak yazı...

Detaylı