Przygotowane według tutoriala z:
http://frogermcs.blogspot.com/2010/09/usugi-dziaajace-w-tle-wstep-do-android.html
Usługi Androida są inne niż usługi Windows. Nie działają w osobnym wątku lub procesie,
a w głównym wątku aplikacji. Ale podobnie, jak usługi Windows nie mogą mieć interfejsu.
Usługa nie jest zamykana przez system (nawet jeżeli aktywność aplikacji zostanie usunięta),
chyba że nie ma innego sposobu na uruchomienie nowej aktywności. Jest przywracana, gdy są
już zasoby (pamięć) niezbędne do jej działania.
1. Tworzymy projekt aplikacji Android o nazwie Uslugi z szablonu Android App (Xamarin), Blank App
2. Interfejs aktywności (dwa przyciski, zegar tylko dla ozdoby):
3. W pliku MainActivity.java definiujemy zmienne dla przycisków i przygotowujemy ich
nasłuchiwacze.
using Android.App;
using Android.OS;
using Android.Support.V7.App;
using Android.Runtime;
using Android.Widget;
namespace Uslugi
{
[Activity(Label = "@string/app_name", Theme = "@style/AppTheme", MainLauncher = true)]
public class MainActivity : AppCompatActivity
{
private Button button1, button2;
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
// Set our view from the "main" layout resource
SetContentView(Resource.Layout.activity_main);
button1 = FindViewById(Resource.Id.button1);
button2 = FindViewById(Resource.Id.button2);
button1.Click += (object sender, System.EventArgs e) => { Toast.MakeText(ApplicationContext, "Uruchamiam usługę", ToastLength.Short).Show(); };
button2.Click += (object sender, System.EventArgs e) => { Toast.MakeText(ApplicationContext, "Zatrzymuję usługę", ToastLength.Short).Show(); };
}
}
}
4. Do projektu dodajemy klasę C#.
Nazwa: Usluga, klasa bazowa: Service (Android.App.Service),
Polecenie: Implement Abstract Class - dodana zostanie metoda OnBind, której nie będziemy używać
5. Wracamy do pliku MainActivity.cs i dodajemy polecenia uruchamiające i zatrzymujące
usługę (odpowiednio do metod obu przycisków).
a. Do pierwszego nasłuchiwacza:
button1.Click +=
(object sender, System.EventArgs e) =>
{
Toast.MakeText(ApplicationContext, "Uruchamiam usługę", ToastLength.Short).Show();
StartService(new Intent(this, typeof(Usluga)));
};
b. Do drugiego nasłuchiwacza:
button2.Click +=
(object sender, System.EventArgs e) =>
{
Toast.MakeText(ApplicationContext, "Zatrzymuję usługę", ToastLength.Short).Show();
StopService(new Intent(this, typeof(Usluga)));
};
Próba uruchomienia usługi, która jest już uruchomiona nie zaszkodzi.
6. Przechodzimy do pliku Usluga.cs.
Usługa posiada metody onCreate, onStart i onDestroy.
W pierwszej utworzymy timer, który będzie odpowiedzialny za wyświetlanie toastu informującego
o działaniu usługi.
Uwaga: wyświetlanie toastu w zadaniu timera wymaga utworzenia toastu poza timerem i tylko
jego aktualizację.
namespace Uslugi
{
[Service] //<--- !!!!!!!!!!!!!!!
class Usluga : Service
{
public override IBinder OnBind(Intent intent)
{
return null;
}
private Java.Util.Timer timer;
private static Toast toastDlaTimera;
class TickingTask : Java.Util.TimerTask
{
public override void Run()
{
//string czas = DateTime.Now.ToLongTimeString();
//toastDlaTimera.SetText("Usługa: " + czas);
//toastDlaTimera.Show();
//wątki (inne niż UI thread) nie mogą dotykać widoku (w tym toast)
//UWAGA! Ten problem będzie omawiany w następnej lekcji
//ToneGenerator toneG = new ToneGenerator(Stream.Alarm, 100);
//toneG.StartTone(Tone.CdmaAlertCallGuard, 200);
}
}
public override void OnCreate()
{
base.OnCreate();
toastDlaTimera = Toast.MakeText(ApplicationContext, "", ToastLength.Short);
timer = new Java.Util.Timer();
timer.ScheduleAtFixedRate( //do domu: zmienić na Timer z .NET
new TickingTask(), 1000, 2000); //co 2s po 1s
Toast.MakeText(ApplicationContext, "Usługa utworzona", ToastLength.Short).Show();
}
public override void OnDestroy()
{
timer.Cancel();
Toast.MakeText(ApplicationContext, "Usługa zatrzymana", ToastLength.Short).Show();
base.OnDestroy();
}
[return: GeneratedEnum]
public override StartCommandResult OnStartCommand(Intent intent, [GeneratedEnum] StartCommandFlags flags, int startId)
{
Toast.MakeText(ApplicationContext, "Usługa uruchomiona", ToastLength.Short).Show();
return base.OnStartCommand(intent, flags, startId);
}
}
}
7. Na koniec, aby uruchomienie usługi było możliwe, musimy do manifestu dodać deklarację usługi (w Java/Android jest to znacznik ).
W Xamarin wystarczy klasę usługi ozdobić atrybutem ServiceAttribute:
namespace Uslugi
{
[Service] //<--- !!!!!!!!!!!!!!!
class Usluga : Service
{
Usługa będzie wyświetlać komunikaty nawet po zamknięciu aplikacji (klawisze telefonu Home lub Wstecz).
8. Aby sprawdzić, czy usługa działa w tle, zdefiniujmy w klasie Usluga statyczną właśność:
[Service]
class Usluga : Service
{
public static bool CzyUtworzona { get; private set; } = false;
public override void OnCreate()
{
base.OnCreate();
...
CzyUtworzona = true;
Toast.MakeText(ApplicationContext, "Usługa utworzona", ToastLength.Short).Show();
}
public override void OnDestroy()
{
timer.Cancel();
CzyUtworzona = false;
Toast.MakeText(ApplicationContext, "Usługa zatrzymana", ToastLength.Short).Show();
base.OnDestroy();
}
Użyjmy tej metody w aktywności, aby informować użytkownika, czy kliknięcie przycisku zmieniło
stan usługi:
button1.Click +=
(object sender, System.EventArgs e) =>
{
if (!Usluga.CzyUtworzona)
{
Toast.MakeText(ApplicationContext, "Uruchamiam usługę", ToastLength.Short).Show();
StartService(new Intent(this, typeof(Usluga)));
}
else Toast.MakeText(ApplicationContext, "Usługa jest już uruchomiona", ToastLength.Short).Show();
};
button2.Click +=
(object sender, System.EventArgs e) =>
{
if (Usluga.CzyUtworzona)
{
Toast.MakeText(ApplicationContext, "Zatrzymuję usługę", ToastLength.Short).Show();
StopService(new Intent(this, typeof(Usluga)));
}
else Toast.MakeText(ApplicationContext, "Usługa nie jest uruchomiona", ToastLength.Short).Show();
};