AsyncTaskLoader onLoadFinished with a pending task and config change

后端 未结 4 1247
醉酒成梦
醉酒成梦 2021-02-02 10:11

I\'m trying to use an AsyncTaskLoader to load data in the background to populate a detail view in response to a list item being chosen. I\'ve gotten it mostly work

4条回答
  •  甜味超标
    2021-02-02 10:56

    In most cases you should just ignore such reports if Activity is already destroyed.

    public void onLoadFinished(Loader loader, String data) {
        Log.d("DemoActivity", "onLoadFinished reporting to activity " + myActivityId);
        if (isDestroyed()) {
           Log.i("DemoActivity", "Activity already destroyed, report ignored: " + data);
           return;
        }
        resultFragment.setResultText(data);
    }
    

    Also you should insert checking isDestroyed() in any inner classes. Runnable - is the most used case.

    For example:

    // UI thread
    final Handler handler = new Handler();
    Executor someExecutorService = ... ;
    someExecutorService.execute(new Runnable() {
        public void run() {
            // some heavy operations
            ...
            // notification to UI thread
            handler.post(new Runnable() {
                // this runnable can link to 'dead' activity or any outer instance
                if (isDestroyed()) {
                    return;
                }
    
                // we are alive
                onSomeHeavyOperationFinished();
            });
        }
    });
    

    But in such cases the best way is to avoid passing strong reference on Activity to another thread (AsynkTask, Loader, Executor, etc).

    The most reliable solution is here:

    // BackgroundExecutor.java
    public class BackgroundExecutor {
        private static final Executor instance = Executors.newSingleThreadExecutor();
    
        public static void execute(Runnable command) {
            instance.execute(command);
        }
    }
    
    // MyActivity.java
    public class MyActivity extends Activity {
        // Some callback method from any button you want
        public void onSomeButtonClicked() {
            // Show toast or progress bar if needed
    
            // Start your heavy operation
            BackgroundExecutor.execute(new SomeHeavyOperation(this));
        }
    
        public void onSomeHeavyOperationFinished() {
            if (isDestroyed()) {
                return;
            }
    
            // Hide progress bar, update UI
        }
    }
    
    // SomeHeavyOperation.java
    public class SomeHeavyOperation implements Runnable {
        private final WeakReference ref;
    
        public SomeHeavyOperation(MyActivity owner) {
            // Unlike inner class we do not store strong reference to Activity here
            this.ref = new WeakReference(owner);
        }
    
        public void run() {
            // Perform your heavy operation
            // ...
            // Done!
    
            // It's time to notify Activity
            final MyActivity owner = ref.get();
            // Already died reference
            if (owner == null) return;
    
            // Perform notification in UI thread
            owner.runOnUiThread(new Runnable() {
                public void run() {
                    owner.onSomeHeavyOperationFinished();
                }
            });
        }
    }
    

提交回复
热议问题