.net开发安卓入门 - Service (服务)


Android Service 概述

移动应用不像桌面应用。 桌面具有大量资源,如屏幕空间、内存、存储空间和连接的电源,移动设备不会。 这些约束强制移动应用的行为方式不同。 例如,移动设备上的小屏幕通常意味着一次只显示一个应用 (,即活动) 可见。 其他活动将移动到后台,并推送到无法执行任何工作的挂起状态。 但是,仅仅因为 Android 应用程序处于后台并不意味着应用无法继续工作。

Android 应用程序至少由以下四个主要组件之一组成:活动、广播接收器、Intent和服务。 活动是许多出色的 Android 应用程序的基石,因为它们提供了允许用户与应用程序交互的 UI。 但是,当涉及到执行并发或后台工作时,活动并不总是最佳选择。

Android 中后台工作的主要机制是 服务。 Android 服务是一个组件,旨在在没有用户界面的情况下执行某些工作。

Service VS Thread (服务和线程之间进行选择)

根据桌面程序开发经验,很容易联想到多线程,因为看上去多线程也能够解决服务所面临的问题,那么在安卓中存在一定由他必然的原因,根据官方文档介绍,我理解成是安卓的一个设计漏洞导致衍生出来的Service这个东西。

官方解释如下(MSDN):
所有 Android 应用程序都有一个 主线程 (也称为 运行活动的 UI 线程) 。 若要使设备保持响应,Android 必须能够以每秒 60 帧的速度更新用户界面。 如果 Android 应用在主线程上执行过多工作,则 Android 会删除帧,这反过来又会导致 UI 显示为混蛋 (有时也称为 简) 。 这意味着,在两个帧之间的时间跨度中,UI 线程上执行的任何工作都应完成,大约 16 毫秒 (每 60 帧 1 秒)

为了解决此问题,开发人员可以使用活动中的线程来执行一些会阻止 UI 的工作。 但是,这可能会导致问题。 Android 可能会销毁并重新创建活动的多个实例。 但是,Android 不会自动销毁线程,这可能会导致内存泄漏。 其中的主要示例是 设备旋转 时 – Android 将尝试销毁活动的实例,然后重新创建一个新实例,这是潜在的内存泄漏 - 活动的第一个实例创建的线程仍将运行。

在这里插入图片描述

那我们看看Google Developer 怎么说的吧
Service 是一种可在后台执行长时间运行操作而不提供界面的应用组件。服务可由其他应用组件启动,而且即使用户切换到其他应用,服务仍将在后台继续运行。此外,组件可通过绑定到服务与之进行交互,甚至是执行进程间通信 (IPC)。例如,服务可在后台处理网络事务、播放音乐,执行文件 I/O 或与内容提供程序进行交互。

在服务和线程之间进行选择
简单地说,服务是一种即使用户未与应用交互也可在后台运行的组件,因此,只有在需要服务时才应创建服务,
如果您必须在主线程之外执行操作,但只在用户与您的应用交互时执行此操作,则应创建新线程。

前台服务

前台服务启动后,它必须通过调用 StartForeground 向 Android 注册自身。 如果服务以 Service.StartForegroundService 该方法启动,但不自行注册,则 Android 将停止该服务并将应用标记为非响应。

StartForeground 采用两个参数,这两个参数都是必需的:

  • 用于标识服务的应用程序中唯一的整数值。
  • 只要 Notification 服务正在运行,Android 就会在状态栏中显示的对象。

只要服务正在运行,Android 就会在状态栏中显示通知。 通知至少将为运行该服务的用户提供视觉提示。 理想情况下,通知应为用户提供应用程序的快捷方式,或者可能提供一些操作按钮来控制应用程序。 例如,这是一个音乐播放器 - 显示的通知可能具有暂停/播放音乐的按钮、回退到上一首歌曲或跳到下一首歌曲。

代码

using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Util;
using Android.Views;
using Android.Widget;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace 我的第一个安卓程序
{
    [Service(Exported = true, Name = "com.lhd.service.TestService")]
    public class TestService : Service
    {
        public override void OnCreate()
        {
            base.OnCreate();

            Log.Info("XXXXAAA", $"日志信息:当前时间{DateTime.Now}");
        }
        public override IBinder OnBind(Intent intent)
        {
            return null;
        }

        [return: GeneratedEnum]
        public override StartCommandResult OnStartCommand(Intent intent, [GeneratedEnum] StartCommandFlags flags, int startId)
        {
            Log.Info("XXXXAAA", $"StartCommandResult:当前时间{DateTime.Now}");
            //DispatchNotificationThatServiceIsRunning();
            //注册ForegroundService
            RegisterForegroundService();
            return StartCommandResult.NotSticky;
        }

        void DispatchNotificationThatServiceIsRunning()
        {
            Notification.Builder notificationBuilder = new Notification.Builder(this, "notice")
                .SetSmallIcon(Resource.Drawable.notice_small)
                .SetContentTitle(Resources.GetString(Resource.String.app_name))
                .SetContentText("TestService 服务!");

            var notificationManager = (NotificationManager)GetSystemService(NotificationService);
            notificationManager.Notify(1000, notificationBuilder.Build());
        }

      private  void RegisterForegroundService()
        {
            var notification = new Notification.Builder(this, "notice")
                .SetContentTitle(Resources.GetString(Resource.String.app_name))
                .SetContentText("卧槽!")
                .SetSmallIcon(Resource.Drawable.notice_small)
                .SetContentIntent(BuildIntentToShowMainActivity())
                .SetOngoing(true)
                .AddAction(BuildRestartTimerAction())
                .AddAction(BuildStopServiceAction())
                .Build();


            // Enlist this instance of the service as a foreground service
            StartForeground(1000, notification);
        }

        /// <summary>
		/// Builds a PendingIntent that will display the main activity of the app. This is used when the 
		/// user taps on the notification; it will take them to the main activity of the app.
		/// </summary>
		/// <returns>The content intent.</returns>
		PendingIntent BuildIntentToShowMainActivity()
        {
            var notificationIntent = new Intent(this, typeof(MainActivity));
            notificationIntent.SetAction("com.lhd.GoMainAction");
            notificationIntent.SetFlags(ActivityFlags.SingleTop | ActivityFlags.ClearTask);
            //notificationIntent.PutExtra(Constants.SERVICE_STARTED_KEY, true);

            var pendingIntent = PendingIntent.GetActivity(this, 0, notificationIntent, PendingIntentFlags.Immutable);
            return pendingIntent;
        }

        /// <summary>
        /// Builds a Notification.Action that will instruct the service to restart the timer.
        /// </summary>
        /// <returns>The restart timer action.</returns>
        Notification.Action BuildRestartTimerAction()
        {
            var restartTimerIntent = new Intent(this, GetType());
            //restartTimerIntent.SetAction(Constants.ACTION_RESTART_TIMER);
            var restartTimerPendingIntent = PendingIntent.GetService(this, 0, restartTimerIntent, PendingIntentFlags.Immutable);

            var builder = new Notification.Action.Builder(Resource.Drawable.ic_mtrl_chip_checked_black,
                                             "周而复始!",
                                              restartTimerPendingIntent);

            return builder.Build();
        }

        /// <summary>
        /// Builds the Notification.Action that will allow the user to stop the service via the
        /// notification in the status bar
        /// </summary>
        /// <returns>The stop service action.</returns>
        Notification.Action BuildStopServiceAction()
        {
            var stopServiceIntent = new Intent(this, GetType());
            //stopServiceIntent.SetAction(Constants.ACTION_STOP_SERVICE);
            var stopServicePendingIntent = PendingIntent.GetService(this, 0, stopServiceIntent, PendingIntentFlags.Immutable);

            var builder = new Notification.Action.Builder(Android.Resource.Drawable.IcMediaPause,
                                                         "事了拂衣去,深藏身与名",
                                                          stopServicePendingIntent);
            return builder.Build();

        }
    }
}

启动前台服务方法

[Java.Interop.Export]
        public void StartService(View view)
        {
            service = new Intent(this, typeof(TestService));
           
            StartForegroundService(service);
           
        }

运行效果

在这里插入图片描述

后台服务

代码

using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Util;
using Android.Views;
using Android.Widget;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace 我的第一个安卓程序
{
    [Service(Exported = true, Name = "com.lhd.service.ConsoleWriteDateTimeService")]
    public class ConsoleWriteDateTimeService : Service
    {
        public override IBinder OnBind(Intent intent)
        {
            return null;
        }

        [return: GeneratedEnum]
        public override StartCommandResult OnStartCommand(Intent intent, [GeneratedEnum] StartCommandFlags flags, int startId)
        {

            Task.Run(() =>
            {
                while (true)
                {
                    Log.Info(nameof(ConsoleWriteDateTimeService), $"ConsoleWriteDateTimeService:当前时间{DateTime.Now}");
                    Task.Delay(3000).Wait();
                }
            });
            return StartCommandResult.NotSticky;
        }
    }
}

启动代码


        [Java.Interop.Export]
        public void StartConsoleWriteDateTimeService(View view)
        {
            StartService(new Intent(this, typeof(ConsoleWriteDateTimeService)));
        }

这两个暂时先不学习了,等有空在学吧!
↓↓↓↓↓↓↓↓↓

绑定服务

绑定服务是客户端-服务器接口中的服务器。借助绑定服务,组件(例如 Activity)可以绑定到服务、发送请求、接收响应,以及执行进程间通信 (IPC)。绑定服务通常只在为其他应用组件提供服务时处于活动状态,不会无限期在后台运行。

AIDL

同系列文章推荐

.net开发安卓入门 - 环境安装
.net开发安卓入门 - Hello world!
.net开发安卓入门 - 基本交互(Button,输入EditText,TextView,Toast)
.net开发安卓入门 - 布局与样式
.net开发安卓入门 - Activity
.net开发安卓入门 - Notification(通知)
.net开发安卓入门 - 四大基本组件
.net开发安卓入门 - Service (服务)
.net开发安卓入门 - 打包(.apk)
.net开发安卓入门 - ImageView 显示网络图片
.net开发安卓入门-文件操作与配置操作
.net开发安卓入门-Dialog
.net开发安卓入门-自动升级(配合.net6 webapi 作为服务端)
vs2022 实现无线调试安卓(Windows)
.net开发安卓从入门到放弃
.net开发安卓从入门到放弃 最后的挣扎(排查程序闪退问题记录-到目前为止仍在继续)
.net开发安卓入门 -记录两个问题处理办法

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值