2015-05-19 14 views
8

Próbuję wykonać pierwszą aplikację systemową dla systemu Android dotyczącą geolokalizacji i powiadomień lokalnych. Wyobrażam sobie, że to jest ... Jest podstawowa aktywność MainActivity. Po uruchomieniu uruchamia usługę TestService, która w przypadku zmiany współrzędnych przesyła je na serwer, a w odpowiedzi otrzymuje komunikat, który będzie wyświetlany jako powiadomienie lokalne. Mam pewne problemy.Powiadomienia z zakresu geolokacji, usług i lokalnych

  1. Jeśli zamknę aplikację (używając menedżera zadań), usługa zostanie zatrzymana, więc po zmianie współrzędnych nic się nie dzieje. Czego potrzebuję, aby ta usługa działała przez cały czas? Czy to niemożliwe?

  2. Po aktywacji lokalnego powiadomienia uruchamia się NotifyActivity, która pokazuje szczegółowe informacje. Tam kliknij buttonDelete - to zamknie się NotifyActivity i rozpocznie MainActivity. Ale jeśli później przełączyłem się na ekran systemu operacyjnego (za pomocą przycisku Back) iz powrotem (za pomocą menedżera zadań), zamiast "MainActivity" ponownie wyświetli się "NotifyActivity". Dlaczego występuje i jak tego uniknąć?

główną działalność

[Activity(Label = "LocationTest", MainLauncher = true, Icon = "@drawable/icon")] 
public class MainActivity : Activity 
{ 
    protected override void OnCreate(Bundle bundle) 
    { 
     base.OnCreate(bundle); 
     SetContentView(Resource.Layout.Main); 

     var button = FindViewById<Button>(Resource.Id.myButton); 
     button.Click += delegate { 
      StartService(new Intent(this, typeof(TestService))); 
      button.Text = "Started"; 
     }; 
    } 
} 

usług geolokalizacji

[Service] 
public class TestService : Service, ILocationListener 
{ 
    // Start service 
    public override StartCommandResult OnStartCommand(Intent intent, StartCommandFlags flags, int startId) 
    { 
     locManager = (LocationManager)GetSystemService(LocationService); 
     locationCriteria = new Criteria(); 

     locationCriteria.Accuracy = Accuracy.Coarse; 
     locationCriteria.PowerRequirement = Power.Low; 

     string locationProvider = locManager.GetBestProvider(locationCriteria, true); 

     // Preferences.MinTime, for example, 60 (seconds) 
     // Preferences.MinDist, for example, 100 (meters) 
     locManager.RequestLocationUpdates(locationProvider, Preferences.MinTime * 1000, Preferences.MinDist, this); 

     return StartCommandResult.Sticky; 
    } 

    public void OnLocationChanged(Location loc) 
    { 
     // Send coordinates to the server, receive a response, and show local notification 
     var msg = new ReceivedMessage(counter++, "Test Title", loc.ToString()); 
     ShowNotification(msg); 
    } 

    // show local notification 
    void ShowNotification(ReceivedMessage msg) 
    { 
     var myContainer = new Bundle(); 
     myContainer.PutLong("msg_id", Convert.ToInt64(msg.Id)); 
     myContainer.PutStringArray("msg_data", new [] { msg.Title, msg.Text }); 
     var resultIntent = new Intent(this, typeof(NotifyActivity)); 
     resultIntent.PutExtras(myContainer); 

     TaskStackBuilder stackBuilder = TaskStackBuilder.Create(this); 
     stackBuilder.AddParentStack(Java.Lang.Class.FromType(typeof(NotifyActivity))); 
     stackBuilder.AddNextIntent(resultIntent); 

     PendingIntent resultPendingIntent = stackBuilder.GetPendingIntent(Convert.ToInt32(msg.Id), PendingIntentFlags.UpdateCurrent); 

     Notification.Builder builder = new Notification.Builder(this) 
      .SetDefaults(NotificationDefaults.Sound | NotificationDefaults.Vibrate) 
      .SetAutoCancel(true) 
      .SetContentIntent(resultPendingIntent) 
      .SetContentTitle(msg.Title) 
      .SetContentText(msg.Text) 
      .SetSmallIcon(Resource.Drawable.Icon); 

     var nm = (NotificationManager)GetSystemService(NotificationService); 
     nm.Notify(Convert.ToInt32(msg.Id), builder.Build()); 
    } 

} 

lokalne powiadomienia

[Activity(Label = "NotifyActivity")]    
public class NotifyActivity : Activity 
{ 
    protected override void OnCreate(Bundle savedInstanceState) 
    { 
     base.OnCreate(savedInstanceState); 

     SetContentView(Resource.Layout.NotifyActivity); 

     var msg_id = Intent.Extras.GetLong("msg_id"); 
     var msg_data = Intent.Extras.GetStringArray("msg_data"); 

     FindViewById<TextView>(Resource.Id.textTitle).Text = msg_data[0]; 
     FindViewById<TextView>(Resource.Id.textDescription).Text = msg_data[1]; 

     FindViewById<Button>(Resource.Id.buttonDelete).Click += delegate { 
      StartActivity(typeof(MainActivity)); 
      Finish(); 
     }; 
    } 
} 

Przykład projekt here

Odpowiedz

1

W MainActivity dodaj ten kod. Ta metoda rozwiąże Twój drugi problem (autobus nadal nie wiem, jak rozwiązać problem z tytułem aplikacji na liście ostatnich aplikacji).

public override bool OnKeyDown (Keycode keyCode, KeyEvent e) 
{ 
    if (keyCode == Keycode.Back) { 
     MoveTaskToBack(true); 
     return true; 
    } 
    return base.OnKeyDown (keyCode, e); 
} 

Działania Beeinga w Androidzie mają wiele pułapek. Dlatego moją sugestią jest uruchomienie usługi MainActivity z usługi, a następnie uruchomienie funkcji NotifyAcitivity. Następnie możesz ponownie uruchomić MainActivity (w tym przypadku musisz ustawić LaunchMode = LaunchMode.SingleTop dla MainActivity).

Dla pierwszego problemu - czy próbowałeś zdefiniować [Service (Process = ":remote")] zamiast [Service]?

1

Nie mam doświadczenia z xamarinem, ale mogę spróbować odpowiedzieć na pytania, ponieważ dotyczą one głównie Androida.

Pytanie 1

Po zamknięciu aplikacji za pośrednictwem menedżera zadań, robisz więcej niż po prostu zamykając aplikację - zabijasz cały proces. Chociaż nie możesz kontrolować zachowania swoich użytkowników, generalnie nie jest to sposób, w jaki użytkownik Androida powinien zatrzymać aplikację. "Prawidłowym" sposobem zamknięcia aplikacji jest po prostu wycofanie się z niej, co nie niszczy procesu i sprawia, że ​​Twoja Usługa działa w tle.

Więc, aby odpowiedzieć na twoje pytanie, nie sądzę, że jest coś, co możesz zrobić, aby ominąć sytuację, w której użytkownik zdecydowanie zabija proces aplikacji. Nie sądzę jednak, abyś musiał się martwić o ten skrajny przypadek, ponieważ w normalnych okolicznościach proces Twojej aplikacji nie zostanie zabity, dopóki system uzna, że ​​jest w porządku lub absolutnie go potrzebuje. Tak więc usługa powinna nadal działać, jeśli aplikacja jest zamknięta w normalny sposób. Docs powiedzieć:

system będzie na bieżąco serwis działa tak długo, jak długo albo jest rozpoczęte lub istnieje jeden lub więcej połączeń do niego z flagą Context.BIND_AUTO_CREATE. Gdy żadna z tych sytuacji nie zostanie zatrzymana, wywoływana jest metoda onDestroy() usługi, a usługa jest skutecznie kończona.

Twoja usługa będzie w porządku.Zasadniczo nie oczekuje się, że Twoja aplikacja obsłuży przypadki, w których jej proces zostanie zdecydowanie zabity.

More information about Processes

More information about the Service lifecycle

Pytanie 2

nie jestem do końca pewien, co się tu dzieje. Jednak patrząc na Twój powiązany projekt, zauważam, że Twój plik AndroidManifest.xml jest ledwo wypełniony. Podejrzewam, że bez tego pliku system android nie wie, jak zainicjować twój backstack, i nie wie, które z twoich działań to aktywność MAIN and LAUNCHER.

Powinieneś zadeklarować swoje działania w AndroidManifest.xml, aw nim powinieneś określić, że MainActivity jest twoją aktywnością MAIN and LAUNCHER i że jest rodzicem NotifyActivity. W ten sposób system będzie wiedział, aby otworzyć MainActivity, gdy aplikacja jest uruchomiona, i będzie wiedział, aby wrócić do niej po uderzeniu "wstecz" z NotifyActivity. Coś takiego:

<application android:label="LocationTest" android:icon="@drawable/icon"> 
    <activity android:name="MainActivity"> 
     <intent-filter> 
      <action android:name="android.intent.action.MAIN" /> 
      <category android:name="android.intent.category.LAUNCHER" /> 
     </intent-filter> 
    </activity> 

    <activity android:name="NotifyActivity" 
     android:parentActivityName="MainActivity"/> 
</application> 

More information about how to use your Android Manifest

Mamy nadzieję, że pomoże Ci rozwiązać Twoje problemy!

+1

Sądzę, że jesteś trochę w błędzie na obu kontach. Po pierwsze, nie sądzę, że OP mówi o sile zamykającej proces, myślę, że odnoszą się one do przesuwania aplikacji z ostatniej listy aplikacji, która powinna tylko zamykać i usuwać ten stos zadań, a nie zatrzymywać całego procesu. Po drugie, w xamarin czynności są deklarowane przy użyciu atrybutów na samych klasach aktywności. Następnie są one później (podczas kompilacji) automatycznie umieszczane w manifeście. – irreal

Powiązane problemy