自学内容网 自学内容网

记录一些项目中常见的概念、方法、控件

等记录多一点内容的时候会分个类

三个绑定类

1、ViewDataBinding

ViewDataBinding 是 Android Data Binding 库的一个特性,它允许开发者在不完全采用 Data Binding 模型的情况下,仍然能够从布局文件中获取绑定的视图。ViewDataBinding 主要是为了减少常见的 findViewById 调用,从而提高代码的可读性和可维护性。

当在项目中启用 Data Binding 后,每个布局文件都会生成一个对应的绑定类。这些类提供了对布局中所有视图的直接访问,而不需要手动查找视图。但是,ViewDataBinding 不包含 Data Binding 的完整功能,如表达式语言和数据观察者。

以下是 ViewDataBinding 接口的一些关键特性和用法:

  1. 绑定视图:ViewDataBinding 提供了对布局文件中所有绑定视图的访问。这意味着你可以在绑定类中直接访问布局文件中的视图,而不需要使用 findViewById。
  2. 数据上下文:ViewDataBinding 接口的实现类提供了一个 getBindingAdapter 方法,该方法返回一个 BindingAdapter 对象,它包含了与数据绑定相关的适配器和绑定器集合。
  3. 生命周期管理:ViewDataBinding 接口的实现类在 Activity 或 Fragment 的生命周期事件中自动处理绑定的创建和销毁。当 Activity 或 Fragment 被销毁时,相关的绑定也会被自动清理,这有助于避免内存泄漏。
  4. 执行表达式:ViewDataBinding 接口的实现类允许你执行数据绑定表达式,这些表达式定义了视图属性和数据源之间的绑定关系。
  5. 生成绑定类:当你在布局文件中使用 <layout> 标签启用数据绑定时,编译器会为每个布局文件生成一个绑定类。这个类名通常遵循 <layoutName>Binding 的命名约定,例如,对于 activity_main.xml,生成的绑定类可能是 ActivityMainBinding。
  6. 使用双向绑定:ViewDataBinding 支持双向绑定,这意味着你可以在布局文件中定义视图和数据源之间的绑定关系,当数据源发生变化时,视图会自动更新,反之亦然。
  7. 访问绑定类:你可以在 Activity 或 Fragment 中通过调用 DataBindingUtil.setContentView 方法来访问布局的绑定类。例如:
public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
        // 现在可以直接使用 binding 对象访问布局中的视图
        binding.someTextView.setText("Hello, Data Binding!");
    }
}

 

 

2、ViewBinding

ViewBinding 是 Android Jetpack 中另一个用于简化视图查找的库。与 DataBinding 不同,ViewBinding 专注于生成一个绑定类,该类包含对布局文件中所有视图的直接引用,但它不涉及数据的绑定。

ViewBinding 通过在模块的 build.gradle 文件中启用 viewBinding 选项来启用。启用后,对于每个XML布局文件,Android Studio 都会生成一个对应的绑定类。这个类包含了对布局中所有视图的引用,开发者可以通过这个类来访问这些视图,而无需调用 findViewById。

ViewBinding 减少了 findViewById 的调用,从而提高了代码的可读性和可维护性。虽然它不提供数据绑定的功能,但它仍然是一个很有用的工具,特别是对于大型项目和复杂的布局。

3、DataBinding

DataBinding 是 Android Jetpack 中的一个库,它允许开发者以声明方式将布局中的 UI 组件与数据对象绑定。这意味着当数据对象发生变化时,UI 会自动更新以反映这些变化,而无需编写额外的代码来手动更新视图。这大大减少了样板代码,并使得UI和数据之间的同步更加直接和高效。

DataBinding 通过布局文件中的 <layout> 标签启用,并允许在布局XML中直接使用变量和数据模型。开发者可以通过 @{} 语法在布局文件中引用数据模型中的属性,从而实现UI与数据的绑定。以下是 Data Binding 的一些关键特点和用法:

  • 减少代码:通过在布局文件中直接引用数据,减少在 Activity 或 Fragment 中的代码量。
  • 类型安全:在编译时检查数据类型,减少运行时错误。
  • 视图与数据分离:将视图的定义与数据的处理分离,提高代码的可维护性。
  • 支持双向绑定:可以自动同步视图和数据源之间的状态。

 


 

回调函数

1、作用

回调函数在编程中扮演着非常重要的角色,特别是在异步编程、事件驱动编程、函数式编程以及处理不确定何时完成的任务时。它们的主要作用包括:

  1. 异步处理

    • 回调函数允许程序在等待某个耗时操作(如网络请求、文件I/O、数据库查询等)完成的同时,继续执行其他任务,而不是阻塞整个程序。
    • 当异步操作完成时,回调函数会被调用,从而可以处理操作的结果。
  2. 事件响应

    • 在事件驱动的程序中,如图形用户界面(GUI)或游戏,回调函数通常用于响应用户输入、定时器事件、系统事件等。
    • 这些函数在特定事件发生时被调用,允许程序做出相应的反应。
  3. 分离关注点

    • 回调函数使得程序的不同部分可以独立开发和测试,因为它们允许将执行逻辑与调用逻辑分离。
    • 例如,一个函数可以执行数据处理,而另一个函数(回调函数)可以决定如何使用处理后的数据。
  4. 灵活性和扩展性

    • 回调函数提供了一种机制,可以根据需要动态地添加或更改功能,而无需修改核心代码。
    • 这对于构建可扩展和可维护的软件系统非常重要。
  5. 错误处理

    • 在处理可能失败的操作时,回调函数可以用于捕获和处理错误或异常,确保程序的健壮性和稳定性。
  6. 链式调用和流水线

    • 回调函数可以被链接在一起,形成一个处理流程或流水线,其中每个回调函数的输出作为下一个函数的输入。
    • 这种模式在数据处理和事件流中非常常见,例如在Node.js的事件循环中。
  7. 函数式编程

    • 在函数式编程范式中,回调函数是第一等公民,可以像其他数据类型一样被传递、存储和返回。
    • 它们被广泛用于map、filter、reduce等高阶函数中,以实现对集合的高级操作。

2、使用

在Kotlin中,回调函数通常是一种将函数作为参数传递给其他函数的方式,以便在某个事件发生时执行。通常以Lambda表达式或函数引用的形式出现,它们可以作为参数传递给其他函数,这样就可以在特定的时机调用。下面我将详细解释如何在Kotlin中定义、使用回调函数以及其执行流程。

定义回调函数:
在Kotlin中,你可以定义一个接受函数类型参数的函数,这个参数就是回调函数。函数类型可以显式地指定,也可以通过lambda表达式隐式推断。例如,定义一个接受回调函数的函数:

fun performAction(action: () -> Unit) {
    // 执行一些操作...
    action() // 调用回调函数
}

这里action参数就是一个回调函数,它没有参数也没有返回值(类型为() -> Unit)。

如果回调函数需要参数或返回值,你可以相应地修改类型,例如:

fun fetchData(callback: (String) -> Unit) {
    // 模拟数据加载
    val data = "Hello, World!"
    callback(data)
}

使用回调函数:

使用回调函数很简单,你只需要在调用接受回调函数的函数时,提供一个lambda表达式或函数引用作为参数。例如,使用上面定义的performAction函数:
 

performAction {
    println("Action performed!")
}
//或者使用fetchData函数:

fetchData { data ->
    println("Received data: $data")
}

执行流程:
当调用一个接受回调函数的函数时,实际的执行流程如下:

  1. 调用者准备回调函数:在调用目标函数时,提供一个lambda表达式或函数引用作为参数。
  2. 目标函数执行主体逻辑:目标函数执行其主要的逻辑,这可能包括异步操作、计算等。
  3. 调用回调函数:在适当的时机,目标函数会调用之前提供的回调函数,传递必要的参数(如果有)。
  4. 回调函数执行:回调函数执行其定义的逻辑,这可能是处理数据、更新UI等。
  5. 控制返回:回调函数执行完毕后,控制权返回到目标函数,目标函数继续执行(如果有剩余逻辑),最后控制权返回到最初的调用者。
示例

import kotlinx.coroutines.*

suspend fun loadData(callback: (String) -> Unit) {
    delay(1000L) // 模拟耗时操作
    val data = "Data loaded successfully"
    callback(data)
}

fun main() {
    runBlocking {
        loadData { data ->
            println("Received data: $data")
        }
    }
}


在这个例子中,loadData函数是挂起函数,它模拟了耗时操作,并在数据加载完成后调用回调函数。main函数使用runBlocking来运行协程,确保loadData函数及其回调函数在协程作用域中执行。

 


abstract

abstract 关键字用于定义抽象类和抽象方法。以下是 abstract 的一些关键点:

1、抽象类:

  • 定义:使用 abstract 关键字定义的类称为抽象类。抽象类不能被实例化,但可以被继承。
  • 目的:抽象类通常用作基类,为子类提供公共的接口和/或实现。


2、抽象方法:

  • 定义:在抽象类中,使用 abstract 关键字定义的方法称为抽象方法。抽象方法没有实现,必须在子类中被重写。
  • 目的:抽象方法强制子类提供具体实现,确保所有子类都遵循相同的协议。


3、关键特点:

  • 不能实例化:不能创建抽象类的实例,但可以创建其子类的实例。
  • 包含抽象方法:抽象类可以包含抽象方法,这些方法没有实现,必须由子类实现。
  • 包含具体方法:除了抽象方法,抽象类也可以包含有具体实现的方法。
  • 被子类继承:子类通过继承抽象类,必须实现所有的抽象方法。
  • 用于共享代码:抽象类用于共享代码和定义一些通用行为。


4、使用场景

  • 定义协议:当你想要定义一个协议或一组行为,但不希望提供具体实现时。
  • 代码复用:当你想要在多个子类之间共享代码时。
  • 多态性:抽象类允许你通过抽象方法实现多态性。

 


 

protected open

在Kotlin中,protected open 是用来修饰类成员(如方法、属性或构造函数)的关键字组合,具体含义如下:

  1. protected:表示该成员在当前类及其子类中可见。如果一个类成员被声明为 protected,则它不能被同一个包中的非子类访问,但可以在子类中访问。
  2. open:表示该成员可以被子类重写(override)。如果一个类成员被声明为 open,则子类可以提供一个不同的实现。

使用场景

  1. 基类中的方法:当你希望一个方法在子类中可以有不同的实现,但同时在基类中提供一个默认实现时,可以使用 protected open。
  2. 基类中的属性:如果你希望子类可以访问并修改基类中的属性,但同时限制其他类访问,可以使用 protected open。
  3. 构造函数:在某些情况下,你可能希望子类能够调用基类的构造函数,但不希望外部直接通过基类的构造函数创建子类的实例。这时,可以将基类的构造函数声明为 protected。

 


 

companion object

在 Kotlin 中,companion object 是一种特殊的非匿名内部类,它属于其外围类的一部分。companion object 主要用于实现与 Java 静态方法和字段类似的功能,但同时也具有面向对象的特性。companion object 可以定义在类内部,但不是该类的实例成员。这意味着你可以在不创建类的实例的情况下访问 companion object 中的属性方法,就像它们是类的静态成员一样。

companion object 是一种特殊的对象声明,它与类或接口关联,并提供静态功能。以下是 companion object 的一些关键特点和用法:

特点:

  • 单例:companion object 在其宿主类的整个生命周期内是单例的,即只有一个实例。
  • 静态访问:可以通过类名直接访问 companion object 的成员,而不需要创建类的实例。
  • 访问宿主类的成员:companion object 可以访问其宿主类的所有成员,包括私有成员。
  • 常用于工厂方法:companion object 常用于实现工厂方法,提供创建类实例的静态方法。


service

在 Android 开发中,Service 是一个运行在后台的组件,它允许应用在没有用户界面的情况下执行长时间运行的操作,甚至是在屏幕关闭或用户切换到其他应用时。服务对于执行后台任务(如音乐播放、文件下载、网络通信等)非常有用。

以下是一些关于 Android Service 的关键点:

1、生命周期:

  1. onCreate():服务创建时调用。
  2. onStartCommand():每次服务启动时调用,可以通过 startService() 方法启动服务。
  3. onBind():当其他组件请求绑定到服务时调用。
  4. onUnbind():当所有客户端都解绑时调用。
  5. onDestroy():服务被销毁时调用。

2、类型:

  1. START_STICKY:如果系统杀死了服务,系统会在内存足够时重启服务。
  2. START_NOT_STICKY:如果系统杀死了服务,不会重启服务。
  3. START_REDELIVER_INTENT:如果服务被系统杀死,系统会尝试重新传递最后一次的 Intent 给服务。

3、绑定服务:
服务可以通过 bindService() 方法绑定到其他组件(如 Activity 或 BroadcastReceiver)。绑定服务允许客户端与服务进行交互,发送请求和接收结果。

4、通信:

使用 Intent 在服务和客户端之间传递请求和结果。
使用 Messenger 或 Binder 在服务和客户端之间进行更复杂的通信。
5、前台服务:
如果服务需要长时间运行,建议将其作为前台服务运行,这样可以减少被系统杀死的可能性。前台服务需要在 onCreate() 或 onStartCommand() 方法中调用 startForeground()。

6、服务的启动:

使用 startService(Intent) 启动服务,服务会一直运行,直到调用 stopService(Intent) 或服务自己调用 stopSelf()。
使用 bindService(Intent, ServiceConnection, int) 绑定服务,服务会与客户端建立连接,并在客户端解绑时停止。
7、服务的停止:

服务可以通过调用 stopSelf() 或 stopSelfResult(int) 停止自己。
客户端可以通过调用 unbindService(ServiceConnection) 解绑服务,服务在没有绑定的客户端时可能会停止。
8、服务的权限:
服务可能需要特定的权限才能运行,这些权限需要在应用的 AndroidManifest.xml 文件中声明。


Builder

"Builder"模式是一种创建对象的设计模式,尤其适用于需要构建复杂对象的场合,其中对象的构建过程可能需要多个步骤,并且可能需要不同的配置选项。Builder模式的主要目的是将构建过程与最终产品的表示分离,这样可以更灵活地构造对象,而不会使构造代码过于臃肿或难以阅读。

Builder 模式的组成:

Builder模式通常包括以下几个部分:

  1. Product:这是最终构建出来的复杂对象。
  2. Builder:定义了构建Product的各个部分的抽象方法,通常以一系列的构建步骤来实现。
  3. Concrete Builders:实现Builder接口,提供具体的构建步骤和方法。
  4. Director:使用一个Builder对象来构建Product的实例。Director决定了构建过程的顺序。

使用场景:

Builder模式在以下场景中特别有用:

  • 构建的对象有多个可选部分或配置选项。
  • 构建的过程需要多个步骤,而且这些步骤的顺序可能会影响最终的产品。
  • 构建的对象的创建过程很复杂,需要解耦合创建逻辑和使用逻辑。

示例:

在Kotlin中,可以使用Builder模式来构建一个相对复杂的对象,例如一个详细的订单。假设有一个电子商务应用,需要创建包含各种细节的订单,如顾客信息、商品列表、支付方式和送货地址等。下面是一个使用Builder模式的示例,演示如何创建这样一个订单:

data class Customer(val name: String, val email: String)

data class Product(val id: String, val name: String, val price: Double)

data class ShippingAddress(val street: String, val city: String, val postalCode: String)

//sealed class通常用于创建类型安全的枚举或表示具有固定子类集的抽象基类。
//使用sealed class可以强制子类必须在同一个文件中定义,或者在编译时确保所有可能的子类都被覆盖
sealed class PaymentMethod {
    data class CreditCard(val number: String, val expirationMonth: Int, val expirationYear: Int) : PaymentMethod()
    data class PayPal(val email: String) : PaymentMethod()
}

data class Order(
    val customer: Customer,
    val products: List<Product>,
    val paymentMethod: PaymentMethod,
    val shippingAddress: ShippingAddress
) {
    class Builder {
        private var customer: Customer? = null
        private val products = mutableListOf<Product>()
        private var paymentMethod: PaymentMethod? = null
        private var shippingAddress: ShippingAddress? = null

        fun customer(customer: Customer) = apply { this.customer = customer }
        fun product(product: Product) = apply { products.add(product) }
        fun paymentMethod(paymentMethod: PaymentMethod) = apply { this.paymentMethod = paymentMethod }
        fun shippingAddress(shippingAddress: ShippingAddress) = apply { this.shippingAddress = shippingAddress }

        fun build(): Order {
            checkNotNull(customer) { "Customer must be set." }
            checkNotNull(paymentMethod) { "Payment method must be set." }
            checkNotNull(shippingAddress) { "Shipping address must be set." }
            return Order(customer!!, products.toList(), paymentMethod!!, shippingAddress!!)
        }
    }
}

fun main() {
    val customer = Customer("Alice", "alice@example.com")
    val product1 = Product("123", "iPhone 12 Pro Max", 999.99)
    val product2 = Product("456", "AirPods Pro", 249.99)
    val shippingAddress = ShippingAddress("123 Apple Street", "Cupertino", "95014")

    val order = Order.Builder()
        .customer(customer)
        .product(product1)
        .product(product2)
        .paymentMethod(PaymentMethod.CreditCard("1234567890123456", 12, 2025))
        .shippingAddress(shippingAddress)
        .build()

    println(order)
}

//在这个例子中,Order类包含了一些必要的属性,如顾客信息、商品列表、支付方式和送货地址。
//Order.Builder类提供了构建Order实例的方法。你可以多次调用product方法来添加多个商品到订单中,
//使用customer、paymentMethod和shippingAddress方法来设定订单的其他部分。
//
//最后,在main函数中,创建了一个Customer实例,两个Product实例,
//一个ShippingAddress实例,并使用Order.Builder构建了一个完整的Order实例。
//通过这种方式,可以清晰地看到订单是如何一步步构建起来的,同时保持了代码的整洁和可读性。


示例代码:

使用 AlertDialog.Builder:

val builder = AlertDialog.Builder(this)
builder.setTitle("提示")
builder.setMessage("确定要退出应用吗?")
builder.setPositiveButton("确定") { dialog, _ ->
    // 执行退出操作
    finish() // 关闭Activity
}
builder.setNegativeButton("取消") { dialog, _ ->
    dialog.dismiss()
}
builder.create().show()


//    在这个示例中:
//
//    使用 AlertDialog.Builder 创建对话框构建器。
//    设置对话框的标题和消息。
//    为“确定”和“取消”按钮设置点击事件。
//    使用 create() 方法创建 AlertDialog 实例。
//    使用 show() 方法显示对话框。

 使用 Notification.Builder:

val builder = Notification.Builder(applicationContext)
    .setContentTitle("标题")
    .setContentText("这是一条通知")
    .setSmallIcon(R.drawable.ic_notification)
    .setContentIntent(pendingIntent)

val notification = builder.build()
NotificationManagerCompat.from(applicationContext)
    .notify(NOTIFICATION_ID, notification)


//    在这个示例中:
//
//    使用 Notification.Builder 创建通知构建器。
//    设置通知的标题、文本、小图标和内容意图。
//    使用 build() 方法构建 Notification 对象。
//    使用 NotificationManagerCompat 发送通知。

 


Dialog

在软件开发中,尤其是桌面和移动应用开发中,对话框(Dialog)是一种常见的用户界面元素,用于在不离开当前屏幕或窗口的情况下向用户提供信息或请求输入。对话框通常浮在应用的其余部分之上,要求用户对其进行响应,例如通过点击按钮确认或取消某个操作。

对话框的类型

对话框可以分为多种类型,每种类型都有其特定的用途:

  1. 模态对话框:阻止用户与应用的其他部分交互,直到对话框被关闭。
  2. 非模态对话框:允许用户在对话框打开时与应用的其他部分交互。
  3. 警告对话框:用于显示警告信息,通常包含一个“确定”按钮。
  4. 确认对话框:询问用户是否确认执行某项操作,通常包含“确定”和“取消”按钮。
  5. 输入对话框:请求用户输入信息,通常包含一个文本框和“确定”按钮。
  6. 信息对话框:仅显示信息给用户,通常只有一个“确定”或“关闭”按钮。

示例:

AlertDialog.Builder(this)
    .setTitle("确认删除?")
    .setMessage("您确定要删除此条目吗?")
    .setPositiveButton("确定") { _, _ ->
        // 用户点击了“确定”按钮,执行删除操作
        deleteEntry()
    }
    .setNegativeButton("取消") { dialog, _ ->
        // 用户点击了“取消”按钮,关闭对话框
        dialog.cancel()
    }
    .setIcon(android.R.drawable.ic_dialog_alert)
    .show()


Provider

在安卓(Android)开发中,"Provider"主要指的是“Content Provider”。Content Provider 是 Android 平台上用于存储和检索数据的一种机制,特别设计用于在多个应用程序之间共享数据。它是 Android 四大组件之一,其它三大组件分别是 Activity、Service 和 BroadcastReceiver。

1、Content Provider 的用途
Content Provider 被设计来提供跨应用的数据访问,这使得一个应用可以提供数据给其它应用使用,同时也可以让一个应用访问另一个应用的数据。例如,联系人列表、日历事件、浏览器书签等通常都是通过 Content Provider 来管理和共享的。

2、Content Provider 的工作原理
Content Provider 通过一组标准的 CRUD(创建、读取、更新、删除)接口来操作数据。数据通常是以类似于 SQL 数据库的形式存储的,虽然实际上可以使用任何类型的持久化存储。

3、主要组成部分
Content Resolver:这是 Android 系统提供的一个接口,应用程序通过它来访问 Content Provider。
Content URI:用于唯一标识数据的 URI。这些 URI 通常是形如 content://com.example.provider/table 的形式。
MIME Type:定义了数据的类型,如 vnd.android.cursor.dir/vnd.com.example.provider.table 或 vnd.android.cursor.item/vnd.com.example.provider.table,分别表示目录(多行记录)或单个项目(单行记录)。
4、使用 Content Provider 的步骤

  1. 创建 Content Provider:继承自 ContentProvider 类,实现必须的方法,如 query(), insert(), update(), delete(), 和 getType()。
  2. 声明 Content Provider:在 AndroidManifest.xml 文件中声明你的 Content Provider。
  3. 定义 URI:创建 URI 用于识别数据,通常以 content:// 开头,后跟包名和路径。
  4. 使用 Content Resolver:在需要访问 Content Provider 的应用中,使用 getContentResolver() 方法来执行 CRUD 操作。


bean

在Android项目中,数据模型类(有时被称为“bean”类,因为它们遵循了JavaBean的编码约定)通常会被放在java源代码目录下的某个包内,比如model、entities或data这样的文件夹下。这些类往往用来封装数据,比如用户信息、商品信息、订单详情等,它们通常包含私有属性和对应的公共getter和setter方法。

  


RadioGroup / RadioButton

RadioGroup是Android中用于包含一组互斥的RadioButton的布局容器。

当一个RadioButton被选中时,同一RadioGroup内的其他RadioButton都会被自动取消选中,确保任何时候只有一项被选中。这在需要用户从多个选项中选择单一答案的场景中非常有用,例如性别选择、问卷调查中的单选题等。

例如:

<RadioGroup
    android:id="@+id/radio_group"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content">

    <RadioButton
        android:id="@+id/radio_male"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Male" />

    <RadioButton
        android:id="@+id/radio_female"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Female" />

    <RadioButton
        android:id="@+id/radio_other"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Other" />

</RadioGroup>


原文地址:https://blog.csdn.net/m0_66843126/article/details/140547470

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!