简体   繁体   中英

BroadcastReceiver onReceive method called before Fragment onCreate()

I have an IntentService which starts when SplashActivity onCreate called:

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

Here is my 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 - If I have huge number of contacts, my broadcastReceiver onReceive method called after Fragment creation, which is ok.

2 - If I have a few number of fragment, onReceive method called before Fragment creation, which does not update my UI at all.

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

What is the solution for 2nd case?

Start by getting rid of the system broadcast. Assuming your code does what is described, you are leaking all the user's contacts to every single app on the device . So, beyond the performance problems and the chance of crashing the app with a too-big Intent , you have a major privacy hole.

Then, get rid of the IntentService . It is deprecated, and it is unnecessary if all you are doing with this data is using it in a UI.

Instead, set up a singleton repository that manages your access to the contacts. Have your activity's ViewModel call some method on the repository to do that, where the repository uses an ordinary background thread (perhaps through an Executor or RxJava type). The repository can emit an event when the work is completed, such as via LiveData or RxJava. Your ViewModel can use LiveData for letting the UI layer know about the data so it can update the UI. And, since LiveData is a value holder, it will hold the value even if the value arrives before the fragment is ready for it.

This approach (repository object with a reactive API) is part of Google's general architecture recommendations.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM