2015-05-19 68 views
8

我想讓我的第一個Android地理位置和本地通知系統應用程序。 我想像這樣...有基本的活動MainActivity。啓動後,它啓動服務TestService,如果座標發生變化,則將其發送到服務器上,並在回覆中收到一些將顯示爲本地通知的消息。 我有一些問題。地理位置,服務和本地通知

  1. 如果我關閉應用程序(使用任務管理器),那麼服務將停止,所以座標改變後沒有任何反應。 我需要做什麼服務一直工作?或者這是不可能的?

  2. 激活本地通知後,它啓動NotifyActivity顯示詳細信息。在那裏我點擊buttonDelete - 它將關閉NotifyActivity並開始MainActivity。但如果在此之後我切換到操作系統屏幕(使用Back按鈕)並返回(使用任務管理器),則將再次顯示'MainActivity'而不顯示'NotifyActivity'。 爲什麼會出現以及如何避免它?

MainActivity

[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"; 
     }; 
    } 
} 

地理定位服務

[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()); 
    } 

} 

本地通知

[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(); 
     }; 
    } 
} 

示例項目here

回答

1

在MainActivity中添加此代碼。這種方法將解決你的第二個問題(巴士仍然不知道如何解決最近應用程序列表中的應用程序標題問題)。

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

Android中的蜜蜂活動有很多缺陷。因此我的建議是從服務啓動MainActivity,然後啓動NotifyAcitivity。然後,您可以再次啓動MainActivity(在這種情況下,您需要爲MainActivity設置LaunchMode = LaunchMode.SingleTop)。

對於第一個問題 - 您是否嘗試過定義[Service (Process = ":remote")]而不是[Service]

1

我沒有Xamarin的經驗,但我可以嘗試回答與Android相關的問題。

問題1

當您通過任務管理器關閉應用程序,你是不是簡單地關閉應用程序做更多的 - 你是殺人的整個過程。儘管您無法控制用戶的行爲,但通常情況下,這不是Android用戶應該停止應用的方式。關閉應用程序的「正確」方式是簡單地退出,不會破壞進程,並使您的服務在後臺運行。

所以要回答你的問題,我不認爲你可以做任何事情來解決這種情況,用戶強行殺死你的應用程序的過程。不過,我認爲您不必擔心這種邊緣情況,因爲在正常情況下,您的應用程序的進程不會在系統認爲可用或絕對需要時纔會被終止。所以如果應用程序以正常方式關閉,服務應該繼續運行。該文件說:

系統將保留該服務,只要它要麼是 啓動或有一個或多個連接到它與 Context.BIND_AUTO_CREATE標誌運行。一旦這兩種情況都不成立, 就會調用該服務的onDestroy()方法,並且服務有效終止服務 。

所以你的服務會好的。通常,您的應用程序不會處理其進程被強行殺死的情況。

More information about Processes

More information about the Service lifecycle

問題2

我不完全知道什麼是怎麼回事。然而,看着你的鏈接項目,我注意到你的AndroidManifest.xml文件幾乎沒有填寫。我懷疑沒有這個文件,android系統不知道如何初始化你的backstack,它不知道你的哪些活動是MAIN和LAUNCHER活動。

你應該AndroidManifest.xml聲明你的活動,並在它應該指定MainActivity是你的主要和啓動活動,而且它是NotifyActivity父。這樣,當應用程序啓動時,系統將知道打開MainActivity,並且當您從NotifyActivity中點擊「返回」時,它將知道返回到它。事情是這樣的:

<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

希望幫助您解決問題!

+1

我認爲你在這兩個賬戶上都有些不對。首先,我不認爲OP正在討論強制關閉流程,我認爲他們指的是從最近的應用程序列表中輕掃應用程序,應該只關閉並刪除該任務堆棧,而不是停止整個過程。其次,在Xamarin中,活動是使用活動類本身的屬性聲明的。然後它們會在編譯時自動放入清單中。 – irreal