Xamarin.Android开发实践(八)

简介: 原文:Xamarin.Android开发实践(八) Xamarin.Android其他类型的服务 一、前言 前面我们已经学了关于服务的很多知识,但是对于真实的开发那些远远不够,通过这节我们将学习其他类型的服务,比如前台服务、IntentService和消息服务。

原文:Xamarin.Android开发实践(八)

Xamarin.Android其他类型的服务

一、前言

前面我们已经学了关于服务的很多知识,但是对于真实的开发那些远远不够,通过这节我们将学习其他类型的服务,比如前台服务、IntentService和消息服务。下面我们开始进入正题。

 

二、前台服务

顾名思义,就是拥有前台的优先等级。当然服务还是不可见的。因为前面我们介绍过 Android系统会在低内存的情况下将一些长时间不用的应用关闭,如果还是不够,那么就会通过关闭服务服务来达到目的,然而对于某些应用而言,这样将会 影响用户的正常使用。比如听音乐,我们基本上都会打开应用选择歌曲后将应用置为后台。但是你会发现通知栏中会存在这个通知并且无法移除,只有正确的退出这 个应用了才会消失,而这节我们就要实现这个功能。

 

首先我们必须要用一个通知,通过这个通知我们的服务才能够变成前台服务,这里我们新建一个名为ForegroundService的服务,然后重写OnStartCommand方法。

1         public override StartCommandResult OnStartCommand(Intent intent, StartCommandFlags flags, int startId)
2  { 3 var notify = new Notification(Resource.Drawable.Icon, "前台服务"); 4 var activityIntent = new Intent(this, typeof(MainActivity)); 5 var activityPintent = PendingIntent.GetActivity(this, 0, activityIntent, PendingIntentFlags.UpdateCurrent); 6 notify.SetLatestEventInfo(this, "标题", "内容", activityPintent); 7 StartForeground((int)NotificationFlags.ForegroundService, notify); 8 return StartCommandResult.Sticky; 9 }

很多代码都是我们在讨论通知的时候都已经掌握的了,既然是前台服务,自然最后发送这个方法是不同的,我们需要使用服务的StartForeground来发送这个通知,同时第一个参数也要设置为前台服务,这样我们就可以看到如图的结果了(需要在MainActivity的OnCreate方法中开启该服务)。

虽然已经是一个前台服务了,但是我们只能通过服务不断的更新这个通知,而无法接收用户的事件,下面我们还要实现一个自定义界面的通知,上面有一个Text和两个Button用户点击不同的按钮后将由服务去更新通知,从而改变Text中的值。

首先我们在Resources/layout/下新建一个NotificationLayout视图,并在其中写入如下的xml标记。


 1 <?xml version="1.0" encoding="utf-8"?>
 2 <RelativeLayout xmlns:p1="http://schemas.android.com/apk/res/android"  3  p1:minWidth="25px"  4  p1:minHeight="25px"  5  p1:layout_width="match_parent"  6  p1:layout_height="match_parent"  7  p1:id="@+id/relativeLayout1">  8 <TextView  9 p1:text="0" 10  p1:textAppearance="?android:attr/textAppearanceLarge" 11  p1:layout_width="wrap_content" 12  p1:layout_height="match_parent" 13  p1:id="@+id/textView1" /> 14 <Button 15 p1:text="显示1" 16  p1:layout_width="wrap_content" 17  p1:layout_height="match_parent" 18  p1:layout_toRightOf="@id/textView1" 19  p1:id="@+id/button1" /> 20 <Button 21 p1:text="显示2" 22  p1:layout_width="wrap_content" 23  p1:layout_height="match_parent" 24  p1:layout_toRightOf="@id/button1" 25  p1:id="@+id/button2" /> 26 </RelativeLayout>

打开ForegroundService并在其中新建一个CreateNotify方法,并在其中写入如下代码。


 1         public Notification CreateNotify(string text)
 2  {  3 notify = new Notification(Resource.Drawable.Icon, "前台服务");  4 var sintent = new Intent(this, typeof(MainActivity));  5  sintent.SetFlags(ActivityFlags.LaunchedFromHistory);  6 notify.ContentView = new RemoteViews(PackageName, Resource.Layout.NotificationLayout);  7 notify.ContentIntent = PendingIntent.GetActivity(this, 0, sintent, PendingIntentFlags.NoCreate);  8  9 var btn1Intent = new Intent(this, typeof(ForegroundService)); 10 btn1Intent.PutExtra("showBtn1", true); 11 var btn1Pintent = PendingIntent.GetService(this, 0, btn1Intent, PendingIntentFlags.UpdateCurrent); 12  notify.ContentView.SetOnClickPendingIntent(Resource.Id.button1, btn1Pintent); 13 14 var btn2Intent = new Intent(this, typeof(ForegroundService)); 15 btn2Intent.PutExtra("showBtn2", true); 16 var btn2Pintent = PendingIntent.GetService(this, 1, btn2Intent, PendingIntentFlags.UpdateCurrent); 17  notify.ContentView.SetOnClickPendingIntent(Resource.Id.button2, btn2Pintent); 18 19  notify.ContentView.SetTextViewText(Resource.Id.textView1, text); 20 return notify; 21 }

这里需要说明下,一旦通知发送出去了我们是无法同ContentViewSet去修改控件的,只能重新发送这个同时去更新旧的通知,所以笔者才需要一个单独的方法负责创建通知。上面的代码我们之前都已经学习过了,不理解的可以看这篇文件《Xamarin.Android通知详解》。笔者设置按钮的点击事件是打开服务本身,同时还通过Intent传递了一个参数,因为后面我们需要通过这些参数去区分哪个按钮按下了,同时还要注意PendingIntentGetService方法的第二个参数,我们两者都是0那么会造成按下按钮1和按纽2都传递同样的参数。下面我们在OnStartCommand中实现响应。


 1         public override StartCommandResult OnStartCommand(Intent intent, StartCommandFlags flags, int startId)
 2  {  3 if (notify == null)  4  {  5 notify = CreateNotify("初始化");  6 StartForeground((int)NotificationFlags.ForegroundService, notify);  7  }  8 bool isBtn1Click = intent.GetBooleanExtra("showBtn1", false);  9 bool isBtn2Click = intent.GetBooleanExtra("showBtn2", false); 10 if (isBtn1Click) 11  { 12 if (notify != null) 13  { 14 notify = CreateNotify("来自按钮1"); 15 StartForeground((int)NotificationFlags.ForegroundService, notify); 16  } 17  } 18 else if (isBtn2Click) 19  { 20 if (notify != null) 21  { 22 notify = CreateNotify("来自按钮2"); 23 StartForeground((int)NotificationFlags.ForegroundService, notify); 24  } 25  } 26 return StartCommandResult.Sticky; 27 }

可以看到我们通过GetBooleanExtra获取了通过意图传递的参数,当然笔者这里的用法不同于前面的方式,我还传入了第二个参数,这样做的目的就是在意图中不存在该值的时候将会把第二参数返回,下面就是进行不同的判断从而更新通知。

最终运行结果如下所示:

按下“显示1”后

按下“显示2”后

至此我们就完成了前台服务的学习。

 

三、IntentService

很多时候我们都需要利用服务进行耗时的操作,势必需要创建新的线程去处理。但是普通的Service并不会主动创建而需要开发者自行在OnStartCommand中去创建,为此就繁衍出了IntentService类,它会为我们创建好线程去执行我们的代码,从而避免一些代码。但是我们不能重写OnStartCommand方法而应该是OnHandleIntent方法。比如下面的代码。

1     [Service]
2     public class MainIntentService : IntentService 3  { 4 protected override void OnHandleIntent(Android.Content.Intent intent) 5  { 6 Thread.Sleep(1000); 7 Toast.MakeText(this, "来自新线程" , ToastLength.Long).Show(); 8  } 9 }

通过下面的截图我们可以看到OnHandleIntent中执行的代码是新建的一个线程

关于IntentService的使用非常简单。

 

四、通信服务

上一节关于绑定服务的学习中,活动必须确切的知道服务的类型才能使用,这样就加大了他们之间的耦合度,而通过本节我们将会学习如何通过消息机制将他们解耦,首先我们需要理解Handler类,它将会负责处理发送过来的消息,我们需要继承该类,并重写HandleMessage方法,我们新建一个MainHandler类并继承该类,然后重写。

1     public class MainHandler : Handler
2  { 3 public override void HandleMessage(Message msg) 4  { 5 Toast.MakeText(Application.Context, "接收到的消息的what为" + msg.What.ToString() + " 内容为" + msg.Data.GetString("_str"), ToastLength.Short).Show(); 6  } 7 }

这里我们仅仅只是简单的输出了消息的类型以及消息传递的参数,下面我们还需要一个服务将这个消息传递给活动。

 1     [Service]
 2     public class MessengerService : Service  3  {  4  Messenger messenger;  5  6 public MessengerService()  7  {  8 messenger = new Messenger(new MainHandler());  9  } 10 11 public override Android.OS.IBinder OnBind(Android.Content.Intent intent) 12  { 13 return messenger.Binder; 14  } 15 }

这里我们还需要Messenger去封装MainHandler,因为MainHandler是无法在OnBind中直接返回的,只有Messenger的Binder属性可以,自然活动那边就需要接收这个接口,下面是IserviceConnection的实现。

 1     public class MessengerServiceConnection : Java.Lang.Object , IServiceConnection
 2  {  3  MainActivity mainActivity;  4  5 public MessengerServiceConnection(MainActivity ma)  6  {  7 mainActivity = ma;  8  }  9 10 public void OnServiceConnected(ComponentName name, Android.OS.IBinder service) 11  { 12 mainActivity.messenger = new Messenger(service); 13  } 14 15 public void OnServiceDisconnected(ComponentName name) 16  { 17  mainActivity.messenger.Dispose(); 18 mainActivity.messenger = null; 19  } 20 }

这里的方式依然是使用之前我们讲述绑定服务时候的方法,只是在我们接收接口的时候是用Messenger的去封装的,这样就统一了。我们的活动只要有Messenger,并且对应的服务都满足这个接口那么我们的活动就可以灵活的绑定任意服务,使用他们的功能了,最后是MainActivity的代码(需要在Main.axml中拖拽两个按钮,以便发送消息给服务)。

 1     [Activity(Label = "OtherService", MainLauncher = true, Icon = "@drawable/icon")]  2 public class MainActivity : Activity  3  {  4 public Messenger messenger;  5  6 protected override void OnCreate(Bundle bundle)  7  {  8 base.OnCreate(bundle);  9  SetContentView(Resource.Layout.Main); 10 BindService(new Intent(this, typeof(MessengerService)), new MessengerServiceConnection(this), Bind.AutoCreate); 11 Button btn1 = FindViewById<Button>(Resource.Id.button1); 12 btn1.Click += (e, s) => 13  { 14 Message msg = Message.Obtain(); 15 Bundle b = new Bundle(); 16 b.PutString("_str", "消息1"); 17 msg.Data = b; 18 msg.What = 1; 19  messenger.Send(msg); 20  }; 21 22 Button btn2 = FindViewById<Button>(Resource.Id.button2); 23 btn2.Click += (e, s) => 24  { 25 Message msg = Message.Obtain(); 26 Bundle b = new Bundle(); 27 b.PutString("_str", "消息2"); 28 msg.Data = b; 29 msg.What = 2; 30  messenger.Send(msg); 31  }; 32  } 33 }

唯一要说的就是发送消息,我们需要实例化Messager(不是Messenger),设置它的what,如果我们还需要传递更多的参数我们可以实例化一个Bundle,然后通过其PutXXX方法赋值,最后赋给MessageData类型,最后要通过Messenger实例的Send方法发送这个消息,那么MainHandler就可以处理这个消息了。

 

下面是实际的运行图。

点击“发送消息1”按钮后

点击“发送消息2”按钮后

 

目录
相关文章
|
21天前
|
Java Android开发
Android 开发获取通知栏权限时会出现两个应用图标
Android 开发获取通知栏权限时会出现两个应用图标
12 0
|
26天前
|
调度 数据库 Android开发
构建高效Android应用:Kotlin协程的实践与优化
在Android开发领域,Kotlin以其简洁的语法和平台友好性成为了开发的首选语言。其中,Kotlin协程作为处理异步任务的强大工具,它通过提供轻量级的线程管理机制,使得开发者能够在不阻塞主线程的情况下执行后台任务,从而提升应用性能和用户体验。本文将深入探讨Kotlin协程的核心概念,并通过实例演示如何在实际的Android应用中有效地使用协程进行网络请求、数据库操作以及UI的流畅更新。同时,我们还将讨论协程的调试技巧和常见问题的解决方法,以帮助开发者避免常见的陷阱,构建更加健壮和高效的Android应用。
35 4
|
28天前
|
移动开发 Java Android开发
构建高效Android应用:Kotlin协程的实践之路
【2月更文挑战第31天】 在移动开发领域,性能优化和流畅的用户体验一直是开发者追求的目标。随着Kotlin语言的流行,其异步编程解决方案——协程(Coroutines),为Android应用带来了革命性的并发处理能力。本文将深入探讨Kotlin协程的核心概念、设计原理以及在Android应用中的实际应用案例,旨在帮助开发者掌握这一强大的工具,从而提升应用的性能和响应能力。
|
29天前
|
移动开发 调度 Android开发
构建高效Android应用:探究Kotlin协程的优势与实践
【2月更文挑战第30天】 在移动开发领域,尤其是针对Android平台,性能优化和应用流畅度始终是开发者关注的重点。近年来,Kotlin语言凭借其简洁性和功能性成为Android开发的热门选择。其中,Kotlin协程作为一种轻量级的线程管理解决方案,为异步编程提供了强大支持,使得编写非阻塞性代码变得更加容易。本文将深入分析Kotlin协程的核心优势,并通过实际案例展示如何有效利用协程提升Android应用的性能和响应速度。
|
1月前
|
XML 缓存 Android开发
Android开发,使用kotlin学习多媒体功能(详细)
Android开发,使用kotlin学习多媒体功能(详细)
96 0
|
1月前
|
数据库 Android开发 开发者
构建高性能微服务架构:从理论到实践构建高效Android应用:探究Kotlin协程的优势
【2月更文挑战第16天】 在当今快速迭代和竞争激烈的软件市场中,微服务架构以其灵活性、可扩展性和独立部署能力而受到企业的青睐。本文将深入探讨如何构建一个高性能的微服务系统,涵盖从理论基础到具体实现的各个方面。我们将重点讨论服务拆分策略、通信机制、数据一致性以及性能优化等关键主题,为读者提供一个清晰、实用的指南,以便在复杂多变的业务环境中构建和维护健壮的微服务体系结构。 【2月更文挑战第16天】 在移动开发领域,性能优化和流畅的用户体验是至关重要的。随着技术的不断进步,Kotlin作为一种现代编程语言,在Android开发中被广泛采用,尤其是其协程特性为异步编程带来了革命性的改进。本文旨在深入
239 5
|
1月前
|
设计模式 人工智能 开发工具
安卓应用开发:构建未来移动体验
【2月更文挑战第17天】 随着智能手机的普及和移动互联网技术的不断进步,安卓应用开发已成为一个热门领域。本文将深入探讨安卓平台的应用开发流程、关键技术以及未来发展趋势。通过分析安卓系统的架构、开发工具和框架,本文旨在为开发者提供全面的技术指导,帮助他们构建高效、创新的移动应用,以满足不断变化的市场需求。
18 1
|
18天前
|
Java Android开发 开发者
构建高效Android应用:Kotlin协程的实践与优化
在响应式编程范式日益盛行的今天,Kotlin协程作为一种轻量级的线程管理解决方案,为Android开发带来了性能和效率的双重提升。本文旨在探讨Kotlin协程的核心概念、实践方法及其在Android应用中的优化策略,帮助开发者构建更加流畅和高效的应用程序。通过深入分析协程的原理与应用场景,结合实际案例,本文将指导读者如何优雅地解决异步任务处理,避免阻塞UI线程,从而优化用户体验。
|
12天前
|
移动开发 API Android开发
构建高效Android应用:探究Kotlin协程的优势与实践
【4月更文挑战第7天】 在移动开发领域,性能优化和应用响应性的提升一直是开发者追求的目标。近年来,Kotlin语言因其简洁性和功能性在Android社区中受到青睐,特别是其对协程(Coroutines)的支持,为编写异步代码和处理并发任务提供了一种更加优雅的解决方案。本文将探讨Kotlin协程在Android开发中的应用,揭示其在提高应用性能和简化代码结构方面的潜在优势,并展示如何在实际项目中实现和优化协程。
|
12天前
|
XML 开发工具 Android开发
构建高效的安卓应用:使用Jetpack Compose优化UI开发
【4月更文挑战第7天】 随着Android开发不断进化,开发者面临着提高应用性能与简化UI构建流程的双重挑战。本文将探讨如何使用Jetpack Compose这一现代UI工具包来优化安卓应用的开发流程,并提升用户界面的流畅性与一致性。通过介绍Jetpack Compose的核心概念、与传统方法的区别以及实际集成步骤,我们旨在提供一种高效且可靠的解决方案,以帮助开发者构建响应迅速且用户体验优良的安卓应用。