Montag, 27. Januar 2014

Android: Displaygröße herausfinden

Mit folgenden Codezeilen können Breite und Höhe des Handy Bildschirms unter Android abgefragt werden:
int ScreenWidth = Resources.DisplayMetrics.WidthPixels;
int ScreenHeight = Resources.DisplayMetrics.HeightPixels;

Dienstag, 21. Januar 2014

Thread Synchronisation mit AutoResetEvent

Hat man im Programm mehrere Threads laufen, ist oft wahrscheinlich eine Synchronisierung nötig, heißt: Ein Thread soll erst dann weiterlaufen, wenn ein bestimmtes Ereignis o.ä. eingetreten ist.
Um dieses Warten zu erledigen, könnte man sich einerseits selbst eine Endlosschleife bauen und so auf den Eintritt warten.
Eine einfachere und zugleich effizientere Möglichkeit bietet die Klasse AutoResetEvent. Diese realisiert genau das, sie stellt Funktionen bereit, mit denen ein Thread auf ein Ereignis warten kann. Beim Warten wird der Thread blockiert und schließlich wieder aufgeweckt, wenn das Ereignis eingetreten ist.
Eine Instanz der Klasse AutoResetEvent speichert den aktuellen Zustand des Ereignisses intern, im Konstruktor kann dieser initialisiert werden (false = wartend, true = eingetreten).
Über die Funktion WaitOne() wartet der aktuelle Thread, bis das Ereignis eintritt. Dieses kann mittels Set() signalisiert werden. Reset() löscht das Ereignis dann wieder.
Im folgenden Beispiel startet das Hauptprogramm einen neuen Thread. Dieser wartet in Dauerschleife auf das Eintreten von Event1, welches durch einen Klick auf den Button ausgelöst wird. Bei Eintritt wird dann eine Meldung angezeigt:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Threading;

namespace ThreadSynchronization
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private AutoResetEvent Event1 = new AutoResetEvent(false);

        private void Form1_Load(object sender, EventArgs e)
        {
            Thread Thread1 = new Thread(Looper);
            Thread1.Start();
        }

        private void Looper()
        {
            while (true)
            {
                Event1.WaitOne();
                MessageBox.Show("Set");
                Event1.Reset();
            }
        }

        private void button1_Click(object sender, EventArgs e)
        {
            Event1.Set();
        }
    }
}

Mittwoch, 15. Januar 2014

Android: Deployment failed. FastDev directory creation failed

Sporadisch tritt bei mir beim Starten der Anwendung über das Xamarin Studio obiger Fehler auf, anstatt die Anwendung auf das Handy zu laden und zu starten erscheint die Meldung: "Deployment failed. FastDev directory creation failed".
Dieses Problem lässt sich glücklicherweise leicht lösen: Unter Projektoptionen (Rechtsklick auf das Projekt in der linken Leiste, Optionen) deaktiviert man dazu unter Erstellen - Android Build "Fast assembly deployment".

Mittwoch, 8. Januar 2014

Android: Programmdaten dauerhaft speichern (im externen Speicher)

Werden die Anwendungen komplexer, möchte man sicherlich bestimmte Daten auch dauerhaft im Handy speichern um z.B. beim nächsten Programmstart auf diese zugreifen zu können. Hierfür bietet Android im wesentlichen 2 Speicherbereiche, den internen und den externen Speicher an.
Im internen Speicher werden die Daten so gespeichert, dass nur die Anwendung darauf zugreifen kann, beim Deinstallieren werden diese automatisch gelöscht.
Der externe Speicher ist dagegen ein Speicher, auf den jeder zugreifen kann, also auch der Nutzer vom PC aus zum Beispiel.
Die Bezeichnung interner und externer Speicher kommt aus den Anfangszeiten von Android, wo Mobiltelefone noch einen kleinen internen Speicher hatten und ggf. einen externen in Form zum Beispiel einer SD – Karte. Heutzutage jedoch sind beide Speicherarten meist im „wirklichen“ internen Speicher des Smartphones untergebracht, die Unterscheidung ist also nur noch in Bezug auf den Zugriff.
Trotzdem sollte immer geprüft werden, ob der externe Speicher vorhanden („gemounted“) ist.
Da ich ein paar Probleme mit dem internen Speicher hatte und meine Daten gerne auch per Hand editieren können möchte, nutzte ich meistens den externen Speicher, über wessen Verwendung ich hier posten möchte.
Damit die App den externen Speicher nutzen kann, muss zuerst die Permission WriteExternalStorage in der AndroidManifest.xml gesetzt werden.
Den Pfad zum externen Speicher erhalten wir über Android.OS.Environment.ExternalStorageDirectory.Path.
Dann können wir wie von Windows bekannt auf diesen zugreifen, Dateien schreiben lesen etc.
Im folgenden kleinen Beispiel wird über die Eigenschaft ExternalStorageState zuerst geprüft, ob der externe Speicher vorhanden ist. Dann erstelle ich die Datei "TestFile.txt“ im Ordner „ExternalStorageTest“ mittels eines StreamWriters und schreibe eine Zeile in diese. Wie unter Windows auch müssen alle vorkommenden Ordner vorhanden sein, deswegen prüfen wir dies mit einem Directory Objekt und legen den Ordner ggf. an.
Da diese Sachen von der Windows Programmierung her bekannt sein sollten, hier einfach der komplette Code:
using System;
using Android.App;
using Android.Content;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Android.OS;

using System.IO;

namespace ExternalStorageExample
{
     [Activity (Label = "ExternalStorageExample", MainLauncher = true)]
     public class MainActivity : Activity
     {
          protected override void OnCreate (Bundle bundle)
          {
               base.OnCreate (bundle);

               // Set our view from the "main" layout resource
               SetContentView (Resource.Layout.Main);

               if (Android.OS.Environment.ExternalStorageState == "mounted") {
                    string Path = Android.OS.Environment.ExternalStorageDirectory.Path + "/ExternalStorageTest/";

                    if (!Directory.Exists (Path))
                         Directory.CreateDirectory (Path);

                    StreamWriter sw = new StreamWriter (new FileStream (Path + "TestFile.txt", FileMode.Create));
                    sw.WriteLine ("Test");
                    sw.Close ();
               }
          }
     }
}


Donnerstag, 2. Januar 2014

Android: Toasts

Android bietet die Möglichkeit sogenannte Toasts anzuzeigen - Nachrichten, die kurz auf dem Bildschirm erscheinen und dann von alleine wieder verschwinden, was so aussieht:


Wir erstellen einen Toast mit der Klasse Toast und übergeben der Erzeugungsmethode die aktuelle Activity, den anzuzeigenden String sowie die Dauer des Toasts, wobei wir hierfür die Aufzählung ToastLength verwenden müssen, welche Short und Long beinhaltet.
Über die Funktion SetGravity() können wir die Ausrichtung des Toasts sowie den Offset einstellen.
Mittels Show() zeigen wir ihn schließlich an:

Toast toast = Toast.MakeText(this, "Toast", ToastLength.);
toast.SetGravity(GravityFlags.Top|GravityFlags.Left, 100, 260);
toast.Show();