Android第六次面试总结(Java设计模式二)

news2025/3/28 23:31:21

在 Android 开发里,ListView 和 RecyclerView 是常用的视图组件,用于展示大量数据列表。不过,这些视图组件本身无法直接展示原始数据源,需要借助 Adapter(适配器)把数据源适配成视图能够展示的数据,这便是适配器模式的实际应用。下面详细介绍 Adapter 在 ListView 和 RecyclerView 中的使用。

适配器模式原理

适配器模式的核心在于把一个类的接口转换为客户期望的另一个接口,让原本由于接口不兼容而不能一起工作的那些类可以协同工作。在 ListView 和 RecyclerView 的场景中,数据源(如数组、集合)和视图组件(ListView、RecyclerView)的接口不匹配,Adapter 就充当了中间的转换器,将数据源适配成视图组件能够识别和展示的形式。

ListView 中的适配器模式

示例代码
import android.app.Activity;
import android.os.Bundle;
import android.widget.ArrayAdapter;
import android.widget.ListView;

import java.util.ArrayList;
import java.util.List;

public class ListViewAdapterExample extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(android.R.layout.activity_list_item);

        // 数据源
        List<String> dataSource = new ArrayList<>();
        dataSource.add("Item 1");
        dataSource.add("Item 2");
        dataSource.add("Item 3");

        // 创建适配器
        ArrayAdapter<String> adapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, dataSource);

        // 获取 ListView 实例
        ListView listView = findViewById(android.R.id.list);

        // 设置适配器
        listView.setAdapter(adapter);
    }
}
代码解释
  • 数据源List<String> dataSource 是一个字符串列表,代表原始的数据集合。
  • 适配器ArrayAdapter 是 Android 提供的一个适配器类,它将 List<String> 类型的数据源适配成 ListView 可以展示的形式。ArrayAdapter 接收三个参数:上下文、列表项的布局资源和数据源。
  • ListView:通过 findViewById 方法获取 ListView 实例,然后调用 setAdapter 方法将适配器设置给 ListView,这样 ListView 就可以根据适配器提供的数据来展示列表项。

RecyclerView 中的适配器模式

示例代码

 

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import java.util.List;

// 自定义适配器类
class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder> {

    private List<String> dataSource;
    private Context context;

    public MyAdapter(Context context, List<String> dataSource) {
        this.context = context;
        this.dataSource = dataSource;
    }

    @NonNull
    @Override
    public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(context).inflate(android.R.layout.simple_list_item_1, parent, false);
        return new MyViewHolder(view);
    }

    @Override
    public void onBindViewHolder(@NonNull MyViewHolder holder, int position) {
        String item = dataSource.get(position);
        holder.textView.setText(item);
    }

    @Override
    public int getItemCount() {
        return dataSource.size();
    }

    static class MyViewHolder extends RecyclerView.ViewHolder {
        TextView textView;

        public MyViewHolder(@NonNull View itemView) {
            super(itemView);
            textView = itemView.findViewById(android.R.id.text1);
        }
    }
}
import android.os.Bundle;
import android.widget.LinearLayout;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import java.util.ArrayList;
import java.util.List;

public class RecyclerViewAdapterExample extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(android.R.layout.activity_list_item);

        // 数据源
        List<String> dataSource = new ArrayList<>();
        dataSource.add("Item 1");
        dataSource.add("Item 2");
        dataSource.add("Item 3");

        // 获取 RecyclerView 实例
        RecyclerView recyclerView = findViewById(android.R.id.list);

        // 设置布局管理器
        recyclerView.setLayoutManager(new LinearLayoutManager(this));

        // 创建适配器
        MyAdapter adapter = new MyAdapter(this, dataSource);

        // 设置适配器
        recyclerView.setAdapter(adapter);
    }
}
代码解释
  • 数据源:同样是 List<String> 类型的 dataSource,代表原始的数据集合。
  • 适配器:自定义的 MyAdapter 类继承自 RecyclerView.Adapter,它需要实现三个重要方法:
    • onCreateViewHolder:用于创建 ViewHolder 实例,ViewHolder 是一个用于缓存视图组件的容器。
    • onBindViewHolder:用于将数据源中的数据绑定到 ViewHolder 中的视图组件上。
    • getItemCount:返回数据源的大小。
  • RecyclerView:通过 findViewById 方法获取 RecyclerView 实例,先设置布局管理器(如 LinearLayoutManager),然后调用 setAdapter 方法将适配器设置给 RecyclerView,从而展示数据列表。

适配器模式的优势

  • 解耦数据源和视图:通过适配器模式,数据源和视图组件之间的耦合度降低,使得数据源和视图可以独立变化。
  • 可扩展性:可以根据需要自定义适配器,实现不同的视图展示效果,提高代码的可扩展性。
  • 代码复用:适配器可以被多个视图组件复用,提高代码的复用性。

在 Android 的 Jetpack 组件中,观察者模式有着广泛的应用,其中 LiveData 就是一个典型的例子,它很好地体现了观察者模式,并且借助注解来提升代码的安全性与可读性。下面详细介绍 LiveData 中的观察者模式以及相关注解的使用。

观察者模式在 LiveData 中的应用

原理

LiveData 是一个可观察的数据持有者类,它遵循观察者模式。LiveData 持有一个数据对象,当这个数据对象的状态发生变化时,所有注册的观察者(即 Observer)都会收到通知并更新自身状态。LiveData 还具备生命周期感知能力,它只会在观察者的生命周期处于活跃状态(如 STARTED 或 RESUMED)时才会通知观察者,避免了内存泄漏和不必要的更新。

示例代码
import androidx.appcompat.app.AppCompatActivity;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.Observer;
import android.os.Bundle;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {

    private MutableLiveData<String> dataLiveData;
    private TextView textView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // 初始化 LiveData
        dataLiveData = new MutableLiveData<>();

        // 获取 TextView 实例
        textView = findViewById(R.id.textView);

        // 创建观察者
        Observer<String> observer = new Observer<String>() {
            @Override
            public void onChanged(String newData) {
                // 当 LiveData 中的数据发生变化时,更新 TextView 的文本
                textView.setText(newData);
            }
        };

        // 注册观察者
        dataLiveData.observe(this, observer);

        // 更新 LiveData 中的数据
        updateData();
    }

    private void updateData() {
        // 模拟数据更新
        dataLiveData.setValue("New data");
    }
}
代码解释
  • LiveData 的创建:使用 MutableLiveData 类创建一个可变的 LiveData 对象 dataLiveData,用于持有数据。
  • 观察者的创建:创建一个 Observer 对象,实现 onChanged 方法,当 LiveData 中的数据发生变化时,该方法会被调用,从而更新 TextView 的文本。
  • 观察者的注册:调用 dataLiveData.observe(this, observer) 方法将观察者注册到 LiveData 上,其中 this 表示当前的 Activity,用于提供生命周期信息。
  • 数据的更新:调用 dataLiveData.setValue("New data") 方法更新 LiveData 中的数据,此时所有注册的观察者都会收到通知。

Jetpack 注解的应用

@NonNull 和 @Nullable 注解

在使用 LiveData 时,为了确保数据的非空性,可以使用 @NonNull 和 @Nullable 注解。这些注解可以帮助开发者在编译时发现潜在的空指针异常。

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;

public class MyViewModel {

    private MutableLiveData<@NonNull String> nonNullLiveData = new MutableLiveData<>();
    private MutableLiveData<@Nullable String> nullableLiveData = new MutableLiveData<>();

    public LiveData<@NonNull String> getNonNullLiveData() {
        return nonNullLiveData;
    }

    public LiveData<@Nullable String> getNullableLiveData() {
        return nullableLiveData;
    }

    public void setNonNullData(@NonNull String data) {
        nonNullLiveData.setValue(data);
    }

    public void setNullableData(@Nullable String data) {
        nullableLiveData.setValue(data);
    }
}
代码解释
  • @NonNull 注解:表示该变量或参数不能为 null,如果尝试将 null 值赋给被 @NonNull 注解修饰的变量或参数,编译器会发出警告。
  • @Nullable 注解:表示该变量或参数可以为 null
@MainThread 和 @WorkerThread 注解

在更新 LiveData 时,需要注意更新操作必须在主线程中进行。可以使用 @MainThread 和 @WorkerThread 注解来明确方法的调用线程。

 

import androidx.annotation.MainThread;
import androidx.annotation.WorkerThread;
import androidx.lifecycle.MutableLiveData;

public class MyViewModel {

    private MutableLiveData<String> liveData = new MutableLiveData<>();

    @MainThread
    public void updateDataOnMainThread(String data) {
        liveData.setValue(data);
    }

    @WorkerThread
    public void updateDataOnWorkerThread(String data) {
        // 在工作线程中更新 LiveData 需要使用 postValue 方法
        liveData.postValue(data);
    }
}
代码解释
  • @MainThread 注解:表示该方法必须在主线程中调用,setValue 方法必须在主线程中调用,因此使用 @MainThread 注解进行标记。
  • @WorkerThread 注解:表示该方法必须在工作线程中调用,postValue 方法可以在工作线程中调用,因此使用 @WorkerThread 注解进行标记。

总结

LiveData 是 Jetpack 中实现观察者模式的重要组件,它通过观察者模式实现了数据的实时更新和通知。同时,Jetpack 提供的注解(如 @NonNull@Nullable@MainThread@WorkerThread 等)可以帮助开发者提高代码的安全性和可读性,避免一些常见的错误。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2321206.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

一站式电脑工具箱,功能全面且实用

小明工具箱是一款集成了系统设置、维护工具、实用工具、图像处理等四大类工具的电脑工具箱&#xff0c;涵盖了上百种实用工具&#xff0c;能够满足用户在文件管理、文本处理、系统优化、图像处理等多方面的需求。 初次使用&#xff0c;需双击软件&#xff0c;便会自动将工具解压…

那些正常的动态规划

文章目录 前言动态规划到底是啥&#xff1f; 线性dp最长上升子序列子集和子序列和子串的区别内容分析 最大上升子序列例题1——[NOIP2004 提高组] 合唱队形分析 最长公共子序列最长公共子串 平面dp例题2——[NOIP2000 提高组] 方格取数分析 例题3——[NOIP2008 提高组] 传纸条分…

华为交换相关

端口模式 &#xff08;1&#xff09;access&#xff1a;只能属于单个VLAN&#xff0c;一般用于连接计算机端口 &#xff08;2&#xff09;trunk&#xff1a;端口允许多个VLAN通过&#xff0c;可以接收和发送多个VLAN报文&#xff0c;默认情况下只有管理VLAN不携带标签信息 &…

Chrome Performance 面板完全指南:从卡顿到丝滑的终极调试术

1.写在前面 前端性能调试是优化网页加载速度和运行效率的关键步骤&#xff0c;Chrome DevTools 的 Performance 面板 是核心工具; 2.Performance 面板使用步骤 ★ 基础 打开面板 在 Chrome 中按 F12 → 切换到 Performance 标签页。 开始录制 方式一&#xff1a;点击 ⚫️ 圆…

JDK 24:Java 24 中的新功能

&#x1f9d1; 博主简介&#xff1a;CSDN博客专家&#xff0c;历代文学网&#xff08;PC端可以访问&#xff1a;历代文学&#xff0c;移动端可微信小程序搜索“历代文学”&#xff09;总架构师&#xff0c;15年工作经验&#xff0c;精通Java编程&#xff0c;高并发设计&#xf…

ubuntu服务器server版安装,ssh远程连接xmanager管理,改ip网络连接。图文教程

ventoy启动服务器版iso镜像&#xff0c;注意看server名称&#xff0c;跟之前desktop版ubuntu不一样。没有gui界面。好&#xff0c;进入命令行界面。语言彻底没汉化了&#xff0c;选英文吧&#xff0c;别的更看不懂。 跟桌面版ubuntu类似&#xff0c;选择是否精简系统&#xff0…

python机器学习——新手入门学习笔记

一&#xff0c;概论 1.什么是机器学习 定义&#xff1a; 机器学习是从数据中自动分析获得模型&#xff0c;并利用模型对未知数据进行预测。 其实就是通过问题和数据&#xff0c;发现规律&#xff0c;并进行预测&#xff0c;与人脑相似。目的就是从历史数据当中获得规律&#x…

LabVIEW 与 PLC 通讯的常见方式

在工业自动化和数据采集系统中&#xff0c;PLC&#xff08;可编程逻辑控制器&#xff09; 广泛用于控制和监测各种设备&#xff0c;而 LabVIEW 作为强大的图形化编程工具&#xff0c;常用于上位机数据处理和可视化。为了实现 LabVIEW 与 PLC 的高效通讯&#xff0c;常见的方法包…

深度学习 Deep Learning 第9章 卷积网络 CNN

深度学习 Deep Learning 第9章 卷积网络 章节概述 本章深入探讨了卷积网络的原理、变体及其在深度学习中的应用。卷积网络通过卷积操作实现了参数共享和稀疏连接&#xff0c;显著提高了模型的效率和性能。本章首先介绍了卷积操作的基本形式及其在不同数据维度上的应用&#x…

Tekton系列之实践篇-从触发到完成的完整执行过程

以下介绍的是基于 Gitee 仓库 的 Tekton 工作流程 操作流程 定义task 克隆代码的task # task-clone.yaml apiVersion: tekton.dev/v1beta1 kind: Task metadata:name: git-clone spec:workspaces:- name: source # 工作目录params:- name: repo-url # 你的 Gitee 仓库地址…

【简单学习】Prompt Engineering 提示词工程

一、Prompt 1、Prompt 是什么&#xff1f; Prompt 是一种人为构造的输入序列&#xff0c;用于引导 GPT 模型根据先前输入的内容生成相关的输出。简单来说&#xff0c;就是你向模型提供的 “提示词”。 在 ChatGpt 中&#xff0c;我们可以通过设计不同的 prompt&#xff0c;让…

零基础入门网络爬虫第5天:Scrapy框架

4周 Srapy爬虫框架 不是一个简单的函数功能库&#xff0c;而是一个爬虫框架 安装&#xff1a;pip install scrapy 检测&#xff1a;scrapy -h Scrapy爬虫框架结构 爬虫框架 爬虫框架是实现爬虫功能的一个软件结构和功能组件集合爬虫框架是一个半成品&#xff0c;能够帮助…

C#设计模式快速回顾

知识点来源&#xff1a;人间自有韬哥在&#xff0c;豆包 目录 一、七大原则1. 单一职责原则 (Single Responsibility Principle)2. 开放封闭原则 (Open-Closed Principle)3. 里氏替换原则 (Liskov Substitution Principle)4. 接口隔离原则 (Interface Segregation Principle)5…

分页查询互动问题(用户端)

文章目录 概要整体架构流程技术细节小结 概要 需求分析以及接口设计 技术细节 1.Controller层 GetMapping("/page")ApiOperation("分页查询问题")public PageDTO<QuestionVO> queryQuestionPage(QuestionPageQuery query){return questionService…

【全队项目】智能学术海报生成系统PosterGenius(项目介绍)

&#x1f308; 个人主页&#xff1a;十二月的猫-CSDN博客 &#x1f525; 系列专栏&#xff1a;&#x1f3c0;大模型实战训练营_十二月的猫的博客-CSDN博客 &#x1f4aa;&#x1f3fb; 十二月的寒冬阻挡不了春天的脚步&#xff0c;十二点的黑夜遮蔽不住黎明的曙光 目录 1. 前…

【线程安全问题的原因和方法】【java形式】【图片详解】

在本章节中采用实例图片的方式&#xff0c;以一个学习者的姿态进行描述问题解决问题&#xff0c;更加清晰明了&#xff0c;以及过程中会发问的问题都会一一进行呈现 目录 线程安全演示线程不安全情况图片解释&#xff1a; 将上述代码进行修改【从并行转化成穿行的方式】不会出…

解决IDEA中maven找不到依赖项的问题

直接去官网找到对应的依赖项jar包&#xff0c;并且下载到本地&#xff0c;然后安装到本地厂库中。 Maven官网&#xff1a;https://mvnrepository.com/ 一、使用mvn install:install-file命令 Maven提供了install:install-file插件&#xff0c;用于手动将jar包安装到本地仓库…

pyside6的QGraphicsView体系,当鼠标位于不同的物体,显示不同的右键菜单

代码&#xff1a; # 设置样本图片的QGraphicsView模型 from PySide6.QtCore import Qt, QRectF, QObject from PySide6.QtGui import QPainter, QPen, QColor, QAction, QMouseEvent from PySide6.QtWidgets import QGraphicsView, QGraphicsScene, QGraphicsPixmapItem, QGra…

Python自动化测试 之 DrissionPage 的下载、安装、基本使用详解

Python自动化测试 之 DrissionPage 使用详解 &#x1f3e1;前言&#xff1a;一、☀️DrissionPage的基本概述二、 &#x1f5fa;️环境安装2.1 ✅️️运行环境2.2 ✅️️一键安装 三、&#x1f5fa;️快速入门3.1 页面类&#x1f6f0;️ChromiumPage&#x1f6eb; SessionPage&…

Java替换jar包中class文件

在更新java应用版本的运维工作中&#xff0c;由于一些原因&#xff0c;开发没办法给到完整的jar包&#xff0c;这个时候&#xff0c;就可以只将修改后的某个Java类的class文件替换掉原来iar包中的class文件&#xff0c;重新启动服务即可&#xff1a; 1、将jar包和将要替换的cl…