在 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 {@Overrideprotected 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@Overridepublic 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);}@Overridepublic void onBindViewHolder(@NonNull MyViewHolder holder, int position) {String item = dataSource.get(position);holder.textView.setText(item);}@Overridepublic 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 {@Overrideprotected 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;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);// 初始化 LiveDatadataLiveData = new MutableLiveData<>();// 获取 TextView 实例textView = findViewById(R.id.textView);// 创建观察者Observer<String> observer = new Observer<String>() {@Overridepublic 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<>();@MainThreadpublic void updateDataOnMainThread(String data) {liveData.setValue(data);}@WorkerThreadpublic void updateDataOnWorkerThread(String data) {// 在工作线程中更新 LiveData 需要使用 postValue 方法liveData.postValue(data);}
}
代码解释
@MainThread
注解:表示该方法必须在主线程中调用,setValue
方法必须在主线程中调用,因此使用@MainThread
注解进行标记。@WorkerThread
注解:表示该方法必须在工作线程中调用,postValue
方法可以在工作线程中调用,因此使用@WorkerThread
注解进行标记。
总结
LiveData
是 Jetpack 中实现观察者模式的重要组件,它通过观察者模式实现了数据的实时更新和通知。同时,Jetpack 提供的注解(如 @NonNull
、@Nullable
、@MainThread
、@WorkerThread
等)可以帮助开发者提高代码的安全性和可读性,避免一些常见的错误。