Android Asenkron Resim Gösterimi (URL - Web'den)

Şu sıralar yeni bir Android projesi ile uğraşmaktayım. Bu seferki projem diğerlerinden farklı olarak bana ait markete koymak için yaptığım bir proje değil. Projenin detaylarına girmeden kısaca başımdan geçen bir olayı sizinle paylaşmak istedim.

Projenin bir menüsünde sunucudan alınan veriler üzerinden yine sunucuda bulunan resimlerin gösterilmesi gerekiyordu. Basitçe “Android ile url (web) kullanarak nasıl resim gösteririm?” sorusunun cevabını araştırmam gerekiyordu.

Dilerseniz ufak bir kod parçasıyla bunu nasıl yaptığımı size özetleyebilirim.

public static Drawable LoadImageFromWebOperations(String url) { try { InputStream is = (InputStream) new URL(url).getContent(); return Drawable.createFromStream(is, "name"); } catch (Exception e) { Log.e("LoadImage", "exception", e); return img.getResources().getDrawable(R.drawable.noimage); } }

Yukarıdaki fonksiyonu statik olarak tanımlarsanız sadece parametre göndererek url'den resminizi elde etmiş olacaksınız.

Bir fonksiyon ile URL’den resim dönüşümü yaptıktan sonra işlerin kolaylaştığını düşünerek uygulamayı çalıştırdım. Uygulama içerisinden resim gösterme kısmına geldiğimde ise hata aldım.

"android.os.NetworkOnMainThreadException"

Hata için önce yazdığım koddan şüphelenip değişik kodlamalar denedikten sonra cevap bulamayınca Google araştırmalarına başladım.  Hatanın tanımı geniş kapsamlı olsa da çözüm sürecinde çoğunlukla “AsyncTask” sınıfıyla karşılaştım. Uygulamamda ilgili ekran için bilgiler bir Thread aracılığıyla Web servis üzerinden alınıyor ve gelen bilgiler ile resimlerin aynı zamanda web’den çekilmesi gerekiyordu. İki network (internet-ağ) işleminin aynı Thread üzerinde aynı anda başlaması sorunun kendisi oluyormuş. Dolayısıyla çözüm için değişiklik şart oldu ve “AsyncTask” sınıfını kullanma gerekliliği ortaya çıktı.

public class LoadImage extends AsyncTask<ImageView, Void, Drawable> { ImageView img; public Drawable LoadImageFromWebOperations(String url) {
try { InputStream is = (InputStream) new URL(url).getContent(); return Drawable.createFromStream(is, "isim"); } catch (Exception e) { Log.e("LoadImageFromWeb", "Hata", e); return img.getResources().getDrawable(R.drawable.noimage); } } @Override protected Drawable doInBackground(ImageView... params) { img = params[0]; return LoadImageFromWebOperations(img.getTag().toString()); } @Override protected void onPostExecute(Drawable result) { img.setImageDrawable(result); }

Async sınıfını kullanarak Thread ile web servis üzerinden aldığım veriyi asenkron iletişime dahil ederek resimlerin gelmesini sağladım. Bu sayede aynı Thread üzerinde web servis ve resim download işleminden vazgeçtim. Yalnız net olmasa da bu hatanın Android 4.0.3 (Ice Cream Sandwich) versiyonundan düşük versiyonlar için kaynaklandığına bir yerde rastladım. Uygulamayı genele yaymak için düşük versiyonlar şart olduğundan çözümü asenkron hale dönüştürmek zorunda kaldım.

Aslında çok basit bir şekilde Thread işleminden vazgeçerek en üstte belirtiğim statik fonksiyonu kullanabilirdim. Fakat uygulama geliştirirken bazen basitlikten çıkmak gerekiyor. Uygulama ekranında Thread kullanmadan yaptığımızda verinin gelme zamanına bağlı olarak ekran donup kalıyor ve kullanıcıya bu durumu izah edemiyorsunuz. Verinin gelmesi ve ekranın düzenlenmesi sırasında Progress Dialog (Yükleniyor ekranı) çıkartarak kullanıcıyı veri hakkında haberdar edebiliyorsunuz. Son olarak thread ile progress dialog nasıl çıkarılır? Yükleniyor (Loading) ekranı ile kullanıcı nasıl haberdar edilir? diye düşünüyorsanız aşağıdaki fonksiyon yardımcınız olur umarım.

Handler mHandler = new Handler(); private void threadprogressdialogyukleme() { // Bu işlemin activity icinde oldugu dusunuluyor // this = Activity final ProgressDialog dialog = ProgressDialog.show(this, "", "Yükleniyor..."); new Thread(new Runnable() { public void run() { get();//Datanın cekildigi yer mHandler.post(new Runnable() { public void run() { // Data çekildikten sonra bu kısımda // gerekli arayüz düzenlemesi yapılabilir. dialog.dismiss(); //Yukleniyor ekranı kapatılır. } }); } }).start(); }

Android uygulama geliştirirken para kazanmak


Hakkında kısmında belirttiğim gibi 2012 yılından beri Android ile uygulama geliştiriyorum.  Hem öğrenme amaçlı hem de bir şeyler yapabilme adına başladığım işten para kazanmanın yollarını keşfettiğimde çok hoşuma gitmişti. Kazanılan paranın büyüklüğü kişiden kişiye fark etse de öyle hayallerdeki gibi büyük meblağlar (tabi bana göre) kazanmayı henüz başaramadım ama uygulama dünyasında kazanamayacağınız anlamına gelmez.  Yine yazılımcı olan bir arkadaşımın sürekli ağzında dolanan artık sloganımız olmuş bir sözü sizinle paylaşmak isterim.

“Bir uygulama bir dolar bir milyon indirme olay bitmiştir”

Gerçekten kabaca bir hesap yaptığımızda 1 milyon dolarlık kazanç bir kişi için 20 yıllık maaşının karşılığıdır. Günümüzde 4bin liralık maaşı (yoksulluk sınırı kabul edilen miktardan fazla) güzel bir maaş olarak kabul edersek basit bir matematiksel hesapla;

(2013) Dolar=1.85 TL Yoksulluk sınırı=3200 TL Google ya da Apple payı: %30

20 senelik maaş geliri
Bir uygulama bir dolar bir milyon indirme
4.000x12x20 = 960.000 TL
1.000.000x1.85x0.70 = 1.295.000 TL

Gördüğünüz gibi sloganın gerçekleşmesi durumunda 20 senelik maaş artı emeklilik primi bir anda elinizde olabilir. Tabi bu iş sloganı üretmek kadar kolay değil. Öncelikle 1milyon kişinin beğenisini kazanacak bir uygulamayı ortaya koyup bir de bunu paralı satabilmek kısmını atlamamak gerekiyor.

Yüksek gelir getiren uygulamalara baktığımızda güçlü firmaların yapımlarının büyük pay aldığını görüyoruz. (Appannie indekslerinden yola çıkarak sizde buradan inceleyebilirsiniz.) Güçlü firmalar çok para, çok çalışan ve büyük projeler demek oluyor. Çok para yatırıp çok kazanmayı bekliyorlar ve beklerken de kendilerini finanse edebiliyorlar.

Uygulamadan çok para kazanmak için illa büyük firma güçlü bir finans şart değil. Kimsenin düşünmediğini düşünmek, basit bir uygulama ile milyonlarca insanın beğenisini kazanmak için kimse sizi engelleyemez. 17 yaşında birinin bir anda milyoner olması uygulama dünyasında şaşılacak bir olay değildir. Önemli olan fikir ve yılmadan çalışmaktır.

Dikkat ederseniz yukarıda anlattıklarım sadece android platformuna özgü bir olay değildir. Aynı şekilde hatta biraz daha iyi pazar payı ile IOS, yeni gelişmekte olan WP-8 platformları da mobil uygulama pazarına dahildir. Benim çalıştığım konu Android platformu olduğundan yazımıza bu şekilde başlamış bulunduk.

Genel perspektifi sloganımız çerçevesinde çizdikten sonra bana ya da sloganı paylaştığım arkadaşlarıma gelecek olursak henüz milyoner olmuş değiliz. Ufukta da öyle milyonları getirecek bir yapım görünmüyor. Peki ,uğraştığımız emek verdiğimiz uygulamalardan nasıl para kazanabiliriz?

  • Uygulamayı paralı olarak kullanıcılara sunarak (Paid)
  • Uygulamayı ücretsiz (bedava, beleş), gelişmiş halini ya da geliştirme eklentilerini paralı sunarak (In-app billing, freemium)
  • Uygulamayı ücretsiz (bedava, beleş) fakat reklam içerikli sunarak (Free with ads)


İlk iki seçeneği henüz demediğim için bu yazımda sizlere 3. Seçeneği anlatmaya çalışacağım. Ücretsiz uygulamaların yüksek çoğunluğu, bazılarının hayrına yaptığı uygulamaların dışında reklamlardan gelir elde eder. Reklamdan gelir elde edebilmek için hitap ettiğiniz kitle ya da siz büyük değilseniz reklam firmalarıyla çalışmanız gerekir. Büyüklük kastım aynı web sayfalarında olduğu gibi yüksek hit oranına sahip değilseniz ya da fatura kesemiyorsanız direkt olarak reklamı siz alamazsınız. Reklamı biz alamıyorsak hangi reklam firmaları ile çalışmamız gerekir?

Mobil uygulama dünyasında birçok reklam şirketi bulunmaktadır. Bunların arasında Türk şirketleri de bulunmaktadır. Ama en popülerlerine bakacak olursak;


Şeklinde özetleyebilirim. (Bazı arkadaşlar bunlara ek olarak birkaç firma daha sayabilir tabi)
Bu reklam şirketlerinden en popüleri bildiğim kadarıyla Admob (yani Google).  Ben de uygulamalarımda Admob reklamlarını kullanmaktayım.

Yukarıda bahsettiğim farklı reklam şirketleri aynı zamanda farklı reklam şekilleriyle de birbirinden ayrılır. Örneğin: Admob standart bir reklam banner’ ı üzerinden reklamcılık yaparken, Airpush ile popup çıkartabilir, StartApp ile indirmeden para kazanabilirsiniz. Tabi hepsinin daha başka ve birbirinin aynı reklam ürünleri de olabilir. (yani Airpush veya Leadbolt ile de banner reklamcılığı da yapabilirsiniz) Konu benim uygulamalarım üzerinden devam edeceği için Admob bu yazıda ağırlık kazanacak.

Uygulamadan para kazanma serüvenim biraz hazin biraz da ağır başladı. İlk yaptığım uygulama daha doğrusu yazılımcı olmayan arkadaşımın yaptığı ilk uygulamayı devşirerek daha gelişmiş bir hal kazandırdıktan sonra Admob reklamlarının uygulama içerisinde yer almasını sağladık.

Admob, Adsense gibi bazı kriterleri sağladıktan sonra kabul edilebileceğiniz bir reklam ağı değildir. Sitesi üzerinden kayıt olup hemen başlayabileceğiniz, geliştirme kitini (SDK) indirdikten sonra uygulamaya ekleyip hemen reklam yayınlayabileceğiniz oldukça basit bir reklam ağıdır.

Arkadaşım sağolsun benim yerime J kaydolup, geliştirme kitini indirdikten sonra uygulama içerisini yerleştirdiğimiz banner ile reklamdan gelir elde etmeye başladık. Hem de ne gelir düşündüğünüz gibi değil J Başlangıçta dediğim gibi uygulamanın indirme ve kullanılma sayısı çok önemli. Dilerseniz size direk rakamları vererek olayı özetleyeyim.

İlk 15 günde 1.33$ yani aşağı yukarı 2 TL J Bu hesapla ayda 4TL olan kazancımız için ödeme almamız (Admob 100$ sonrası ödeme yapar) 40 aydan fazla alacaktı J Bir anda gelirleri artırıp milyoner olamadık. Tabi bu benim yaşadığım örnek, internette daha fazla araştırdığınızda ilk ayda binler kazanan uygulamalar yok değil.

Yılmadan çalışmaya devam ettik. Daha güzel bir arayüz, hadi bir de İngilizcesini deneyelim derken iki ay sonunda 4 küsür dolar ile müthiş bir gelir elde ettik. Bu noktada bir mola verip düşünmeye başladım. Nasıl bir uygulama yapmam gerekir ki reklamdan daha fazla para getirsin. Uzun market (Google play) araştırmaları sonucunda karar verip illeryollar uygulamasını hayata geçirdim. Bu noktadan sonra indirme sayılarının ve kullanımın artmasına bağlı olarak gelirler de artmaya başladı. Artık ödeme alabilecektim J

Sonrasında diğer uygulamalar gelmeye başladı ve ilk hedefim olan aylık ödeme yani ayda 100$ sınırını yakalamaya başladım. Sonrasında koyduğum günde 5$ hedefine ulaşmam bayağı uzun bir zaman aldı. Sene sonuna doğru zirve yapmaya başladım. 

Uygulamaların popülerliğini yitirmesi, düşük puanlamalar kullanımın azalması en sıkıntılı konular. Hele de bazı kullanıcıların uygulamayı farklı yorumlayıp düşük puan vermesi sizi çileden çıkartabiliyor.

Bu arada bir ayı yüksek gelirle geçiriyor olmanız artık kurtardığınız anlamına gelmiyor. O ay ki reklam değerleri ve/veya sizin uygulamalarınızın popülerliği de artmış olabilir. 

İlleryollar' dan sonra yaptığım Tv Turk televizyon rehberi uygulaması ile gelirlerimi bir parça daha artırmaya başlamıştım. Uygulama popülerliği başlangıçta iyi olsa da sonradan gelen yorumlarla uygulamada geriye gidiş başlamış oldu. Tabi bu yorumların hepsi haklı değildi. Açıklamasında rehber olduğunu belirtsem de aşağıdaki yorumlardan kaçamadım.


Tabi bu yorumların fazla oluşu diğer kullanıcıları o kadar etkilemiş ki bir kullanıcıdan çok farklı bir yorum da aldım. Biraz müstehcen olduğu için karalama yapmam gerekti.



Sonuç olarak bugün uygulamalardan para kazanmaya devam ediyorum. Henüz milyoner olmuş değilim ama her geçen gün uygulama portföyümü genişletmeye çalışıyorum. Sadece reklam amaçlı içi boş uygulama da yapmak istemiyorum markette kalıcı ve belli seviyede kalmak istiyorum. Para kazanılıyor mu? Evet kazanılıyor. Çok para kazanır mısın? Ben kazanmadım ama kazanılabileceğini görüyorum. Sadece çalışmak ve biraz da şans diyelim.

Android RadioGroup, RadioButton ve ImageView (Resim)

Geçen gün bahsettiğim android uygulamalarını hayata geçirirken bazı sorunlarla karşılaştım ve bunları sizinle paylaşmak istedim. Öncelikle uygulamada çocukların öğrendiklerini test etme amaçlı bir test arayüzü (activity) yazmak istedim. Test dediğimiz zaman programcı olarak aklımıza gelmesi  gereken elemanlardan (component) ilki radiobutton ‘ dur.

RadioButton, RadioGroup ile kullanıldığında size otomatik olarak çoktan seçmeli bir arayüz oluşturacaktır. RadioGroup içerisine atayacağınız her radiobutton (seçenek) için radiogroup size sadece birisini seçmenizi sağlayacaktır. Zaten test arayüzünden bizim de istediğimiz budur, yani soruya seçenekler içerisinden verilecek tek cevap.

Basitçe kodlayacak olursak;

final RadioGroup radioGroup = new RadioGroup(this); radioGroup.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT)); for (int i=0; i<4; i++) { final RadioButton radio = new RadioButton(this); radio.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)); int resid = i; Drawable image=getResources().getDrawable(resid); image.setBounds(0, 0, 128, 128); radio.setCompoundDrawables(image, null, null, null); radio.setText(" "); radioGroup.addView(radio); }
             
Yazdığımız kod sonucunda yandaki gibi soru seçenekleri oluşacaktır. Yazı (text) bazlı seçenekler için gayet basit bir çözüm oluyor.

Peki ya yazı değil de seçenekleri resimden oluşturmak istersek nasıl kodlama yapmamız gerekecek?

Öncelikli olarak belirtmek isterim araştırmadan kafamdakilerle olaya başladığımdan sürekli sorun yaşadım. Toplamda 3 farklı yol izleyerek kendimi gereksiz yere yordum ve sonuncu seçenekte doğruyu buldum. Gerçi doğruyu bulduğumda da bir başka bug ile karşılaştım ama sonunda sorun çözülmüş oldu.
Konuyu fazla uzatmadan direkt olarak size çözümü belirtip arkasından diğer uygulamalardaki sıkıntıları sizinle paylaşacağım.

RadioButton üzerinde setCompoundDrawables() adlı  fonksiyonu kullanarak RadioButton üzerine yazıdan önce veya sonra resim çizebiliyoruz. Aşağıdaki kodda drawable klasöründe bulunan bir resimi kullanarak radioButton (seçenek) üzerine resim çizmiş oluyoruz.


Yazıyı boş bırakınca veya boşluk olarak kullanınca seçeneğimiz ( radiobutton) sağdaki şekilde görünecektir. Bu sayede resimli seçenek oluşturmayı basitçe halletmiş olacağız. Yalnız burada daha önceden sözü geçen bug olayından bahsetmek isterim. RadioButton özelliklerinden padding seçeneğini kullandığınızda yani kenar radiobutton için kenar boşluklarını ayarlamak istediğinizde alakasız biçimde oluşturduğunuz seçenek aşağıdaki gibi olacaktır.

Ne yaptıysam ne kadar araştırdıysam da buna bir çözüm bulamadım. En son çözüm olarak kenar boşluklarından (padding) vazgeçtim ve düzeldi.

Aslında resimli seçenek oluşturma çözümü yukarıda bahsettiğim şekilde gerçekleştirilebilir. Tabi bu yöntemi bulmadan önce iki farklı ve zahmetli çözümle yola çıktım. Kısaca yöntemlerden ve yaşadığım sorunlardan bahsedelim.

İlk olarak seçenekler için kullandığım radio button için background özelliğine bitmap resim yerleştirmek istedim. Hayvan resimlerini radiobutton için ölçeklendirip arkaplan resmi olarak kullandım.

float ratio = 0; Bitmap bitmap = BitmapFactory.decodeResource(this.getResources(), Integer.valueOf(question.OptionResources.get(i).Resource.toString())); if(bitmap.getHeight()>=bitmap.getWidth()) {
ratio = Float.valueOf(ImageSizeOption) /bitmap.getHeight(); int newwidth = (int)(bitmap.getWidth()*ratio); bitmap = Bitmap.createScaledBitmap(bitmap.copy(Bitmap.Config.ARGB_8888, true), newwidth, ImageSizeOption, false); } else { ratio = Float.valueOf(ImageSizeOption) /bitmap.getWidth(); int newheight = (int)(bitmap.getHeight()*ratio); bitmap = Bitmap.createScaledBitmap(bitmap.copy(Bitmap.Config.ARGB_8888, true), ImageSizeOption, newheight, false); } int radiowidth = Constants.pixelFromDp(this, 60); Bitmap layoutbitmap = Bitmap.createBitmap(ImageSize*2, bitmap.getHeight(), Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(layoutbitmap); canvas.drawBitmap(bitmap, radiowidth, 1, null); BitmapDrawable bit = new BitmapDrawable(layoutbitmap); radio.setBackgroundDrawable(bit); radio.setText(" "); radioGroup.addView(radio);

Görüldüğü üzere kod bir önceki koda göre oldukça büyüdü ve yapılan işlem sayısı arttı. Resmi ekran boyutuna göre ölçeklendirmek için kontroller geldi. Sonuç olarak bu işlem sayesinde resimli seçeneği oluşturmuş oldum.


Bu yöntemin dezavantajı yavaş kalması, bazı ekranlarda ölçeğin bozulması ve bazı telefonlarda arka plan resminin gözükmemesi oldu. Bu nedenle bu yöntemden vazgeçtim.


Bir de RadioGroup kullanmadan LinearLayout kullanarak RadioButton ve ImageView ikilisini yan yana getirerek seçenekleri oluşturmaya çalıştım. RadioGroup kullanmadığım zaman resimler ne kadar güzel görünse de seçeneklerin hepsi aynı anda seçilir hale geldi.

Seçeneklerin tek tek seçilebilmesi için radiogroup elemanının otomatik olarak yapacağı işi kendim kodlayarak yeni kontrol ekleyerek yapmaya çalıştım. Sonuç olarak yaptm ama kod bir hayli büyüdü. Çözüm güzel olsa da yönetilebilirlik azaldığı için bu yöntemden de vazgeçmiş oldum.

Meyveler ve Hayvanlar

Merhabalar,
Tembel developer olarak .Net platformu (C#) ve hobi olarak android platfomu üzerine kod yazmada tembellik ettiğimi söyleyebilirim. Son olarak android uygulamalarıma iki yeni uygulamayı daha eklemiş bulunmaktayım. Meyveler ve Hayvanlar uygulamaları özellikle okul öncesi çocuklar için hazırlanmış eğitici uygulamalardır.

Meyveler uygulaması ile çocuklar 20 adet meyvenin resmini ve ismini öğrenebilir. Sonra da test arayüzünü kullanarak kendisini test edebilir. Aslında test arayüzünde soruların yazılı olması sorun gibi görünse de çocuklar sorunun şeklinden nasıl cevap vereceğini hemen anlayabilmektedir.

Aynı şekilde Hayvanlar uygulaması ile çocuklar 25 hayvanın farklı resimlerini, isimlerini ve ek olarak çıkardıkları sesleri öğrenebilirler. Meyveler uygulamasından farklı olarak her hayvana ait ses test kısmına da eklenmiştir.


Tembellik etmeyip aynı tarzda bir uygulama daha çıkarmayı düşünüyorum. Artık onu da çıkardığım zaman sizinle paylaşırım. Şimdilik bu kadar görüşmek dileğiyle...