Android ilk çıktığı zamanlarda baştan başlayarak bir makale dizisi yazmayı hayal etmiştim. Ancak zamansızlıktan yalan oldu. Şimdi ise iş arkadaşlarımın yemek seçme kararlarını beklerken hızlıca ufak bir makale yazayım dedim.

Bir programcı için yazdığı uygulamanın kitlenmesi neredeyse bir kara leke gibi birşeydir herhalde. Hemen damgalanır. Son kullanıcı durmandan oraya buraya basar uygulama da her aksiyonu işlemek zorunda olduğu ve işlemci gücü yetmediğinden kitlenir. Gayet doğal bir sonuç ama çözümü elbette var! Kullanıcıyı gereksiz aksiyondan uzak tutmak. Yani bir işlem yaparkan Progress Dialog çıkartmak gerek en basitinden. Kullanıcıyı işlem hakkında bilgilendirmek gerek.

Bazı işlemler de var ki uzun sürer ama o süre boyunca kullanıcıyı boşuna bekletmek yersiz. Arkaplanda kullanıcının ruhu duymadan işlemi yapmak için “Asenkron İşler” yardımımıza koşar. Anlatacağım işlemler her dilde hemen hemen aynıdır yani en azından mantık bakımından. Hadi yapalım bakalım.

Örneğin, uygulama açılırken kullanıcıyı bekletmeden arka planda versiyon kontrol edelim. Uygulamamızın yeni sürümü çıkmışsa kullanıcıyı bilgilendirelim.

onStart eventinde checkUpdate metodunu çağıralım. Metodun içeriğini inceleyelim.


private void checkUpdate() {

  // Kullanici bir onceki ekrandan tekrar buraya geldiyse tekrar tekrar calismamasi icin bir kontrol
  if (isUpdateChecked)
   return;

  // Islemi bir thread altinda yapiyor olacagiz.
  // Thread de bir Runnable nesnesinin icerisindeki run metodunu cagiracaktir.
  // Biz de o run metodunun icerigini dolduracagiz.
  Thread th = new Thread(new Runnable() {

   @Override
   public void run() {

    // Serverdan guncel versiyonun bilgileri cekilip nesneye donusturulmus hali. CustomPackageInfo diye bir class.
     CustomPackageInfo cpi = GetLatestVersionInformation();

     try {

      if (cpi != null) {
       PackageInfo pi; // suan telefonda yuklu olan uygulamamizin versiyon bilgileri
       pi = getPackageManager().getPackageInfo(
         getPackageName(), 0);
       if (cpi.VersionCode > pi.versionCode
         && !cpi.VersionName.equals(pi.versionName)) {
        {
         // Guncelleme icin kullanilacak activity ekrani (UpdateActivity.class) 'nin sabit degiskenleri
         UpdateActivity.WhatsNew = cpi.WhatsNew;
         UpdateActivity.GoToURL = cpi.Url;

         // Sabit degiskenler yerine bundle ile de parametreleri gonderebilirsiniz.

         // Kullaniciyi bilgilendirme amacli uyari sistemini kullanalim
         NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
         int icon = R.drawable.logo;
         CharSequence tickerText = "Uygulamimizin yeni bir sürümü mevcut! Lütfen yükleyiniz!";
         long when = System.currentTimeMillis();
         Notification notification = new Notification(
           icon, tickerText, when);
         notification.defaults |= Notification.DEFAULT_SOUND;
         Context context = getApplicationContext();
         CharSequence contentTitle = "Güncelleme bulundu!";
         CharSequence contentText = "Uygulamamizin yeni sürümünü yükleyiniz!";

         // Uyari sisteminden bizim uyariya tiklaninca hangi intentin yani hangi activity - ya da ekran da diyebilirsiniz - inin calisacagini belirtiyoruz.
         Intent notificationIntent = new Intent(
           getApplicationContext(),
           UpdateActivity.class); // UpdateActivity.class bizim guncelleme hakkinda bilgi verdigimiz ekran

         // Uyari sisteminde bekleyen uyarilarilara bizim uyariyi ekliyoruz.
         PendingIntent contentIntent = PendingIntent
           .getActivity(
             getApplicationContext(), 0,
             notificationIntent, 0);

         // Uyari sisteminde bizim uyarinin en son uyari oldugunu belirtiyoruz.
         notification.setLatestEventInfo(context,
           contentTitle, contentText,
           contentIntent);

         // Ve son olarak uyari sistemine uyarimizi gonderiyoruz. Geri kullanici ile telefonu arasinda.
         mNotificationManager
           .notify(0, notification);
        }
       }
      }
     } catch (NameNotFoundException e) {
      e.printStackTrace();
     }
    }
    isUpdateChecked = true;

  });
  th.start(); // ve son olarak bu asenkron islemi baslatiyoruz. Start dedikten sonra run metodunu icerigi calisacaktir.

 }

Aslında yukarda böyle bir kod yazmayı düşünmemiştim. Ama olsun. Arada Android’te Uyarı Merkezini (Notification Manager) incelemiş olduk.

Kısacası yapmak istediğimiz işleri Thread altında yapıyoruz. Keşke bu kadar kolay olsa herşey. Aslında direk olarak herhangi UI birimine (bir edittext’e vs) çalışma anında erişmiyorsak sorun olmaz. Peki erişmek istersek o zaman ne yaparız? UI güncellemeleri için sisteme bir mesaj göndeririz. Sırası geldiğinde UI’i güncelleyecektir. Birçok yolu mevcut aslında. Hadi birini yapalım.

onCreate metodunda istediğimiz gibi UI’i değiştirelim sorunsuz bir şekilde günceleyecektir. Ancak content tamamen yüklendikten sonra UI’e eriştiğimizde thread hatasıyla karşılaşabiliriz. Bu tür süpriz durumların olmaması için şöyle yapıyoruz.

Diyelim ki bir butona basınca serverdan data çekip, sonra da o datayı UI birimlerine bind edeceğiz. Bu süre boyunca kullanıcıya bir Progress Dialog çıkartmakta yarar var.


Runnable dataRunnable = new Runnable() {

   @Override
   public void run() {
       getData();
   }
  };
  Thread th = new Thread(null, dataRunnable, "backgroundJob");
  th.start();

// mProgressDialog değişkenimiz bir field ki başka yerden erişmemiz gerekecek

// ki işlemimiz bitince progress dialogu kapatacağız.
// Progress Dialog'u çıkartıyoruz.
  mProgressDialog = ProgressDialog
    .show(this, "Lütfen Bekleyiniz...","Data getiriliyor... ");

/*
 getData metodunda datayı çektikten sonra UI ile ilgi bir güncellememiz olduğunu bildirmemiz gerekecek.
*/

private void getData(){

mErrorMessage = "";
  try {

   // Serverdan datamizi cekiyoruz.
   mResult = new DataManager().getNewData();
   // isimlere takilmayin suan tamamen salliyorum. :)

  } catch (Exception e) {
     mErrorMessage = "Bir hata oluştu! " + e.getMessage();
  } finally {
      // en onemli kisim: her durumda islemi sonlandirip kullaniciyi bilgilendirmemiz gerekecek.
   // iste UI ile ilgili bir islem yapacagimizi bildirdigimiz yer burasi
   runOnUiThread(mReturnResultRunnable); // mReturnResultRunnable UI ile ilgili islemlerimizi yapacagiz. Private bir field
  }

}

 private Runnable mReturnResultRunnable = new Runnable() {

  @Override
  public void run() {

      // Herhangi bir hata olusup olusmadigini kontrol ediyoruz. Datamizi dogruluyoruz.

      // Burda datamizi UI birimlerine bind ediyoruz.

   // Ornegin: mResult bir Collection ise ve biz de bu datayi ListView'da gosteriyorsa bu islemi burda yapacagiz.

   mProgressDialog.dismiss(); // islem bitti. Progress Dialog'umuzu kapatiyoruz.

  }
 };

 private String mErrorMessage;

 

İşte en basit anlamda en çok ihtiyaç duyulan bu konuda işler böyle yapılabilir.

Başka bir zaman ne yazarım bilmiyorum gerçekten :(

Görüşmek üzere

İyi kodlamalar ;)

Merhabalar,

Yine uzun bir ara verdim yazmak için ama inanın elimde değil :) Ancak böyle reklam yapmak için fırsat buluyorum işte :) Oysa yazılımla ilgili deneyimlerimi size aktarmam lazım. Çok istiyorum! Konular da baya birikti… Ben de yazmak için sabırsızlanıyorum! Bu arada kaybolmuşken çok hızlıca bir Android uygulaması geliştirdim Java ile. Dün(17 Mart) release oldu ve ilk önce Samsung Türkiye’nin Android Marketinde sergilendi. İlk gün top 5′te idik. Yükselmeye devam ediyor. Hatta bu yazıyı yazarken bakayım dedim. 1. sıraya çıkmışız bile(19 Mart’ta-hala öyle). Uygulamayı download eden herkese çok teşekkür ederim. (Düzenleme(21 Nisan): Bu post’u 17 Mart’ta ilk yazmaya başlamıştım ancak bu bile yarım kaldı :) )

Peki bu uygulama kullanıcıya neler sunuyor?

  • Öncellikle mobil dünyanın bütün avantajlarından olabildiğince yararlanmaya çalıştık. Lokasyon bilginize göre yakınınızdaki mekanlar ve şehrin en iyileri listeleniyor. Bu mekanlar daha önce kullanıcıların yaptığı yorum ve puanlarından derlenerek size sunuluyor.
    Mekanlar listeleniyor
  • Dilerseniz başka şehirdeki mekanları da keşfedebilirsiniz. ;)
  • Mekanist.net’teki bütün ana kategori ve alt kategorilerini listeleyebilir, seçtiğiniz kategori altındaki mekanları inceleyebilirsiniz.
    Kategoriler listeleniyor
  • Seçtiğiniz mekanın detaylarında en son kullanıcı yorumu ve tüm yorumlarına, yorum sayısını ve yorum dağılımını, puanını, varsa fotoğraf galerisine, adresine, harita ve telefon bilgisine ulaşabilirsiniz. Direk uygulama üzerinden mekanı arayabilir ya da harita üzerinden yol tarifi alabilirsiniz.
    Mekan detayı görüntüleniyorMekan detayı görüntüleniyor-2Mekan adresine yol tarifi alınıyor
  • Mekan’a ait bütün yorumlara erişilebiliyor.
    Mekan'a ait tüm yorumlar görüntüleniyor
  • Dilerseniz mekan ile ilgili düşüncelerinizi yorum yazarak Mekanist.net kullanıcılarıyla paylaşabilirsiniz.
    Yorum yazılıyor
  • İl, ilçe ya da yakınınızdaki mekanlarla ilgili arama yapıp sonuçları harita üzerinde göstertebilirsiniz.
  • Arama ekranıArama sonuçlarıSonuçlar harita üzerinde gösteriliyor.
Şimdilik bu kadar. :) Uygulamayı geliştirmeye devam ediyoruz. Yakında yepyeni ve süpriz özelliklerini duyuracağız.
Şimdi, Android sistemler için uygulama geliştirmek hakkında nacizhane fikrimi paylaşayım. Öncelikle çok rahat bir geliştirme ortamı var. Java ile herhangi bir IDE üzerinden geliştirme yapabiliyorsunuz. Ben Ubuntu x64′te Eclipse IDE’si üzerinde geliştirdim. Android’in dökümantasyonu yeterli ama örnekleri az haliyle. Ama nette bolca kaynak  bulabilirsiniz. ;) Fırsat olsa da burda bolca örnek yazsaydım. Uygulamayı test etmek için Android Plug-in’i aracılığyla bir tane emülatör oluşturup kullanabiliyorsunuz. Çok başarılı buldum. Çünkü istediğiniz özelliklerde bir cihaz emülatörü oluşturabiliyorsunuz. Eğer cihazınız varsa direk uygulamayı cihazınınz üzerinden de test edebilirsiniz. Herhangi bir key almanız gerekmiyor. Google map kullanımı için Google’dan bir map key almanız gerekiyor. Uygulamanızı Android Market’e atmak ise çok kolay ve bir o kadar da hızlı. Herhangi bir onay işlemi olmadan hemen yayınlanıyor. Üstelik Android Market çok güzel bir istatistik bilgisi de sunuluyor. Özellikle uygulamanın kaç kişi tarafından indirilip, silindiği, hata raporları gibi bilgilere ulaşmak da cabası. Bu da Google farkı herhalde :)
Başka bir yazıda görüşmek üzere hoşçakalın! İyi kodlamalar! :)

Wpf çıkalı birkaç yıl olmasına rağmen hala bir html editör bulunmamaktadır. Neyseki WindowsFormsHost classı yardımıyla Windows Forms Controllerini WPF’te de kullanabiliyoruz.

Windows Forms için açık kaynak kodlu bir html editör buldum www.windowsclient.net te.  Başarılı bir derlemenin ardından WPF’e entegre işlemine başlayalım. WPF uygulamamızın referanslarına WindowsFormsIntegration.dll, System.Windows.Forms.dll ve daha önce indirip derlediğimiz HTML editörünün dll kütüphanelerini ekliyoruz.

İşte başlıyoruz bakın ne kadar kolay. :)

Even WPF has been released for a few years still there is no html editor. Happily, we can use Windows Forms Controls in WPF via WindowsFormsHost class.

I found an open source html editor for Windows Forms from www.windowsclient.net. Let’s start to create an example in WPF after a succesful compilation. Firstly, add these libraries to your WPF application references: WindowsFormsIntegration.dll, System.Windows.Forms.dll and HTML Editor’s libraries which we’ve downloaded already and compiled.

Here we go to start and see how it’s so easy. :)

 public partial class Window1 : Window
 {
 WindowsFormsHost wfh = new WindowsFormsHost(); // Windows Form Controllerini WPF içerisinde barındırmamız sağlayacak.
//Provide to host Windows Forms Controllers
 Microsoft.ConsultingServices.HtmlEditor.HtmlEditorControl htmlEditor; // WinForm HTML editör.
// The HTML Editor.
 public Window1()
 {
 InitializeComponent();
 Loaded += new RoutedEventHandler(Window1_Loaded);
 }
 void Window1_Loaded(object sender, RoutedEventArgs e)
 {
 htmlEditor = new Microsoft.ConsultingServices.HtmlEditor.HtmlEditorControl();
 wfh.Child = htmlEditor; // barındıralacak controllü setliyoruz. // we are setting the control which is going to host inside the Windows Forms Host.
 grd.Children.Add(wfh); // ve son olarak da Grid'imize Windows Form Host'u  ekleyoruz. // And finally we add the Windows Form Host to our Grid.
 }
 }

Happy Coding ;)

Merhabalar,

Hepimizin çok ihtiyacı olan bir konu sanırım. Herhangi bir dosyayı, bir URL’in içeriğini ya da içeriğini bizim belirleyebileceğimiz pdf dosyaları yapmak isteyebiliriz. Bu konu ile ilgili birkaç hazır component var. Ben de bunlardan WebSupergoo‘nun ABCpdf7 componentini kullanarak örnek yaptım.

Hello,

I think the issue is a need for all of us. We may want to create pdf files from a file, an Uri’s content or own customization. There are a few components to do that. I used WebSupergoo‘s ABCpdf7 component to creae this example.

using (WebSupergoo.ABCpdf7.Doc pdfDocument = new WebSupergoo.ABCpdf7.Doc())
{
        //theDoc.Rect.Inset(0, 0);

	pdfDocument.Page = pdfDocument.AddPage();
	int pageId = pdfDocument.AddImageUrl("http://www.google.com.tr/"); // Herhangi bir sitenin anasayfasının ekran görüntüsünü alıyorum. Ancak site içeriğinin uzunluğunu bilemeyebiliriz. O yüzden az sonra aşağıda görüntüyü sayfalara böleceğiz.
	// I want to get a screen shot from any web site. Maybe we don't have any idea about the page length that's why we seperate the picture to pages.
	while (true)
	{
		pdfDocument.FrameRect();
		if (!pdfDocument.Chainable(pageId))
		break;
		pdfDocument.Page = pdfDocument.AddPage();
		pageId = pdfDocument.AddImageToChain(pageId);
	}

    for (int i = 1; i <= pdfDocument.PageCount; i++)
	{
		pdfDocument.PageNumber = i;
		pdfDocument.Flatten();
	}

	string pdfFilePath = "testpdffile.pdf";

	pdfDocument.Save(pdfFilePath);
	pdfDocument.Clear();
}

Bu aralar / Nowadays

Posted: March 13, 2010 in Kişisel

Uzun bir tembellik sürecinden sonra işe atılmış bulunmaktayım. Bu aralar neler yapıyorsun diye soruyorlar bana. Hemen cevaplayayım. Öncellikle yeni bir işe girdim. Özel bir TV kanalı için 5 kişilik ekiple beraber bir Content Management System uygulaması ve Web sitesi yapıyoruz. WPF, WCF ve ASP.NET MVC kullanmaktayız. Bu konularda edindiğim, edineceğim zorlu tecrübeleri sizinle blogumda paylaşıyor olacağım. Aynı zamanda, Android ve iPhone için de bişeyler düşünüyorum. Fırsat bulursam tabi ki. Fırsat buldukça makale yazmaya çalışacağım.

After a long time I’ve been working for a new job. My friends are asking about what I’m doing nowadays. Let me answer it. I just got a new job. With 5 people, trying to developing a Content Management Sistem with WPF, WCF and ASP.NET both Windows and Web Applications for a special TV channel. I’ll share my hard experiences with you on my blog about these subjects. And also, I’m thinking to write some articles about Android and iPhone as I can get a change for writing.

Resource: http://abstrusegoose.com/249

Merhabalar,

Bildiğiniz üzere Silverlight ile gelen varsayılan sayfadaki html IE8 ile uyumsuzluk göstermektedir. IE8 ile gelen uyumluluk modunu kullanarak da bu düzeltilebillir ancak bunu kullanıcı düşünmeyebilir ayrıca düşünmek zorunda da değil herkes programcı değil o yüzden biz düşünüp çözelim. :) Şöyle bir kod ihtiyacımızı görecektir. ;)

<div id="silverlightControlHost" style="position: absolute; top: 0px; left: 0px; right: 0px; bottom: 0px;">
  <center>
    
        <object data="data:application/x-silverlight-2,"  type="application/x-silverlight-2" width="100%" height="100%">
		  <param name="source" value="ClientBin/SilverLightApplication.xap"/>
		  <param name="onError" value="onSilverlightError" />
		  <param name="background" value="white" />
		  <param name="minRuntimeVersion" value="3.0.40624.0" />
		  <param name="autoUpgrade" value="true" />
		  <param name="windowless" value="true" />
		  <param name="Culture" value="auto"  />
          <param name="UICulture" value="auto" />
          <param name="windowless" value="true"/>
       	  <a href="http://go.microsoft.com/fwlink/?LinkID=149156&v=3.0.40624.0" style="text-decoration:none">
 			  <img src="http://go.microsoft.com/fwlink/?LinkId=108181" alt="Get Microsoft Silverlight" style="border-style:none"/>
		  </a>
	    </object>

	</center>
</div>

ya da header kısmına şu meta tag’ini ekleyerek de bu sorunu giderebilirsiniz.

<meta http-equiv="X-UA-Compatible" content="IE=7" />

Merhabalar,

Bildiğiniz gibi geçen haftalarda Silverlight 3 beta çıktı developerlar için. Biz de hemen kullanılan bir projede test etmek istedik. :) Gerekli kurulum işlemlerini yaptıktan sonra convert etti Visual Studio. Projeyi publish ettik ancak  yeni sürüm henüz release olmadığı için kullanıcı ancak Silverlight 2 sürümünü yükleyebiliyor.

Bu durumda otomatik güncelleme işlemini kendiniz yapmanız gerekiyor. Hadi yapalım.

<body style="height: 100%; margin: 0;">
<div id="errorLocation"></div>
<form id="form1" runat="server" style="height: 100%;">
<div style="height: 100%;" id="silverlightControlHost">
    <object data="data:application/x-silverlight-2," type="application/x-silverlight-2"  width="100%" height="100%"><param name="source" value="ClientBin/IPTVSilverLightClient.xap" /><param name="onerror" value="onSilverlightError" /><param name="background" value="white" /><param name="minRuntimeVersion" value="3.0.40307.0" /><param name="autoUpgrade" value="false" />              <a href="http://go.microsoft.com/fwlink/?LinkID=143433" style="text-decoration: none;">                      <img src="http://go.microsoft.com/fwlink/?LinkId=108181" alt="Get Microsoft Silverlight"   style="border-style: none" /> </a>    </object></div>
</form>
</body>

onSilverlightError olayında hata mesajını yakalayıp ona göre ilgili işlemi yapmak lazım.

<script language="javascript" type="text/javascript">
        function onSilverlightError(sender, args) {

            document.getElementById("silverlightControlHost").style.display = "none";

            if (args.ErrorCode == 8001) {
                var msg = "<a href=\"http://go.microsoft.com/fwlink/?LinkID=143433\"><img src='http://go.microsoft.com/fwlink/?LinkId=108181' alt='Get Microsoft Silverlight'    style='border-style: none' /></a>.";
                var hostContainer = document.getElementById("errorLocation");
                hostContainer.innerHTML = msg;
            }
        }
    </script>

Dipnot: Projenizi Silverlight 3′e convert ettikten sonra geriye dönmek biraz zahmetli bir iş. İhtiyacınız olabilir diye linki bırakıyorum.
http://blogs.msdn.com/amyd/archive/2009/03/18/switching-from-silverlight-3-tools-to-silverlight-2-tools.aspx

Happy Coding :)
i-developer

Son Yazılımcı Yandım Aram

Sonunda film de çevirdik :P :)

Merhabalar,
Sınırsız ağaç yapısını TreeView controlünde göstermek zahmetli bir iş iken bazı componentlerde çok basit yolla yapılabiliyor. Örneğimizde RadTreeView componentini kullandım.

            this.rtvCategories.DataMember = "Category";
            this.rtvCategories.DisplayMember = "CategoryName";
            this.rtvCategories.ValueMember = "CategoryID";
            this.rtvCategories.ParentIDMember = "MainCategoryID";
            this.rtvCategories.DataSource = dsCategories;
            this.rtvCategories.ExpandAll();

Direk dataset’i bağladığınızda istediğimizi elde etmiş olmayacağız. Her ne kadar Nested bir relation da yazsak ona rağmen istediğimizi gene elde edemeyeceğiz. Bunun için ilişkiyi oluşturduktan sonra o dataset yardımı ile dataları locale(xml) yazdırmamız gerekiyor. Sonrasında yeni bir dataset tanımlayıp ReadXml methodu ile o dataları okumak lazım.

İlişkiyi aşağıdaki gibi yazabiliriz.

               DataRelation drltCategories = new DataRelation ("Category_CategoryID_MainCategoryID",dsTempCategories.Tables[0].Columns["CategoryID"],dsTempCategories.Tables[0].Columns["MainCategoryID"]);
               drltCategories.Nested = true;

Ve sonuç:

Unlimited TreeView

Sadece bununla da bitmiyor control’ün yetenekleri. Bunun yanında sürüklü-bırak, ekle, sil, düzenleme gibi işlemleri de mevcut. ;)

Happy Coding :)
i-developer