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

发布于:2025-03-25 ⋅ 阅读:(37) ⋅ 点赞:(0)

在 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 等)可以帮助开发者提高代码的安全性和可读性,避免一些常见的错误。