如何在Activity间传递数据及通过startActivityForResult更新数据与界面
嘿,我来帮你搞定这两个Android开发的问题,结合你给的代码片段详细拆解~
问题一:如何从通过getIntent()接收数据的Activity中发送数据?
其实不管这个Activity是不是通过getIntent()接收数据的,发送数据的逻辑和普通Activity完全一致,分两种场景:
- 如果是要把数据返回给上一个启动它的Activity:用
setResult()配合finish()就行,就像你在AddNewContact里做的那样。比如当前Activity是接收了数据的ViewContact,现在要回传数据给Activity A,代码可以这么写:// 准备返回的Intent和数据 Intent resultIntent = new Intent(); resultIntent.putExtra("KEY_UPDATED_CONTACT_ID", contactId); // 设置结果码和数据 setResult(RESULT_OK, resultIntent); finish(); // 关闭当前Activity,回到上一个 - 如果是要启动新的Activity并传递数据:直接用
startActivity()就行,和普通场景没区别,比如从ViewContact启动另一个Activity:Intent intent = new Intent(this, OtherActivity.class); intent.putExtra("KEY_CONTACT_INFO", contact); startActivity(intent);
简单说:接收Intent数据的身份,不会限制你发送Intent的能力~
问题二:能否在Activity B中用startActivityForResult(),在Activity C修改数据后更新B的数据库与布局?
当然可以!你的思路完全没问题,代码里的更新没生效,大概率是数据库更新是异步操作,但你没在更新完成后触发UI刷新,不一定非要用LiveData,但LiveData会让这个过程更省心。
先分析你的现有代码问题
你在ViewContact的onActivityResult里拿到了编辑后的联系人数据,调用了contactRepository.update(contact),但UI没变化:
- 如果你的Repository的
update方法是异步的(比如用Room的suspend方法、Coroutine或者AsyncTask),数据库确实会更新,但ViewContact的UI没有收到“数据已更新”的通知,所以不会自动刷新。 - 另外,注意
startActivityForResult()已经被AndroidX废弃了,推荐用registerForActivityResult(),后面会给你示例。
解决方案:两种方式实现UI更新
方式一:手动刷新UI(简单直接,适合小场景)
在数据库更新完成后,重新查询该联系人的最新数据,然后手动更新ViewContact的所有控件:
// 修改onActivityResult里的更新逻辑 if (requestCode == EDIT_CONTACT_REQUEST && resultCode == RESULT_OK) { // ... 前面获取name、phone等数据的代码 Contact contact = new Contact( name, surname, company, phoneNumber, phoneType, email, emailType, address, postcode); contact.setId(id); // 用Coroutine在后台更新数据库,避免阻塞主线程 CoroutineScope(Dispatchers.IO).launch { contactRepository.update(contact); // 后台查询最新的联系人数据 Contact updatedContact = contactRepository.getContactByIdSync(id); // 切回主线程更新UI withContext(Dispatchers.Main) { // 手动更新所有显示控件 tvName.setText(updatedContact.getName()); tvSurname.setText(updatedContact.getSurname()); tvPhone.setText(updatedContact.getPhoneNumber()); // 其他控件同理更新 } } Toast.makeText(this, "联系人已更新", Toast.LENGTH_SHORT).show(); }
这里假设你的Repository有一个同步查询的getContactByIdSync方法,如果用Room的话,这个方法要放在后台线程调用。
方式二:用LiveData自动监听数据库变化(推荐,符合MVVM规范)
如果你的ViewContact一开始就是通过LiveData来观察联系人数据的,那么当数据库更新时,LiveData会自动通知UI刷新,完全不用手动触发:
- 首先确保你的Room DAO和Repository提供返回LiveData的查询方法:
// DAO层 @Dao interface ContactDao { @Update suspend fun update(contact: Contact); @Query("SELECT * FROM contacts WHERE id = :id") fun getContactById(id: Int): LiveData<Contact>; } // Repository层 class ContactRepository(application: Application) { private val contactDao: ContactDao; init { ContactDatabase db = ContactDatabase.getDatabase(application); contactDao = db.contactDao(); } suspend fun update(contact: Contact) { contactDao.update(contact); } fun getContactById(id: Int): LiveData<Contact> { return contactDao.getContactById(id); } } - 在ViewContact的
onCreate里观察这个LiveData,初始化UI并自动监听变化:@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_view_contact); // 获取要查看的联系人ID int contactId = getIntent().getIntExtra(EXTRA_ID, -1); ContactRepository contactRepository = new ContactRepository(getApplication()); // 观察LiveData,数据变化时自动更新UI contactRepository.getContactById(contactId).observe(this, contact -> { if (contact != null) { tvName.setText(contact.getName()); tvSurname.setText(contact.getSurname()); tvPhone.setText(contact.getPhoneNumber()); // 其他控件初始化/更新 } }); } - 然后在
onActivityResult里只需要异步更新数据库即可,LiveData会自动触发UI刷新:@Override public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == EDIT_CONTACT_REQUEST && resultCode == RESULT_OK) { // ... 前面获取数据的代码 Contact contact = new Contact( name, surname, company, phoneNumber, phoneType, email, emailType, address, postcode); contact.setId(id); // 异步更新数据库 CoroutineScope(Dispatchers.IO).launch { contactRepository.update(contact); } Toast.makeText(this, "联系人已更新", Toast.LENGTH_SHORT).show(); } else { Toast.makeText(this, "联系人未更新", Toast.LENGTH_SHORT).show(); } }
补充:替换废弃的startActivityForResult()
从AndroidX Activity 1.2.0开始,startActivityForResult()被废弃,推荐用registerForActivityResult(),代码示例如下:
// 在ViewContact里定义ActivityResultLauncher private ActivityResultLauncher<Intent> editContactLauncher = registerForActivityResult( new ActivityResultContracts.StartActivityForResult(), result -> { if (result.getResultCode() == RESULT_OK) { Intent data = result.getData(); if (data != null) { int id = data.getIntExtra(EXTRA_ID, -1); if (id == -1) { Toast.makeText(this, "联系人未更新", Toast.LENGTH_SHORT).show(); return; } // 这里处理返回的数据,和原来的onActivityResult逻辑一致 String name = data.getStringExtra(EXTRA_NAME); // ... 其他数据获取和更新逻辑 } } else { Toast.makeText(this, "联系人未更新", Toast.LENGTH_SHORT).show(); } }); // 启动编辑页面Activity C时调用 Intent intent = new Intent(this, AddNewContact.class); intent.putExtra(EXTRA_ID, contactId); // 传递要编辑的联系人ID editContactLauncher.launch(intent);
内容的提问来源于stack exchange,提问作者George
相关产品推荐
相关产品推荐

