【问题标题】:BroadcastReceiver onReceive method called before Fragment onCreate()在 Fragment onCreate() 之前调用的 BroadcastReceiver onReceive 方法
【发布时间】:2020-04-08 19:45:32
【问题描述】:

我有一个 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 方法会在 Fragment 创建后调用,这没关系。

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);
        }
    };

第二种情况的解决方案是什么?

【问题讨论】:

    标签: android broadcastreceiver intentservice


    【解决方案1】:

    首先摆脱系统广播。假设您的代码执行了所描述的操作,您将所有用户的联系人泄露给设备上的每个应用程序。因此,除了性能问题和使用太大的Intent 导致应用程序崩溃的可能性之外,您还有一个重大的隐私漏洞。

    然后,摆脱IntentService。它已被弃用,如果您对这些数据所做的所有操作都是在 UI 中使用它,则它是不必要的。

    相反,设置一个单独的存储库来管理您对联系人的访问。让您的活动的ViewModel 调用存储库上的某个方法来执行此操作,其中存储库使用普通后台线程(可能通过Executor 或RxJava 类型)。存储库可以在工作完成时发出事件,例如通过LiveData 或 RxJava。您的 ViewModel 可以使用 LiveData 让 UI 层了解数据,以便它可以更新 UI。而且,由于LiveData 是一个值持有者,即使值在片段准备好之前到达,它也会持有该值。

    这种方法(具有反应式 API 的存储库对象)是 Google 通用架构建议的一部分。

    【讨论】:

    • I have an implementation for that in master branch。我应该将我的 RxJava 请求移动到存储库单例吗?我应该将我的 LiveData 保存在 ViewModel 中吗?我可以在 SplashActivity 的存储库单例中调用我的 RxJava 请求吗?
    • @ali: “我可以从 SplashActivity 调用我的 RxJava 请求吗?” -- 我会使用ViewModel 作为中介,如果你是从一个活动中做到这一点的。 “我在主分支中有一个实现” - FWIW,您的代码似乎没有在调度程序上完成工作。 Observable.just() 立即开始工作。 “我应该将我的 RxJava 请求移动到存储库单例吗?” -- 如果您需要跨多个活动的这些数据,是的。 “我应该将我的 LiveData 保存在 ViewModel 中吗?” -- 这是一种方便的方法,尽管有一些方法可以跳过它并一直使用 RxJava 到片段。
    • composeObservable 是我的BaseViewModel 中的一个方法,其中包括Observable.just() 语句。我希望ContactUtil.getContacts 在调用 SplashActivity onCreate 后立即开始执行,并在结果可用时立即在 MainActivity 中显示结果。每个 Activity 都需要多个 viewModel 吗?
    • @Ali:“每个活动我都需要多个视图模型吗?” ——我无法回答。如果需要(例如,为了重用),您可以拥有多个视图模型。
    • 我不知道如何在调用 SplashActivity onCreate 后立即执行 ContactUtil.getContacts,并在结果可用后立即在 MainActivity 中显示结果。 LiveData 在MainViewModel 我可以在两个活动中创建两个视图模型实例吗?我认为这行不通。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-12-15
    • 1970-01-01
    • 2012-12-19
    • 2017-08-20
    相关资源
    最近更新 更多