ToB企服应用市场:ToB评测及商务社交产业平台

标题: Android---Kotlin语言基础快速入门(看图详解版!!!) [打印本页]

作者: 花瓣小跑    时间: 2024-11-20 03:18
标题: 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、“?:”:操纵符左右两边都吸取一个表达式,若左表达式的效果不为空就返回左边表达式的效果,否则返回右边表达式的效果。
       

3、偶然间编写的代码会存在空指针风险,实时是已经做了非空检查,但是扔无法编译通过,若想强行通过编译,可以使用非空断言工具,写法是在对象背面加上”!!” 。就是告诉Kotlin,我非常确信这里的对象不会为空,不用帮我做空指针检查,如果出现问题,直接抛出空指针异常。

4、”let”:既不是操纵符也不是关键字,而是一个函数,提供了函数式API的编程接口,并将原始调用对象作为参数传递到Lambda表达式中。

调用obj对象的let函数,然后Lambda表达式中的代码会立即实行,而且这个obj对象自己会作为参数传递到Lambda表达式中。为防止变量重名,参数名改成了obj2,现实上他们是同一个对象。
Lambda表达式参数列表中只有一个参数时,可以不声明参数名,直接用it关键字取代即可
   
 

let函数可以处置惩罚全局变量的判空问题,而if判断语句无法做到。
c.基础知识—尺度函数with、run、apply

  1. Kotlin中的标准函数指的是Standard.kt文件中定义的函数,可以自由的调用
复制代码
1、with函数
吸取两个参数,参数1可以是一个恣意类型的对象,参数2是一个Lambda表达式。with函数会在Lambda表达式中提供第一个参数对象的上下文,并使用Lambda表达式中的最后一行代码作为返回值返回。
2、run函数
run函数一样平常不会直接调用,而是要在某个对象的基础上调用。run函数只吸取一个Lambda参数,而且会在Lambda表达式中提供调用对象的上下文,其他和with函数相同。
3、apply函数
要在某个对象上调用,只吸取一个Lambda函数,也会在Lambda表达式中提供调用对象的上下文,但是apply函数无法指定返回值,而是会主动返回调用对象自己。
下面举个例子哈:
1、
     2、

3、
     4、

上面四种运行方式的效果最终都是相同的,效果如下:

二、Activity

A:初识Activity

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

简介:Toast用来进行页面文本提示,表现一段时间后自行消失,可以给用户进行通知。
用法:

参数1:Context。是Toast的上下文,Activity自己就是一个Context对象。
参数2:text,就是要弹出的文本内容。
参数3:Toast表现的时间长短,有Toast.LENGTH_LONG和Toast.LENGTH_SHORT可选。
许多初学者很容易忘记.show()的使用,将文本表现出来。

C:Menu菜单栏

简介:我们在手机的右上角常常看到的3个小点点,就是我们这里所要介绍的Menu,点击三个点后,就可以看到内里所表现的内容。
用法:在res目录下新建menu文件夹,并创建名为‘main’的menu文件

<item>标签用于创建具体的菜单项
在Activity中重写方法,实现Activity菜单的创建

         
       

inflate()第一个参数指定通过哪个资源文件创建菜单,第二个参数指定将菜单项添加到哪一个Menu
  1. 定义出来的菜单还需要实现菜单的响应事件
  2. 那么可以在MainActivity中重写onOptionsItemSelected()方法实现点击监听
复制代码

item.itemId时间上就是调用的item的getItemId()方法--------语法糖
D:Activity跳转—Intent

方法一:表现Intent

所谓表现Intent就是在Activity中通过Intent构造函数进行参数传递实现。

Tips:在获取button2这个按钮的时间并没有通过findViewById(R.id.xxx),而是通过视图绑定的方法进行完成的。这的条件是需要在build.gradle(:app)中提进步行配置。并在Activity中进行Layout文件的绑定。

方法二:隐式Intent

隐,就是很含蓄,不会明白指出跳转到哪个Activity,而是在AndroidManifest进行配置。

注:只有和中的内容同时匹配Intent中的action和category,Activity才会响应Intent
注:每个Intent只能有一个action但是可以有多个category

Activity跳转—隐式Intent扩展

1、网页跳转


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、拨打电话


3、也可以通过geo表现地理位置


也可以进行发送邮件,总而言之,隐式Intent的功能是很强大的。
向下一个Activity传递数据

思绪:Intent中又一系列的putExtra()方法的重载,可以先将数据暂存在Intent中,在启动另一个Activity的时间将数据取出即可。



返回数据给上一个Activity

问:返回上一个Activity只需按下Back键,但并没有用于启动Activity的Intent来传递数据,这该怎么给上一个Activity返回数据呢?
答:其实Activity类还有一个用于启动Activity的startActivityForResult()方法,它期望Activity烧毁的时间返回一个效果给上一个Activity。

参数1:Intent
参数2:请求码,用于之后回调中判断数据的来源

setResult方法专门用于向上一个Activity返回数据


问:如果不点击button按钮返回到上一个Activity,直接按下Back键,这样数据还能返回吗????
答:自然是不可以的。但是可以在Activity中重写onBackPressed()方法办理这个问题。

方法还是那个方法,只是重写了onBackPressed()方法进行响应按下Back键这个动作。
E:Activity最佳启动方法

假设在启动SecondActivity时需要两个非常重要的参数,风俗性在MainActivity的写法如下:

这么写确实没毛病,但是在项目对接中容易不清楚传递哪些数据,是很贫苦的。那么换一种方法,在SecondActivity中添加如下代码:

Kotlin规定,全部定义在companion object中的方法都可以使用类似于Java静态方法形式的调用。
在MainActivity中只需要一行代码就可以启动SecondActivity并传递参数

F:Activity生命周期—状态和生存期

Android中的Activity是可以层叠的,每次启动一个Activity就会覆盖在原来的Activity之上,按下Back键就会烧毁最上面的运动,这是通过栈来实现的。

  1. 每个Activity最多有4种状态:运行状态、暂停状态(仍可见)、停止状态、销毁状态
  2. Activity中有7个回调方法:
  3. 1、onCreate()  会在Activity第一次被创建的时候调用,常用于初始化、加载布局、绑定事件
  4. 2、onStart()     Activity由不可见变为可见时调用
  5. 3、onResume()  Activity准备好和用户交互时调用,此时Activity一定处于栈顶  
  6. 4、onPause()  在系统准备去启动或者恢复另一个Activity的时候进行调用
  7. 5、onStop()   Activity完全不可见的时候进行调用(停止状态)
  8. 6、onDeatory()  Activity在被销毁之前进行调用
  9. 7、onRestart()  Activity在重新启动的时候(停止-->运行状态)之前调用
  10. 完整生存期:onCreate() 与onDeatory() 之间
  11. 可见生存期:onStart()与onStop() 之间
  12. 前台生存期:onResume()与onPause() 之间
复制代码
为更好理解Activity的生命周期,下面提供了表现图

下面进行体验一下Activit生命周期在操纵器件到底是怎么变化的!!!
条件:创建两个Activity,分别是NormalActivity(平凡)和DialogActivity(对话框)
在AndroidManifest.xml文件下进行配置,将Activity设置为对话框模式。

在MainActivity中设置页面跳转逻辑,并重写生命运动的方法
    

效果分析:
1、第一次创建MainActivity

2、启动NormalActivity

3、back

4、启动DialogActivity

5、back

6、back

G:Activity被回收了怎么办?????

我们知道啊,当Activity进入了克制状态,如果内存空间不敷的话,是有可能被体系回收的,那这种现象是有些可骇的!那怎么办呢?
Activity中提供了一个onSaveInstanceState()回调方法,会携带一个Bundle类型的参数,Bundle提供了一系列的方法用于生存数据,可以保证在Activity在回收之前肯定会被调用。
在MainActivity中添加下边的代码,就可以将数据生存下来:

怎么取值规复呢???
其实onCreate()方法也有一个Bundle类型的参数,一样平常是null,但是Activity被体系回收之前,通过onSaveInstanceState()方法生存数据,这个参数就会带有之宿世存的全部数据。
在MainActivity中添加下面代码,取出值后再做相应的规复就行了。

H:Activity的启动模式

1、standard

这就是Activity默认的启动模式,每启动一个Activity就会放入栈顶,不管栈中是否存在该Activity,都会创建一个新的该Activity的实例。
比如,我们在MainActivity中编写如下代码,进行启动MainActivity自己(无现实意义)



2、singleTop

在启动Activity时如果发现返回栈的栈顶已经是该Activity,则可以直接使用,是不需要再重新创建新的Activity实例的。
首先需要对AndroidManifest.xml文件进行修改

重新运行步伐,并多次点击按钮,发现不会创建新的实例对象啦。

那如果MainActivity并没有在栈顶的位置,再次启动MainActivity会创建新的实例的。
例:修改MainActivity

修改SecondActivity



3、singleTask

对于singleTop而已,如果Activity没有处于栈顶,还是可能会创建多个Activity实例的,而singleTask模式就可以做到让某个Activity在整个应用步伐的上下文只有一个实例。
其实原理很简单,就是每次启动该Activity时,体系先去栈中检查是否存在该Activity的实例,如果存在,就将该Activity之上的全部Activity全部出栈,不存在就创建。
首先还是修改AndroidManifest.xml文件:

在MainActivity中重写onRestart()方法
在SecondActivity中重写onDestroy()方法
     
       

4、singleInstance

指定为singleInstance模式的Activity会启动一个新的、单独的返回栈来管理这个Activity
可以将SecondActivity启动模式设置为singleInstance模式(修改.xml文件,不多说了)
修改一下MainActivity中的代码,进行打印当前返回栈的id:

(上述taskId现实上是调用的父类的getTaskID()方法)
同样的方法,在SecondActivity、ThirdActivity中打印taskId(返回栈的id),并实现MainActivity—>SecondActivity—>ThirdActivity的页面跳转逻辑:


三、常用控件以及基本结构

1、常用控件

(1)、TextView

很简单,就是在页面上表现笔墨信息。

id:唯一标识
layout_width:宽
layout_height:高
gravity:指定笔墨的对齐方式,可选值有top、bottom、start、end、center等,可以用“|”同时指定多个值。center表现效果等同于center_vertical|center_horizon
textColor:笔墨颜色
textSize:笔墨大小,单位用sp表现
text:文本内容

(2)、Button


textAllCaps:Button按钮文本中的英文默认大写表现,false表现保存原始笔墨内容。

Button按钮的监听方式:
①在MainActivity中为Button按钮注册监听器

②使用实现接口的方式进行注册

(3)、EditText

允许用户输入信息的文本框。

hint:输入框中的提示笔墨,只要输入内容就会消失。
maxLines:指定EditText的最大行数,输入的内容凌驾行数时,文本就会向上滚动,EditText就不会再继续拉伸。

还可以与Button按钮联动,获取输入框中输入的内容。
调用toString()方法将获取的内容转换成字符串、
(4)、ImageView

用于在页面上展示图片。
               
            

此外,与Button按钮进行联动可以动态的修改图片资源

(5)、ProgressBar

用于在页面上表现一个进度条,表现步伐正在加载数据。
怎么让旋转的进度条消失呢?用到一个全部Android控件都有的一个属性android:visibility,可选值有visible、invisible、gone三种,默认是visible,invisible表现不可见但仍占据页面空间,gone表现不可见而且不占据屏幕的任何空间。
Button按钮与进度条显隐联动:

将圆形进度条更改为程度进度条,通过max属性还可以动态的更改进度条的进度:

(6)、AlertDialog

在当前页面弹出对话框,置于全部页面元素之上,能屏蔽其他组件的交互:
       

2、基本结构

(1)、LinearLayout

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

(2)、RelativeActivity

看名字就知道是相对结构,比较随意分列

每个控件都是相对于父结构进行的,下面演示相对于控件进行定位:

android:layout_alignLeft表现让一个控件与另一个控件的左边沿对齐
同理还有:
android:layout_alignRight
android:layout_alignTop
android:layout_alignBottom
(3)、FrameLayout

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

1、引入结构

在layout文件夹下有一个title.xml结构文件。        

怎么引入结构呢???        只需一条语句:

可以将体系默认的标题栏隐藏:

2、创建自定义控件

引入结构确实方便,但是当控件需要响应事件的时间就需要自定义控件啦


4、Android最常用和最难用的控件—ListView


聚集的数据无法直接传递给ListView,需要用到适配器完成。
我们这里所引用的子项结构,是Android内置的结构文件,内里只有一个TextView用于表现一段文本。
适配器中传递的三个参数分别是:Activity实例、ListView子项结构id、数据源。
只表现文本是不是有点太单调了呢??我们来点稍微复杂的。
用实体类作为ListView适配器的适配类型:

为ListView的子项指定一个自定义结构

创建一个自定义适配器FruitAdapter,适配器继续自ArrayAdapter,并将泛型指定为Fruit类

接下来在MainActivity创建并添加适配器:





提升ListView的运行服从:

1、在FruitAdapter的getView()方法中,每次都将结构重新加载一遍,服从很低。这可以通过convertView参数优化,该参数用于将之前加载好的结构进行缓存,以便之后重用。

问题:如果使用该参数进行优化的话,好像binding在这个地方是不可以使用的,因为binding吸取到的是FruitItemBinding而convertView吸取到的是View
2、每次在getView方法中仍会调用View的findViewById()方法来获取一次控件的实例。
可以借助ViewHolder对这部分进行性能优化。

这样全部控件的实例都缓存在了ViewHolder中,不需要每次通过findViewById()方法获取控件实例了
5、更强大的滚动部件—RecyclerView

适配器创建好之后,就可以开始使用RecyclerView了,修改MainActivity:

RecyclerView—实现横向滚动

ListView做不到的事情,那就交给俺RecyclerView来做吧。
首先需要对子项结构fruit_item.xml文件进行修改,让其垂直分列。

然后只需要在MainActivity中添加一行代码即可让控件横向分列


RecyclerView内置结构—StaggeredGirdLayoutManager瀑布流结构

还是先修改fruit_item.xml文件,瀑布流应根据结构的列数主动式主动适配,而不应是固定值

再在MainActivity中将结构形式改成瀑布流

                        
                             

RecyclerView的点击事件

RecyclerView需要我们给子项具体的View去注册点击事件,更加方便为子项恣意控件和结构添加点击事件。这样的话仅需要对适配器进行更改,在适配器中添加相应的点击事件即可。

上述代码分别为最外层结构和ImageView都注册了点击事件,先获取用户点击的position,再通过position拿到相应的Fruit实例。
这样就实现了点击图像和文本时有不同的响应动作。
四、广播

1、广播简介

Android中的广播机制是一种允许应用步伐组件之间进行通讯的方式。广播可以被发送和吸取,而且可以携带信息。这些消息可以是体系事件(如屏幕关闭或开机)或应用步伐定义的事件。广播可以被其他组件吸取并响应,从而实现组件之间的通讯和数据共享。
广播重要可以分为两种:尺度广播、有序广播

尺度:几乎同时收到这条广播信息
有序:同一时刻只有一个BroadcastReceiver能收到广播信息,而且可以截断广播。
2、吸取体系广播----------动态注册监听时间变化

BroadcastReceiver的创建方法:只需创建一个类,让其继续BroadcastReceiver并重写父类的onReceive()就行了,有广播到来时,onReceive()方法就会得到实行。

<Android SDK>/platforms/api版本/data/broadcast_actions.txt该路径下可以查看各个广播的字符串action
3、吸取体系广播—静态注册实现开机启动

动态注册有一个缺点,必须在步伐启动之后才能吸取广播,所以注册的逻辑写在onCreate()中。在Android8.0后隐式广播都不允许使用静态注册的方法进行吸取。
原本是通过创建内部类创建的BroadcastReceiver,还可以通过studio快捷创建new->Other

静态的BroadcastReceiver必须在AndroidManifest.xml文件中(标签内)进行注册才能够使用。

enabled:是否启用这个BroadcastReceiver
exported:是否允许BroadcastReceive吸取本步伐以外的广播
在标签中声明相应的action
为掩护用户设备的安全和隐私,对于用户说是一些比较敏感的操纵。必须在AndroidManifest.xml文件中(<application>标签外)进行权限的声明。

3、发送自定义广播—尺度广播

发送广播之前,先定义一个BroadcastReceiver来吸取广播,不然发出去也是白发。



静态注册的BroadcastReceiver是无法吸取隐式广播的。而我们发送的自定义广播每每都是隐式广播。因此肯定要使用setPackage()方法来指定这条广播室发送给哪个应用步伐的,从而让其变成一条表现广播。
4、发送自定义广播—有序广播



点击按钮后,会弹出两次信息,因为在MyBroadcastReceiver和OtherBroadcastReceiver中都吸取到了发送的广播,但如今发送的仍旧是尺度广播。
修改MainActivity,让其发送的广播变成有序广播:

参数1:仍是Intent
参数2:权限干系,直接传null
如今已经是有序广播了,但是看起来好像和尺度广播没有区别,这是因为有序广播还没有进行广播截断。
怎样设定BroadcastReceiver的先后次序呢???必然是在注册的时间设置优先级!!!

优先级越高就先越先收到广播

onReceive()方法中调用的abortBroadcast()方法表现将广播截断。
再次点击发送按钮,只有MyBroadcastReceiver中能够Toast出信息。
5、广播的最佳实践—实现强制下线功能

账号在别的设备上登录时,常常会出现强制下线。思绪很简单,就是在页面上弹出一个对话框,用户无法取消对话框,只能点击对话框中的“确认”按钮,强制返回到登录页面即可。
强制下线功能需要先关闭全部的Activity,然后回到登录页面。
先创建一个类用来管理全部的Activity:

然后创建一个类作为全部Activity的父类:

先做一个简单的模拟登录的功能,创建一个LoginActivity让其继续BaseActivity:

MainActivity就是登录成功后的主页面,主页面不需要什么功能,只需要加入一个强制下线功能即可。
在MainActivity中,通过监听点击按钮事件用于触发强制下线功能。

可以发现强制用户下线的逻辑并没有写在MainActivity中,而是应该写在吸取这条广播的BroadcastReceiver中。这样强制下线的功能就不会依附于任何页面,不管是在步伐的任何地方,只要发出这样的一条广播,都可以完成强制下线的功能。
BroadcastReceiver中需要弹出一个对话框来阻止用户操纵,但如果创建一个静态注册的BroadcastReceiver是没有办法在onReceive()方法中弹出对话框这样的UI控件,而显然也不可能在每个Activity中注册一个动态的BroadcastReceiver,所以该怎么办呢???????
只需要在BaseActivity(全部Activity的父类)中动态注册一个BroadcastReceiver,代码如下:


发现了吗,注册和取消注册原本是写在onCreate和onDestory中的,但是如今写在了onResume和onPause中,这是因为我们始终需要保证只有处于栈顶的Activity才能吸取到这条强制下线广播,非栈顶的Activity不应该也没须要吸取这条广播。
自此,强制下线的逻辑已经完成,下面需要在AndroidManifest.xml中修改主启动Activity




五、通知

1、使用通知

发出通知后,手机状态栏会有一个通知的图标,下拉状态栏可以看到具体的内容。
Android8.0后引入了通知渠道的概念,就是每条通知都要属于一个对应的渠道。但是通知渠道的控制权在用户的手中,而且通知渠道一旦创建,开发者就无法修改。

需要一个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对象。

此时的通知是不能点击的,想要实现点击效果,需要借助与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代码:

点击按钮跳转后,状态栏上的通知图标还没有消失,这显然是不是很合理的额,办理方法有两种,一种就是在NotificationCompat.Build中再连缀一个setAutoCancel()方法,另一种是显式的调用NotificationManager的cancel()方法进行取消。

2、通知的进阶本事

NotificationCompat.Build中有很丰富的API,可以创造出多样的通知效果。
setStyle()方法允许我们构造出富文本的通知内容,该方法吸取一个NotificationCompat.Style参数,该参数用来构建富文本信息,如长笔墨、图片等。
在通知中如果信息文本太长,则不能全部加载完全,这时就可以借助setStyle()方法了。

除了表现长笔墨以外,还可以表现一张大图片:

通过BitmapFactory的decodeResource()方法将图片剖析成Bitmap对象,再传入bigPicture()方法中。
不同重要等级的通知渠道对通知的行为有不同的影响。等级越高越容易引起用户注意。
Tips:开发者只能在创建通知渠道的时间指定初识的重要等级,用户可以随时修改,但开发者无权调解修改(不可以通过代码修改)。


六、Service

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

a、继续的方式(耦合较高,不推荐)

b、Runnable接口定义一个线程

c、如果不想专门定义一个类去实现Runnable接口, 可以使用Lambda方式

d、otlin还提供了一种更加简单的开启线程的方式,这里的thread是一个Kotlin内置的顶层函数。

2、Android多线程编程—在子线程中更新UI

Android 的UI 是线程不安全的, 更新应用步伐的UI元素, 必须在主线程中进行, 否则会出现异常。如果在子线程中直接更新UI,会出现瓦解。


问:Android不允许在子线程中进行UI操纵,但偶然我们必须在子线程中实行一些耗时的使命,然后跟使命的实行效果来更新相应的UI控件,这该怎么办????????
答:Android中提供了一套异步消息处置惩罚机制,完美办理了在子线程中进行UI操纵的问题。

这并没有在子线程中直接进行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


定义了MyService,继续于Service,onBind()方法是Service中唯一的抽象方法,必须在子类中实现。
onCreate()方法会在Service创建的时间调用,
onStartCommand()方法会在每次Service启动的时间调用,
onDestroy()方法会在Service烧毁的时间调用。
注:每个Service都需要在AndroidManifest.xml文件中进行注册(<application>标签内注册)才能见效

6、Service基本用法----启动和克制Service

Service的启动和克制重要是借助Intent实现的。

stratService()和stopService()都是定义在Context类中的,可以直接在Activity中直接调用。别的,Service也可以自我克制,只需在Service内部调用stopSelf()即可。

7、Service基本用法----Activity与Service进行通讯

虽然Service是在Activity中启动的,但是点那个Service启动后,Activity与Service好像就没什么关系了,Service一直处于运行状态,具体运行的什么逻辑,Activity控制不了。
借助Service中的唯一抽象方法onBind()可以使其关系更加紧密。
比如说,盼望在MyService里提供一个下载功能,然后在Activity中可以决定何时开始下载,以及随时查看下载进度。实现这个功能的思绪是创建一个专门的Binder对象来对下载功能进行管理。修改MyService中的代码,如下所示:

1、创建了一个DownloadBinder类并继续于Binder类,内部提供了开始下载和查看下载进度两个模拟方法。
2、在MyService中创建了DownloadBinder实例
3、在onBind()方法中返回了实例
当一个Activity与Service绑定了之后,就可以调用该Service中的Binder提供的方法了。

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绑定按钮:

startDownload和getProgress方法都得到了实行,说明Activity成功调用了Service中的方法。
点击Activity与Service解绑按钮:

注:任何一个Service在整个应用步伐范围内都是通用的,即MyService可以与任何一个Activity进行绑定,而且在绑定完成后,它们都可以获取相同的DownloadBInder实例。
8、Service的更多本事----使用前台Service

只有应用保持在前台可见状态下,Service才能保证稳固运行,一旦应用进入配景之后,Service就随时有可能被体系回收。
前台Service和平凡Service最大的区别就在于,它会一直有一个正在运行的图标在体系的状态栏表现,下拉状态栏后可以看到更加具体的信息,非常类似于通知的效果。
由于状态栏中一直有一个正在运行的图标,相当于我们的应用以别的一种形式保持在前台可见状态,所以体系不会倾向于回收前台Service。
修改MyService中的onCreate()方法:

这其实就是前面所讲的通知的设置,只不过这次在构建Notification对象后没有使用NotificationManager将通知表现出来,而是调用了startForeground()方法。参数1是通知的id,参数2是构建的Notification对象。调用startForeground()方法后就会让MyService变成一个前台Service,并在状态栏表现出来。
使用前台Service必须在AndroidManifest.xml文件中进行权限声明才行:

9、Service的更多本事----使用IntentService

Service中的代码都是默认运行在主线程当中的,如果直接在Service中处置惩罚一些耗时的逻辑,就很容易出现ANR(Application Not Responding)。
所以就需要用到Android多线程编程技能,应该在Service的每个具体的方法里开启一个子线程,在这里处置惩罚耗时的逻辑。
故:一个尺度的Service就可以写成如下形式:(仅展示MyService的一个方法)

Service一旦启动就会一直处于运行状态,所以必须调用stopService()或stopSelf()方法或者被体系回收,Service才会克制。
虽然写法比较简单,但是开启线程或者调用stopSelf()都是比较容易忘记的。
Android提供了一个IntentService类,可以很好的办理这种问题。



IntentService有个特性就是Service在运行竣事后应该是会主动克制的。日记打印也验证了。
Tip:记得去AndroidManifest.xml文件中对Service进行注册。


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4