遇到的问题

Classloader执行流程

1.线程和协程的区别

线程(Thread):

线程是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。

每个线程可以独立执行,有自己的调用堆栈和局部变量。

线程间的切换由操作系统内核管理,涉及到上下文切换的成本,包括保存和加载不同线程的状态。

线程适用于执行长时间的计算密集型任务。

协程(Coroutine):

协程是一种轻量级的线程。它们通过协作而非抢占式的方式进行切换,即协程需要显式地进行切换。

协程运行在单个线程中,因此不需要多线程的同步机制,如锁,这减少了开销。

协程提供了非常有效的异步编程模型,可以在等待操作(如 I/O)完成时挂起,这样可以处理大量并发的操作而不占用多个线程。

区别

1. 调度方式

线程:由操作系统内核进行调度和管理,线程的切换需要内核介入,开销较大。

协程:由用户态的调度器进行调度,协程的切换在用户态完成,开销较小。

2. 资源消耗

线程:每个线程都需要独立的栈空间和内核资源,线程数量受到系统限制。

协程:协程共享线程的栈空间,资源消耗较小,可以在一个线程中运行成千上万个协程。

3. 编程模型

线程:编程模型相对复杂,需要处理线程同步、死锁等问题。

协程:编程模型简单,通过挂起和恢复操作实现协作式多任务处理,避免了复杂的同步问题。

4. 并发性

线程:真正的并行执行,适合计算密集型任务,CPU密集型任务。

协程:协作式并发,适合I/O密集型任务,通过主动让出CPU实现并发。

5. 控制权

线程:操作系统控制线程的执行和调度。

协程:程序员控制协程的执行流程,通过显式的挂起和恢复操作进行调度。


2.kotlin和Java的对比

(1)代码量:kotlin比Java代码量少很多。kotlin通过使用简洁的语法和函数式编程的概念来简化java代码,减少代码的复杂性。

(2)空指针安全:kotlin 通过引入空指针安全机制来避免空指针异常,而Java需要手动检查null值。

(3)扩展函数:kotlin中有一个强大的功能叫扩展函数,它允许用户将一个已存在的类进行扩展

(4)函数式编程概念:kotlin 支持更多的函数式编程概念,比如lambda表达式、高阶函数等

(5)数据类:kotlin 中引入了数据类,它允许程序员快速创建简单的数据类,这些数据类型可以自动生成一些有用的方法,如equals、hashCode、toString等。这使得开发人员可以更快地创建和使用自定义数据类型。。相比之下Java需要编写大量的样板代码

(6)类型推断

类型推断是Kotlin的一个核心概念,它允许开发人员在声明变量时不需要指定变量的类型,而是由编译器根据变量的值自动推断出变量的类型。这使得Kotlin的代码更简洁,更易于阅读和维护。

总的来说kotlin 相对于Java拥有更简洁的语法,更多的功能和更高的生产效率,但是Java拥有更成熟的生态,更广泛的支持和更好的跨平台支持。

(7)委托

委托是Kotlin的一个核心概念,它允许开发人员在一个类型上委托给另一个类型的属性和方法。这使得开发人员可以在不修改原始类型的情况下,为其添加新的功能。


扩展函数示例:

在 Kotlin 中,扩展函数是一种非常有用的特性,它允许你为不属于自己的类添加新的方法。这在很多情况下非常有用,例如为标准库中的类(如 String、List 等)添加额外的功能,或者给第三方库的类添加功能。

定义扩展函数

要定义一个扩展函数,你需要使用 fun 关键字,后面跟着接收者类型(即你想要扩展的类),然后是这个类型后面的点(.),接着是函数名和参数列表。

1、示例:为 String 类添加一个扩展函数

fun String.capitalizeFirstLetter(): String {

    return this.substring(0, 1).toUpperCase() + this.substring(1)

}

在这个例子中,capitalizeFirstLetter 是为 String 类型添加的扩展函数。你可以像调用普通成员函数一样调用它

val myString = "hello"

println(myString.capitalizeFirstLetter())  // 输出 "Hello"

扩展函数与成员函数的区别

调用方式:扩展函数使用点符号(.)调用,而成员函数直接通过对象调用。

可见性:扩展函数不能访问接收者的私有成员。成员函数可以访问类的私有成员。

静态分发:扩展函数是静态分派的,而成员函数是动态分派的(在运行时根据对象实际类型调用方法)。

示例:为 List 添加扩展函数来计算总和

fun <T> List<T>.sumByInt(selector: (T) -> Int): Int {

    var sum = 0

    for (item in this) {

        sum += selector(item)

    }

    return sum

}

在这个例子中,sumByInt 是一个泛型扩展函数,用于对列表中的元素应用一个转换函数,并返回所有转换结果的总和。

val numbers = listOf(1, 2, 3, 4)

println(numbers.sumByInt { it })  // 输出 10

注意事项

命名冲突:如果你定义了一个与已有类的成员函数同名的扩展函数,那么在调用时将调用扩展函数而不是成员函数。可以通过使用导入限定符(如 String.capitalizeFirstLetter())来明确指定使用哪个函数。

性能考虑:虽然扩展函数很有用,但它们是通过代理对象实现的,这可能会带来一些性能开销。在性能敏感的代码中,应谨慎使用。

扩展函数是 Kotlin 中一个强大且灵活的特性,可以极大地增加代码的可读性和复用性。

数据类

数据类的一个例子是下面的代码:

data class Person(val name:String,val age:Int)

fun main(args:Array<String>){

val person1=Person("Alice",30)

val person2=Person("Bob",25)

println(person1==person2)// false

println(person1.hashCode())// 123

println(person1.toString())// Person(name=Alice, age=30)}

在这个例子中,Person是一个数据类,它有两个属性:name和age。由于Person是一个数据类,编译器会自动生成一些有用的方法,如equals、hashCode和toString。我们可以直接在Person类型上调用这些方法,而无需手动实现它们。

委托的一个例子:

class DelegatingClass(private val delegate):Any{

operatorfunget(property:KProperty<*>)=delegate.get(property)

operatorfunset(property:KProperty<*>,value:Any)=delegate.set(property,value)

}

fun main(args:Array<String>){

val delegate=object: Any(){

val name="Alice"

val age=30

}

val delegatingClass=DelegatingClass(delegate)

println(delegatingClass.name)// Alice

println(delegatingClass.age)// 30

}

在这个例子中,DelegatingClass是一个委托类,它在构造函数中接受一个delegate参数。DelegatingClass实现了get和set操作符,这使得它可以委托给delegate的属性和方法。我们可以直接在DelegatingClass类型上调用name和age属性,而无需手动实现它们。

3.多线程访问修改list怎么保证数据安全

Android 中list是线程不安全的,意味着在多线程中同时访问和修改list时,可能会导致不确定的结果和数据不一致性。为了确保list的线程安全,可以采用以下方式

(1)使用同步集合类

            在多线程环境下,使用同步集合类保证list的线程安全性,Android 提供了Collections.synchronizedList()方法

            例如:LIst<String> list = new ArrayList();

            List<String> synchronizedList = Collections.synchronizedList(list);

操作时还是需要手动进行同步

synchronized(list) {

}

(2) 使用并发集合类

    CopyOnWriteArrayList<String> concurrentList = new CopyOnWriteArrayList();

(3) 使用锁机制 来保证list的线程安全性, 可以使用 ReentrantLock 或者synchronized关键字来实现互斥访问。

使用 synchronized 关键字
List<String> list = new ArrayList<>();

public void addElement(String element) {

    synchronized (list) {

        list.add(element);

    }

}

public String getElement(int index) {

    synchronized (list) {

        return list.get(index);

    }

}

使用 ReentrantLock

List<String> list = new ArrayList<>();

private final ReentrantLock lock = new ReentrantLock();

public void addElement(String element) {

    lock.lock();

    try {

        list.add(element);

    } finally {

        lock.unlock();

    }

}

public String getElement(int index) {

    lock.lock();

    try {

        return list.get(index);

    } finally {

        lock.unlock();

    }

}


4.okhttp拦截器

addInterceptor和addNetworkInterceptor

选择使用 addInterceptor 还是 addNetworkInterceptor 时,取决于你希望拦截的网络层级。

addInterceptor

方法用于拦截应用层级的请求和响应。这意味着它可以访问应用程序发送的请求和服务器返回的响应,但不能访问底层的网络传输细节。通常情况下,这足以满足大多数的需求,比如添加身份验证、修改请求头等。

addNetworkInterceptor

方法用于拦截网络层级的请求和响应。这意味着它可以访问底层的网络传输细节,包括请求和响应的字节流。它可以用于监视网络流量、修改网络传输行为或进行缓存控制。但要注意,addNetworkInterceptor 方法不会拦截从缓存中提供的响应。

根据你的需求,选择适合的拦截器方法。如果你只需要访问应用层级的请求和响应,一般情况下使用 addInterceptor 就足够了。如果你需要对网络层级进行更深入的控制,可以使用 addNetworkInterceptor。需要注意的是,在使用 addNetworkInterceptor 时,要谨慎处理请求和响应的字节流,以免引起潜在的问题。

时机

addInterceptor 和 addNetworkInterceptor 方法添加的拦截器在 OkHttp 中的调用时机略有不同:

addInterceptor 方法添加的拦截器在应用层级的调用时机是在请求发出后、服务器响应之前。它会被应用于所有的网络请求,包括重定向和重试的请求。在请求链中,每个拦截器的 intercept 方法会按照添加的顺序依次被调用。

addNetworkInterceptor 方法添加的拦截器在网络层级的调用时机是在请求发出后、服务器响应之前,并且只会被调用一次。它可以访问到底层的网络传输细节,如请求和响应的字节流。然而,addNetworkInterceptor 方法不会拦截从缓存中提供的响应。


5.点击按钮的事件分发

Android 的事件分发机制主要包括以下几个步骤:

事件生成:用户在设备上进行触摸、滑动等操作时,系统会生成相应的事件,如触摸事件(MotionEvent)。

事件发送:生成的事件会被发送到当前活动(Activity)或视图(View)树的根节点。

事件分发:

Activity:首先,事件会被传递给活动的 dispatchTouchEvent() 方法。这个方法决定如何将事件进一步分发。

ViewGroup:如果当前活动包含 ViewGroup(如 LinearLayout、RelativeLayout 等),dispatchTouchEvent() 会先调用 ViewGroup 的 onInterceptTouchEvent() 方法。如果返回 true,则 ViewGroup 会处理事件;如果返回 false,则将事件传递给子视图。

View:对于普通的视图(View),会调用其 onTouchEvent() 方法来处理事件。

事件处理:

onTouchEvent():当视图接收到事件后,会根据事件的类型(如按下、移动、抬起等)在此方法中处理相应的逻辑。

事件处理过程可能涉及多个视图,尤其是在有嵌套的视图结构中。

事件消费:如果某个视图处理了事件(返回 true),后续的视图将不会再接收到这个事件。如果没有视图消费事件,事件将向上传递,直到达到活动。

最终结果:处理完成后,结果可能会影响用户界面的状态或行为。

注意事项:

onInterceptTouchEvent():在 ViewGroup 中使用,决定是否拦截子视图的事件。

事件的传递顺序:从上到下(Activity → ViewGroup → View),处理顺序是从下到上(View → ViewGroup → Activity)。


事件传递的对象:

事件在 Android 中主要在 Activity、ViewGroup 和 View 之间传递。

Activity 作为应用的入口,首先接收事件;ViewGroup 可能根据需要拦截事件,而具体的 View 则负责执行实际的事件处理。这种多层次的传递机制保证了事件处理的灵活性和精确性。

事件分发顺序

Activity:当用户触摸屏幕时,事件首先被发送到当前的 Activity。Activity 会调用其 dispatchTouchEvent() 方法,决定事件的后续处理。

ViewGroup:如果 Activity 的 dispatchTouchEvent() 方法未拦截事件,事件将传递到 ViewGroup。ViewGroup 会执行 onInterceptTouchEvent() 方法,判断是否拦截该事件。如果返回 true,则事件会在 ViewGroup 中处理;如果返回 false,事件会继续传递到子视图。

View:最终,事件将传递到具体的 View,在 View 中调用 onTouchEvent() 方法来处理事件。视图可以根据事件的类型(如点击、滑动等)执行相应的逻辑。

事件分发过程中的方法

dispatchTouchEvent():

作用:负责分发触摸事件。

调用时刻:当 Activity 或 ViewGroup 收到触摸事件时首先调用。它决定事件是否继续传递给子视图或直接处理。

onInterceptTouchEvent():

作用:用于判断 ViewGroup 是否拦截事件。

调用时刻:在 ViewGroup 的 dispatchTouchEvent() 内部调用。通常用于处理复杂的触摸交互,比如滑动或拖动。

onTouchEvent():

作用:处理具体的触摸事件。

调用时刻:在 dispatchTouchEvent() 内部调用。用于执行视图的响应逻辑,比如状态更新、动画触发等。


6、线程锁

在Android应用程序中,线程锁是用于实现多线程同步和防止竞争条件(race condition)的重要工具。线程锁通常用于确保在多个线程之间对共享资源的访问进行协调,以避免并发问题。

以下是Android中线程锁的一些常见形式:

1.同步块(Synchronized Blocks):

使用 synchronized 关键字可以创建同步块,确保只有一个线程可以进入同步块内部的代码段。这通常用于保护共享资源,以防止多个线程同时访问。

例如:

synchronized(lockObject){// 同步的代码块}

2.同步方法(Synchronized Methods):

在方法声明中使用 synchronized 关键字,将整个方法标记为同步。这使得只有一个线程可以同时访问这个方法。

例如:

publicsynchronizedvoidmySynchronizedMethod(){// 同步的方法体}

3.ReentrantLock:

ReentrantLock 是Java中的一个高级锁机制,允许更灵活的锁控制。与 synchronized 不同,ReentrantLock 允许可中断的锁、超时的锁等。

例如:

Locklock=newReentrantLock();lock.lock();// 获得锁try{// 同步的代码块}finally{lock.unlock();// 释放锁}

4.Condition:

Condition 是与 ReentrantLock 一起使用的,用于线程等待和通知。它可以用于创建更复杂的线程同步方案,如生产者-消费者问题。

例如:

Locklock=newReentrantLock();

Conditioncondition=lock.newCondition();

// 等待条件

condition.await();

// 通知条件

condition.signal();

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 220,699评论 6 513
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,124评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 167,127评论 0 358
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,342评论 1 294
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,356评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,057评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,654评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,572评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,095评论 1 318
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,205评论 3 339
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,343评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 36,015评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,704评论 3 332
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,196评论 0 23
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,320评论 1 271
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,690评论 3 375
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,348评论 2 358

推荐阅读更多精彩内容