花瓣小跑 发表于 2024-11-20 03:18:53

Android---Kotlin语言基础快速入门(看图详解版!!!)

一、 Kotlin语言基础知识

a.基础知识—日记工具Log的使用

1、Log.v()打印最琐碎、意义最小的日记信息。对应级别verbose
2、Log.d()打印调试信息,适用于调试步伐和分析问题。对应级别debug
3、Log.i()打印重要数据,分析用户行为的数据。对应级别info
4、Log.w()打印警告信息,提示步伐可能存在的风险。对应级别warn
5、Log.e()打印错误信息,如步伐进入catch语句。对应级别error
级别:verbose<debug<info<warn<error
b.基础知识—判空辅助工具

可为空的类型体系就是在类名背面加上一个“?”。比如可为空的整形为:Int?
1、”?.” :当对象不为空时正常调用相应的方法,对象为空时什么都不做
2、“?:”:操纵符左右两边都吸取一个表达式,若左表达式的效果不为空就返回左边表达式的效果,否则返回右边表达式的效果。
https://i-blog.csdnimg.cn/direct/1470ec7e7ab24cfc82e5052d7dbbdc18.png         https://i-blog.csdnimg.cn/direct/6804bd75de4f46e5a883d4199e2cb372.png
3、偶然间编写的代码会存在空指针风险,实时是已经做了非空检查,但是扔无法编译通过,若想强行通过编译,可以使用非空断言工具,写法是在对象背面加上”!!” 。就是告诉Kotlin,我非常确信这里的对象不会为空,不用帮我做空指针检查,如果出现问题,直接抛出空指针异常。
https://i-blog.csdnimg.cn/direct/4aedd1ec481349e983b6da079e343f8b.png
4、”let”:既不是操纵符也不是关键字,而是一个函数,提供了函数式API的编程接口,并将原始调用对象作为参数传递到Lambda表达式中。
https://i-blog.csdnimg.cn/direct/434f4f5b552a4b5c97cc3a330dc08481.png
调用obj对象的let函数,然后Lambda表达式中的代码会立即实行,而且这个obj对象自己会作为参数传递到Lambda表达式中。为防止变量重名,参数名改成了obj2,现实上他们是同一个对象。
Lambda表达式参数列表中只有一个参数时,可以不声明参数名,直接用it关键字取代即可
https://i-blog.csdnimg.cn/direct/5731bfe164e444d385acd78583be02ab.png     https://i-blog.csdnimg.cn/direct/b68e93043e2249758b678119d2eb639f.png   https://i-blog.csdnimg.cn/direct/7fc6375d246e4fe58e60fa0747cf4213.png
let函数可以处置惩罚全局变量的判空问题,而if判断语句无法做到。
c.基础知识—尺度函数with、run、apply

Kotlin中的标准函数指的是Standard.kt文件中定义的函数,可以自由的调用
1、with函数
吸取两个参数,参数1可以是一个恣意类型的对象,参数2是一个Lambda表达式。with函数会在Lambda表达式中提供第一个参数对象的上下文,并使用Lambda表达式中的最后一行代码作为返回值返回。
2、run函数
run函数一样平常不会直接调用,而是要在某个对象的基础上调用。run函数只吸取一个Lambda参数,而且会在Lambda表达式中提供调用对象的上下文,其他和with函数相同。
3、apply函数
要在某个对象上调用,只吸取一个Lambda函数,也会在Lambda表达式中提供调用对象的上下文,但是apply函数无法指定返回值,而是会主动返回调用对象自己。
https://i-blog.csdnimg.cn/direct/c5380a6ec9174dd6ad398678faff8e46.png https://i-blog.csdnimg.cn/direct/9407d6a4c64448d6931873d720115984.png https://i-blog.csdnimg.cn/direct/9f1acee2bbfe458eafee8b8cd95d050d.png 下面举个例子哈:
1、https://i-blog.csdnimg.cn/direct/c47e12c5b75a4bc48d2fe00f9e9fd286.png      2、https://i-blog.csdnimg.cn/direct/d536df80f6934a48b50e58812f3edb1e.png
3、https://i-blog.csdnimg.cn/direct/f899f16ad004427db8cddf134773ac57.png      4、https://i-blog.csdnimg.cn/direct/9a25d9534d0d4947b13511b0336fc74b.png
上面四种运行方式的效果最终都是相同的,效果如下:
https://i-blog.csdnimg.cn/direct/5328726a97e748ec91b6b9d03ed66a2a.png#pic_center
二、Activity

A:初识Activity

定义:在Android开发中,Activity 是一个非常重要的组件,它是应用步伐与用户交互的界面。每个Activity 代表一个单独的屏幕,用户可以在这个屏幕上进行操纵和查看信息。
功能:
1、用户界面(UI)。 Activity 提供了一个窗口,用于展示用户界面。
2、生命周期管理。创建、运行、停息、规复、克制和烧毁等状态。
3、事件处置惩罚。 Activity 可以吸取并响应用户的输入事件,如点击、触摸、键盘输入等。
4、数据传递。Activity 可以通过Intent进行Activity之间的通讯和数据传递。
B:Toast

简介:Toast用来进行页面文本提示,表现一段时间后自行消失,可以给用户进行通知。
用法:
https://i-blog.csdnimg.cn/direct/e9abad35f31a45c8a7e3aa4407d362ed.png
参数1:Context。是Toast的上下文,Activity自己就是一个Context对象。
参数2:text,就是要弹出的文本内容。
参数3:Toast表现的时间长短,有Toast.LENGTH_LONG和Toast.LENGTH_SHORT可选。
许多初学者很容易忘记.show()的使用,将文本表现出来。
https://i-blog.csdnimg.cn/direct/b07d313bc49d4d7cabd94aaff2da0f0d.png#pic_center
C:Menu菜单栏

简介:我们在手机的右上角常常看到的3个小点点,就是我们这里所要介绍的Menu,点击三个点后,就可以看到内里所表现的内容。
用法:在res目录下新建menu文件夹,并创建名为‘main’的menu文件
https://i-blog.csdnimg.cn/direct/e9d4d8b4765040c889481ca2a9031811.png#pic_center
<item>标签用于创建具体的菜单项
在Activity中重写方法,实现Activity菜单的创建
https://i-blog.csdnimg.cn/direct/17cb95cda6c04f3e9d8a174d37e3bfa3.png#pic_center
         https://i-blog.csdnimg.cn/direct/ff7044da0e9f47eb97fdcb530a252cd1.png        https://i-blog.csdnimg.cn/direct/91e7d1f5b1de487098e57fc44f889200.png
inflate()第一个参数指定通过哪个资源文件创建菜单,第二个参数指定将菜单项添加到哪一个Menu
定义出来的菜单还需要实现菜单的响应事件
那么可以在MainActivity中重写onOptionsItemSelected()方法实现点击监听
https://i-blog.csdnimg.cn/direct/7791bab4650a4bfba6a1bbde9490122e.png
item.itemId时间上就是调用的item的getItemId()方法--------语法糖
D:Activity跳转—Intent

方法一:表现Intent

所谓表现Intent就是在Activity中通过Intent构造函数进行参数传递实现。
https://i-blog.csdnimg.cn/direct/20fd9b86c3e14e5cac9b3c778a505e80.png#pic_center
Tips:在获取button2这个按钮的时间并没有通过findViewById(R.id.xxx),而是通过视图绑定的方法进行完成的。这的条件是需要在build.gradle(:app)中提进步行配置。并在Activity中进行Layout文件的绑定。
https://i-blog.csdnimg.cn/direct/f5f3f68a424442bdb3420ceddb9e8eb6.png#pic_center
方法二:隐式Intent

隐,就是很含蓄,不会明白指出跳转到哪个Activity,而是在AndroidManifest进行配置。
https://i-blog.csdnimg.cn/direct/81f2dc36961c4faeb74a39a37293f260.png#pic_center
注:只有和中的内容同时匹配Intent中的action和category,Activity才会响应Intent
注:每个Intent只能有一个action但是可以有多个category
https://i-blog.csdnimg.cn/direct/4edbb22f3c194866a2f2c20c92daf5e0.png#pic_center
Activity跳转—隐式Intent扩展

1、网页跳转

https://i-blog.csdnimg.cn/direct/03d1592d1333429e90b4c672ab82f437.png#pic_center
Intent的action是Android体系内置的动作Intent.ACTION_VIEW。
Uri.parse将字符串剖析成一个Uri对象。
最后通过Intent的setData()方法将Uri传入。
Tips:可以在标签中配置一个标签,准确的指定当前Activity能够响应的数据。
①android:scheme 指定命据的协议部分,如https
②android:host 指定命据的主机名部分,如www.baidu.com
③android:port 指定命据的端口部分
④android:path 指定主机名和端口之后的部分
⑤android:mimeType 指定可以处置惩罚的数据类型
举例:<data android:scheme:https />
2、拨打电话

https://i-blog.csdnimg.cn/direct/ab277a7a2f1845bead97a6faa96fd672.png#pic_center
3、也可以通过geo表现地理位置

https://i-blog.csdnimg.cn/direct/8aa2d0d7dcda40ad913732f778c58d77.png#pic_center
也可以进行发送邮件,总而言之,隐式Intent的功能是很强大的。
向下一个Activity传递数据

思绪:Intent中又一系列的putExtra()方法的重载,可以先将数据暂存在Intent中,在启动另一个Activity的时间将数据取出即可。
https://i-blog.csdnimg.cn/direct/e2c90b8a22ae4a4899dc47dc15b2438b.png
https://i-blog.csdnimg.cn/direct/62ee6f638b50451ab3acc195dc56c211.png
https://i-blog.csdnimg.cn/direct/454dcd399ccc415582022c85e3b19311.png
返回数据给上一个Activity

问:返回上一个Activity只需按下Back键,但并没有用于启动Activity的Intent来传递数据,这该怎么给上一个Activity返回数据呢?
答:其实Activity类还有一个用于启动Activity的startActivityForResult()方法,它期望Activity烧毁的时间返回一个效果给上一个Activity。
https://i-blog.csdnimg.cn/direct/2133811835104117bf6b5106db83e7d9.png#pic_center
参数1:Intent
参数2:请求码,用于之后回调中判断数据的来源
https://i-blog.csdnimg.cn/direct/969444e1e8de41e4b8f68674ac2b1d5a.png#pic_center
setResult方法专门用于向上一个Activity返回数据
https://i-blog.csdnimg.cn/direct/a76d0006a3c64a7bac2f74ccbd1bf029.png#pic_center
https://i-blog.csdnimg.cn/direct/f47fd5bf63b34fd19abb63559f10dbfa.png#pic_center
问:如果不点击button按钮返回到上一个Activity,直接按下Back键,这样数据还能返回吗????
答:自然是不可以的。但是可以在Activity中重写onBackPressed()方法办理这个问题。
https://i-blog.csdnimg.cn/direct/f4d7a571ada949aa91a292b88b6601af.png#pic_center
方法还是那个方法,只是重写了onBackPressed()方法进行响应按下Back键这个动作。
E:Activity最佳启动方法

假设在启动SecondActivity时需要两个非常重要的参数,风俗性在MainActivity的写法如下:
https://i-blog.csdnimg.cn/direct/91d49079f8b7460ba808a853e400d29a.png#pic_center
这么写确实没毛病,但是在项目对接中容易不清楚传递哪些数据,是很贫苦的。那么换一种方法,在SecondActivity中添加如下代码:
https://i-blog.csdnimg.cn/direct/4bdd6c79e60041a9bd57cb8f40d0ec80.png#pic_center
Kotlin规定,全部定义在companion object中的方法都可以使用类似于Java静态方法形式的调用。
在MainActivity中只需要一行代码就可以启动SecondActivity并传递参数
https://i-blog.csdnimg.cn/direct/e75ae8b5384e4678adac031cda217398.png
F:Activity生命周期—状态和生存期

Android中的Activity是可以层叠的,每次启动一个Activity就会覆盖在原来的Activity之上,按下Back键就会烧毁最上面的运动,这是通过栈来实现的。
https://i-blog.csdnimg.cn/direct/77afa6599bcf4d48a2692c5a72337f31.png#pic_center
每个Activity最多有4种状态:运行状态、暂停状态(仍可见)、停止状态、销毁状态
Activity中有7个回调方法:
1、onCreate()会在Activity第一次被创建的时候调用,常用于初始化、加载布局、绑定事件
2、onStart()   Activity由不可见变为可见时调用
3、onResume()Activity准备好和用户交互时调用,此时Activity一定处于栈顶
4、onPause()在系统准备去启动或者恢复另一个Activity的时候进行调用
5、onStop()   Activity完全不可见的时候进行调用(停止状态)
6、onDeatory()Activity在被销毁之前进行调用
7、onRestart()Activity在重新启动的时候(停止-->运行状态)之前调用

完整生存期:onCreate() 与onDeatory() 之间
可见生存期:onStart()与onStop() 之间
前台生存期:onResume()与onPause() 之间
为更好理解Activity的生命周期,下面提供了表现图
https://i-blog.csdnimg.cn/direct/fb46eed41a654740b231d923804e4bf0.png#pic_center
下面进行体验一下Activit生命周期在操纵器件到底是怎么变化的!!!
条件:创建两个Activity,分别是NormalActivity(平凡)和DialogActivity(对话框)
在AndroidManifest.xml文件下进行配置,将Activity设置为对话框模式。
https://i-blog.csdnimg.cn/direct/00870c76d8ce4bfd8272e50ecfcd1912.png#pic_center
在MainActivity中设置页面跳转逻辑,并重写生命运动的方法
https://i-blog.csdnimg.cn/direct/da51e4c7a31947c4a8aaefdce6f30fd0.png    https://i-blog.csdnimg.cn/direct/d932f7d7a27b48498edf3a72fd7828f0.png
效果分析:
1、第一次创建MainActivity
https://i-blog.csdnimg.cn/direct/d547e4be47db44e2bc346bca23d196f9.png#pic_center
2、启动NormalActivity
https://i-blog.csdnimg.cn/direct/6811a26fa4904df894de710cf66d2a85.png#pic_center
3、back
https://i-blog.csdnimg.cn/direct/9dd807c13b744ebabdc989c665e5d0eb.png#pic_center
4、启动DialogActivity
https://i-blog.csdnimg.cn/direct/b4c3a8d406014723bf5123156cde3298.png#pic_center
5、back
https://i-blog.csdnimg.cn/direct/c5d5b7465140433c8d65687be9710725.png#pic_center
6、back
https://i-blog.csdnimg.cn/direct/1e00de28716343629a1221d6ddad68d8.png#pic_center
G:Activity被回收了怎么办?????

我们知道啊,当Activity进入了克制状态,如果内存空间不敷的话,是有可能被体系回收的,那这种现象是有些可骇的!那怎么办呢?
Activity中提供了一个onSaveInstanceState()回调方法,会携带一个Bundle类型的参数,Bundle提供了一系列的方法用于生存数据,可以保证在Activity在回收之前肯定会被调用。
在MainActivity中添加下边的代码,就可以将数据生存下来:
https://i-blog.csdnimg.cn/direct/3f585cb31fc94b94b352d20fde30de41.png#pic_center
怎么取值规复呢???
其实onCreate()方法也有一个Bundle类型的参数,一样平常是null,但是Activity被体系回收之前,通过onSaveInstanceState()方法生存数据,这个参数就会带有之宿世存的全部数据。
在MainActivity中添加下面代码,取出值后再做相应的规复就行了。
https://i-blog.csdnimg.cn/direct/18e8d91901fd4893a688c128079f6d57.png#pic_center
H:Activity的启动模式

1、standard

这就是Activity默认的启动模式,每启动一个Activity就会放入栈顶,不管栈中是否存在该Activity,都会创建一个新的该Activity的实例。
比如,我们在MainActivity中编写如下代码,进行启动MainActivity自己(无现实意义)
https://i-blog.csdnimg.cn/direct/3b3d87a164a641c8a868c8df38daba8d.png#pic_center
https://i-blog.csdnimg.cn/direct/e1919afd818a4acd88abfcf627b756e4.png#pic_center
https://i-blog.csdnimg.cn/direct/14042dc3f71042c4a0897fbffb544e82.png#pic_center
2、singleTop

在启动Activity时如果发现返回栈的栈顶已经是该Activity,则可以直接使用,是不需要再重新创建新的Activity实例的。
首先需要对AndroidManifest.xml文件进行修改
https://i-blog.csdnimg.cn/direct/11d4fde7c1334800bfe0ddc73cc98a4f.png#pic_center
重新运行步伐,并多次点击按钮,发现不会创建新的实例对象啦。
https://i-blog.csdnimg.cn/direct/6adb54a169144682a5b86df54b34366a.png
那如果MainActivity并没有在栈顶的位置,再次启动MainActivity会创建新的实例的。
例:修改MainActivityhttps://i-blog.csdnimg.cn/direct/228dd733e4f7463cb9f27f32208a80dc.png#pic_center
修改SecondActivity
https://i-blog.csdnimg.cn/direct/61062139771047d08dedf8a210cdc828.png#pic_center
https://i-blog.csdnimg.cn/direct/8f0497b43abf498faeccc3558381171e.png#pic_center
https://i-blog.csdnimg.cn/direct/9037fe1a19dc4be68b6f256535f61502.png#pic_center
3、singleTask

对于singleTop而已,如果Activity没有处于栈顶,还是可能会创建多个Activity实例的,而singleTask模式就可以做到让某个Activity在整个应用步伐的上下文只有一个实例。
其实原理很简单,就是每次启动该Activity时,体系先去栈中检查是否存在该Activity的实例,如果存在,就将该Activity之上的全部Activity全部出栈,不存在就创建。
首先还是修改AndroidManifest.xml文件:
https://i-blog.csdnimg.cn/direct/4b0b5c4c9e41445cb2c14128563757b7.png
在MainActivity中重写onRestart()方法
在SecondActivity中重写onDestroy()方法
     https://i-blog.csdnimg.cn/direct/3820795530234064a6b6c617ae83c62f.png       https://i-blog.csdnimg.cn/direct/376354eb5f1c44c79005dc299b570fab.png
4、singleInstance

指定为singleInstance模式的Activity会启动一个新的、单独的返回栈来管理这个Activity
可以将SecondActivity启动模式设置为singleInstance模式(修改.xml文件,不多说了)
修改一下MainActivity中的代码,进行打印当前返回栈的id:
https://i-blog.csdnimg.cn/direct/69ff5a366af44e95b2968547462ea548.png#pic_center
(上述taskId现实上是调用的父类的getTaskID()方法)
同样的方法,在SecondActivity、ThirdActivity中打印taskId(返回栈的id),并实现MainActivity—>SecondActivity—>ThirdActivity的页面跳转逻辑:
https://i-blog.csdnimg.cn/direct/95857084b3894217a6457696fbc7f4dd.png#pic_center
https://i-blog.csdnimg.cn/direct/2443bb1df0ce41bc91c87668242b7fed.png#pic_center
三、常用控件以及基本结构

1、常用控件

(1)、TextView

很简单,就是在页面上表现笔墨信息。
https://i-blog.csdnimg.cn/direct/1024b6d9a0b44de183e8a08fb341a37f.png#pic_center
id:唯一标识
layout_width:宽
layout_height:高
gravity:指定笔墨的对齐方式,可选值有top、bottom、start、end、center等,可以用“|”同时指定多个值。center表现效果等同于center_vertical|center_horizon
textColor:笔墨颜色
textSize:笔墨大小,单位用sp表现
text:文本内容
https://i-blog.csdnimg.cn/direct/744f1574ebea47c09073779e13f663ec.png#pic_center
(2)、Button

https://i-blog.csdnimg.cn/direct/bf2104aa652649e19fa9a8e3e013cb00.png#pic_center
textAllCaps:Button按钮文本中的英文默认大写表现,false表现保存原始笔墨内容。
https://i-blog.csdnimg.cn/direct/b7d8a1af0e8940a686ba1d8e4d60fb94.png#pic_center
Button按钮的监听方式:
①在MainActivity中为Button按钮注册监听器
https://i-blog.csdnimg.cn/direct/378d71a853a54741ab1400fbf5b460e5.png#pic_center
②使用实现接口的方式进行注册
https://i-blog.csdnimg.cn/direct/5f87d9f0a1124dacb41270bb47baea1e.png#pic_center
(3)、EditText

允许用户输入信息的文本框。
https://i-blog.csdnimg.cn/direct/69eb0ced1fe940efbab7485b73b76216.png#pic_center
hint:输入框中的提示笔墨,只要输入内容就会消失。
maxLines:指定EditText的最大行数,输入的内容凌驾行数时,文本就会向上滚动,EditText就不会再继续拉伸。
https://i-blog.csdnimg.cn/direct/445f10d9b8184586a843f227c81f03fc.png#pic_center
还可以与Button按钮联动,获取输入框中输入的内容。
https://i-blog.csdnimg.cn/direct/284ab36ddb004b378d8d812082004cb7.png#pic_center调用toString()方法将获取的内容转换成字符串、
(4)、ImageView

用于在页面上展示图片。
               https://i-blog.csdnimg.cn/direct/68dc1143d20947f4be41a7b1e77bbe29.png            https://i-blog.csdnimg.cn/direct/5fb0a504a95245eeb54573258b2fa625.png
此外,与Button按钮进行联动可以动态的修改图片资源
https://i-blog.csdnimg.cn/direct/1b3e1dead94e43f29073a1cd9ef4d128.png#pic_center
(5)、ProgressBar

用于在页面上表现一个进度条,表现步伐正在加载数据。
https://i-blog.csdnimg.cn/direct/90034235e69c45ecb98dcdc2d0f16dad.png#pic_center怎么让旋转的进度条消失呢?用到一个全部Android控件都有的一个属性android:visibility,可选值有visible、invisible、gone三种,默认是visible,invisible表现不可见但仍占据页面空间,gone表现不可见而且不占据屏幕的任何空间。
Button按钮与进度条显隐联动:
https://i-blog.csdnimg.cn/direct/e879f5c7abee472cab66e91843f3d1bf.png#pic_center
将圆形进度条更改为程度进度条,通过max属性还可以动态的更改进度条的进度:
https://i-blog.csdnimg.cn/direct/d7e3719b72184d878d465b8f846a9c7f.png#pic_center
(6)、AlertDialog

在当前页面弹出对话框,置于全部页面元素之上,能屏蔽其他组件的交互:
https://i-blog.csdnimg.cn/direct/28de37b347824cfea304e428a1ceaad2.png       https://i-blog.csdnimg.cn/direct/eb94f27790de461291fcfc3c89e82a9d.png
2、基本结构

(1)、LinearLayout

看名字就知道是线性结构
https://i-blog.csdnimg.cn/direct/da5792c4a82e43229310f91bf40d86d1.png#pic_center这个属性很简单,值为vertical则控件垂直分列,为horizontal则控件程度分列。
但是有点需要注意LinearLayout分列方向是vertical时,内部的控件就绝对不能将高度设置为match_parent,horizontal时不能将宽度设为match_parent。
android:layout_gravity属性指定控件在结构中的对齐方式。
注意:当LinearLayout是horizontal时只有垂直方向上的对齐方式才访问效,当LinearLayout是vertical时只有程度方向上的对齐方式才访问效
LinearLayout还有一个重要的属性-----------android:layout_weight
允许我们使用比例的方式指定控件的大小(在手机屏幕适配性方面)
https://i-blog.csdnimg.cn/direct/037e6f860e6d45949fb77388a60e8a23.png#pic_center
(2)、RelativeActivity

看名字就知道是相对结构,比较随意分列
https://i-blog.csdnimg.cn/direct/2ae464ca182b4a3e8d687ab9e69a1865.png#pic_center
每个控件都是相对于父结构进行的,下面演示相对于控件进行定位:
https://i-blog.csdnimg.cn/direct/344455cfe6a44cbb93834141a0cab92e.png#pic_center
android:layout_alignLeft表现让一个控件与另一个控件的左边沿对齐
同理还有:
android:layout_alignRight
android:layout_alignTop
android:layout_alignBottom
(3)、FrameLayout

帧结构,全部控件默认摆放在结构的左上角,全都堆放在一个角落
这是默认效果,可以使用layout_gravity指定控件在结构中的对齐方式。
FrameLayout由于定位欠缺,用的很少,就不多讲。
3、Android控件不够用?创建自定义结构!!!

1、引入结构

在layout文件夹下有一个title.xml结构文件。        https://i-blog.csdnimg.cn/direct/e50436aff2a040b08a1949ca48877a0a.png
怎么引入结构呢???        只需一条语句:
https://i-blog.csdnimg.cn/direct/93c25662c5974c04af7eecc87b74e320.png#pic_center
可以将体系默认的标题栏隐藏:
https://i-blog.csdnimg.cn/direct/470c21cbe0e948388265b8a6075e58d9.png#pic_center
2、创建自定义控件

引入结构确实方便,但是当控件需要响应事件的时间就需要自定义控件啦
https://i-blog.csdnimg.cn/direct/2a962b7486b24082b46de1afd849d748.png#pic_center
https://i-blog.csdnimg.cn/direct/a20042e8965a408bac9044ecda160196.png#pic_center
4、Android最常用和最难用的控件—ListView

https://i-blog.csdnimg.cn/direct/05bbedb7a43a448fb9e5c29408003271.png#pic_center
聚集的数据无法直接传递给ListView,需要用到适配器完成。
我们这里所引用的子项结构,是Android内置的结构文件,内里只有一个TextView用于表现一段文本。
适配器中传递的三个参数分别是:Activity实例、ListView子项结构id、数据源。
只表现文本是不是有点太单调了呢??我们来点稍微复杂的。
用实体类作为ListView适配器的适配类型:
https://i-blog.csdnimg.cn/direct/22ed202d7e124c43b569289f1f4ef72c.png
为ListView的子项指定一个自定义结构
https://i-blog.csdnimg.cn/direct/ed90456fe4d9471db12ee682013b5844.png#pic_center
创建一个自定义适配器FruitAdapter,适配器继续自ArrayAdapter,并将泛型指定为Fruit类
https://i-blog.csdnimg.cn/direct/34772dbb6e044ea694d106bf952cd127.png#pic_center
接下来在MainActivity创建并添加适配器:
https://i-blog.csdnimg.cn/direct/58447817095b4be89134e3778ecbbc69.png#pic_center




提升ListView的运行服从:

1、在FruitAdapter的getView()方法中,每次都将结构重新加载一遍,服从很低。这可以通过convertView参数优化,该参数用于将之前加载好的结构进行缓存,以便之后重用。
https://i-blog.csdnimg.cn/direct/bf5473b6e6064c46be90a45bbd9d65d0.png#pic_center
问题:如果使用该参数进行优化的话,好像binding在这个地方是不可以使用的,因为binding吸取到的是FruitItemBinding而convertView吸取到的是View
2、每次在getView方法中仍会调用View的findViewById()方法来获取一次控件的实例。
可以借助ViewHolder对这部分进行性能优化。
https://i-blog.csdnimg.cn/direct/c2e7c83ee75546debb947de90eaf2373.png#pic_center
这样全部控件的实例都缓存在了ViewHolder中,不需要每次通过findViewById()方法获取控件实例了
5、更强大的滚动部件—RecyclerView

适配器创建好之后,就可以开始使用RecyclerView了,修改MainActivity:
https://i-blog.csdnimg.cn/direct/dc83ce488e7f466da98a45e91514d912.png#pic_center
RecyclerView—实现横向滚动

ListView做不到的事情,那就交给俺RecyclerView来做吧。
首先需要对子项结构fruit_item.xml文件进行修改,让其垂直分列。
https://i-blog.csdnimg.cn/direct/75f2ca033995452392f185995bf62758.png#pic_center
然后只需要在MainActivity中添加一行代码即可让控件横向分列
https://i-blog.csdnimg.cn/direct/fde99025596444c4a2222081bf9656b9.png#pic_center
https://i-blog.csdnimg.cn/direct/fd3f238c3497407fb3b75b104260f72d.png#pic_center
RecyclerView内置结构—StaggeredGirdLayoutManager瀑布流结构

还是先修改fruit_item.xml文件,瀑布流应根据结构的列数主动式主动适配,而不应是固定值
https://i-blog.csdnimg.cn/direct/8725e3d5d60845f0a1546a228fcb441e.png
再在MainActivity中将结构形式改成瀑布流
https://i-blog.csdnimg.cn/direct/94407f77ec684a55a95be02e65da7494.png
                        https://i-blog.csdnimg.cn/direct/3a571ba70856497e8543a2f34593f83f.png                             https://i-blog.csdnimg.cn/direct/c51d8781b8214778be2f47f623cb3143.png
RecyclerView的点击事件

RecyclerView需要我们给子项具体的View去注册点击事件,更加方便为子项恣意控件和结构添加点击事件。这样的话仅需要对适配器进行更改,在适配器中添加相应的点击事件即可。
https://i-blog.csdnimg.cn/direct/fab5f1a99bf0445386964f1bab7c846a.png#pic_center
上述代码分别为最外层结构和ImageView都注册了点击事件,先获取用户点击的position,再通过position拿到相应的Fruit实例。
这样就实现了点击图像和文本时有不同的响应动作。
四、广播

1、广播简介

Android中的广播机制是一种允许应用步伐组件之间进行通讯的方式。广播可以被发送和吸取,而且可以携带信息。这些消息可以是体系事件(如屏幕关闭或开机)或应用步伐定义的事件。广播可以被其他组件吸取并响应,从而实现组件之间的通讯和数据共享。
广播重要可以分为两种:尺度广播、有序广播
https://i-blog.csdnimg.cn/direct/3b542e96264e444c9f8dc6e1e1890b90.png#pic_center
尺度:几乎同时收到这条广播信息
有序:同一时刻只有一个BroadcastReceiver能收到广播信息,而且可以截断广播。
2、吸取体系广播----------动态注册监听时间变化

BroadcastReceiver的创建方法:只需创建一个类,让其继续BroadcastReceiver并重写父类的onReceive()就行了,有广播到来时,onReceive()方法就会得到实行。
https://i-blog.csdnimg.cn/direct/4d8ab7f7cca440e195a178aae23e11d4.png#pic_center
<Android SDK>/platforms/api版本/data/broadcast_actions.txt该路径下可以查看各个广播的字符串action
3、吸取体系广播—静态注册实现开机启动

动态注册有一个缺点,必须在步伐启动之后才能吸取广播,所以注册的逻辑写在onCreate()中。在Android8.0后隐式广播都不允许使用静态注册的方法进行吸取。
原本是通过创建内部类创建的BroadcastReceiver,还可以通过studio快捷创建new->Other
https://i-blog.csdnimg.cn/direct/cfa5d23214ec481f9370252a50375e4f.png#pic_center
静态的BroadcastReceiver必须在AndroidManifest.xml文件中(标签内)进行注册才能够使用。
https://i-blog.csdnimg.cn/direct/df17bbaef27c47989f2da1ea477ec27b.png#pic_center
enabled:是否启用这个BroadcastReceiver
exported:是否允许BroadcastReceive吸取本步伐以外的广播
在标签中声明相应的action
为掩护用户设备的安全和隐私,对于用户说是一些比较敏感的操纵。必须在AndroidManifest.xml文件中(<application>标签外)进行权限的声明。
https://i-blog.csdnimg.cn/direct/015af3340f2842c0a3df549183efccfa.png#pic_center
3、发送自定义广播—尺度广播

发送广播之前,先定义一个BroadcastReceiver来吸取广播,不然发出去也是白发。
https://i-blog.csdnimg.cn/direct/cee82bd803d247dc91abd89756e33de4.png#pic_center
https://i-blog.csdnimg.cn/direct/979b8d79473d45f2b629137959f325b7.png#pic_center
https://i-blog.csdnimg.cn/direct/07f006e2e5854502a4f80f50a106129c.png#pic_center
静态注册的BroadcastReceiver是无法吸取隐式广播的。而我们发送的自定义广播每每都是隐式广播。因此肯定要使用setPackage()方法来指定这条广播室发送给哪个应用步伐的,从而让其变成一条表现广播。
4、发送自定义广播—有序广播

https://i-blog.csdnimg.cn/direct/b1764171cd3b4e8c9fdee829a3214f2d.png
https://i-blog.csdnimg.cn/direct/c79ae7b9ee5a4958870e07ebac89fb87.png#pic_center
点击按钮后,会弹出两次信息,因为在MyBroadcastReceiver和OtherBroadcastReceiver中都吸取到了发送的广播,但如今发送的仍旧是尺度广播。
修改MainActivity,让其发送的广播变成有序广播:
https://i-blog.csdnimg.cn/direct/13bb8d33231b48a5ae4caf2e22fc19e7.png#pic_center
参数1:仍是Intent
参数2:权限干系,直接传null
如今已经是有序广播了,但是看起来好像和尺度广播没有区别,这是因为有序广播还没有进行广播截断。
怎样设定BroadcastReceiver的先后次序呢???必然是在注册的时间设置优先级!!!
https://i-blog.csdnimg.cn/direct/828405e8dc3e4a419bc030803a027c2c.png#pic_center
优先级越高就先越先收到广播
https://i-blog.csdnimg.cn/direct/a9f693c7c6aa4840b69a705877c5c717.png#pic_center
onReceive()方法中调用的abortBroadcast()方法表现将广播截断。
再次点击发送按钮,只有MyBroadcastReceiver中能够Toast出信息。
5、广播的最佳实践—实现强制下线功能

账号在别的设备上登录时,常常会出现强制下线。思绪很简单,就是在页面上弹出一个对话框,用户无法取消对话框,只能点击对话框中的“确认”按钮,强制返回到登录页面即可。
强制下线功能需要先关闭全部的Activity,然后回到登录页面。
先创建一个类用来管理全部的Activity:
https://i-blog.csdnimg.cn/direct/af5c550476ff49d68a9399794737cca3.png#pic_center
然后创建一个类作为全部Activity的父类:
https://i-blog.csdnimg.cn/direct/06c40d9e38fb4754b3b724d980f776b9.png#pic_center
先做一个简单的模拟登录的功能,创建一个LoginActivity让其继续BaseActivity:
https://i-blog.csdnimg.cn/direct/28fe074535614eb4ac24d66b28f6ec75.png
MainActivity就是登录成功后的主页面,主页面不需要什么功能,只需要加入一个强制下线功能即可。
在MainActivity中,通过监听点击按钮事件用于触发强制下线功能。
https://i-blog.csdnimg.cn/direct/64441400dd2d417c8665094647b48baf.png
可以发现强制用户下线的逻辑并没有写在MainActivity中,而是应该写在吸取这条广播的BroadcastReceiver中。这样强制下线的功能就不会依附于任何页面,不管是在步伐的任何地方,只要发出这样的一条广播,都可以完成强制下线的功能。
BroadcastReceiver中需要弹出一个对话框来阻止用户操纵,但如果创建一个静态注册的BroadcastReceiver是没有办法在onReceive()方法中弹出对话框这样的UI控件,而显然也不可能在每个Activity中注册一个动态的BroadcastReceiver,所以该怎么办呢???????
只需要在BaseActivity(全部Activity的父类)中动态注册一个BroadcastReceiver,代码如下:
https://i-blog.csdnimg.cn/direct/5bb064833aec4b5c90c9b21bfb513714.png#pic_center
https://i-blog.csdnimg.cn/direct/5b859441c9234ac7805e5326b2653a51.png#pic_center
发现了吗,注册和取消注册原本是写在onCreate和onDestory中的,但是如今写在了onResume和onPause中,这是因为我们始终需要保证只有处于栈顶的Activity才能吸取到这条强制下线广播,非栈顶的Activity不应该也没须要吸取这条广播。
自此,强制下线的逻辑已经完成,下面需要在AndroidManifest.xml中修改主启动Activity
https://i-blog.csdnimg.cn/direct/07d138d26b5d497daa75612fb6dac5ed.png#pic_center


https://i-blog.csdnimg.cn/direct/4687b97dd1bd47e3bff2796fbc334401.png#pic_center
五、通知

1、使用通知

发出通知后,手机状态栏会有一个通知的图标,下拉状态栏可以看到具体的内容。
Android8.0后引入了通知渠道的概念,就是每条通知都要属于一个对应的渠道。但是通知渠道的控制权在用户的手中,而且通知渠道一旦创建,开发者就无法修改。
https://i-blog.csdnimg.cn/direct/dc817e0835624d54a14321ef50af2650.png#pic_center
需要一个NotificationManager对通知进行管理,可以调用Context的getSystemService()方法获取,方法吸取 一个字符串用于确定获取体系的哪个服务。
然后使用NotificationChannel类构建一个通知渠道,通过调用NotificationManager的createNotificationChannel()方法完成创建。
该类和方法都是Android8.0新增的API,故要进行版本判断
通知渠道的创建至少需要渠道ID、渠道名称、重要等级这3个参数。渠道ID可随意定义但要保证唯一。渠道名称是展示给用户的。重要等级重要有IMPORTANCE_HIGH、IMPORTANCE_DEFAULT、IMPORTANCE_LOW、IMPORTANCE_MIN,重要程度由高到低。
创建通知首先需要 一个Builder构造器来创建Notification对象,未办理Android体系API不稳固的问题,使用AndroidX库中提供的NotificationCompat类创建Notification对象。Builder()构造函数中吸取两个参数,参数1是Context上下文,参数2是渠道ID,需要和在创建通知渠道时指定的渠道ID相匹配才可以。在最终的build()方法之前还可以连缀恣意多的设置方法丰富Notification对象。
在全部工作完成之后,只需调用NotificationManager的notify()方法就能通知表现出来。该方法吸取两个参数,参数1是id,要保证每个通知的id是不同的,参数2是一个Notification对象。
https://i-blog.csdnimg.cn/direct/efefc82690d94cdca6de02448b5a7ef4.png#pic_center
此时的通知是不能点击的,想要实现点击效果,需要借助与Intent相似的PendingIntent
PendingIntent和Intent都可以用于启动Activity、启动Service、发送广播。不同的是Intent倾向于立即实行实行某个动作,而PendingIntent倾向于在某个合适的时机实行某个动作。
PendingIntent提供了几个静态方法用于获取该实例,根据情况选择使用getActivity()、getBroadcase()、getService()方法,这些方法都是吸取4个参数,参数1为Context上下文,参数2是一样平常用不到,直接传入0,参数3是一个Intent对象,可以通过这个对象构造出PendingIntent的意图。参数4用于确定PendingIntent的行为,有FLAG_ONE_SHOT、FLAG_NO_CRETE、FLAG_CANCEL_CURRENT、FLAG_UPDATE_CURRENT四个值可选,通常直接传入0
NotificationCompat.Builder这个构造器还可以连缀一个setContentIntent()方法,吸取的参数恰好是一个PendingIntent对象,因此构造出一个延迟实行的意图,当用户点击通知的时间就可以启动NotificationActivity。
修改MainActivity代码:
https://i-blog.csdnimg.cn/direct/38549e1af4d84b11820a5e571e8710d5.png#pic_center
点击按钮跳转后,状态栏上的通知图标还没有消失,这显然是不是很合理的额,办理方法有两种,一种就是在NotificationCompat.Build中再连缀一个setAutoCancel()方法,另一种是显式的调用NotificationManager的cancel()方法进行取消。
https://i-blog.csdnimg.cn/direct/d0ae3aa528c2434ba164739326aba855.png#pic_center
2、通知的进阶本事

NotificationCompat.Build中有很丰富的API,可以创造出多样的通知效果。
setStyle()方法允许我们构造出富文本的通知内容,该方法吸取一个NotificationCompat.Style参数,该参数用来构建富文本信息,如长笔墨、图片等。
在通知中如果信息文本太长,则不能全部加载完全,这时就可以借助setStyle()方法了。
https://i-blog.csdnimg.cn/direct/a60c7673c9fe4088a961f9d45e2dcbf2.png#pic_center
除了表现长笔墨以外,还可以表现一张大图片:
https://i-blog.csdnimg.cn/direct/34611deeaa7a41cfa7b8b2c8a823764f.png#pic_center
通过BitmapFactory的decodeResource()方法将图片剖析成Bitmap对象,再传入bigPicture()方法中。
不同重要等级的通知渠道对通知的行为有不同的影响。等级越高越容易引起用户注意。
Tips:开发者只能在创建通知渠道的时间指定初识的重要等级,用户可以随时修改,但开发者无权调解修改(不可以通过代码修改)。
https://i-blog.csdnimg.cn/direct/ef040bc2b9444594b6385c567fbc5bab.png#pic_center
https://i-blog.csdnimg.cn/direct/68f6625c3ee443b182499ffb5c4d1740.png#pic_center
六、Service

Service是什么?????
Service是Android中实现步伐配景运行的办理方案,非常适合实行那些不需要和用户交互而且还要求长期运行的使命。Service的运行不依赖任何用户页面,而且Service并不是运行在一个独立的进程当中的,而是依赖于创建Service时所在的应用步伐进程,当某个应用进程被杀掉时,所以依赖于该进程的Service也会克制。
Service不会主动开启线程,全部的代码都是默认运行在主线程当中的,所以我们需要在Service内部手动创建子线程,并在这内里实行具体的使命,否则就有可能会出现主线程被壅闭的情况。
1、Android多线程编程—线程基本用法

a、继续的方式(耦合较高,不推荐)
https://i-blog.csdnimg.cn/direct/f99b7a98091c4b3a85ee240ec58fde11.png
b、Runnable接口定义一个线程
https://i-blog.csdnimg.cn/direct/38c533a789204846abdd288a5f33cd9a.png
c、如果不想专门定义一个类去实现Runnable接口, 可以使用Lambda方式
https://i-blog.csdnimg.cn/direct/d9fae99506cf400a86577e0c82531180.png
d、otlin还提供了一种更加简单的开启线程的方式,这里的thread是一个Kotlin内置的顶层函数。
https://i-blog.csdnimg.cn/direct/8c7ab4a3871947318fdb87d549a5cf4c.png
2、Android多线程编程—在子线程中更新UI

Android 的UI 是线程不安全的, 更新应用步伐的UI元素, 必须在主线程中进行, 否则会出现异常。如果在子线程中直接更新UI,会出现瓦解。
https://i-blog.csdnimg.cn/direct/bdee8db2c792415c9af96cc7f4ec1c20.png#pic_center
https://i-blog.csdnimg.cn/direct/72c284de035b4b8fb46e0aa624cd825a.png#pic_center
问:Android不允许在子线程中进行UI操纵,但偶然我们必须在子线程中实行一些耗时的使命,然后跟使命的实行效果来更新相应的UI控件,这该怎么办????????
答:Android中提供了一套异步消息处置惩罚机制,完美办理了在子线程中进行UI操纵的问题。
https://i-blog.csdnimg.cn/direct/c0fc626b285d4905b33cbc9566c8912d.png#pic_center
这并没有在子线程中直接进行UI操纵,而是创建了一个Message对象进行操纵的。先指定Message的what字段的值,然后调用Handler的sendMessage方法将Message发送出去。很快Handle就会收到这条Message并在handleMessage()中进行处置惩罚。
由于Handler的构造函数中传入了Looper.getMainLooper(),此时handleMessage()方法中的代码就是在主线程中运行的了,所以可以放心的进行UI操纵。
3、Android多线程编程—剖析异步消息处置惩罚机制

Android中的异步消息重要由4部分构成:Message、Handler、MessageQueue、Looper。
1、Message:在线程之间传递消息,可以携带少量的信息进行线程之间传递数据。what、arg1、arg2字段可以携带少量的整形数据,obj字段可以携带一个Object对象。
2、Handler:用于发送和处置惩罚消息,发送消息使用Handler的sendMessage()或post()方法等。
发出的消息会传递到Handler的handleMessage()方法中。
3、MessageQueue:消息队列,用于存放全部通过Handler发送的信息,在消息队列中等待被处置惩罚,每个线程只有一个MessageQueue对象。
4、Looper:每个线程中MessageQueue的管家,调用Looper的loop()方法后就会进入到一个无穷循环中,每当发现MessageQueue中存在消息时就将其取出并传递到handleMessage()方法中,每个线程只有一个Looper对象。
4、Android多线程编程—使用AsyncTask

AsyncTask背后的实现原理也是基于异步消息处置惩罚机制的额,只是Android做了很好的封装。
AsyncTask是一个抽象类,要使用它就必须要创建一个类去继续它,在继续时可以为其指定3个泛型参数:
1、Params。在实行AsyncTask时需要传入的参数,可用于在配景表现。
2、Progress。在配景使命实行时,若需要在页面上表现当前的进度,则使用这里指定的泛型作为进度单位。
3、Result。使命实行完毕后,若要对效果进行返回,则使用这里指定的泛型作为返回值类型
class DownloadTask :AsyncTask<Unit, Int, Boolean> () {

}
当前是一个空使命,无任何现实操纵,需要重写4个方法:
1 onPreExecute() 在使命实行前调用,用于初始化操纵
2 doInBackground(Params…) 在子线程中实行, 实行具体耗时使命
3 onProgressUpdate(Progress…) 配景使命调用,进行UI操纵
4 onPostExecute(Result) 配景使命实行完毕并通过return返回时, 收尾工作
要启动这个使命,DownloadTask().execute(),也可以为execute()方法传入恣意数量的参数,这些参数会传递到doInBackground()中。
5、Service基本用法----定义一个Service

https://i-blog.csdnimg.cn/direct/51c4358a6c4a44eab9652bbde1721cde.png#pic_center
定义了MyService,继续于Service,onBind()方法是Service中唯一的抽象方法,必须在子类中实现。
onCreate()方法会在Service创建的时间调用,
onStartCommand()方法会在每次Service启动的时间调用,
onDestroy()方法会在Service烧毁的时间调用。
注:每个Service都需要在AndroidManifest.xml文件中进行注册(<application>标签内注册)才能见效
https://i-blog.csdnimg.cn/direct/73927b5cc6904ab68b37205d3676d082.png#pic_center
6、Service基本用法----启动和克制Service

Service的启动和克制重要是借助Intent实现的。
https://i-blog.csdnimg.cn/direct/09d8bf378ce34f3abe84c0748e2f7e8d.png#pic_center
stratService()和stopService()都是定义在Context类中的,可以直接在Activity中直接调用。别的,Service也可以自我克制,只需在Service内部调用stopSelf()即可。
https://i-blog.csdnimg.cn/direct/5e4f8ca0dc384f899ea8faac0b6373f9.png#pic_center
7、Service基本用法----Activity与Service进行通讯

虽然Service是在Activity中启动的,但是点那个Service启动后,Activity与Service好像就没什么关系了,Service一直处于运行状态,具体运行的什么逻辑,Activity控制不了。
借助Service中的唯一抽象方法onBind()可以使其关系更加紧密。
比如说,盼望在MyService里提供一个下载功能,然后在Activity中可以决定何时开始下载,以及随时查看下载进度。实现这个功能的思绪是创建一个专门的Binder对象来对下载功能进行管理。修改MyService中的代码,如下所示:
https://i-blog.csdnimg.cn/direct/e1d8ed6cc0064d50b9f2a8cbf383a16c.png#pic_center
1、创建了一个DownloadBinder类并继续于Binder类,内部提供了开始下载和查看下载进度两个模拟方法。
2、在MyService中创建了DownloadBinder实例
3、在onBind()方法中返回了实例
当一个Activity与Service绑定了之后,就可以调用该Service中的Binder提供的方法了。
https://i-blog.csdnimg.cn/direct/1b9c9660427e47f296c220f21a33bba4.png#pic_center
1、创建了ServiceConnection匿名类实例并重写了方法。
onServiceConnected()方法会在Activity与Service成功绑定的时间调用,onServiceDisconnected()方法只有在Service的创建进程瓦解或者被杀掉的时间才会调用。
2、通过向下转型得到了DownloadBinder实例。关系变的非常亲密。
如今就可以在Activity中根据具体的情景调用DownloadBinder中任何public方法,即实现了指挥Service干什么Service就去干什么,这里只是做了测试。
bindService()方法将Activity与Service进行绑定,该方法吸取3个参数
参数1为Intent对象。参数2为创建出的ServiceConnection实例。
参数3是一个标志位,传入BIND_AUTO_CREATE表现绑定后主动创建
Service,这会使得MyService的onCreate()实行而onStartCommand()不会实行
点击Activity与Service绑定按钮:
https://i-blog.csdnimg.cn/direct/0367889d71f145c0a54d3b37bed39e52.png#pic_center#pic_center
startDownload和getProgress方法都得到了实行,说明Activity成功调用了Service中的方法。
点击Activity与Service解绑按钮:
https://i-blog.csdnimg.cn/direct/6c1e540276bd44e987ef95c9b2afdd2d.png#pic_center
注:任何一个Service在整个应用步伐范围内都是通用的,即MyService可以与任何一个Activity进行绑定,而且在绑定完成后,它们都可以获取相同的DownloadBInder实例。
8、Service的更多本事----使用前台Service

只有应用保持在前台可见状态下,Service才能保证稳固运行,一旦应用进入配景之后,Service就随时有可能被体系回收。
前台Service和平凡Service最大的区别就在于,它会一直有一个正在运行的图标在体系的状态栏表现,下拉状态栏后可以看到更加具体的信息,非常类似于通知的效果。
由于状态栏中一直有一个正在运行的图标,相当于我们的应用以别的一种形式保持在前台可见状态,所以体系不会倾向于回收前台Service。
修改MyService中的onCreate()方法:
https://i-blog.csdnimg.cn/direct/5c676e3a77664aa8baff6b8a31658e99.png#pic_center
这其实就是前面所讲的通知的设置,只不过这次在构建Notification对象后没有使用NotificationManager将通知表现出来,而是调用了startForeground()方法。参数1是通知的id,参数2是构建的Notification对象。调用startForeground()方法后就会让MyService变成一个前台Service,并在状态栏表现出来。
使用前台Service必须在AndroidManifest.xml文件中进行权限声明才行:
https://i-blog.csdnimg.cn/direct/7b836c50e7b04e328b1caa1079050acd.png#pic_center
9、Service的更多本事----使用IntentService

Service中的代码都是默认运行在主线程当中的,如果直接在Service中处置惩罚一些耗时的逻辑,就很容易出现ANR(Application Not Responding)。
所以就需要用到Android多线程编程技能,应该在Service的每个具体的方法里开启一个子线程,在这里处置惩罚耗时的逻辑。
故:一个尺度的Service就可以写成如下形式:(仅展示MyService的一个方法)
https://i-blog.csdnimg.cn/direct/2848cf91c7c748f4b42ece212ff0ea57.png
Service一旦启动就会一直处于运行状态,所以必须调用stopService()或stopSelf()方法或者被体系回收,Service才会克制。
虽然写法比较简单,但是开启线程或者调用stopSelf()都是比较容易忘记的。
Android提供了一个IntentService类,可以很好的办理这种问题。
https://i-blog.csdnimg.cn/direct/9ed198c4fb76449a89e12885657b9c39.png#pic_center
https://i-blog.csdnimg.cn/direct/42317c660a274fd59a27a1240bb84601.png#pic_center
https://i-blog.csdnimg.cn/direct/ab5ff67e544140a0bca552c0954e4455.png#pic_center
IntentService有个特性就是Service在运行竣事后应该是会主动克制的。日记打印也验证了。
Tip:记得去AndroidManifest.xml文件中对Service进行注册。
https://i-blog.csdnimg.cn/direct/a64dcdd0bf554a5980f265f6acc80849.gif#pic_center

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: Android---Kotlin语言基础快速入门(看图详解版!!!)