How should a fragment get notified about the result of an asynchronous task?

后端 未结 1 1247
栀梦
栀梦 2020-12-29 08:26

I have an Activity that uses fragments. These fragments may come and go, based on the users interactions. Many of these fragments launch jobs to an IntentService, which get

相关标签:
1条回答
  • 2020-12-29 08:54

    I noticed the same problem in IOSched App (Google I/O App for Android).

    They created DetachableResultReceiver, which extends SDK class ResultReciever.

    And they easily use it in Fragments.

    Receiver:

    /**
     * Proxy {@link ResultReceiver} that offers a listener interface that can be
     * detached. Useful for when sending callbacks to a {@link Service} where a
     * listening {@link Activity} can be swapped out during configuration changes.
     */
    public class DetachableResultReceiver extends ResultReceiver {
        private static final String TAG = "DetachableResultReceiver";
    
        private Receiver mReceiver;
    
        public DetachableResultReceiver(Handler handler) {
            super(handler);
        }
    
        public void clearReceiver() {
            mReceiver = null;
        }
    
        public void setReceiver(Receiver receiver) {
            mReceiver = receiver;
        }
    
        public interface Receiver {
            public void onReceiveResult(int resultCode, Bundle resultData);
        }
    
        @Override
        protected void onReceiveResult(int resultCode, Bundle resultData) {
            if (mReceiver != null) {
                mReceiver.onReceiveResult(resultCode, resultData);
            } else {
                Log.w(TAG, "Dropping result on floor for code " + resultCode + ": "
                        + resultData.toString());
            }
        }
    }
    

    Activity and Fragment:

    public class HomeActivity extends BaseActivity {
        private static final String TAG = "HomeActivity";
    
        private SyncStatusUpdaterFragment mSyncStatusUpdaterFragment;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
    
            //...
    
            mTagStreamFragment = (TagStreamFragment) fm.findFragmentById(R.id.fragment_tag_stream);
    
            mSyncStatusUpdaterFragment = (SyncStatusUpdaterFragment) fm
                    .findFragmentByTag(SyncStatusUpdaterFragment.TAG);
            if (mSyncStatusUpdaterFragment == null) {
                mSyncStatusUpdaterFragment = new SyncStatusUpdaterFragment();
                fm.beginTransaction().add(mSyncStatusUpdaterFragment,
                        SyncStatusUpdaterFragment.TAG).commit();
    
                triggerRefresh();
            }
        }
    
        private void triggerRefresh() {
            final Intent intent = new Intent(Intent.ACTION_SYNC, null, this, SyncService.class);
            intent.putExtra(SyncService.EXTRA_STATUS_RECEIVER, mSyncStatusUpdaterFragment.mReceiver);
            startService(intent);
    
            if (mTagStreamFragment != null) {
                mTagStreamFragment.refresh();
            }
        }
    
        /**
         * A non-UI fragment, retained across configuration changes, that updates its activity's UI
         * when sync status changes.
         */
        public static class SyncStatusUpdaterFragment extends Fragment
                implements DetachableResultReceiver.Receiver {
            public static final String TAG = SyncStatusUpdaterFragment.class.getName();
    
            private boolean mSyncing = false;
            private DetachableResultReceiver mReceiver;
    
            @Override
            public void onCreate(Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);
                setRetainInstance(true);
                mReceiver = new DetachableResultReceiver(new Handler());
                mReceiver.setReceiver(this);
            }
    
            /** {@inheritDoc} */
            public void onReceiveResult(int resultCode, Bundle resultData) {
                HomeActivity activity = (HomeActivity) getActivity();
                if (activity == null) {
                    return;
                }
    
                switch (resultCode) {
                    case SyncService.STATUS_RUNNING: {
                        mSyncing = true;
                        break;
                    }
                    //...
                }
    
                activity.updateRefreshStatus(mSyncing);
            }
    
            @Override
            public void onActivityCreated(Bundle savedInstanceState) {
                super.onActivityCreated(savedInstanceState);
                ((HomeActivity) getActivity()).updateRefreshStatus(mSyncing);
            }
        }
    }
    
    0 讨论(0)
提交回复
热议问题