BroadcastReceiver onReceive 方法在 Fragment onCreate() 之前调用
BroadcastReceiver onReceive method called before Fragment onCreate()
我有一个 IntentService,它在调用 SplashActivity onCreate 时启动:
class SplashActivity : AppCompatActivity() {
private val handler = Handler(Looper.getMainLooper())
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_splash)
startService(Intent(applicationContext, ContactsService::class.java))
handler.postDelayed({
val intent = Intent(this, MainActivity::class.java)
startActivity(intent)
}, SPLASH_DELAY.toLong())
}
}
private const val SPLASH_DELAY = 1500
这是我的 IntentService :
override fun onHandleIntent(intent: Intent?) {
val cursor = ContactUtil.getContactsCursor(null, null, this)
val contacts = ContactUtil.getContacts(cursor, this)
cursor?.close()
val contactsIntent = Intent(CONTACTS_RECEIVER)
contactsIntent.putParcelableArrayListExtra(CONTACTS, ArrayList<Parcelable>(contacts))
sendBroadcast(contactsIntent)
}
1 - 如果我有大量联系人,我的 broadcastReceiver onReceive
方法会在片段创建后调用,这没问题。
2 - 如果我有几个片段,onReceive
方法在片段创建之前调用,根本不会更新我的 UI。
private BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
List<Contact> contacts = intent.getParcelableArrayListExtra(CONTACTS);
mContacts = contacts;
mAdapter.setItems(contacts, true);
mProgressBar.setVisibility(View.GONE);
mAppBarLayout.setVisibility(View.VISIBLE);
mRecyclerView.setVisibility(View.VISIBLE);
}
};
第二种情况的解决方案是什么?
首先摆脱系统广播。假设您的代码执行所描述的操作,您会将所有用户的联系人泄露给设备上的每个应用程序。因此,除了性能问题和应用过大 Intent
导致应用程序崩溃的可能性之外,您还有一个重大的隐私漏洞。
然后,去掉IntentService
。它已被弃用,如果您对这些数据所做的一切都是在 UI.
中使用它,则没有必要
相反,设置一个单独的存储库来管理您对联系人的访问。让你的 activity 的 ViewModel
调用存储库上的一些方法来执行此操作,其中存储库使用普通后台线程(可能通过 Executor
或 RxJava 类型)。存储库可以在工作完成时发出事件,例如通过 LiveData
或 RxJava。您的 ViewModel
可以使用 LiveData
让 UI 层知道数据,以便它可以更新 UI。而且,由于 LiveData
是一个值持有者,即使值在片段准备好之前到达,它也会持有该值。
这种方法(具有反应性 API 的存储库对象)是 Google 的一般架构建议的一部分。
我有一个 IntentService,它在调用 SplashActivity onCreate 时启动:
class SplashActivity : AppCompatActivity() {
private val handler = Handler(Looper.getMainLooper())
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_splash)
startService(Intent(applicationContext, ContactsService::class.java))
handler.postDelayed({
val intent = Intent(this, MainActivity::class.java)
startActivity(intent)
}, SPLASH_DELAY.toLong())
}
}
private const val SPLASH_DELAY = 1500
这是我的 IntentService :
override fun onHandleIntent(intent: Intent?) {
val cursor = ContactUtil.getContactsCursor(null, null, this)
val contacts = ContactUtil.getContacts(cursor, this)
cursor?.close()
val contactsIntent = Intent(CONTACTS_RECEIVER)
contactsIntent.putParcelableArrayListExtra(CONTACTS, ArrayList<Parcelable>(contacts))
sendBroadcast(contactsIntent)
}
1 - 如果我有大量联系人,我的 broadcastReceiver onReceive
方法会在片段创建后调用,这没问题。
2 - 如果我有几个片段,onReceive
方法在片段创建之前调用,根本不会更新我的 UI。
private BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
List<Contact> contacts = intent.getParcelableArrayListExtra(CONTACTS);
mContacts = contacts;
mAdapter.setItems(contacts, true);
mProgressBar.setVisibility(View.GONE);
mAppBarLayout.setVisibility(View.VISIBLE);
mRecyclerView.setVisibility(View.VISIBLE);
}
};
第二种情况的解决方案是什么?
首先摆脱系统广播。假设您的代码执行所描述的操作,您会将所有用户的联系人泄露给设备上的每个应用程序。因此,除了性能问题和应用过大 Intent
导致应用程序崩溃的可能性之外,您还有一个重大的隐私漏洞。
然后,去掉IntentService
。它已被弃用,如果您对这些数据所做的一切都是在 UI.
相反,设置一个单独的存储库来管理您对联系人的访问。让你的 activity 的 ViewModel
调用存储库上的一些方法来执行此操作,其中存储库使用普通后台线程(可能通过 Executor
或 RxJava 类型)。存储库可以在工作完成时发出事件,例如通过 LiveData
或 RxJava。您的 ViewModel
可以使用 LiveData
让 UI 层知道数据,以便它可以更新 UI。而且,由于 LiveData
是一个值持有者,即使值在片段准备好之前到达,它也会持有该值。
这种方法(具有反应性 API 的存储库对象)是 Google 的一般架构建议的一部分。