Android开发

Android

Adapter是将数据绑定到UI界面上的桥接类
比如:

当lambada中只有一个参数时,可以用it指代

@Target和@Retention是由Java提供的元注解,所谓元注解就是标记其他注解的注解,下面分别介绍
https://blog.csdn.net/javazejian/article/details/71860633#%E5%A3%B0%E6%98%8E%E6%B3%A8%E8%A7%A3%E4%B8%8E%E5%85%83%E6%B3%A8%E8%A7%A3

activity是UI界面的抽象,而application是应用程序的抽象。

一个 app应用只会存在一个Application,它的生命周期是只要 app不被进程kill掉,则一直存在。所以初始化 一些系统级变量或者方法的时候要在 Application 的onCreate 方法中完成。

data class
data class算是Kotlin中一大闪光点,data class就是一个类中只包含一些数据字段,类似于vo,pojo,java bean。一般而言,我们在Java中定义了这个数据类之后要重写一下toString,equals等方法。要生成get,set方法。

然而在Kotlin中这些都不在需要自己手动去敲了,编译器在背后默默给我们生成了如下的东西:

equals()/hashCode()
toString()方法
componentN()方法
copy()方法

在申明一个 data class 有一些需要注意的事项。

主构造函数必须要至少有一个参数
主构造函数中的所有参数必须被标记为val或者var
数据类不能有以下修饰符:abstract,inner,open,sealed
data class只能实现接口(Kotlin1.1以前的规则),现在也可以继承其它类

https://blog.csdn.net/zhaoyanjun6/article/details/94649274

retrofit
以使用刚才所学的@Path注解的方式来解决,但是这样会有些麻烦,Retrofit针对这种带参数的
GET请求,专门提供了一种语法支持:
interface ExampleService {
@GET(“get_data.json”)
fun getData(@Query(“u”) user: String, @Query(“t”) token: String): Call
}
这里在getData()方法中添加了user和token这两个参数,并使用@Query注解对它们进行声
明。这样当发起网络请求的时候,Retrofit就会自动按照带参数GET请求的格式将这两个参数构
建到请求地址当中。

单例类
object
函数都可以静态调用,因为构造方法私有化,外界无法new,只得通过函数访问,所以函数在kotlin中默认是静态的,不想被外界访问加private

然单例模式也有很多种写法,这里就演示一种最常见的Java写法吧:
public class Singleton {
private static Singleton instance;
private Singleton() {}
public synchronized static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
public void singletonTest() {
System.out.println(“singletonTest is called.”);
}
}
这段代码其实很好理解,首先为了禁止外部创建Singleton的实例,我们需要用private关键
字将Singleton的构造函数私有化,然后给外部提供了一个getInstance()静态方法用于获
取Singleton的实例。在getInstance()方法中,我们判断如果当前缓存的Singleton实例
为null,就创建一个新的实例,否则直接返回缓存的实例即可,这就是单例模式的工作机制。
而如果我们想调用单例类中的方法,也很简单,比如想调用上述的singletonTest()方法,
就可以这样写:
Singleton singleton = Singleton.getInstance();
singleton.singletonTest();

匿名类
object
或object:(所实现的类名)+(构造参数){函数}

lambda
定义函数

内联函数
第一行代码 320页

const val /var

const val ->public static (Const ‘val’ are only allowed on top level or in objects)
val -> private static(当作public final static )
var ->private(当作public final)

var 和 val 实质是private 但是可以当做public使用,是由于kotlin的语法糖

private val/ private var 是真正的private即没有get/set方法

https://blog.csdn.net/sinat_31057219/article/details/90142204

协程

549页
GlobalScope.launch{} 程序结束不依赖这个
runBlocking{} 这个运行完才往下执行
runBlocking函数通常只应
该在测试环境下使用,在正式环境中使用容易产生一些性能上的问题。

创建多个协程呢?很简单,使用launch函数就可以了
注意这里的launch函数和我们刚才所使用的GlobalScope.launch函数不同。首先它必须在
协程的作用域中才能调用,其次它会在当前协程的作用域下创建子协程。子协程的特点是如果
外层作用域的协程结束了,该作用域下的所有子协程也会一同结束。相比而言,
GlobalScope.launch函数创建的永远是顶层协程,这一点和线程比较像,因为线程也没有层
级这一说,永远都是顶层的。

  • suspend

挂起函数,它不会造成线程阻塞,但是会挂起协程,并且只能在协程中使用。
我们在launch函数中编写的代码是拥有协程作用域的,但是
提取到一个单独的函数中就没有协程作用域了,那么我们该如何调用像delay()这样的挂起函
数呢?
为此Kotlin提供了一个suspend关键字,使用它可以将任意函数声明成挂起函数,而挂起函数
之间都是可以互相调用的,如下所示:

suspend fun printDot() {
 println(".")
 delay(1000)
}

但是,suspend关键字只能将一个函数声明成挂起函数,是无法给它提供协程作用域的。比如
你现在尝试在printDot()函数中调用launch函数,一定是无法调用成功的,因为launch函
数要求必须在协程作用域当中才能调用。
这个问题可以借助coroutineScope函数来解决。

  • coroutineScope

coroutineScope函数也是一个挂起函数,
因此可以在任何其他挂起函数中调用。它的特点是会继承外部的协程的作用域并创建一个子协
程,借助这个特性,我们就可以给任意挂起函数提供协程作用域了。示例写法如下:

suspend fun printDot() = coroutineScope {
 launch {
 println(".")
 delay(1000)
 }
}

coroutineScope函数和runBlocking函数还有点类似,它可以保证其作用域内的所
有代码和子协程在全部执行完之前,外部的协程会一直被挂起。

虽然看上去coroutineScope函数和runBlocking函数的作用是有点类似的,但是
coroutineScope函数只会阻塞当前协程,既不影响其他协程,也不影响任何线程,因此是不
会造成任何性能上的问题的。而runBlocking函数由于会挂起外部线程,如果你恰好又在主线
程中当中调用它的话,那么就有可能会导致界面卡死的情况,所以不太推荐在实际项目中使
用。

  • CoroutineScope

GlobalScope.launch这种协程作用域构建器,在实际项目中也是不太常用的。下面我
来演示一下实际项目中比较常用的写法:

val job = Job()
val scope = CoroutineScope(job)
scope.launch {
 // 处理具体的逻辑
}
job.cancel()

可以看到,我们先创建了一个Job对象,然后把它传入CoroutineScope()函数当中,注意这
里的CoroutineScope()是个函数,虽然它的命名更像是一个类。CoroutineScope()函数
会返回一个CoroutineScope对象,这种语法结构的设计更像是我们创建了一个
CoroutineScope的实例,可能也是Kotlin有意为之的。有了CoroutineScope对象之后,就
可以随时调用它的launch函数来创建一个协程了。

  • 获取协程结果

async函数必须在协程作用域当中才能调用,它会创建一个新的子协程并返回一个Deferred对
象,如果我们想要获取async函数代码块的执行结果,只需要调用Deferred对象的await()
方法即可,代码如下所示:

fun main() {
 runBlocking {
 val result = async {
 5 + 5
 }.await()
 println(result)
 }
}

不过async函数的奥秘还不止于此。事实上,在调用了async函数之后,代码块中的代码就会
立刻开始执行。当调用await()方法时,如果代码块中的代码还没执行完,那么await()方法
会将当前协程阻塞住,直到可以获得async函数的执行结果。

  • suspendCoroutine

suspendCoroutine函数必须在协程作用域或挂起函数中才能调用,它接收一个Lambda表达
式参数,主要作用是将当前协程立即挂起,然后在一个普通的线程中执行Lambda表达式中的
代码。Lambda表达式的参数列表上会传入一个Continuation参数,调用它的resume()方
法或resumeWithException()可以让协程恢复执行。

必须运行恢复协程的命令,否则会一直阻塞

suspend fun request(address: String): String {
 return suspendCoroutine { continuation ->
 HttpUtil.sendHttpRequest(address, object : HttpCallbackListener {
 override fun onFinish(response: String) {
 continuation.resume(response)
 }
 override fun onError(e: Exception) {
 continuation.resumeWithException(e)
 }
 })
 }
}

接着我们在Lambda表达式中调用
HttpUtil.sendHttpRequest()方法发起网络请求,并通过传统回调的方式监听请求结果。
如果请求成功就调用Continuation的resume()方法恢复被挂起的协程,并传入服务器响应
的数据,该值会成为suspendCoroutine函数的返回值。如果请求失败,就调用
Continuation的resumeWithException()恢复被挂起的协程,并传入具体的异常原因。

ViewModel

ViewModel可以

ViewModel还有一个非常重要的特性。我们都知道,当手机发生横竖屏旋转的时候,
Activity会被重新创建,同时存放在Activity中的数据也会丢失。而ViewModel的生命周期和
Activity不同,它可以保证在手机屏幕发生旋转的时候不会被重新创建,只有当Activity退出的
时候才会跟着Activity一起销毁。因此,将与界面相关的变量存放在ViewModel当中,这样即
使旋转手机屏幕,界面上显示的数据也不会丢失。

不带参数(634页)

class MainActivity : AppCompatActivity() {
 lateinit var viewModel: MainViewModel
 override fun onCreate(savedInstanceState: Bundle?) {
 super.onCreate(savedInstanceState)
 setContentView(R.layout.activity_main)
 viewModel = ViewModelProvider(this).get(MainViewModel::class.java)
 plusOneBtn.setOnClickListener {
 viewModel.counter++
 refreshCounter()
 }
 refreshCounter()
 }
 private fun refreshCounter() {
 infoText.text = viewModel.counter.toString()
 }
}

带参数(利用Factory)

class MainViewModelFactory(private val countReserved: Int) : ViewModelProvider.Factory {
 override fun <T : ViewModel> create(modelClass: Class<T>): T {
 return MainViewModel(countReserved) as T
 }
}
class MainActivity : AppCompatActivity() {
 lateinit var viewModel: MainViewModel
 lateinit var sp: SharedPreferences
 override fun onCreate(savedInstanceState: Bundle?) {
 super.onCreate(savedInstanceState)
 setContentView(R.layout.activity_main)
 sp = getPreferences(Context.MODE_PRIVATE)
 val countReserved = sp.getInt("count_reserved", 0)
 viewModel = ViewModelProvider(this, MainViewModelFactory(countReserved))
 .get(MainViewModel::class.java)
 ...

LifeCycles
在一个非Activity
的类中去感知Activity的生命周期
借助LifecycleOwner通知activity发生生命周期事件的时候去调用
LifeCycles的地方

class MyObserver : LifecycleObserver {
 @OnLifecycleEvent(Lifecycle.Event.ON_START)
 fun activityStart() {
 Log.d("MyObserver", "activityStart")
 }
 @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
 fun activityStop() {
 Log.d("MyObserver", "activityStop")
 }
}

在activity里通过这一行代码加载

lifecycleOwner.lifecycle.addObserver(MyObserver())

只要Activity是继承自AppCompatActivity的,或者你的Fragment是继承自
androidx.fragment.app.Fragment的,那么它们本身就是一个LifecycleOwner的实例

在类中这样写就可以

lifecycle.addObserver(MyObserver())//省略this

LiveData

它可以包含任何类型的数据,并在数据发生
变化的时候通知给观察者。LiveData特别适合与ViewModel结合在一起使用,虽然它也可以单
独用在别的地方,但是在绝大多数情况下,它是使用在ViewModel当中的

MutableLiveData是一种可变的LiveData,它的用法很简单,主要
有3种读写数据的方法,分别是getValue()、setValue()和postValue()方法。

class MainViewModel(countReserved: Int) : ViewModel() {
 val counter = MutableLiveData<Int>()
 init {
 counter.value = countReserved
 }
 fun plusOne() {
 val count = counter.value ?: 0
 counter.value = count + 1
 }
 fun clear() {
 counter.value = 0
 }
}

class MainActivity : AppCompatActivity() {
 ...
 override fun onCreate(savedInstanceState: Bundle?) {
 ...
 plusOneBtn.setOnClickListener {
 viewModel.plusOne()
 }
 clearBtn.setOnClickListener {
 viewModel.clear()
 }
 viewModel.counter.observe(this, Observer { count ->
 infoText.text = count.toString()
 })
 }
 override fun onPause() {
 super.onPause()
 sp.edit {
 putInt("count_reserved", viewModel.counter.value ?: 0)
 }
 }
}

接下来到最关键的地方了,这里调用了viewModel.counter的observe()方法来观察数据的
变化。经过对MainViewModel的改造,现在counter变量已经变成了一个LiveData对象,任
何LiveData对象都可以调用它的observe()方法来观察数据的变化。observe()方法接收两
个参数:第一个参数是一个LifecycleOwner对象,有没有觉得很熟悉?没错,Activity本身
就是一个LifecycleOwner对象,因此直接传this就好;第二个参数是一个Observer接口,
当counter中包含的数据发生变化时,就会回调到这里,因此我们在这里将最新的计数更新到
界面上即可。

如果你需要在子线程中给LiveData设置数据,一定要调用postValue()方法,
而不能再使用setValue()方法,否则会发生崩溃。

不过在2019年的Google I/O大会上,Android团队官宣了Kotlin First,并且承诺未来会在
Jetpack中提供更多专门面向Kotlin语言的API。其中,lifecycle-livedata-ktx就是一个专门为
Kotlin语言设计的库,这个库在2.2.0版本中加入了对observe()方法的语法扩展。我们只需要
在app/build.gradle文件中添加如下依赖:

dependencies {
 ...
 implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.2.0"
}
然后就可以使用如下语法结构的observe()方法了:
viewModel.counter.observe(this) { count ->
 infoText.text = count.toString()
}

带layout_和不带layout_的区别

带layout_:此组件相对于父组件的位置
不带layout_:此组件内部的排版方式

inflate

https://blog.csdn.net/u012702547/article/details/52628453

第二个参数root不为空则会,把root的属性限制到第一参数layout中,并且让第一个参数layout中的layout_*属性生效。
inflate会把视图展现在父布局上。

xml属性

gravity:表示组件内的文字的对齐方式;

layout_gravity:针对LinearLayout的一种组件对齐方式,可以把值设置成下列值:

center_vertical、center_horizontal、center等等
layout_centerHorizontal:是相对于RelativeLayout的布局属性),除此之外还有下列几项,有兴趣的可以到Android的官方参考文档去研究下:
android:layout_centerHorizontal – If true, centers this child
horizontally within its parent.

android:layout_centerInParent --If true, centers this child
horizontally and vertically within its parent.

android:layout_centerVertical – If true, centers this child
vertically within its parent.
android:layout_toEndOf本元素在某个元素结束

Android layout属性大全

https://www.cnblogs.com/jiuyi/p/5867452.html

- 第一类:属性值 true或者 false

       Android:layout_centerHrizontal 水平居中                     
       android:layout_centerVertical 垂直居中
       android:layout_centerInparent 相对于父元素完全居中  
       android:layout_alignParentBottom 贴紧父元素的下边缘  
       android:layout_alignParentLeft 贴紧父元素的左边缘 
       android:layout_alignParentRight 贴紧父元素的右边缘 
       android:layout_alignParentTop 贴紧父元素的上边缘
    
       android:layout_alignWithParentIfMissing 如果对应的兄弟元素找不到的话就以父元素做参照物

       android:layout_alignParentStart紧贴父元素结束位置开始

       android:layout_alignParentEnd紧贴父元素结束位置结束

       android:animateLayoutChanges布局改变时是否有动画效果

       android:clipChildren定义子布局是否一定要在限定的区域内

       android:clipToPadding定义布局间是否有间距

       android:animationCache定义子布局也有动画效果

       android:alwaysDrawnWithCache定义子布局是否应用绘图的高速缓存

       android:addStatesFromChildren定义布局是否应用子布局的背景

       android:splitMotionEvents定义布局是否传递touch事件到子布局

       android:focusableInTouchMode定义是否可以通过touch获取到焦点

       android:isScrollContainer定义布局是否作为一个滚动容器 可以调整整个窗体

       android:fadeScrollbars滚动条自动隐藏

       android:fitsSystemWindows设置布局调整时是否考虑系统窗口(如状态栏)

       android:visibility定义布局是否可见

       android:requiresFadingEdge定义滚动时边缘是否褪色

       android:clickable定义是否可点击

       android:longClickable定义是否可长点击

       android:saveEnabled设置是否在窗口冻结时(如旋转屏幕)保存View的数据

       android:filterTouchesWhenObscured所在窗口被其它可见窗口遮住时,是否过滤触摸事件

       android:keepScreenOn设置屏幕常亮

       android:duplicateParentState是否从父容器中获取绘图状态(光标,按下等)

       android:soundEffectsEnabled点击或触摸是否有声音效果

       android:hapticFeedbackEnabled设置触感反馈

- 第二类:属性值必须为id的引用名“@id/id-name”

     android:layout_alignBaseline 本元素的文本与父元素文本对齐
     android:layout_below 在某元素的下方
     android:layout_above 在某元素的的上方			
     android:layout_toLeftOf 在某元素的左边
     android:layout_toRightOf 在某元素的右边

     android:layout_toStartOf本元素从某个元素开始
     android:layout_toEndOf本元素在某个元素结束
     android:layout_alignTop 本元素的上边缘和某元素的的上边缘对齐
      android:layout_alignLeft 本元素的左边缘和某元素的的左边缘对齐
      android:layout_alignBottom 本元素的下边缘和某元素的的下边缘对齐
      android:layout_alignRight 本元素的右边缘和某元素的的右边缘对齐

     android:layout_alignStart本元素与开始的父元素对齐

     android:layout_alignEnd本元素与结束的父元素对齐

     android:ignoreGravity 指定元素不受重力的影响

     android:layoutAnimation定义布局显示时候的动画

     android:id 为布局添加ID方便查找

     android:tag为布局添加tag方便查找与类似

     android:scrollbarThumbHorizontal设置水平滚动条的drawable。

     android:scrollbarThumbVertical设置垂直滚动条的drawable

     android:scrollbarTrackHorizontal设置水平滚动条背景(轨迹)的色drawable

     android:scrollbarTrackVertical设置垂直滚动条背景(轨迹)的色drawable

     android:scrollbarAlwaysDrawHorizontalTrack 设置水平滚动条是否含有轨道

     android:scrollbarAlwaysDrawVerticalTrack 设置垂直滚动条是否含有轨道

     android:nextFocusLeft 设置左边指定视图获得下一个焦点

     android:nextFocusRight设置右边指定视图获得下一个焦点

     android:nextFocusUp设置上边指定视图获得下一个焦点

     android:nextFocusDown设置下边指定视图获得下一个焦点

     android:nextFocusForward设置指定视图获得下一个焦点

     android:contentDescription 说明

     android:OnClick 点击时从上下文中调用指定的方法

- 第三类:属性值为具体的像素值,如30dip,40px,50dp

     android:layout_width定义本元素的宽度

    android:layout_height定义本元素的高度

   android:layout_margin 本元素离上下左右间的距离  
   android:layout_marginBottom 离某元素底边缘的距离
   android:layout_marginLeft 离某元素左边缘的距离 
   android:layout_marginRight 离某元素右边缘的距离、
   android:layout_marginTop 离某元素上边缘的距离

    android:layout_marginStart本元素里开始的位置的距离

    android:layout_marginEnd本元素里结束位置的距离

    android:scrollX水平初始滚动偏移

    android:scrollY垂直初始滚动偏移

    android:background本元素的背景

    android:padding指定布局与子布局的间距

    android:paddingLeft指定布局左边与子布局的间距

    android:paddingTop指定布局上边与子布局的间距

    android:paddingRight指定布局右边与子布局的间距

    android:paddingBottom指定布局下边与子布局的间距

    android:paddingStart指定布局左边与子布局的间距与android:paddingLeft相同

    android:paddingEnd指定布局右边与子布局的间距与android:paddingRight相同

    android:fadingEdgeLength 设置边框渐变的长度

    android:minHeight最小高度

    android:minWidth最小宽度

    android:translationX 水平方向的移动距离

    android:translationY垂直方向的移动距离

    android:transformPivotX相对于一点的水平方向偏转量

    android:transformPivotY相对于一点的垂直方向偏转量

- 第四类:属性值问Android内置值的

    android:gravity控件布局方式

    android:layout_gravity布局方式

    android:persistentDrawingCachehua定义绘图的高速缓存的持久性   

    android:descendantFocusability控制子布局焦点获取方式 常用于listView的item中包含多个控件 点击无效

    android:scrollbars设置滚动条的状态

    android:scrollbarStyle设置滚动条的样式

    android:fitsSystemWindows设置布局调整时是否考虑系统窗口(如状态栏)

    android:scrollbarFadeDuration设置滚动条淡入淡出时间

    android:scrollbarDefaultDelayBeforeFade设置滚动条N毫秒后开始淡化,以毫秒为单位。

    android:scrollbarSize设置滚动调大小

    android:fadingEdge 设置拉滚动条时 ,边框渐变的放向

    android:drawingCacheQuality设置绘图时半透明质量

    android:OverScrollMode滑动到边界时样式

    android:alpha设置透明度

    android:rotation旋转度数

    android:rotationX水平旋转度数

    android:rotationY垂直旋转度数

    android:scaleX设置X轴缩放

    android:scaleY设置Y轴缩放

    android:verticalScrollbarPosition摄者垂直滚动条的位置

    android:layerType设定支持

    android:layoutDirection定义布局图纸的方向

    android:textDirection定义文字方向

    android:textAlignment文字对齐方式

    android:importantForAccessibility设置可达性的重要行

    android:labelFor添加标签

Gone和Invisible

1、Gone

设置控件隐藏了,界面不保留该控件所占的空间。

2、Invisible

设置控件不可见,控件“用肉眼看不到”,界面保留该控件所占的空间。也就是说:这个控件还在这个地方,只是看不到,如果有其他控件基于这个控件对齐,位置还是不受影响

scrollview

https://blog.csdn.net/qq_36243942/article/details/82185051

include
在xml中引入其他layout布局

SimpleDateFormat

https://blog.csdn.net/qq_27093465/article/details/53034427

yyyy:年
MM:月
dd:日
hh:1~12小时制(1-12)
HH:24小时制(0-23)
mm:分
ss:秒
S:毫秒
E:星期几
D:一年中的第几天
F:一月中的第几个星期(会把这个月总共过的天数除以7)
w:一年中的第几个星期
W:一月中的第几星期(会根据实际情况来算)
a:上下午标识
k:和HH差不多,表示一天24小时制(1-24)。
K:和hh差不多,表示一天12小时制(0-11)。
z:表示时区

如果lambda表达式只有一个参数,那么在调用该lambda表达式时,可以不指定它的参数名字.在lambda函数体内用it来代表这个参数.
如果lambda表达式有多个参数,那么在调用该lambda表达式时,必须指定每一个参数的名字.

repeat(3){函数内容}

repeat是后面的函数只有一个参数,所以省略了

SharedPreferences
第一个参数用于指定SharedPreferences文件的名称,如果指定的
文件不存在则会创建一个

问题
T.()为什么可以传参入T类型的参数??????????????

跳转到新activity时不finish(),执行返回键,是会返回到原来的activity的,否则不会。

Fragment Activity
fragment会关联activity,且在第一个生命周期函数之前
所以所有的生命周期函数都在activity关联之后

  • onActivityCreated()

当Activity中的onCreate方法执行完后调用。当执行onActivityCreated()的时候 activity的onCreate才刚完成。所以在onActivityCreated()调用之前activity的onCreate可能还没有完成,所以不能再onCreateView()中进行与activity有交互的UI操作,UI交互操作可以在onActivityCreated()里面进行。所以呢,这个方法主要是初始化那些你需要你的父Activity或者Fragment的UI已经被完整初始化才能初始化的元素。

typealias
typealias关键字可以用于给任意类型指定一个别名
例如

typealias PermissionCallback = (Boolean, List<String>) -> Unit

git clone 会增加origin地址

LayoutInflater

具体作用:

1、对于一个没有被载入或者想要动态载入的界面,都需要使用LayoutInflater.inflate()来载入;

2、对于一个已经载入的界面,就可以使用Activiyt.findViewById()方法来获得其中的界面元素。

ViewBinding
替换extensions

区间表示
0…10闭区间
0 until 10 左闭右开
每次运行 加1
若想加其数 则后面加 step 2 就是每次循环加2,类似如此

when 和if 都有返回值
如果函数定义的执行逻辑只有一行代码(表达式),则可以省略{}和return 换成‘=’
如fun test() = if(2>3)3 else 4
class 默认不能被继承,加上 open 就可以了

主构造函数
特点是没有函数体,直接定义在类名的后面即
可。比如下面这种写法:
一定要有 val 或 var

class Student(val sno: String, val grade: Int) : Person() {
}

主构造函数没有函数体,如果我想在主构造函数中编写一些逻辑,该怎么办呢?
Kotlin给我们提供了一个init结构体,所有主构造函数中的逻辑都可以写在里面:

class Student(val sno: String, val grade: Int) : Person() {
 init {
 println("sno is " + sno)
 println("grade is " + grade)
 }
}

继承
子类的主构造函数调用父类中的哪个构造函数,在继承的时候通过括号来指定。因此再来看一
遍这段代码,你应该就能理解了吧。

class Student(val sno: String, val grade: Int) : Person() {
}

次构造函数
次构造函数是通过constructor关键字来定义的
你要知道,任何一个类只能有一个主构造函数,但是可以有多个次构造函数。次构造函数也可
以用于实例化一个类,这一点和主构造函数没有什么不同,只不过它是有函数体的。
Kotlin规定,当一个类既有主构造函数又有次构造函数时,所有的次构造函数都必须调用主构造
函数(包括间接调用)。

那么接下来我们就再来看一种非常特殊的情况:类中只有次构造函数,没有主构造函数。这种
情况真的十分少见,但在Kotlin中是允许的。当一个类没有显式地定义主构造函数且定义了次构
造函数时,它就是没有主构造函数的。我们结合代码来看一下:

class Student : Person {
 constructor(name: String, age: Int) : super(name, age) {
 }
}

因为是没有主构造函数,而父类的构造函数执行需要依靠student的主构造函数,所以也不需要调主构造函数,而是在次构造函数调用。

继承和实现都是用冒号,且和java一样只能继承一个实现多个,多个类与接口之间用逗号隔开。

List 可以有重复的元素,set不可以
listof setof 创建不可变类型
mutable*of创建可变类型

atudio快捷键
ctrl+P 参数提示
ctrl+H 类继承视图
ctrl+B 打开方法实现,相当于ctrl+鼠标右键
Ctrl+[或]可以跳到大括号的开头结尾
Ctrl+Shift+Backspace可以跳转到上次编辑的地方
Ctrl+F12,可以显示当前文件的结构
Ctrl+F7可以查询当前元素在当前文件中的引用,然后按F3可以选择
Ctrl+W可以选择单词继而语句继而行继而函数
Ctrl+O可以选择父类的方法进行重写
ctrl+alt+space 代码提示
Ctrl+Alt+ left/right 返回至上次浏览的位置
ALT+C 拾色器(自己设置的)

RelativeLayout专用的属性
layout_centerInParent
layout_alignBottom
layout_toRightOf
类似的
RecyclerView布局
RecyclerView使用布局管理器(layoutmanager)管理布局
有:LinearLayoutManager,GridLayoutManager和
StaggeredGridLayoutManager。

ListView 没有layoutmanager。

注意事项
1.fragment需要写name属性,否则会编译失败。
2.Retrofit里的参数会自动编码,如果不编码的话需要设置encoded=true
3.如果只需要获取bitmap的宽和高,只需要在BitmapFactory.Options中设置inJustDecodeBounds为true,然后在调用BitmapFactory.decodeResource()
4.采用LinearLayout布局时,有以下特殊情况需要我们注意:

(1)当 android:orientation=“vertical” 时,
android:layout_gravity只有水平方向的设置才起作用,垂直方向的设置不起作用。即:left,right,center_horizontal是生效的。
(2)当 android:orientation=“horizontal” 时,
android:layout_gravity只有垂直方向的设置才起作用,水平方向的设置不起作用。即:top,bottom,center_vertical是生效的。

5.在retrofit enquen里的callback类中,body.string()这个函数只有第一次调用返回内容,之后调用回返回空。谨慎使用!

6.当提示in unnamed module of loader 'app’时,需要把类名写成带有构造参数的形式,如:

  • Gson().fromJson(gson,HashMap()::class.java) 如果写成Gson().fromJson(gson,HashMap::class.java)就会报错。

7.在api28及之后,会对非加密网络请求加以限制,导致无法访问,所以在build.gradle里面改为targetSdk 27就可以了。

use函数
用完后自动关闭外层流。

RecycleView
1.每次onCreateView时都需要使用或创建未被使用的view
2.如果既想监控livedata又不想再livedata里操作,也要增加观察者,用来在viewmodel里操作。
例子:自己写的京东商城里recycleview不让每次都获取网络图片的操作。
3.

离屏缓冲
setLayerType()(view级别离屏缓冲,写在init{}里,即只需要调用一次)
saveLayer()/restoreToCount()

Bitmap Drawable
drawable转bitmap,在内部创建一个bitmap把drawable画到bitmap上面,返回bitmap
bitmap转drawable,本质是转成BitmapDrawabl在绘制时还是绘制的drawable就相当于转成了drawable

Paint
Paint(Paint.ANTI_ALIAS_FLAG)抗锯齿

View绘制流程
onMeasure()
onLayout()
onDraw()

onTouchEvent

  • 从子view开始,在到viewgroup
  • 返回值:返回true表示被消费,在它下面的view(包括它的父view)都不会在执行自己的onTouchEvent,而且需要是ACTION_DOWN(即按下时)返回true才表示当前序列(包括和当前按下事件对应的滑动和抬起等事件被这个View消费后续View不在响应和这个按下对应的抬起和滑动,即如果按下事件不消费返回false那么后续的滑动和抬起事件也不会传到这个View对应的onTouchEvent中)事件。

嵌套滑动

若支持嵌套滑动
SDK 21 以下:需要去实现
v4包里面的NestedScrollingChild,或者NestedScrollingParent SDK
21及以上,View以及ViewGroup自带嵌套滑动,继承View就行。

  • 注意点

1.和事件分发不同,事件分发是从viewgroup到view,嵌套滑动的调用是从view到view到viewgroup

大体步骤是这样:
1.Action_move事件分发到view
2.view检查是否有嵌套滑动,有的话请求嵌套滑动,向具有或开启嵌套滑动功能的父viewgroup请求滑动。
Android开发_第1张图片

    //作为父view
    //接受子View请求父View对滑动的预先处理,在这里我们可以预先滑动消耗一部分滑动距离
    override fun onNestedPreScroll(target: View, dx: Int, dy: Int, consumed: IntArray, type: Int) {
        super.onNestedPreScroll(target, dx, dy, consumed, type)
    }
    override fun onInterceptTouchEvent(ev: MotionEvent?): Boolean {
//        MyLog(ev.toString()+"拦截")
//        如果拦截返回(返回true),并调用自己的onTouchEvent,后续事件(指的是和当前动作序列匹配的后续事件,如果新的ACTION_MOVE事件进入则会重新调用判断拦截)则不调用onInterceptTouchEvent
//        return ev?.actionMasked == MotionEvent.ACTION_MOVE
        return super.onInterceptTouchEvent(ev)
    }

像微信一样,开启后台通知

首先使用这样的函数启动服务

startForegroundService()

再service的生命周期中调用下面的函数

 startForeground()

调用具体过程如下

        val notification = NotificationCompat.Builder(service, "1")
            .setContentTitle("赚8")
            .setSmallIcon(R.drawable.ic_action_name)
            .setAutoCancel(true)
        startForeground(1,notification.setContentText("")
            .build())

原因是当用这个startForegroundService()启动服务后,需要在service中5秒内调用 startForeground()否则会报错。然后再执行下面的函数让显示在通知中的服务标志消失

stopForeground(true)

这样就开启了后台服务。
再从设置里面找到电池优化,把该应用取消电池优化,就可以一直在后台运行了。

你可能感兴趣的:(android)