引言
在Android应用开发中,跨Activity的数据传递和界面更新是开发者经常面临的挑战。由于Android的Activity生命周期管理机制,直接调用另一个Activity的方法并不推荐,这会导致紧耦合和潜在的内存泄漏问题。本文将深入探讨几种安全、高效的跨Activity通信方式,包括使用Intent传递数据、startActivityForResult机制、ViewModel共享数据、EventBus事件总线等,并详细分析常见错误及其处理技巧。
1. 使用Intent传递数据(基础方式)
1.1 基本原理
Intent是Android组件间通信的核心机制,通过Bundle携带数据,支持基本数据类型和实现了Parcelable/Serializable接口的对象。
1.2 代码示例:传递基本数据类型
// 发送Activity (MainActivity.java)
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button btnNavigate = findViewById(R.id.btn_navigate);
btnNavigate.setOnClickListener(v -> {
// 创建Intent,指定当前Activity和目标Activity
Intent intent = new Intent(MainActivity.this, DetailActivity.class);
// 携带基本数据类型
intent.putExtra("USER_ID", 1001);
intent.putExtra("USER_NAME", "张三");
intent.putExtra("SCORE", 95.5);
// 启动目标Activity
startActivity(intent);
});
}
}
// 接收Activity (DetailActivity.java)
public class DetailActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_detail);
// 从Intent获取数据
Intent intent = getIntent();
if (intent != null) {
int userId = intent.getIntExtra("USER_ID", -1);
String userName = intent.getStringExtra("USER_NAME");
double score = intent.getDoubleExtra("SCORE", 0.0);
// 更新UI
TextView tvInfo = findViewById(R.id.tv_info);
tvInfo.setText(String.format("用户ID: %d\n姓名: %s\n分数: %.1f",
userId, userName, score));
}
}
}
1.3 传递自定义对象(Parcelable实现)
// 自定义User对象,实现Parcelable接口
public class User implements Parcelable {
private int id;
private String name;
private String email;
// 构造方法
public User(int id, String name, String email) {
this.id = id;
this.name = name;
this.email = email;
}
// Parcelable实现
protected User(Parcel in) {
id = in.readInt();
name = in.readString();
email = in.readString();
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(id);
dest.writeString(name);
dest.writeString(email);
}
@Override
public int describeContents() {
return 0;
}
public static final Creator<User> CREATOR = new Creator<User>() {
@Override
public User createFromParcel(Parcel in) {
return new User(in);
}
@Override
public User[] newArray(int size) {
return new User[size];
}
};
// Getter方法
public int getId() { return id; }
public String getName() { return name; }
public String getEmail() { return email; }
}
// 发送Activity
public class MainActivity extends AppCompatActivity {
private void navigateWithUser() {
User user = new User(1001, "李四", "lisi@example.com");
Intent intent = new Intent(this, DetailActivity.class);
intent.putExtra("USER", user); // 直接传递Parcelable对象
startActivity(intent);
}
}
// 接收Activity
public class DetailActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_detail);
User user = getIntent().getParcelableExtra("USER");
if (user != null) {
// 使用user对象更新UI
updateUI(user);
}
}
}
1.4 优缺点分析
优点:
- 简单直接,适合一次性数据传递
- 系统级支持,性能较好
- 无需额外依赖库
缺点:
- 只能传递实现了Parcelable/Serializable接口的对象
- 数据量大时Bundle大小受限(约50KB)
- 无法传递生命周期长的对象,容易导致内存泄漏
2. startActivityForResult机制(双向通信)
2.1 基本原理
通过startActivityForResult()启动Activity,在目标Activity完成后调用setResult()返回数据,原Activity通过onActivityResult()接收结果。
2.2 代码示例:用户选择场景
// MainActivity.java
public class MainActivity extends AppCompatActivity {
private static final int REQUEST_CODE_SELECT_USER = 100;
private TextView tvSelectedUser;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tvSelectedUser = findViewById(R.id.tv_selected_user);
Button btnSelectUser = findViewById(R.id.btn_select_user);
btnSelectUser.setOnClickListener(v -> {
Intent intent = new Intent(this, UserSelectActivity.class);
// 启动并等待结果
startActivityForResult(intent, REQUEST_CODE_SELECT_USER);
});
}
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_CODE_SELECT_USER && resultCode == RESULT_OK && data != null) {
// 接收返回的用户数据
User selectedUser = data.getParcelableExtra("SELECTED_USER");
if (selectedUser != null) {
tvSelectedUser.setText("选中用户: " + selectedUser.getName());
}
} else if (resultCode == RESULT_CANCELED) {
// 用户取消选择
Toast.makeText(this, "已取消选择", Toast.LENGTH_SHORT).show();
}
}
}
// UserSelectActivity.java
public class UserSelectActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_user_select);
Button btnSelectAlice = findViewById(R.id.btn_select_alice);
Button btnSelectBob = findViewById(R.id.btn_select_bob);
btnSelectAlice.setOnClickListener(v -> {
// 创建结果数据
User alice = new User(1, "Alice", "alice@example.com");
Intent resultIntent = new Intent();
resultIntent.putExtra("SELECTED_USER", alice);
// 设置结果并结束当前Activity
setResult(RESULT_OK, resultIntent);
finish();
});
btnSelectBob.setOnClickListener(v -> {
User bob = new User(2, "Bob", "bob@example.com");
Intent resultIntent = new Intent();
resultIntent.putExtra("SELECTED_USER", bob);
setResult(RESULT_OK, resultIntent);
finish();
});
// 取消按钮
findViewById(R.id.btn_cancel).setOnClickListener(v -> {
setResult(RESULT_CANCELED);
finish();
});
}
}
2.3 优缺点分析
优点:
- 支持双向通信,适合需要用户交互后返回结果的场景
- 生命周期管理相对简单
缺点:
- 回调地狱(Callback Hell)风险
- 代码耦合度较高
- 在Activity结果返回前,原Activity可能已被销毁,导致内存泄漏
3. ViewModel + LiveData(现代推荐方式)
3.1 基本原理
ViewModel以生命周期感知的方式存储和管理界面相关数据,LiveData则提供可观察的数据存储器。多个Activity/Fragment可以共享同一个ViewModel实例(通过ViewModelStoreOwner)。
3.2 代码示例:共享数据模型
// SharedViewModel.java
public class SharedViewModel extends ViewModel {
// 使用LiveData存储用户数据
private final MutableLiveData<User> selectedUser = new MutableLiveData<>();
private final MutableLiveData<String> message = new MutableLiveData<>();
public void selectUser(User user) {
selectedUser.setValue(user);
}
public LiveData<User> getSelectedUser() {
return selectedUser;
}
public void sendMessage(String msg) {
message.setValue(msg);
}
public LiveData<String> getMessage() {
return message;
}
}
// MainActivity.java
public class MainActivity extends AppCompatActivity {
private SharedViewModel viewModel;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 获取ViewModel实例(作用域为Activity)
viewModel = new ViewModelProvider(this).get(SharedViewModel.class);
Button btnNavigate = findViewById(R.id.btn_navigate);
btnNavigate.setOnClickListener(v -> {
// 在跳转前设置数据
User user = new User(1001, "张三", "zhangsan@example.com");
viewModel.selectUser(user);
// 启动新Activity
startActivity(new Intent(this, DetailActivity.class));
});
// 观察数据变化(可选,用于接收返回数据)
viewModel.getMessage().observe(this, msg -> {
if (msg != null) {
Toast.makeText(this, "收到消息: " + msg, Toast.LENGTH_SHORT).show();
}
});
}
}
// DetailActivity.java
public class DetailActivity extends AppCompatActivity {
private SharedViewModel viewModel;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_detail);
// 获取同一个ViewModel实例
viewModel = new ViewModelProvider(this).get(SharedViewModel.class);
// 观察用户数据变化
viewModel.getSelectedUser().observe(this, user -> {
if (user != null) {
// 更新UI
TextView tvInfo = findViewById(R.id.tv_info);
tvInfo.setText(String.format("用户ID: %d\n姓名: %s\n邮箱: %s",
user.getId(), user.getName(), user.getEmail()));
}
});
// 发送反馈消息回MainActivity
Button btnSendFeedback = findViewById(R.id.btn_send_feedback);
btnSendFeedback.setOnClickListener(v -> {
viewModel.sendMessage("DetailActivity操作完成");
finish(); // 结束当前Activity
});
}
}
3.3 优缺点分析
优点:
- 生命周期感知,自动处理配置更改(如屏幕旋转)
- 数据驱动UI更新,代码更清晰
- 支持多Fragment/Activity共享数据
- 无内存泄漏风险
缺点:
- 需要AndroidX依赖
- 仅适用于同一应用内通信
- 对于简单数据传递可能显得复杂
4. EventBus(事件总线模式)
4.1 基本原理
EventBus是一个基于发布-订阅模式的开源库,允许组件通过事件进行通信,无需显式引用彼此。
4.2 代码示例:事件驱动通信
// 1. 定义事件类
public class UserEvent {
private User user;
private String action;
public UserEvent(User user, String action) {
this.user = user;
this.action = action;
}
public User getUser() { return user; }
public String getAction() { return action; }
}
// 2. 发送事件的Activity
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button btnSendEvent = findViewById(R.id.btn_send_event);
btnSendEvent.setOnClickListener(v -> {
User user = new User(1001, "EventBus用户", "event@example.com");
// 发布事件
EventBus.getDefault().post(new UserEvent(user, "UPDATE"));
// 启动新Activity(可选)
startActivity(new Intent(this, DetailActivity.class));
});
}
@Override
protected void onStart() {
super.onStart();
EventBus.getDefault().register(this);
}
@Override
protected void onStop() {
super.onStop();
EventBus.getDefault().unregister(this);
}
// 接收事件的方法
@Subscribe(threadMode = ThreadMode.MAIN)
public void onUserEvent(UserEvent event) {
Toast.makeText(this, "MainActivity收到事件: " + event.getAction(),
Toast.LENGTH_SHORT).show();
}
}
// 3. 接收事件的Activity
public class DetailActivity extends AppCompatActivity {
private TextView tvEventInfo;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_detail);
tvEventInfo = findViewById(R.id.tv_event_info);
}
@Override
protected void onStart() {
super.onStart();
EventBus.getDefault().register(this);
}
@Override
protected void onStop() {
super.onStop();
EventBus.getDefault().unregister(this);
}
// 接收事件并更新UI
@Subscribe(threadMode = ThreadMode.MAIN)
public void onUserEvent(UserEvent event) {
if ("UPDATE".equals(event.getAction())) {
User user = event.getUser();
tvEventInfo.setText(String.format("EventBus接收:\n用户: %s\n邮箱: %s",
user.getName(), user.getEmail()));
}
}
}
4.3 依赖配置
// app/build.gradle
dependencies {
implementation 'org.greenrobot:eventbus:3.3.1'
}
4.4 优缺点分析
优点:
- 解耦彻底,组件间无引用关系
- 支持线程切换(ThreadMode)
- 事件可被多个订阅者接收
- 适合全局事件通知
缺点:
- 增加依赖库
- 事件类型定义需谨慎,避免命名冲突
- 调试困难(事件流不直观)
- 可能导致”事件风暴”(过度使用事件总线)
5. 其他通信方式
5.1 静态方法调用(不推荐)
// 不推荐的方式:直接调用静态方法
public class DataHolder {
private static User currentUser;
public static void setCurrentUser(User user) {
currentUser = user;
}
public static User getCurrentUser() {
return currentUser;
}
}
// 在Activity中使用
public class MainActivity extends AppCompatActivity {
private void navigate() {
// 设置数据
DataHolder.setCurrentUser(new User(1, "Test", "test@example.com"));
// 跳转
startActivity(new Intent(this, DetailActivity.class));
}
}
public class DetailActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 获取数据
User user = DataHolder.getCurrentUser();
// 使用数据...
}
}
问题:内存泄漏风险,无法自动清理,不适合复杂场景。
5.2 单例模式存储
// 单例数据管理器
public class DataManager {
private static DataManager instance;
private final Map<String, Object> dataMap = new HashMap<>();
private DataManager() {}
public static DataManager getInstance() {
if (instance == null) {
synchronized (DataManager.class) {
if (instance == null) {
instance = new DataManager();
}
}
}
return instance;
}
public void putData(String key, Object value) {
dataMap.put(key, value);
}
public Object getData(String key) {
return dataMap.remove(key); // 使用后立即移除,避免内存泄漏
}
}
注意:必须及时清理数据,否则会导致内存泄漏。
6. 常见错误及处理技巧
6.1 错误1:TransactionTooLargeException(数据传递过大)
问题描述:
Android 7.0+限制了Intent传递的数据大小(约1MB),超过限制会抛出TransactionTooLargeException。
解决方案:
// 错误示例:传递大量数据
Intent intent = new Intent(this, DetailActivity.class);
intent.putExtra("LARGE_LIST", (Serializable) largeDataList); // 可能崩溃
// 正确做法1:传递引用ID,通过单例或数据库获取数据
public class DataCache {
private static final Map<Integer, List<LargeData>> cache = new HashMap<>();
private static int idCounter = 0;
public static int storeData(List<LargeData> data) {
int id = idCounter++;
cache.put(id, data);
return id;
}
public static List<LargeData> getData(int id) {
return cache.remove(id); // 使用后立即清理
}
}
// 使用
int dataId = DataCache.storeData(largeDataList);
Intent intent = new Intent(this, DetailActivity.class);
intent.putExtra("DATA_ID", dataId);
startActivity(intent);
// 正确做法2:使用文件/数据库存储
// 将数据序列化到文件,传递文件路径
6.2 错误2:内存泄漏(Memory Leak)
问题描述: 在Activity中启动新Activity时,如果持有新Activity的引用或回调,会导致旧Activity无法被回收。
错误示例:
public class MainActivity extends AppCompatActivity {
private DetailActivity detailActivity; // 错误:持有Activity引用
private void navigate() {
Intent intent = new Intent(this, DetailActivity.class);
startActivity(intent);
// 错误:直接引用会导致内存泄漏
detailActivity = new DetailActivity(); // 不应该手动创建
}
}
解决方案:
// 1. 使用弱引用(WeakReference)
public class MainActivity extends AppCompatActivity {
private WeakReference<DetailActivity> detailActivityRef;
private void navigate() {
Intent intent = new Intent(this, DetailActivity.class);
startActivity(intent);
// 如果必须引用,使用弱引用
// detailActivityRef = new WeakReference<>(detailActivity);
}
}
// 2. 更好的做法:使用ViewModel或事件总线,避免直接引用
// 3. 在onDestroy中清理
@Override
protected void onDestroy() {
super.onDestroy();
// 清理所有可能泄漏的引用
detailActivityRef = null;
}
6.3 错误3:NullPointerException(空指针异常)
问题描述: 接收数据时未检查Intent或数据是否为null。
解决方案:
// 错误示例
public class DetailActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 直接使用,可能NPE
String name = getIntent().getStringExtra("USER_NAME");
TextView tv = findViewById(R.id.tv_name);
tv.setText(name); // 如果name为null,显示"null"
}
}
// 正确做法:防御性编程
public class DetailActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_detail);
Intent intent = getIntent();
if (intent == null) {
finish(); // 没有Intent,直接结束
return;
}
String name = intent.getStringExtra("USER_NAME");
if (name == null) {
name = "默认用户"; // 提供默认值
}
TextView tv = findViewById(R.id.tv_name);
if (tv != null) {
tv.setText(name);
}
// 或者使用更简洁的方式
String safeName = Objects.requireNonNullElse(intent.getStringExtra("USER_NAME"), "默认用户");
tv.setText(safeName);
}
}
6.4 错误4:ViewModel作用域混淆
问题描述: 在不同Activity中获取ViewModel时,作用域设置错误导致数据不共享。
错误示例:
// MainActivity
SharedViewModel viewModel1 = new ViewModelProvider(this).get(SharedViewModel.class);
// DetailActivity
SharedViewModel viewModel2 = new ViewModelProvider(this).get(SharedViewModel.class);
// 这两个ViewModel实例是不同的!
解决方案:
// 正确做法:使用同一个ViewModelStoreOwner
// 方法1:在Application级别共享(不推荐,可能导致内存泄漏)
public class MyApplication extends Application implements ViewModelStoreOwner {
private ViewModelStore appViewModelStore;
@Override
public ViewModelStore getViewModelStore() {
if (appViewModelStore == null) {
appViewModelStore = new ViewModelStore();
}
return appViewModelStore;
}
}
// 在Activity中获取
SharedViewModel viewModel = new ViewModelProvider(
(ViewModelStoreOwner) getApplication()).get(SharedViewModel.class);
// 方法2:使用ActivityResultRegistry(推荐)
public class MainActivity extends AppCompatActivity {
private final ActivityResultRegistry registry = new ActivityResultRegistry();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 使用ActivityResultLauncher
ActivityResultLauncher<Intent> launcher = registerForActivityResult(
new ActivityResultContracts.StartActivityForResult(),
result -> {
if (result.getResultCode() == RESULT_OK && result.getData() != null) {
// 处理结果
}
});
}
}
6.5 错误5:生命周期不匹配
问题描述: 在Activity的onCreate()中访问尚未初始化的视图或数据。
解决方案:
// 错误示例
public class DetailActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 错误:在setContentView之前访问视图
TextView tv = findViewById(R.id.tv_info); // 返回null
tv.setText("Hello"); // NPE
setContentView(R.layout.activity_detail);
}
}
// 正确做法
public class DetailActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_detail); // 先设置布局
// 再访问视图
TextView tv = findViewById(R.id.tv_info);
if (tv != null) {
tv.setText("Hello");
}
// 处理数据
handleIntentData();
}
private void handleIntentData() {
Intent intent = getIntent();
if (intent == null) return;
// 延迟处理数据,确保视图已初始化
if (savedInstanceState == null) {
// 只在首次创建时处理
processIntentData(intent);
}
}
}
6.6 错误6:重复注册监听器
问题描述: 在onCreate()中注册EventBus或LiveData监听器,但未在onDestroy()中注销,导致重复注册和内存泄漏。
解决方案:
// EventBus正确注册/注销
@Override
protected void onStart() {
super.onStart();
if (!EventBus.getDefault().isRegistered(this)) {
EventBus.getDefault().register(this);
}
}
@Override
protected void onStop() {
super.onStop();
if (EventBus.getDefault().isRegistered(this)) {
EventBus.getDefault().unregister(this);
}
}
// LiveData正确观察
private void setupObservers() {
// 使用viewLifecycleOwner(在Fragment中)
// 在Activity中使用this
viewModel.getData().observe(this, data -> {
// 更新UI
});
}
// 避免重复观察
private boolean isObserverSetup = false;
private void setupObservers() {
if (isObserverSetup) return;
isObserverSetup = true;
// 设置观察器...
}
6.7 错误7:混淆onActivityResult与新API
问题描述:
AndroidX推荐使用ActivityResultLauncher替代startActivityForResult,但开发者仍使用旧API。
解决方案:
// 旧API(已废弃)
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
// 处理结果...
}
// 新API(推荐)
public class MainActivity extends AppCompatActivity {
// 定义Launcher
private ActivityResultLauncher<Intent> userSelectLauncher;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 注册Launcher
userSelectLauncher = registerForActivityResult(
new ActivityResultContracts.StartActivityForResult(),
result -> {
if (result.getResultCode() == RESULT_OK && result.getData() != null) {
User user = result.getData().getParcelableExtra("SELECTED_USER");
if (user != null) {
// 更新UI
TextView tv = findViewById(R.id.tv_selected_user);
tv.setText("选中: " + user.getName());
}
}
});
Button btnSelect = findViewById(R.id.btn_select);
btnSelect.setOnClickListener(v -> {
Intent intent = new Intent(this, UserSelectActivity.class);
userSelectLauncher.launch(intent);
});
}
}
7. 最佳实践总结
7.1 选择策略
- 简单数据传递:使用Intent + Parcelable
- 双向通信/结果返回:使用ActivityResultLauncher
- 多Fragment/Activity共享数据:使用ViewModel + LiveData
- 全局事件通知:使用EventBus(谨慎使用)
- 避免:静态变量、单例直接存储Activity引用
7.2 性能优化
// 1. 使用SparseArray替代HashMap(针对整数键)
SparseArray<User> userCache = new SparseArray<>();
// 2. 延迟初始化
private TextView tvInfo;
private TextView getTvInfo() {
if (tvInfo == null) {
tvInfo = findViewById(R.id.tv_info);
}
return tvInfo;
}
// 3. 使用LruCache缓存对象
private LruCache<Integer, User> userCache = new LruCache<>(100);
// 4. 异步处理大数据
private void processLargeDataAsync(List<LargeData> data) {
new Thread(() -> {
// 耗时操作
List<Result> results = processData(data);
// 回到主线程更新UI
runOnUiThread(() -> updateUI(results));
}).start();
}
7.3 安全性考虑
// 1. 数据验证
public class SecureDataTransmitter {
public static boolean validateUserData(User user) {
if (user == null) return false;
if (user.getId() <= 0) return false;
if (user.getName() == null || user.getName().isEmpty()) return false;
return true;
}
}
// 2. 防止Intent注入
public class SafeActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Intent intent = getIntent();
if (intent != null && intent.getData() != null) {
// 验证URI来源
Uri data = intent.getData();
if (!isValidUri(data)) {
finish();
return;
}
}
}
private boolean isValidUri(Uri uri) {
// 检查URI是否来自可信来源
return "com.yourapp".equals(uri.getHost());
}
}
7.4 调试技巧
// 1. 添加日志追踪数据流
public class DebugDataTransmitter {
private static final String TAG = "DataFlow";
public static void logDataTransfer(String from, String to, Object data) {
Log.d(TAG, String.format("Transfer: %s -> %s, Data: %s",
from, to, data != null ? data.getClass().getSimpleName() : "null"));
}
}
// 2. 使用StrictMode检测问题
public class MyApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
if (BuildConfig.DEBUG) {
StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
.detectAll()
.penaltyLog()
.build());
StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
.detectAll()
.penaltyLog()
.build());
}
}
}
8. 总结
跨Activity通信是Android开发的核心技能,选择合适的方案取决于具体场景:
- Intent传递:适合简单、一次性数据传递
- ActivityResultLauncher:适合需要返回结果的交互场景
- ViewModel:现代推荐方式,适合共享数据和配置更改
- EventBus:适合解耦的全局事件,但需谨慎使用
关键原则:
- 避免直接引用Activity实例
- 及时清理资源,防止内存泄漏
- 做好空值检查和异常处理
- 遵循Android生命周期规范
- 优先使用AndroidX推荐的新API
通过合理选择通信方式并遵循最佳实践,可以构建出健壮、高效、可维护的Android应用。# Android开发中如何跨Activity调用方法解决数据传递与界面更新问题及常见错误处理技巧
引言
在Android应用开发中,跨Activity的数据传递和界面更新是开发者经常面临的挑战。由于Android的Activity生命周期管理机制,直接调用另一个Activity的方法并不推荐,这会导致紧耦合和潜在的内存泄漏问题。本文将深入探讨几种安全、高效的跨Activity通信方式,包括使用Intent传递数据、startActivityForResult机制、ViewModel共享数据、EventBus事件总线等,并详细分析常见错误及其处理技巧。
1. 使用Intent传递数据(基础方式)
1.1 基本原理
Intent是Android组件间通信的核心机制,通过Bundle携带数据,支持基本数据类型和实现了Parcelable/Serializable接口的对象。
1.2 代码示例:传递基本数据类型
// 发送Activity (MainActivity.java)
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button btnNavigate = findViewById(R.id.btn_navigate);
btnNavigate.setOnClickListener(v -> {
// 创建Intent,指定当前Activity和目标Activity
Intent intent = new Intent(MainActivity.this, DetailActivity.class);
// 携带基本数据类型
intent.putExtra("USER_ID", 1001);
intent.putExtra("USER_NAME", "张三");
intent.putExtra("SCORE", 95.5);
// 启动目标Activity
startActivity(intent);
});
}
}
// 接收Activity (DetailActivity.java)
public class DetailActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_detail);
// 从Intent获取数据
Intent intent = getIntent();
if (intent != null) {
int userId = intent.getIntExtra("USER_ID", -1);
String userName = intent.getStringExtra("USER_NAME");
double score = intent.getDoubleExtra("SCORE", 0.0);
// 更新UI
TextView tvInfo = findViewById(R.id.tv_info);
tvInfo.setText(String.format("用户ID: %d\n姓名: %s\n分数: %.1f",
userId, userName, score));
}
}
}
1.3 传递自定义对象(Parcelable实现)
// 自定义User对象,实现Parcelable接口
public class User implements Parcelable {
private int id;
private String name;
private String email;
// 构造方法
public User(int id, String name, String email) {
this.id = id;
this.name = name;
this.email = email;
}
// Parcelable实现
protected User(Parcel in) {
id = in.readInt();
name = in.readString();
email = in.readString();
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(id);
dest.writeString(name);
dest.writeString(email);
}
@Override
public int describeContents() {
return 0;
}
public static final Creator<User> CREATOR = new Creator<User>() {
@Override
public User createFromParcel(Parcel in) {
return new User(in);
}
@Override
public User[] newArray(int size) {
return new User[size];
}
};
// Getter方法
public int getId() { return id; }
public String getName() { return name; }
public String getEmail() { return email; }
}
// 发送Activity
public class MainActivity extends AppCompatActivity {
private void navigateWithUser() {
User user = new User(1001, "李四", "lisi@example.com");
Intent intent = new Intent(this, DetailActivity.class);
intent.putExtra("USER", user); // 直接传递Parcelable对象
startActivity(intent);
}
}
// 接收Activity
public class DetailActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_detail);
User user = getIntent().getParcelableExtra("USER");
if (user != null) {
// 使用user对象更新UI
updateUI(user);
}
}
}
1.4 优缺点分析
优点:
- 简单直接,适合一次性数据传递
- 系统级支持,性能较好
- 无需额外依赖库
缺点:
- 只能传递实现了Parcelable/Serializable接口的对象
- 数据量大时Bundle大小受限(约50KB)
- 无法传递生命周期长的对象,容易导致内存泄漏
2. startActivityForResult机制(双向通信)
2.1 基本原理
通过startActivityForResult()启动Activity,在目标Activity完成后调用setResult()返回数据,原Activity通过onActivityResult()接收结果。
2.2 代码示例:用户选择场景
// MainActivity.java
public class MainActivity extends AppCompatActivity {
private static final int REQUEST_CODE_SELECT_USER = 100;
private TextView tvSelectedUser;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tvSelectedUser = findViewById(R.id.tv_selected_user);
Button btnSelectUser = findViewById(R.id.btn_select_user);
btnSelectUser.setOnClickListener(v -> {
Intent intent = new Intent(this, UserSelectActivity.class);
// 启动并等待结果
startActivityForResult(intent, REQUEST_CODE_SELECT_USER);
});
}
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_CODE_SELECT_USER && resultCode == RESULT_OK && data != null) {
// 接收返回的用户数据
User selectedUser = data.getParcelableExtra("SELECTED_USER");
if (selectedUser != null) {
tvSelectedUser.setText("选中用户: " + selectedUser.getName());
}
} else if (resultCode == RESULT_CANCELED) {
// 用户取消选择
Toast.makeText(this, "已取消选择", Toast.LENGTH_SHORT).show();
}
}
}
// UserSelectActivity.java
public class UserSelectActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_user_select);
Button btnSelectAlice = findViewById(R.id.btn_select_alice);
Button btnSelectBob = findViewById(R.id.btn_select_bob);
btnSelectAlice.setOnClickListener(v -> {
// 创建结果数据
User alice = new User(1, "Alice", "alice@example.com");
Intent resultIntent = new Intent();
resultIntent.putExtra("SELECTED_USER", alice);
// 设置结果并结束当前Activity
setResult(RESULT_OK, resultIntent);
finish();
});
btnSelectBob.setOnClickListener(v -> {
User bob = new User(2, "Bob", "bob@example.com");
Intent resultIntent = new Intent();
resultIntent.putExtra("SELECTED_USER", bob);
setResult(RESULT_OK, resultIntent);
finish();
});
// 取消按钮
findViewById(R.id.btn_cancel).setOnClickListener(v -> {
setResult(RESULT_CANCELED);
finish();
});
}
}
2.3 优缺点分析
优点:
- 支持双向通信,适合需要用户交互后返回结果的场景
- 生命周期管理相对简单
缺点:
- 回调地狱(Callback Hell)风险
- 代码耦合度较高
- 在Activity结果返回前,原Activity可能已被销毁,导致内存泄漏
3. ViewModel + LiveData(现代推荐方式)
3.1 基本原理
ViewModel以生命周期感知的方式存储和管理界面相关数据,LiveData则提供可观察的数据存储器。多个Activity/Fragment可以共享同一个ViewModel实例(通过ViewModelStoreOwner)。
3.2 代码示例:共享数据模型
// SharedViewModel.java
public class SharedViewModel extends ViewModel {
// 使用LiveData存储用户数据
private final MutableLiveData<User> selectedUser = new MutableLiveData<>();
private final MutableLiveData<String> message = new MutableLiveData<>();
public void selectUser(User user) {
selectedUser.setValue(user);
}
public LiveData<User> getSelectedUser() {
return selectedUser;
}
public void sendMessage(String msg) {
message.setValue(msg);
}
public LiveData<String> getMessage() {
return message;
}
}
// MainActivity.java
public class MainActivity extends AppCompatActivity {
private SharedViewModel viewModel;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 获取ViewModel实例(作用域为Activity)
viewModel = new ViewModelProvider(this).get(SharedViewModel.class);
Button btnNavigate = findViewById(R.id.btn_navigate);
btnNavigate.setOnClickListener(v -> {
// 在跳转前设置数据
User user = new User(1001, "张三", "zhangsan@example.com");
viewModel.selectUser(user);
// 启动新Activity
startActivity(new Intent(this, DetailActivity.class));
});
// 观察数据变化(可选,用于接收返回数据)
viewModel.getMessage().observe(this, msg -> {
if (msg != null) {
Toast.makeText(this, "收到消息: " + msg, Toast.LENGTH_SHORT).show();
}
});
}
}
// DetailActivity.java
public class DetailActivity extends AppCompatActivity {
private SharedViewModel viewModel;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_detail);
// 获取同一个ViewModel实例
viewModel = new ViewModelProvider(this).get(SharedViewModel.class);
// 观察用户数据变化
viewModel.getSelectedUser().observe(this, user -> {
if (user != null) {
// 更新UI
TextView tvInfo = findViewById(R.id.tv_info);
tvInfo.setText(String.format("用户ID: %d\n姓名: %s\n邮箱: %s",
user.getId(), user.getName(), user.getEmail()));
}
});
// 发送反馈消息回MainActivity
Button btnSendFeedback = findViewById(R.id.btn_send_feedback);
btnSendFeedback.setOnClickListener(v -> {
viewModel.sendMessage("DetailActivity操作完成");
finish(); // 结束当前Activity
});
}
}
3.3 优缺点分析
优点:
- 生命周期感知,自动处理配置更改(如屏幕旋转)
- 数据驱动UI更新,代码更清晰
- 支持多Fragment/Activity共享数据
- 无内存泄漏风险
缺点:
- 需要AndroidX依赖
- 仅适用于同一应用内通信
- 对于简单数据传递可能显得复杂
4. EventBus(事件总线模式)
4.1 基本原理
EventBus是一个基于发布-订阅模式的开源库,允许组件通过事件进行通信,无需显式引用彼此。
4.2 代码示例:事件驱动通信
// 1. 定义事件类
public class UserEvent {
private User user;
private String action;
public UserEvent(User user, String action) {
this.user = user;
this.action = action;
}
public User getUser() { return user; }
public String getAction() { return action; }
}
// 2. 发送事件的Activity
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button btnSendEvent = findViewById(R.id.btn_send_event);
btnSendEvent.setOnClickListener(v -> {
User user = new User(1001, "EventBus用户", "event@example.com");
// 发布事件
EventBus.getDefault().post(new UserEvent(user, "UPDATE"));
// 启动新Activity(可选)
startActivity(new Intent(this, DetailActivity.class));
});
}
@Override
protected void onStart() {
super.onStart();
EventBus.getDefault().register(this);
}
@Override
protected void onStop() {
super.onStop();
EventBus.getDefault().unregister(this);
}
// 接收事件的方法
@Subscribe(threadMode = ThreadMode.MAIN)
public void onUserEvent(UserEvent event) {
Toast.makeText(this, "MainActivity收到事件: " + event.getAction(),
Toast.LENGTH_SHORT).show();
}
}
// 3. 接收事件的Activity
public class DetailActivity extends AppCompatActivity {
private TextView tvEventInfo;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_detail);
tvEventInfo = findViewById(R.id.tv_event_info);
}
@Override
protected void onStart() {
super.onStart();
EventBus.getDefault().register(this);
}
@Override
protected void onStop() {
super.onStop();
EventBus.getDefault().unregister(this);
}
// 接收事件并更新UI
@Subscribe(threadMode = ThreadMode.MAIN)
public void onUserEvent(UserEvent event) {
if ("UPDATE".equals(event.getAction())) {
User user = event.getUser();
tvEventInfo.setText(String.format("EventBus接收:\n用户: %s\n邮箱: %s",
user.getName(), user.getEmail()));
}
}
}
4.3 依赖配置
// app/build.gradle
dependencies {
implementation 'org.greenrobot:eventbus:3.3.1'
}
4.4 优缺点分析
优点:
- 解耦彻底,组件间无引用关系
- 支持线程切换(ThreadMode)
- 事件可被多个订阅者接收
- 适合全局事件通知
缺点:
- 增加依赖库
- 事件类型定义需谨慎,避免命名冲突
- 调试困难(事件流不直观)
- 可能导致”事件风暴”(过度使用事件总线)
5. 其他通信方式
5.1 静态方法调用(不推荐)
// 不推荐的方式:直接调用静态方法
public class DataHolder {
private static User currentUser;
public static void setCurrentUser(User user) {
currentUser = user;
}
public static User getCurrentUser() {
return currentUser;
}
}
// 在Activity中使用
public class MainActivity extends AppCompatActivity {
private void navigate() {
// 设置数据
DataHolder.setCurrentUser(new User(1, "Test", "test@example.com"));
// 跳转
startActivity(new Intent(this, DetailActivity.class));
}
}
public class DetailActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 获取数据
User user = DataHolder.getCurrentUser();
// 使用数据...
}
}
问题:内存泄漏风险,无法自动清理,不适合复杂场景。
5.2 单例模式存储
// 单例数据管理器
public class DataManager {
private static DataManager instance;
private final Map<String, Object> dataMap = new HashMap<>();
private DataManager() {}
public static DataManager getInstance() {
if (instance == null) {
synchronized (DataManager.class) {
if (instance == null) {
instance = new DataManager();
}
}
}
return instance;
}
public void putData(String key, Object value) {
dataMap.put(key, value);
}
public Object getData(String key) {
return dataMap.remove(key); // 使用后立即移除,避免内存泄漏
}
}
注意:必须及时清理数据,否则会导致内存泄漏。
6. 常见错误及处理技巧
6.1 错误1:TransactionTooLargeException(数据传递过大)
问题描述:
Android 7.0+限制了Intent传递的数据大小(约1MB),超过限制会抛出TransactionTooLargeException。
解决方案:
// 错误示例:传递大量数据
Intent intent = new Intent(this, DetailActivity.class);
intent.putExtra("LARGE_LIST", (Serializable) largeDataList); // 可能崩溃
// 正确做法1:传递引用ID,通过单例或数据库获取数据
public class DataCache {
private static final Map<Integer, List<LargeData>> cache = new HashMap<>();
private static int idCounter = 0;
public static int storeData(List<LargeData> data) {
int id = idCounter++;
cache.put(id, data);
return id;
}
public static List<LargeData> getData(int id) {
return cache.remove(id); // 使用后立即清理
}
}
// 使用
int dataId = DataCache.storeData(largeDataList);
Intent intent = new Intent(this, DetailActivity.class);
intent.putExtra("DATA_ID", dataId);
startActivity(intent);
// 正确做法2:使用文件/数据库存储
// 将数据序列化到文件,传递文件路径
6.2 错误2:内存泄漏(Memory Leak)
问题描述: 在Activity中启动新Activity时,如果持有新Activity的引用或回调,会导致旧Activity无法被回收。
错误示例:
public class MainActivity extends AppCompatActivity {
private DetailActivity detailActivity; // 错误:持有Activity引用
private void navigate() {
Intent intent = new Intent(this, DetailActivity.class);
startActivity(intent);
// 错误:直接引用会导致内存泄漏
detailActivity = new DetailActivity(); // 不应该手动创建
}
}
解决方案:
// 1. 使用弱引用(WeakReference)
public class MainActivity extends AppCompatActivity {
private WeakReference<DetailActivity> detailActivityRef;
private void navigate() {
Intent intent = new Intent(this, DetailActivity.class);
startActivity(intent);
// 如果必须引用,使用弱引用
// detailActivityRef = new WeakReference<>(detailActivity);
}
}
// 2. 更好的做法:使用ViewModel或事件总线,避免直接引用
// 3. 在onDestroy中清理
@Override
protected void onDestroy() {
super.onDestroy();
// 清理所有可能泄漏的引用
detailActivityRef = null;
}
6.3 错误3:NullPointerException(空指针异常)
问题描述: 接收数据时未检查Intent或数据是否为null。
解决方案:
// 错误示例
public class DetailActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 直接使用,可能NPE
String name = getIntent().getStringExtra("USER_NAME");
TextView tv = findViewById(R.id.tv_name);
tv.setText(name); // 如果name为null,显示"null"
}
}
// 正确做法:防御性编程
public class DetailActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_detail);
Intent intent = getIntent();
if (intent == null) {
finish(); // 没有Intent,直接结束
return;
}
String name = intent.getStringExtra("USER_NAME");
if (name == null) {
name = "默认用户"; // 提供默认值
}
TextView tv = findViewById(R.id.tv_name);
if (tv != null) {
tv.setText(name);
}
// 或者使用更简洁的方式
String safeName = Objects.requireNonNullElse(intent.getStringExtra("USER_NAME"), "默认用户");
tv.setText(safeName);
}
}
6.4 错误4:ViewModel作用域混淆
问题描述: 在不同Activity中获取ViewModel时,作用域设置错误导致数据不共享。
错误示例:
// MainActivity
SharedViewModel viewModel1 = new ViewModelProvider(this).get(SharedViewModel.class);
// DetailActivity
SharedViewModel viewModel2 = new ViewModelProvider(this).get(SharedViewModel.class);
// 这两个ViewModel实例是不同的!
解决方案:
// 正确做法:使用同一个ViewModelStoreOwner
// 方法1:在Application级别共享(不推荐,可能导致内存泄漏)
public class MyApplication extends Application implements ViewModelStoreOwner {
private ViewModelStore appViewModelStore;
@Override
public ViewModelStore getViewModelStore() {
if (appViewModelStore == null) {
appViewModelStore = new ViewModelStore();
}
return appViewModelStore;
}
}
// 在Activity中获取
SharedViewModel viewModel = new ViewModelProvider(
(ViewModelStoreOwner) getApplication()).get(SharedViewModel.class);
// 方法2:使用ActivityResultRegistry(推荐)
public class MainActivity extends AppCompatActivity {
private final ActivityResultRegistry registry = new ActivityResultRegistry();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 使用ActivityResultLauncher
ActivityResultLauncher<Intent> launcher = registerForActivityResult(
new ActivityResultContracts.StartActivityForResult(),
result -> {
if (result.getResultCode() == RESULT_OK && result.getData() != null) {
// 处理结果
}
});
}
}
6.5 错误5:生命周期不匹配
问题描述: 在Activity的onCreate()中访问尚未初始化的视图或数据。
解决方案:
// 错误示例
public class DetailActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 错误:在setContentView之前访问视图
TextView tv = findViewById(R.id.tv_info); // 返回null
tv.setText("Hello"); // NPE
setContentView(R.layout.activity_detail);
}
}
// 正确做法
public class DetailActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_detail); // 先设置布局
// 再访问视图
TextView tv = findViewById(R.id.tv_info);
if (tv != null) {
tv.setText("Hello");
}
// 处理数据
handleIntentData();
}
private void handleIntentData() {
Intent intent = getIntent();
if (intent == null) return;
// 延迟处理数据,确保视图已初始化
if (savedInstanceState == null) {
// 只在首次创建时处理
processIntentData(intent);
}
}
}
6.6 错误6:重复注册监听器
问题描述: 在onCreate()中注册EventBus或LiveData监听器,但未在onDestroy()中注销,导致重复注册和内存泄漏。
解决方案:
// EventBus正确注册/注销
@Override
protected void onStart() {
super.onStart();
if (!EventBus.getDefault().isRegistered(this)) {
EventBus.getDefault().register(this);
}
}
@Override
protected void onStop() {
super.onStop();
if (EventBus.getDefault().isRegistered(this)) {
EventBus.getDefault().unregister(this);
}
}
// LiveData正确观察
private void setupObservers() {
// 在Fragment中使用viewLifecycleOwner
// 在Activity中使用this
viewModel.getData().observe(this, data -> {
// 更新UI
});
}
// 避免重复观察
private boolean isObserverSetup = false;
private void setupObservers() {
if (isObserverSetup) return;
isObserverSetup = true;
// 设置观察器...
}
6.7 错误7:混淆onActivityResult与新API
问题描述:
AndroidX推荐使用ActivityResultLauncher替代startActivityForResult,但开发者仍使用旧API。
解决方案:
// 旧API(已废弃)
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
// 处理结果...
}
// 新API(推荐)
public class MainActivity extends AppCompatActivity {
// 定义Launcher
private ActivityResultLauncher<Intent> userSelectLauncher;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 注册Launcher
userSelectLauncher = registerForActivityResult(
new ActivityResultContracts.StartActivityForResult(),
result -> {
if (result.getResultCode() == RESULT_OK && result.getData() != null) {
User user = result.getData().getParcelableExtra("SELECTED_USER");
if (user != null) {
// 更新UI
TextView tv = findViewById(R.id.tv_selected_user);
tv.setText("选中: " + user.getName());
}
}
});
Button btnSelect = findViewById(R.id.btn_select);
btnSelect.setOnClickListener(v -> {
Intent intent = new Intent(this, UserSelectActivity.class);
userSelectLauncher.launch(intent);
});
}
}
7. 最佳实践总结
7.1 选择策略
- 简单数据传递:使用Intent + Parcelable
- 双向通信/结果返回:使用ActivityResultLauncher
- 多Fragment/Activity共享数据:使用ViewModel + LiveData
- 全局事件通知:使用EventBus(谨慎使用)
- 避免:静态变量、单例直接存储Activity引用
7.2 性能优化
// 1. 使用SparseArray替代HashMap(针对整数键)
SparseArray<User> userCache = new SparseArray<>();
// 2. 延迟初始化
private TextView tvInfo;
private TextView getTvInfo() {
if (tvInfo == null) {
tvInfo = findViewById(R.id.tv_info);
}
return tvInfo;
}
// 3. 使用LruCache缓存对象
private LruCache<Integer, User> userCache = new LruCache<>(100);
// 4. 异步处理大数据
private void processLargeDataAsync(List<LargeData> data) {
new Thread(() -> {
// 耗时操作
List<Result> results = processData(data);
// 回到主线程更新UI
runOnUiThread(() -> updateUI(results));
}).start();
}
7.3 安全性考虑
// 1. 数据验证
public class SecureDataTransmitter {
public static boolean validateUserData(User user) {
if (user == null) return false;
if (user.getId() <= 0) return false;
if (user.getName() == null || user.getName().isEmpty()) return false;
return true;
}
}
// 2. 防止Intent注入
public class SafeActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Intent intent = getIntent();
if (intent != null && intent.getData() != null) {
// 验证URI来源
Uri data = intent.getData();
if (!isValidUri(data)) {
finish();
return;
}
}
}
private boolean isValidUri(Uri uri) {
// 检查URI是否来自可信来源
return "com.yourapp".equals(uri.getHost());
}
}
7.4 调试技巧
// 1. 添加日志追踪数据流
public class DebugDataTransmitter {
private static final String TAG = "DataFlow";
public static void logDataTransfer(String from, String to, Object data) {
Log.d(TAG, String.format("Transfer: %s -> %s, Data: %s",
from, to, data != null ? data.getClass().getSimpleName() : "null"));
}
}
// 2. 使用StrictMode检测问题
public class MyApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
if (BuildConfig.DEBUG) {
StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
.detectAll()
.penaltyLog()
.build());
StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
.detectAll()
.penaltyLog()
.build());
}
}
}
8. 总结
跨Activity通信是Android开发的核心技能,选择合适的方案取决于具体场景:
- Intent传递:适合简单、一次性数据传递
- ActivityResultLauncher:适合需要返回结果的交互场景
- ViewModel:现代推荐方式,适合共享数据和配置更改
- EventBus:适合解耦的全局事件,但需谨慎使用
关键原则:
- 避免直接引用Activity实例
- 及时清理资源,防止内存泄漏
- 做好空值检查和异常处理
- 遵循Android生命周期规范
- 优先使用AndroidX推荐的新API
通过合理选择通信方式并遵循最佳实践,可以构建出健壮、高效、可维护的Android应用。
