Windows Phone 8 için Pil Durumu uygulaması

Windows Phone 8 için güncel pil durumunu görebileceğimiz bir uygulama geliştireceğiz.

Bu uygulamanın geliştirilmesi sırasında Battery, PhoneApplicationPage, ApplicationBar, TimeSpan gibi yapıları kullandığımız kodlar yazacağız.

Öncelikle BatteryLevel isimli yeni bir Windows Phone App projesi oluşturalım;

Battery Level Windows Phone Application Project

Proje oluşturduktan sonra gelen Windows Phone Platform versiyon seçim penceresinde Windows Phone OS 8.0 seçeneğinin seçili olduğundan emin olmalıyız;

Windows Phone 8.0 SDK

MainPage.xaml dosyasını aşağıdaki gibi güncelleyelim;

<Grid x:Name=”LayoutRoot” Background=”Transparent”> <Grid.RowDefinitions> <RowDefinition Height=”Auto”/> </Grid.RowDefinitions>

&lt;StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28"&gt;
    &lt;TextBlock Text="PİL SEVİYESİ" Style="{StaticResource PhoneTextNormalStyle}" Margin="12,0"/&gt;
&lt;/StackPanel&gt;
&lt;TextBlock HorizontalAlignment="Stretch" Margin="0,0,70,-125" TextWrapping="Wrap" Text="- / 100" Name="lblRemainingChargePercent" VerticalAlignment="Bottom" Width="340"/&gt;
&lt;TextBlock HorizontalAlignment="Stretch" Margin="35,0,105,-180" TextWrapping="Wrap" Text="- / 100" Name="lblRemainingDischargeTime" VerticalAlignment="Bottom" Width="340"/&gt; &lt;/Grid&gt;

<phone:PhoneApplicationPage.ApplicationBar> <shell:ApplicationBar IsVisible=”True”> <shell:ApplicationBarIconButton IconUri=”/Assets/appbar.refresh.png” Text=”Güncelle” Click=”RefreshBatteryLabel” /> </shell:ApplicationBar> </phone:PhoneApplicationPage.ApplicationBar></pre>

İki TextBlock nesnesinde güncel pil durumunu göstereceğiz. Ayrıca eklediğimiz ApplicationBar sayesinde telefonun altında bir güncelleme butonu konumlandırmış olacağız.

ApplicationBar‘a eklediğimiz ApplicationBarIconButton nesnesine basıldığında RefreshBatteryLabel() method’unun tetiklenmesini sağlıyoruz.

MainPage.xaml.cs dosyasına RefreshBatteryLevel() method’unu ekleyelim;

private void RefreshBatteryLabel(object sender, EventArgs e)
{
    Battery Pil = Battery.GetDefault();

    int Yuzde = Pil.RemainingChargePercent;
    int Gun = Pil.RemainingDischargeTime.Days;
    int Saat = Pil.RemainingDischargeTime.Hours;
    int Dakika = Pil.RemainingDischargeTime.Minutes;

    string SarjYuzdesi = string.Format("Kalan pil : {0} / 100", Yuzde);

    string SarjSuresi = "Kalan şarj süresi : ";

    if (Gun > 0)
    {
        SarjSuresi += string.Format("{0} gün ", Gun);
    }
    if (Saat > 0)
    {
        SarjSuresi += string.Format("{0} saat ", Saat);
    }
    if (Dakika > 0)
    {
        SarjSuresi += string.Format("{0} dakika ", Dakika);
    }

    lblRemainingChargePercent.Text = SarjYuzdesi;

    lblRemainingDischargeTime.Text = SarjSuresi;
}

Son olarak, MainPage sınıfının constructor‘ında RefreshBatteryLevel() method’unu çağırırsak, uygulama ilk açıldığında pil seviyesi güncellenmiş olur;

RefreshBatteryLabel(null, null);


Uygulamayı çalıştırdığımızda aşağıdaki ekran görüntüsünü görüyor olmamız lazım;

![Battery Level Windows Phone 8 Application](/assets/uploads/2012/12/BatteryLevel3.png)

Projenin kodlarını buradan indirebilirsiniz.

Windows Phone 8 için Radyo Frekansları uygulaması

Windows Phone 8 için şehir-şehir radyo frekanslarını görebileceğimiz bir uygulama geliştireceğiz.

Bu uygulamanın geliştirilmesi sırasında Pivot, PivotItem, LongListSelector, DataTemplate, WebClient gibi sınıfları kullandığımız kodlar yazacağız.

Öncelikle RadyoListe isimli yeni bir Windows Phone App projesi oluşturalım;

Windows Phone App Project

Proje oluşturduktan sonra gelen Windows Phone Platform versiyon seçim penceresinde Windows Phone OS 8.0 seçeneğinin seçili olduğundan emin olmalıyız;

Windows Phone 8.0 SDK

Uygulama ihtiyaç duyduğu veriyi internetten indireceği için WMAppManifest.xml dosyasında Network erişim izninin istenmiş olması gerekiyor;

<Capabilities> <Capability Name=”ID_CAP_NETWORKING” /> </Capabilities></pre>

Radyo listesi için json formatında hazırladığım veriyi kendi sunucuma radyolar.json ismi ile yükledim.

Json formatında okuyacağımız bu veriyi işlemek için References içerisine Newtonsoft Json.Net (4.5.11) Nuget paketini eklemeliyiz;

Newtonsoft Json.Net Nuget Package

Models isminde bir dizin ekleyip, içerisinde LiveData, City, Channel, Frequency isimli sınıflar oluşturalım;

LiveData.cs

public class LiveData
{
    public IEnumerable<City> Cities { get; private set; }

    public IEnumerable<Channel> Channels { get; private set; }

    public IEnumerable<Frequency> Frequencies { get; private set; }

    public LiveData()
    {
        this.Cities = new List<City>();
        this.Channels = new List<Channel>();
        this.Frequencies = new List<Frequency>();
    }

    public LiveData(string LiveDataResponse)
    {
        var LiveDataResult = JsonConvert.DeserializeObject<LiveData>(LiveDataResponse);

        this.Cities = LiveDataResult.Cities;
        this.Channels = LiveDataResult.Channels;
        this.Frequencies = LiveDataResult.Frequencies;
    }
}

City.cs

public class City
{
    public int ID { get; set; }

    public string Name { get; set; }
}

Channel.cs

public class Channel
{
    public int ID { get; set; }

    public string Name { get; set; }
}

Frequency.cs

public class Frequency
{
    public int CityID { get; set; }

    public int ChannelID { get; set; }

    public float No { get; set; }
}

Uygulama ilk açıldığında çalıştırılan App (App.xaml.cs) sınıfına aşağıdaki kodları ekleyelim;

public static Action DataLoaded;

public static LiveData ViewModel = null;

public async static void LoadData()
{
    WebClient wc = new WebClient();

    wc.DownloadStringCompleted += (s, e) =>
    {
        if (e.Error == null)
        {
            ViewModel = new LiveData(e.Result);

            if (DataLoaded != null)
            {
                DataLoaded();
            }
        }
    };

    wc.DownloadStringAsync(new Uri("http://www.enginpolat.com/application-data/radyolar.json"));
}

App sınıfının constructor’ında LoadData() method’unu çağıralım;

LoadData();

Kodları inceleyecek olursak;

Sınıf seviyesinde tanımlanan LiveData tipindeki ViewModel değişkeni, LoadData() method’u içerisinde asenkron olarak doldurulur. ViewModel değişkenine değer ataması yapıldıktan sonra DataLoaded action‘ını dinleyen bir method varsa tetiklenir.

Bu sayede uygulamanın açılışı esnasında internetten verinin indirilmesi ve deserialize edilmesi asenkron olarak yapılmış olur.

MainPage.xaml dosyasında ekranda sadece bir Pivot kontrolünün gösterilmesini sağlayalım;

<Grid x:Name="LayoutRoot" Background="Transparent">
    <Grid.RowDefinitions>
        <RowDefinition Height="*"/>
    </Grid.RowDefinitions>
    <phone:Pivot Margin="0,10,10,10" Title="Radyo Listesi" Name="pvtSehirListesi" Grid.RowSpan="1" />
</Grid>

Artık MainPage.xaml.cs dosyasındaki constructor‘a giderek ekranı dolduracak kodları yazabiliriz;

App.DataLoaded = () =>
{
    foreach (City Sehir in App.ViewModel.Cities)
    {
        PivotItem pi = new PivotItem();
        pi.Header = Sehir.Name;

        LongListSelector list = new LongListSelector();
        list.ItemTemplate = Application.Current.Resources["FrequencyListItemTemplate"] as DataTemplate;
        list.ItemsSource = (from Frekans in App.ViewModel.Frequencies
            join Kanal in App.ViewModel.Channels on Frekans.ChannelID equals Kanal.ID
            where Frekans.CityID == Sehir.ID
            select new { ChannelName = Kanal.Name, Frequency = Frekans.No.ToString("00.0") }).ToList();

        pi.Content = list;

        pvtSehirListesi.Items.Add(pi);
    }
};

Böylece App sınıfında, ViewModel değişkenine değer yükledikten sonra tetiklediğimiz Action içerisinde bir foreach döngüsü çağırmış oluyoruz.

Döngü içerisinde ilk önce yeni bir PivotItem tipinde değişken oluşturuyoruz ve Header özelliğine döngü değişkeninden elde ettiğimiz şehir ismi bilgisini atıyoruz.

PivotItem tipindeki değişkenin Content özelliğine, LongListSelector tipinde yeni bir değişken atıyoruz.

LongListSelector tipindeki değişkenin ItemsSource özelliğine App.ViewModel değişkenindeki değerlerden LINQ Expression ile oluşturduğumuz listeyi atıyoruz.

Aynı şekilde LongListSelector tipindeki değişkenin ItemTemplate özelliğine

Application.Current.Resources["FrequencyListItemTemplate"] as DataTemplate;

değerini atıyoruz.

Son olarak, App.xaml dosyasına FrequencyListItemTemplate ismindeki Resource‘u ekliyoruz;

<Application.Resources>
    <DataTemplate x:Name="FrequencyListItemTemplate">
        <StackPanel Margin="0,0,0,17">
            <TextBlock Text="{Binding ChannelName}" TextWrapping="Wrap" Style="{StaticResource PhoneTextExtraLargeStyle}"/>
            <TextBlock Text="{Binding Frequency}" TextWrapping="Wrap" Margin="12,-6,12,0" Style="{StaticResource PhoneTextSubtleStyle}"/>
        </StackPanel>
    </DataTemplate>
</Application.Resources>


Uygulamayı çalıştırdığımızda aşağıdaki ekran görüntüsünü görüyor olmamız lazım;

![Radyo Liste Windows Phone 8 Application](/assets/uploads/2012/12/RadyoListe4.png)

Projenin kodlarını buradan indirebilirsiniz.

Windows 8 Uygulamalarda Toast Notification Kullanımı

Windows 8 uygulaması geliştirirken kullanıcıyı bilgilendirmek isteyebiliriz. Kullanıcıya sadece bilgi vermek için MessageDialog kullanmak doğru olmayacaktır, kullanıcı bir süre sonra rahatsızlık duymaya başlayacak ve belkide uygulamayı kullanmaktan vazgeçecektir.

Kullanıcıyı bilgilendirmenin daha doğru yolu Toast Notification sistemini kullanmaktır.

Toast Notification sistemini kullanırken dikkat etmemiz gereken ToastTemplateType enum yapısıdır.

MSDN‘de yer alan ToastTemplateType enumeration sayfasından hangi tiplerde toast notification gösterebileceğinizi öğrenebilirsiniz.

using kısmına

Windows.UI.Notifications</pre>

eklemeliyiz. Örnek kullanım;

public static void ShowNotification(string Title, string Message)
{
    const ToastTemplateType template = ToastTemplateType.ToastText02;
    var toastXml = ToastNotificationManager.GetTemplateContent(template);

    var toastText = toastXml.GetElementsByTagName("text");
    toastText[0].AppendChild(toastXml.CreateTextNode(Title));
    toastText[1].AppendChild(toastXml.CreateTextNode(Message));

    var toast = new ToastNotification(toastXml);

    var toastNotifier = ToastNotificationManager.CreateToastNotifier();
    toastNotifier.Show(toast);
}

public static void ShowNotification(string Title, string Message, string ImageFileName)
{
    const ToastTemplateType template = ToastTemplateType.ToastImageAndText01;
    var toastXml = ToastNotificationManager.GetTemplateContent(template);

    var toastText = toastXml.GetElementsByTagName("text");
    toastText[0].AppendChild(toastXml.CreateTextNode(Title));
    toastText[1].AppendChild(toastXml.CreateTextNode(Message));

    var toastImage = toastXml.GetElementsByTagName("image");
    toastImage.SetAttribute("src", ImageFileName);

    var toast = new ToastNotification(toastXml);

    var toastNotifier = ToastNotificationManager.CreateToastNotifier();
    toastNotifier.Show(toast);
}

Hatta Toast Notification gösterimi esnasında uyarı sesi bile çaldırabiliriz. Bunu yapmak için audio elementini kullanacağız. Sistemde kayıtlı uyarı sesleri;

  • ms-winsoundevent:Notification.Default
  • ms-winsoundevent:Notification.IM
  • ms-winsoundevent:Notification.Mail
  • ms-winsoundevent:Notification.Reminder
  • ms-winsoundevent:Notification.SMS
  • ms-winsoundevent:Notification.Looping.Alarm
  • ms-winsoundevent:Notification.Looping.Alarm2
  • ms-winsoundevent:Notification.Looping.Call
  • ms-winsoundevent:Notification.Looping.Call2

Örnek kullanım;

public static void ShowNotification(string Title, string Message, string ImageFileName, string SoundName)
{
    const ToastTemplateType template = ToastTemplateType.ToastImageAndText01;
    var toastXml = ToastNotificationManager.GetTemplateContent(template);

    var toastText = toastXml.GetElementsByTagName("text");
    toastText[0].AppendChild(toastXml.CreateTextNode(Title));
    toastText[1].AppendChild(toastXml.CreateTextNode(Message));

    var toastImage = toastXml.GetElementsByTagName("image");
    toastImage.SetAttribute("src", ImageFileName);

    var toastAudio = toastXml.GetElementsByTagName("audio");
    toastAudio.SetAttribute("src", SoundName);

    var toast = new ToastNotification(toastXml);

    var toastNotifier = ToastNotificationManager.CreateToastNotifier();
    toastNotifier.Show(toast);
}


Son olarak, yukarıdaki kodların çalışması için uygulamanın *Package.appxmanifest* dosyasında **Toast Capable** seçeneğine **Yes** değerini vermeyi *unutmamalıyız*

Windows Phone 8 ile WebClient sınıfında async kullanımı

İnternet üzerinden veri indirmeden Windows Phone 8 ile uygulama geliştirmek genellikle pek beklenmez.

async ve await anahtar kelimeleri hayatımıza girdikten sonra internetten veri indirmek gibi uzun sürebilecek işleri asenkron yapmaya başladık.

Fakat WebRequest ve WebClient sınıflarında async/await pattern‘inin eksikleri hissediliyor.

Örneğin WebClient sınıfının DownloadStringAsync method’unu inceleyelim;

public void DownloadStringAsync(Uri address);</pre>

Gördüğümüz gibi, geriye Task veya Task<T> tipinde sonuç döndürmüyor.

Bu yüzden bu method’u await anahtar kelimesi ile kullanamıyoruz;

WebClient wc = new WebClient();
await wc.DownloadStringAsync(new Uri("http://www.enginpolat.com"));

Daha derleme esnasında

// Cannot await "void"

hatası alırız.

Fakat aşağıdaki sınıfı ve extension method’u kullanarak WebClient sınıfına Task<T> sonuç döndüren method ekleyebiliriz;

public static class Extensions
{
    public static Task<string> DownloadStringTask(this WebClient client, Uri uri)
    {
        var tcs = new TaskCompletionSource<string>();

        client.DownloadStringCompleted += (s, e) =>
        {
            if (e.Error != null)
            {
                tcs.SetException(e.Error);
            }
            else
            {
                tcs.SetResult(e.Result);
            }
        };

        client.DownloadStringAsync(uri);

        return tcs.Task;
    }
}

Örnek kullanım;

WebClient wc = new WebClient();
return await wc.DownloadStringTask(new Uri("http://www.enginpolat.com"));


Uygulamalar Windows Phone 8 ile (çok) daha hızlı

Windows Phone 7.X kullanıcılarının en çok şikayet ettiği konulardan biri uygulamaların yeterince hızlı başlatılamaması idi. Microsoft, Windows Phone 8 tanıtımından beri yayınlanan bildirilerde uygulama başlangıç sürelerinin yaklaşık yarı yarıya azaldığını söylüyor.

Hızlı başlangıç süreleri, az pil tüketimi ve toplamda performans konularını inceleyelim;

.Net Framework, CoreCLR ve Garbage Collector

Windows Phone 8 ile birlikte en güncel versiyon olan .Net Framework 4.5 geliyor. Framework’te yapılan (hemen hemen) tüm güncellemeler ve iyileştirmelerden hem uygulama geliştirici hem de son kullanıcı olarak faydalanabiliyoruz.

Ayrıca Windows Phone 8, öncüllerinden farklı olarak .Net Compact Framework yerine CoreCLR motoru içeriyor.

CoreCLR .Net Framework 4.5 CLR ile (hemen hemen) aynı özellikleri ve optimizasyonları içerir, .Net Compact Framework‘ten çok daha verimli ve daha hızlıdır.

Özellikle Garbage Collector performansı hissedilebilir şekilde arttırılmıştır. Oyunlar gibi saniyedeki işlem adedi yüksek olan uygulamalarda Garbage Collector‘daki performans artışı uygulamanın toplam performansına büyük etki eder.

Async Framework

.Net Framework 4.5‘teki en önemli yeni gelişme C# 5 ve VB.Net 11 tarafından tanıtılan yeni asenkron programlama modelidir.

CoreCLR ve .Net Framework kütüphanelerinde yapılan güncellemeler ile birlikte Windows Phone 8 asenkron programlama modelinin tüm nimetlerinden faydalanabiliyor.

Windows Phone 8 cihazların çok çekirdekli işlemciye sahip olması, async, await anahtar kelimelerinin ve Task Parallel Library kullanımının uygulamaların başlangıç ve kullanım hızlarının artmasına katkısı büyük.

Asenkron kütüphanelerin (hemen hemen) tamamı .Net Framework içerisine gömülmüş durumda. Fakat bazı kütüphanelere async desteğinin (özellikle System.Net namespace’i altındakiler) NuGet aracılığı ile indirilmesi gerekiyor.

Microsoft.Bcl.Async paketini NuGet üzerinden indirebilirsiniz. Daha ayrıntılı bilgi için MSDN’deki BCL Blog makalesini okumanızı tavsiye ederim.

Cloud Derleyici ile çok daha hızlı kod

Windows Phone 8‘de yüksek performans ve pil ömründen tasarruf için çok daha uygun olan yeni bir kod oluşturma yaklaşımı benimsenmiş.

Uygulamaları son kullanıcı cihazlara indirilmeden önce Windows Phone Store tarafından yüksek kalitede ARM koduna derleniyorlar.

Bu sayede Windows Phone 7.X cihazlar için uygulamanın her çalıştırılması esnasında yapılan derleme işlemi, Windows Phone 8 cihazlar için gerçekleştirilmiyor.

CPU yükünü artıran ve pil tüketimine olumsuz etkisi bulunan bu işlemin aradan çıkartılmış olması Windows Phone 8 cihazlarda uygulamaların daha hızlı başlatılmasını ve pil tüketimlerinin azalmasını sağlamış.

Microsoft pre-compile (ön-derleme) sürecini son kullanıcı cihazdan alarak Washington Columbia nehri üzerine kurdukları bir jeneratör aracılığı ile beslenen bir sisteme devretmiş durumda.

Not : Cep telefonu pili yerine enerjinin bir nehirden sağlanması iyi düşünülmüş.

Engin Polat hakkında

Chief Architect, Microsoft RD, Microsoft MVP

Ada ve Ege'nin babası ;)

Kategoriler

İstatistik

Makale Adedi: 458

Creative Commons Lisansı