学习Android的第二十八天

news2024/11/15 3:48:34

目录

Android Service (服务)

线程

Service (服务)

Service 相关方法

Android 非绑定 Service

startService() 启动 Service

验证 startService() 启动 Service 的调用顺序

Android 绑定 Service

bindService() 启动 Service

验证 BindService 启动 Service 的顺序

startService() 启动 Service 后 bindService() 绑定

Android IntentService 耗时操作

IntentService

范例


Android Service (服务)

在 Android 中,Service 主要用于在后台执行长时间运行的操作,并且提供了与其他组件交互的机制。Service 和 Thread 有一些相似之处,但也存在着明显的区别。 Thread  在应用程序的进程内创建的轻量级执行单元。一个进程可以有多个线程,它们共享相同的内存空间和资源,是 Java 中用于实现并发的基本单位。

线程

我们先来看看 Thread (线程) 有关的一些概念:

  1. 程序(Program):指的是为了完成特定任务而用某种编程语言编写的一组指令集合,通常是静态的代码文件。
  2. 进程(Process):是操作系统中的一个独立执行单位,运行中的程序。每个进程都有独立的内存空间,操作系统为每个进程分配一段内存空间,用于存储程序的代码、数据以及运行时的状态信息。进程是操作系统进行资源分配和调度的基本单位,一个进程可以包含多个线程。
  3. 线程(Thread):是比进程更小的执行单元,是程序执行流的最小单元。一个进程中可以有多个线程,它们共享相同的内存空间和资源,但拥有各自的执行路径。线程由程序负责管理,而进程则由操作系统进行调度。
  4. 多线程的理解:多线程是指在一个程序中同时执行多个线程,每个线程都独立运行,并且可能同时访问共享的内存空间。虽然在单核处理器上实际上是分时执行的,但由于线程切换的速度非常快,用户会感觉到线程是同时执行的。
  5. 线程的生命周期:线程的生命周期包括创建、就绪、运行、阻塞和销毁等状态。线程的状态会随着执行过程中的不同操作而发生变化。

关于创建线程的方式,有三种常见的方法:

  • 继承 Thread 类:定义一个类继承自 Thread,并重写其 run() 方法来定义线程执行的任务。
  • 实现 Runnable 接口:定义一个类实现 Runnable 接口,并实现其 run() 方法,然后将该类的实例传递给 Thread 的构造方法。
  • 实现 Callable 接口:定义一个类实现 Callable 接口,并实现其 call() 方法,然后将该类的实例传递给 ExecutorService 的 submit() 方法。

在 Android 开发中,通常推荐使用第二种方式,即实现 Runnable 接口来创建线程。常见的做法是通过创建一个 Runnable 对象,并将其传递给 Thread 类的构造方法来创建新的线程。另外,也可以使用匿名类的方式来创建线程,这在 Android 开发中更为常见。

Service (服务)

在 Android 中,Service 是一种用于执行长时间运行操作的组件,可以在后台执行任务而不需要用户界面。Service 的生命周期包括以下方法:

1.onCreate():当 Service 第一次创建时调用。在此方法中,通常进行一次性的初始化操作,例如创建线程、初始化变量等。

2. onStartCommand(Intent, int, int):当通过 startService() 方法启动 Service 时调用。在此方法中,Service 可以处理启动请求并执行相应的操作。该方法会返回一个整数值,用于指示系统在 Service 终止后是否应该尝试重新启动该 Service。

3. onBind(Intent):当通过 bindService() 方法启动 Service 时调用。在此方法中,Service 返回一个 IBinder 对象,允许客户端与 Service 进行通信。如果不想允许绑定,则可以返回 null。

4. onUnbind(Intent):当所有客户端与 Service 解绑时调用。在此方法中,通常执行一些资源清理或其他必要的操作。

5. onDestroy():当 Service 即将销毁时调用。在此方法中,通常释放资源、停止线程等清理工作。

Android 中使用 Service 的方式有两种:

1. startService():通过调用 Context 的 startService() 方法来启动 Service。调用此方法后,Service 将会在后台运行,即使启动它的组件已经销毁。通常用于执行一次性任务,例如下载文件、播放音乐等。

2. bindService():通过调用 Context 的 bindService() 方法来绑定 Service。绑定 Service 后,客户端可以与 Service 进行通信,直到所有客户端解绑。通常用于需要与 Service 进行交互的场景,例如绑定到音乐播放器 Service 并控制播放状态。

这两种方式可以结合使用,例如通过 bindService() 方法绑定到 Service 并获取其实例,然后再调用其方法执行任务。

Service 相关方法

1、onCreate():

  • 说明:当 Service 第一次被创建后立即回调该方法。该方法在整个生命周期中只会调用一次。
  • 用途:通常在这个方法中进行一次性的初始化操作,比如创建线程、初始化变量等。

2、onDestroy():

  • 说明:当 Service 被关闭时会回调该方法。该方法只会在 Service 被销毁时调用一次。
  • 用途:通常在这个方法中执行一些清理工作,释放资源、停止线程等。

3、onStartCommand(intent, flag, startId)(在早期版本是 onStart(intent, startId)):

  • 说明:当客户端调用 startService(Intent) 方法时会回调。可多次调用 startService() 方法,但不会再创建新的 Service 对象,而是继续复用前面产生的 Service 对象,会继续回调onStartCommand() 方法。
  • 用途:用于处理客户端对 Service 的启动请求,执行相应的操作。方法的参数包括 Intent 对象(携带启动服务的请求信息)、flag(标志位)和 startId(启动命令的唯一标识)。

4、onBind(intent):

  • 说明:Service 必须实现的方法,该方法会返回一个 IBinder 对象,应用程序通过该对象与 Service 组件进行通信。
  • 用途:用于实现与客户端绑定的通信接口,返回的 IBinder 对象用于客户端与 Service 进行通信。

5、onUnbind(intent):

  • 说明:Service 上绑定的所有客户端都断开连接时会回调该方法。
  • 用途:通常在这个方法中执行一些资源清理或其他必要的操作。

Android 非绑定 Service

startService() 启动 Service

startService() 方法用于启动一个 Service。第一次启动 Service 时,会创建一个新的 Service 实例,并按顺序调用 onCreate() 和 onStartCommand() 方法。

一旦 Service 进入运行状态,再次调用 startService() 时,不会创建新的 Service 实例,而是系统会直接复用之前创建的 Service 实例,并调用其 onStartCommand() 方法。

这种 Service 与其调用者之间没有必然的联系,即使调用者的生命周期结束了,只要没有调用 stopService() 方法,Service 仍然会继续运行。

不论调用了多少次 startService(),只需调用一次 stopService() 就可以停止 Service 的运行。

验证 startService() 启动 Service 的调用顺序

1、MyService.java:

package com.example.myapplication2;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;

public class MyService extends Service {
    private static final String TAG = "MyService";

    @Override
    public void onCreate() {
        super.onCreate();
        Log.d(TAG, "onCreate()已调用");
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.d(TAG, "使用startId调用onStartCommand(): " + startId);
        return START_STICKY;
    }

    @Override
    public IBinder onBind(Intent intent) {
        // 不是绑定式服务,返回 null
        return null;
    }
}

2、MainActivity.java:

package com.example.myapplication2;

import android.os.Bundle;
import android.content.Intent;
import android.util.Log;
import androidx.appcompat.app.AppCompatActivity;

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Log.d(TAG, "正在启动MyService。。。");
        Intent serviceIntent = new Intent(this, MyService.class);
        startService(serviceIntent);
    }
}

3、确保在 AndroidManifest.xml 文件中注册了 MyService:

<service android:name=".MyService"/>

4、运行效果如下

Android 绑定 Service

bindService() 启动 Service

bindService(Intent Service,ServiceConnection conn,int flags)

bindService() 方法是用于在 Android 应用程序中绑定服务的方法。下面是对参数的解释:

  • service:通过这个 Intent 参数指定要启动的服务。Intent 中包含了服务的标识符和其他必要的信息。
  • conn:ServiceConnection 对象,用于监听访问者与服务之间的连接情况。当连接成功时,会回调该对象中的 onServiceConnected(ComponentName, IBinder) 方法。当服务由于异常终止或其他原因与访问者断开连接时,会调用 onServiceDisconnected(ComponentName) 方法。需要注意的是,主动通过 unBindService() 方法断开连接并不会调用 onServiceDisconnected() 方法。
  • flags:指定绑定时是否自动创建服务。可以使用以下两个常量之一:0(不自动创建)或 BIND_AUTO_CREATE(自动创建)。如果服务还未创建且设置为自动创建,则在绑定时会自动创建服务。

通过调用 bindService() 方法,应用程序可以与服务建立连接,并通过 ServiceConnection 监听连接状态的变化。这样可以实现应用程序与服务之间的交互和通信。

注意:

  • 使用 bindService() 方法来启动服务,并通过参数传递要启动的服务以及一个 ServiceConnection 对象,用于监听连接情况。
  • 在 ServiceConnection 对象中,可以通过 onServiceConnected() 方法来处理与服务连接成功的情况,并在其中获取 IBinder 对象,以实现与服务之间的通信。
  • 如果服务所在的宿主异常终止或其他原因终止,会调用 onServiceDisconnected() 方法。
  • 解除与服务的绑定可以通过调用 unbindService() 方法来实现,此时会调用服务的 onUnbind() 和 onDestroy() 方法。
  • 多个客户端绑定同一个服务时,当所有客户端都解除绑定后,系统会销毁服务,除非服务也被 startService() 方法启动。
  • 在自定义服务中,一般需要继承 Binder 类并实现自己的 IBinder 对象,并在 onBind() 方法中返回该对象。

综上所述,通过绑定服务,应用程序能够与服务之间建立更为紧密的连接,并进行双向通信。

验证 BindService 启动 Service 的顺序

1、MainActivity.java:

package com.example.myapplication2;

import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.util.Log;

import androidx.appcompat.app.AppCompatActivity;

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";

    private TimerService timerService;
    private boolean isBound = false;

    private ServiceConnection serviceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            TimerService.TimerBinder binder = (TimerService.TimerBinder) service;
            timerService = binder.getService();
            isBound = true;
            Log.d(TAG, "onServiceConnected:TimerService已连接");
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            isBound = false;
            Log.d(TAG, "onServiceDisconnected:TimerService已断开连接");
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // 启动并绑定服务
        Intent intent = new Intent(this, TimerService.class);
        bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (isBound) {
            unbindService(serviceConnection);
            isBound = false;
        }
    }
}

2、MyService.java:

package com.example.myapplication2;

import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.util.Log;

public class TimerService extends Service {
    private static final String TAG = "TimerService";

    private final IBinder binder = new TimerBinder();
    private boolean isRunning = false;

    public class TimerBinder extends Binder {
        TimerService getService() {
            return TimerService.this;
        }
    }

    @Override
    public IBinder onBind(Intent intent) {
        Log.d(TAG, "onBind:TimerService绑定");
        return binder;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        Log.d(TAG, "onCreate:TimerService已创建");
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.d(TAG, "StartCommand:TimerService已启动");
        return START_NOT_STICKY;
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.d(TAG, "onDestroy:TimerService已销毁");
    }

    // 启动计时器的方法
    public void startTimer() {
        Log.d(TAG, "StartTimer:计时器已启动");
        isRunning = true;
    }

    // 停止计时器的方法
    public void stopTimer() {
        Log.d(TAG, "stopTimer:计时器已停止");
        isRunning = false;
    }
}

3、确保在 AndroidManifest.xml 文件中注册了 TimerService:

<service android:name=".TimerService"/>

startService() 启动 Service 后 bindService() 绑定

当一个服务已经通过 startService() 方法启动后,即使有其他客户端通过 bindService() 方法绑定到该服务,服务仍然会保持运行状态,直到所有客户端都调用了 unbindService() 方法来解除绑定,并且没有其他客户端通过 startService() 方法启动了该服务,才会触发服务的销毁。

在这种情况下,如果调用 bindService() 来绑定到一个已经启动的服务,系统只是将服务的内部 IBinder 对象传递给客户端,不会将服务的生命周期与客户端绑定。因此,即使客户端调用 unbindService() 方法解除绑定,服务也不会被销毁。

总结起来,对于已经通过 startService() 启动的服务,即使有其他客户端通过 bindService() 方法绑定到该服务,服务也只有在所有客户端都调用了 unbindService() 方法解除绑定,并且没有其他客户端通过 startService() 方法启动了该服务时才会被销毁。

Android IntentService 耗时操作

IntentService

IntentService 是 Android 平台提供的一种服务,用于处理异步请求。它是 Service 类的一个子类,但相比普通的 Service,IntentService 更适合用来执行需要较长时间的操作,而且它可以在后台自动停止,无需手动控制。

下面是 IntentService 的一般用法:

  1. 启动 IntentService:客户端通过调用 startService(Intent) 方法来启动 IntentService。这个 Intent 包含了要执行的操作的描述。
  2. 自动停止:IntentService 在执行完所有的请求后会自动停止。这意味着我们不需要手动去停止 IntentService。
  3. 多次启动:IntentService 可以被启动多次。每次启动时,请求的 Intent 会被加入到工作队列中,然后按照队列顺序依次执行。注意,虽然可以多次启动 IntentService,但是每次只会执行一个工作线程,确保操作的顺序性和线程安全性。
  4. onHandleIntent() 回调方法:每个请求的操作会在 IntentService 的 onHandleIntent(Intent) 回调方法中执行。这个方法在工作线程中执行,因此可以执行耗时操作,而不会阻塞主线程。

通过这些特性,IntentService 提供了一种方便的方式来处理异步操作,尤其适合那些需要按顺序执行的任务或者需要在后台执行的长时间操作。

范例

1、MyIntentService.java

package com.example.myapplication2;

import android.app.IntentService;
import android.content.Intent;
import android.util.Log;

public class MyIntentService extends IntentService {

    private static final String TAG = "MyIntentService";

    public MyIntentService() {
        super("MyIntentService");
    }

    @Override
    protected void onHandleIntent(Intent intent) {

        // 打印一些日志
        for (int i = 0; i < 5; i++) {
            Log.d(TAG, "正在执行任务 " + i);
            try {
                // 模拟耗时操作
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        // 任务完成后,IntentService 会自动停止
    }
}

2、确保在 AndroidManifest.xml 文件中注册了 MyIntentService:

<service
    android:name=".MyIntentService"
    android:exported="false" />

3、接下来,在应用中启动这个 IntentService:

package com.example.myapplication2;

import android.content.Intent;
import android.os.Bundle;

import androidx.appcompat.app.AppCompatActivity;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Intent intent = new Intent(this, MyIntentService.class);
        startService(intent);

    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1518404.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

《LeetCode热题100》笔记题解思路技巧优化_Part_3

《LeetCode热题100》笔记&题解&思路&技巧&优化_Part_3 &#x1f60d;&#x1f60d;&#x1f60d; 相知&#x1f64c;&#x1f64c;&#x1f64c; 相识&#x1f622;&#x1f622;&#x1f622; 开始刷题链表&#x1f7e2;1. 相交链表&#x1f7e2;2. 反转链表&…

html5cssjs代码 020 推荐网址

html5&css&js代码 020 推荐网址 一、代码二、解释 这段HTML代码定义了一个网页&#xff0c;它包含了一个标题、一些样式和一个表格。表格中列出了一些推荐的网址&#xff0c;包括序号、名称、网址、描述和备注。每个表格行都包含一个链接到相应网址的超链接。页面的样式…

一种基于宏和serde_json实现的rust web中统一返回类

本人rust萌新&#xff0c;写web碰到了这个&#xff0c;基于ChatGPT和文心一言学了宏&#xff0c;强行把这玩意实现出来了&#xff0c;做个学习记录&#xff0c;如果有更好的方法&#xff0c;勿喷。 先看效果&#xff0c;注意不支持嵌套&#xff0c;且kv映射要用>(因为它这个…

《JAVA与模式》之抽象工厂模式

系列文章目录 文章目录 系列文章目录前言一、使用简单工厂模式的解决方案二、引进抽象工厂模式三、抽象工厂模式结构四、抽象工厂模式的优缺点前言 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站,这篇文章男女通用,看…

MC78L05ACDR2G线性稳压器芯片中文资料规格书PDF数据手册引脚图参数图片价格

产品概述&#xff1a; MC78L00A系列线性稳压器价格便宜&#xff0c;易于使用&#xff0c;适用于各种需要最高100mA的调节电源的应用。与大功率MC7800和MC78M00系列一样&#xff0c;这款稳压器也提供内部电流限制和高温关断&#xff0c;因此非常坚固耐用。在很多应用中&#xf…

提高工作效率,这 10 款 AI 工具不能错过

作为一个职场打工人&#xff0c;我深知时间和效率的重要性。正是因为如此&#xff0c;我开始使用各种人工智能工具来帮助我提高工作效率。在这篇文章中&#xff0c;我将会分享 10 款必备的 AI 工具&#xff0c;这些工具可以让你的工作更加高效&#xff0c;从而为你节省更多的时…

windows 11访问Debian10上的共享目录

步骤 要在Windows 11上访问Debian 10.0.0的共享目录&#xff0c;可以通过以下步骤来实现&#xff1a; 1. 设置Samba服务&#xff1a;在Debian系统上&#xff0c;需要安装并配置Samba服务&#xff0c;以便能够实现文件夹共享。Samba是一个允许Linux/Unix服务器与Windows操作系…

Windows系统搭建Cloudreve结合内网穿透打造可公网访问的私有云盘

目录 ⛳️推荐 1、前言 2、本地网站搭建 2.1 环境使用 2.2 支持组件选择 2.3 网页安装 2.4 测试和使用 2.5 问题解决 3、本地网页发布 3.1 cpolar云端设置 3.2 cpolar本地设置 4、公网访问测试 5、结语 ⛳️推荐 前些天发现了一个巨牛的人工智能学习网站&#xff…

C#,数值计算,数据测试用的对称正定矩阵(Symmetric Positive Definite Matrix)的随机生成算法与源代码

C.Hermite 1、对称矩阵 对称矩阵(Symmetric Matrices)是指以主对角线为对称轴,各元素对应相等的矩阵。在线性代数中,对称矩阵是一个方形矩阵,其转置矩阵和自身相等。1855年,埃米特(C.Hermite,1822-1901年)证明了别的数学家发现的一些矩阵类的特征根的特殊性质,如称为埃…

AI智能电话机器人的核心技术是什么?

电话机器人是近几年兴起的人工智能产品&#xff0c;它主要通过电话群呼潜在客户&#xff0c;沟通进行信息筛选&#xff0c;帮助企业选择意向客户。企业使用电话机器人可以减少人工成本&#xff0c;提高工作效率。我们一起来看看智能电话机器人的核心技术是什么&#xff1f; 电话…

Tengine编译安装

首先下载源码 可以去官网&#xff1a;The Tengine Web Server 当前最新版地址&#xff1a;https://tengine.taobao.org/download/tengine-3.1.0.tar.gz 安装编译依赖 yum -y install gcc pcre-devel zlib-devel openssl-devel libxml2-devel \libxslt-devel gd-devel GeoIP…

安装linux_centos7虚拟机_开启网络_ssh_防火墙

文章目录 安装linux_centos7虚拟机_开启网络_ssh_防火墙安装centos7虚拟机1. 进入VMware --> 点击文件 --> 新建虚拟机2. 选择典型 --> 选择下一步3. 选择--> 稍后安装操作系统4. 选择--> Linux --> CentOS 7 64位5. 在虚拟机名称输入(虚拟机名) --> 选择…

一条 SQL 更新语句如何执行的

Server 层 存储引擎层 总流程 查询语句 连接器 查询缓存 分析器 优化器 执行器 更新语句 redo log&#xff08;节省的是随机写磁盘的 IO 消耗&#xff08;转成顺序写&#x…

windows达梦安装

1.首先准备好windows安装系统&#xff0c;准备工作的做好&#xff0c;然后把素材包dm8_20230418_x86_win_64放进去&#xff0c;进行解压 解压完成之后&#xff0c;把dm8_20230418_x86_win_64再次进行解压&#xff0c;然后点击安装setup进行安装 然后点击接受进行下一步&#xf…

网络安全msf学习1

工具&#xff1a;netcat 用途 &#xff1a;端口连接、数据提交 工具nmap 用途&#xff1a;端口扫描、服务识别、操作系统指纹识别 工具 httprint 用途&#xff1a;通过远程http指纹判断http服务类型 工具&#xff1a; tamper ie 用途&#xff1a; http数据包修改、转发工…

直方图及数据95%置信区间及特征筛选

rm(list ls()) library(Rmisc) library(ggplot2) library(dplyr)data <- iris x<-iris$Sepal.Length #求置信区间方法1## confidence_interval <- t.test(x)$conf.int print(confidence_interval) #[1] 5.709732 5.976934 #attr(,"conf.level") #[1] 0.95#…

翻转时钟效果

时分秒三个部分结构功能完全一致&#xff0c;均有四块构成&#xff0c;上下各两块。 正面可见&#xff0c;背面不可见&#xff0c;同时需要调整翻转过程中的z-index。 初始状态card2为已经翻转状态。 calendar.html <!DOCTYPE html> <html lang"en">&…

Excel第26享:模糊查找之Hlookup函数与通配符的嵌套

1、需求描述 如下图所示&#xff0c;现第一行有三个参考值&#xff1a;人S、羊E、猪3&#xff0c;在第三行有5个字&#xff1a;马、牛、人、羊、猪&#xff0c;每个字如果出现在第一行的三个参考值中&#xff0c;就返回该单元格的数值。如&#xff0c;人&#xff0c;就返回“人…

unicloud update 修改

update 修改 使用腾讯云时更新方法必须搭配doc、where方法使用&#xff0c;db.collection(‘test’).update()会报如下错误&#xff1a;param should have required property ‘query’ collection.doc().update(Object data)未使用set、remove更新操作符的情况下&#xff0c…

vue:功能:table动态合并+前端导出

场景&#xff1a;第一列WM 名字相同&#xff0c;行内合并&#xff0c;后面的列合并的行数根据第一列合并的行来。第二列‘累计请假天数根据合并的几列显示数值。后续需合并的列以第一列合并行数为基准 注&#xff09;当前数据表头固定&#xff0c;行内数据不固定。以第一列WM为…