什么是接口?
接口可以理解为一个 “契约” 或 “规范”,它定义了一组方法(抽象方法、默认方法、静态方法)和常量,但没有提供这些方法的具体实现。

在 Java 中,接口使用 interface 关键字来定义。
核心特点:
- 纯抽象: 接口中的方法在 Java 8 之前都是抽象的(只有声明,没有实现),从 Java 8 开始,接口可以包含
default方法和static方法的实现。 - 实现关系: 类通过
implements关键字来实现一个或多个接口,一个实现接口的类,必须实现该接口中所有的抽象方法(除非该类本身是抽象类)。 - 多态: 接口是实现多态的重要方式,你可以将接口类型的变量指向任何实现了该接口的类的实例,从而调用接口中定义的方法。
为什么要在 Android 中使用接口?(核心优势)
接口是 Android 开发中极其重要的概念,主要有以下几个原因:
a. 解耦
这是接口最重要的作用,它允许你定义一个组件(Activity 或 Fragment)需要的行为,而不需要关心这个行为具体是由谁提供的。

- 例子:
OnClickListener。Button不需要知道点击事件的具体逻辑是什么,它只需要知道“有某个东西想监听我的点击”,这个“某个东西”就是实现了OnClickListener接口的对象,你的Activity实现了这个接口,并把this传给Button,这样,Button和你的Activity的具体逻辑就解耦了。
b. 实现组件间的通信
这是 Android 中最常见的用法,尤其是在 Fragment 和 Activity 之间通信。
- 场景: 一个
Fragment中发生了一个事件(比如用户点击了按钮、选择了列表项),需要通知承载它的Activity去执行某些操作(比如跳转到另一个页面、更新数据)。 - 解决方案: 在
Fragment中定义一个接口,Activity实现这个接口,当事件发生时,Fragment调用接口方法,Activity就能接收到并处理。
c. 定义回调
回调是一种异步编程模式,当一个耗时操作完成时,通过回调通知调用者。
- 例子: 从网络加载数据,你不能在主线程(UI线程)进行网络请求,你通常会启动一个后台任务(如
AsyncTask,Retrofit,Kotlin Coroutines),当数据加载完成后,你需要一个方式把数据传回 UI 线程来更新界面,这个“传回”的动作就是通过回调接口实现的。onSuccess(List<Data> data)- 成功时调用onFailure(String error)- 失败时调用
d. 实现多态
你可以定义一个接口类型的变量,然后让它指向不同实现类的对象,这使得你的代码更加灵活和可扩展。
如何在 Android 中使用接口?(实践案例)
我们通过几个最经典的 Android 场景来学习接口的具体用法。
Fragment 与 Activity 通信(最经典)
目标: 在 FragmentA 中点击一个按钮,通知 MainActivity 更新标题。
步骤 1: 在 Fragment 中定义接口
// MyFragment.java
public class MyFragment extends Fragment {
// 1. 定义一个接口,用于与宿主 Activity 通信
public interface OnFragmentInteractionListener {
void onItemClicked(String itemTitle);
}
private OnFragmentInteractionListener mListener;
// 2. 重写 onAttach() 方法,获取宿主 Activity 的引用
@Override
public void onAttach(@NonNull Context context) {
super.onAttach(context);
// 检查宿主 Activity 是否实现了我们的接口
if (context instanceof OnFragmentInteractionListener) {
mListener = (OnFragmentInteractionListener) context;
} else {
throw new RuntimeException(context.toString()
+ " must implement OnFragmentInteractionListener");
}
}
// 3. 在 Fragment 销毁时,清除引用,避免内存泄漏
@Override
public void onDetach() {
super.onDetach();
mListener = null;
}
// ... Fragment 的其他代码,onCreateView ...
public void onMyButtonClicked() {
// 4. 当某个事件发生时,调用接口中的方法
if (mListener != null) {
mListener.onItemClicked("新标题来自 Fragment");
}
}
}
步骤 2: 在 Activity 中实现接口
// MainActivity.java
public class MainActivity extends AppCompatActivity implements MyFragment.OnFragmentInteractionListener {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 获取 Fragment 实例(假设已经添加到布局中)
MyFragment myFragment = (MyFragment) getSupportFragmentManager().findFragmentById(R.id.my_fragment);
// 当你从 Fragment 内部触发事件时,会自动调用这里的方法
// myFragment.onMyButtonClicked();
}
// 5. 实现接口方法
@Override
public void onItemClicked(String itemTitle) {
Log.d("MainActivity", "收到来自Fragment的消息: " + itemTitle);
// 在这里更新UI,比如更新Toolbar的标题
if (getSupportActionBar() != null) {
getSupportActionBar().setTitle(itemTitle);
}
}
}
自定义回调(网络请求)
目标: 模拟一个网络请求,成功后返回数据,失败后返回错误信息。
步骤 1: 定义回调接口
// ApiResponseCallback.java
public interface ApiResponseCallback {
// 请求成功时调用
void onSuccess(String data);
// 请求失败时调用
void onFailure(String errorMessage);
}
步骤 2: 创建一个执行网络请求的工具类
// NetworkUtils.java
public class NetworkUtils {
public static void fetchData(String url, ApiResponseCallback callback) {
// 模拟网络请求
new Thread(new Runnable() {
@Override
public void run() {
try {
// 模拟耗时操作
Thread.sleep(2000);
// 模拟请求成功
String response = "这是从服务器获取的数据";
// 在主线程回调
((Activity) callback).runOnUiThread(new Runnable() {
@Override
public void run() {
callback.onSuccess(response);
}
});
} catch (InterruptedException e) {
// 模拟请求失败
String error = "网络连接失败";
((Activity) callback).runOnUiThread(new Runnable() {
@Override
public void run() {
callback.onFailure(error);
}
});
}
}
}).start();
}
}
注意: 在上面的
NetworkUtils中,我们通过将callback强转为Activity来使用runOnUiThread,这是一种不太优雅但能说明问题的做法,更好的方式是让ApiResponseCallback的实现者自己处理线程切换(比如在 ViewModel 或 Presenter 中)。
步骤 3: 在 Activity/Fragment 中使用
// 在 MainActivity 或 Fragment 中
public class MyActivity extends AppCompatActivity implements ApiResponseCallback {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_my);
Button fetchDataButton = findViewById(R.id.fetch_data_button);
fetchDataButton.setOnClickListener(v -> {
// 发起网络请求,并传入当前 Activity 作为回调的实现者
NetworkUtils.fetchData("https://api.example.com/data", this);
});
}
@Override
public void onSuccess(String data) {
// 在主线程中执行,更新UI
Toast.makeText(this, "请求成功: " + data, Toast.LENGTH_LONG).show();
TextView textView = findViewById(R.id.result_text_view);
textView.setText(data);
}
@Override
public void onFailure(String errorMessage) {
// 在主线程中执行,更新UI
Toast.makeText(this, "请求失败: " + errorMessage, Toast.LENGTH_LONG).show();
}
}
接口的最佳实践和高级用法
a. 使用接口避免内存泄漏
在 Fragment 的 onAttach / onDetach 模式中,我们已经看到了这一点,将 Fragment 对 Activity 的引用(mListener)在 onDetach 时置为 null,可以防止 Activity 因被 Fragment 长期持有而无法被回收,从而造成内存泄漏。
b. 接口中的默认方法 (Default Methods - Java 8+)
从 Java 8 开始,接口可以有默认实现,这在 Android 开发中非常有用,尤其是在升级第三方库时。
- 作用: 为接口方法提供一个默认的实现,这样,当接口升级新增了带有默认实现的方法时,所有已经实现了该接口的类无需修改就能自动获得这个新功能。
- 例子: 假设你的
OnFragmentInteractionListener接口新增了一个可选方法onItemLongClicked()。
public interface OnFragmentInteractionListener {
void onItemClicked(String itemTitle);
// 新增一个有默认实现的方法
default void onItemLongClicked(String itemTitle) {
Log.d("Default", "Long click on: " + itemTitle);
// 默认什么都不做,或者提供一个通用的处理逻辑
}
}
你的 MainActivity 不需要实现 onItemLongClicked,但它仍然可以正常工作。MainActivity 想提供自己的长按逻辑,只需重写该方法即可。
c. 函数式接口 与 Lambda 表达式
如果一个接口中只有一个抽象方法(不包括 default 和 static 方法),那么它就是一个函数式接口。
- 优点: 可以使用更简洁的 Lambda 表达式 来代替匿名内部类。
- 例子:
OnClickListener就是一个经典的函数式接口。
传统方式(匿名内部类):
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// 点击逻辑
}
});
Lambda 表达式:
button.setOnClickListener(v -> {
// 点击逻辑
// 这里的 'v' View 参数
});
对于自定义的回调接口,也可以使用 Lambda:
// 定义一个函数式接口
@FunctionalInterface
public interface MyClickListener {
void onClick();
}
// 使用
MyButton.setOnClickListener(() -> {
Log.d("MyButton", "Clicked with Lambda!");
});
| 特性 | 描述 | Android 中的应用场景 |
|---|---|---|
| 定义 | 一组方法的契约,不包含具体实现。 | 定义组件间通信的“协议”。 |
| 核心优势 | 解耦、多态、回调。 | Fragment-Activity 通信 异步任务回调 (网络、数据库) 自定义 View 的事件监听 |
| 实现方式 | class MyClass implements MyInterface |
MainActivity implements OnFragmentInteractionListener |
| 最佳实践 | 在 onAttach 中检查并赋值引用。在 onDetach 中置空引用,防止内存泄漏。使用函数式接口和 Lambda 简化代码。 |
Fragment 通信模式的 onAttach/onDetach 生命周期管理。 |
| 高级特性 | 默认方法 (Java 8+) 用于接口演进,Lambda 表达式 用于简化代码。 | 当你维护的库需要升级接口时,提供默认实现以保持向后兼容。 |
掌握接口是成为一名合格 Android 开发者的必经之路,它不仅是 Java 语言的基础,更是构建灵活、健壮、可维护的 Android 应用的核心设计模式,多加练习,你就能在项目中游刃有余地使用它。
