AsyncTask.cancel()的结束问题

解决异步任务取消难题
本文探讨了在用户快速切换详情界面时,如何有效管理异步任务以避免资源浪费和OOM问题。通过深入分析AsyncTask的cancel方法,并提供具体实现案例。

实际项目中有这么一个问题,用户进入详情界面,那么我们就要网络加载数据并展现在UI上,这个加载用线程或者异步。

这里就拿项目中统一用异步任务来获取网络数据把。

用户可能会有这么一个操作,它在一个商品(说说等)列表中,点击一个列表项,进入到相应的详情界面,这时候,我们会开启一个异步任务来获取网络数据,但是网络差的情况下, 用户可能就不愿意等了,立马按后退按钮回到列表,点击下一个别的列表项进入详情界面,发现加载太慢,又按后退键,如此反复,那么就导致此时有多个异步任务在执行,或者出现OOM问题,或者出现异步任务等待问题。

那么,作为开发者,我们对应的解决方案,便是在用户在详情界面按退出按钮退回到上一个界面的时候,把没有执行完的异步任务给结束掉。

------------------------------------------------------------------------------------------------------------------------------

现在我们发现了这个问题,又有了解决方案。那么就用代码来实现了。

那么 取消异步任务怎么做?

我一开始这样做,AsyncTask.cancel(true);

看下参数的定义:

@param mayInterruptIfRunning <tt>true</tt> if the thread executing this
     *        task should be interrupted; otherwise, in-progress tasks are allowed
     *        to complete.

1、如果是true,如果线程执行,则会被打断

2、如果是false,线程将会被运行执行完成

 

看到这,很显然,我们以为.cancel(true)就会结束掉我们开启的正在执行的异步任务

但是实际上并没有结束掉我们想要结束的异步任务~~

看了些别人对此的解释:

AsyncTask不会不考虑结果而直接结束一个线程。调用cancel()其实是给AsyncTask设置一个"canceled"状态。这取决于你去检查AsyncTask是否已经取消,之后决定是否终止你的操作。对于mayInterruptIfRunning——它所作的只是向运行中的线程发出interrupt()调用。在这种情况下,你的线程是不可中断的,也就不会终止该线程。

那么该如何结束线程呢?

可见.cancel()是给AsyncTask设置一个"canceled"的状态,那么想要终止异步任务,就需要在异步任务当中结束。

@Override
public void onProgressUpdate(Integer... value) {
// 判断是否被取消
if(isCancelled()) return;
.........
}

@Override
protected Integer doInBackground(Void... mgs) {
// Task被取消了,马上退出
if(isCancelled()) return null;
.......
// Task被取消了,马上退出

if(isCancelled()) return null;
}
...

 

另外结束异步任务的条件:

if(loadAsyncVedio!=null && !loadAsyncVedio.isCancelled()
                    && loadAsyncVedio.getStatus() == AsyncTask.Status.RUNNING){
                loadAsyncVedio.cancel(true);
                loadAsyncVedio = null;
            }
loadAsyncVedio(异步任务)

如此,便可以有效及时的结束异步任务

 

2025-09-01 15:04:06.851 30380-30415 USBOfflineUpdater com.kotei.overseas.navi I message: 解密验签 KVM_Navi_EU_148_1.zip: 238.2MB/3.0GB progress:16.28 2025-09-01 15:04:07.852 30380-30415 USBOfflineUpdater com.kotei.overseas.navi I message: 解密验签 KVM_Navi_EU_148_1.zip: 250.3MB/3.0GB progress:16.3 2025-09-01 15:04:08.853 30380-30415 USBOfflineUpdater com.kotei.overseas.navi I message: 解密验签 KVM_Navi_EU_148_1.zip: 263.9MB/3.0GB progress:16.33 2025-09-01 15:04:09.854 30380-30415 USBOfflineUpdater com.kotei.overseas.navi I message: 解密验签 KVM_Navi_EU_148_1.zip: 276.0MB/3.0GB progress:16.36 2025-09-01 15:04:10.855 30380-30415 USBOfflineUpdater com.kotei.overseas.navi I message: 解密验签 KVM_Navi_EU_148_1.zip: 290.0MB/3.0GB progress:16.38 2025-09-01 15:04:11.856 30380-30415 USBOfflineUpdater com.kotei.overseas.navi I message: 解密验签 KVM_Navi_EU_148_1.zip: 303.6MB/3.0GB progress:16.41 2025-09-01 15:04:12.873 30380-30415 USBOfflineUpdater com.kotei.overseas.navi I message: 解密验签 KVM_Navi_EU_148_1.zip: 316.0MB/3.0GB progress:16.44 2025-09-01 15:04:12.913 30380-30380 VRI[MainAc...y]@44606a7 com.kotei.overseas.navi I ViewPostIme pointer 0 2025-09-01 15:04:12.914 30380-30380 VRI[MainAc...y]@44606a7 com.kotei.overseas.navi I call setFrameRateCategory for touch hint category=high hint, reason=touch, vri=VRI[MainActivity]@44606a7 2025-09-01 15:04:12.954 30380-30380 VRI[MainAc...y]@44606a7 com.kotei.overseas.navi I onDisplayChanged oldDisplayState=2 newDisplayState=2 2025-09-01 15:04:13.007 30380-30380 VRI[MainAc...y]@44606a7 com.kotei.overseas.navi I ViewPostIme pointer 1 2025-09-01 15:04:13.012 30380-30380 USBOfflineUpdater com.kotei.overseas.navi E 等待任务结束失败 java.util.concurrent.CancellationException at java.util.concurrent.FutureTask.report(FutureTask.java:121) at java.util.concurrent.FutureTask.get(FutureTask.java:191) at android.os.AsyncTask.get(AsyncTask.java:618) at com.kotei.overseas.navi.update.USBOfflineUpdater.cancelUpdate(USBOfflineUpdater.java:502) at com.kotei.overseas.navi.update.USBOfflineUpdater.cancelUpdate(USBOfflineUpdater.java:487) at com.kotei.overseas.navi.mvvm.update.ReadyUpdateViewDataHelper.cancel(ReadyUpdateViewDataHelper.java:152) at com.kotei.overseas.navi.mvvm.update.ReadyUpdateViewDataHelper.lambda$initViews$2(ReadyUpdateViewDataHelper.java:70) at com.kotei.overseas.navi.mvvm.update.ReadyUpdateViewDataHelper.$r8$lambda$hh-Jh_pDx-tL_E17Th2DTMSn55o(Unknown Source:0) at com.kotei.overseas.navi.mvvm.update.ReadyUpdateViewDataHelper$$ExternalSyntheticLambda2.onClick(D8$$SyntheticClass:0) at android.view.View.performClick(View.java:8464) at android.view.View.performClickInternal(View.java:8441) at android.view.View.-$$Nest$mperformClickInternal(Unknown Source:0) at android.view.View$PerformClick.run(View.java:32966) at android.os.Handler.handleCallback(Handler.java:959) at android.os.Handler.dispatchMessage(Handler.java:100) at android.os.Looper.loopOnce(Looper.java:257) at android.os.Looper.loop(Looper.java:342) at android.app.ActivityThread.main(ActivityThread.java:9638) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:619) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:929) 2025-09-01 15:04:13.016 30380-30415 USBOfflineUpdater com.kotei.overseas.navi I resultCode: 8 message:用户取消更新 2025-09-01 15:04:13.016 30380-30415 USBOfflineUpdater com.kotei.overseas.navi I resultCode: 8 message:用户取消更新 2025-09-01 15:04:13.022 30380-30380 BLASTBufferQueue_Java com.kotei.overseas.navi I update, w= 1920 h= 1200 mName = VRI[MainActivity]@44606a7 mNativeObject= 0xb400007b43fee100 sc.mNativeObject= 0xb400007b43fc5f80 format= -3 caller= android.view.ViewRootImpl.updateBlastSurfaceIfNeeded:3386 android.view.ViewRootImpl.relayoutWindow:11361 android.view.ViewRootImpl.performTraversals:4544 android.view.ViewRootImpl.doTraversal:3708 android.view.ViewRootImpl$TraversalRunnable.run:12542 android.view.Choreographer$CallbackRecord.run:1751 2025-09-01 15:04:13.022 30380-30380 VRI[MainAc...y]@44606a7 com.kotei.overseas.navi I Relayout returned: old=(0,0,1920,1200) new=(0,0,1920,1200) relayoutAsync=true req=(1920,1200)0 dur=0 res=0x0 s={true 0xb400007b440ff800} ch=false seqId=0 2025-09-01 15:04:13.023 1360-8154 WindowManager system_server V Relayout Window{dd67d0d u0 com.kotei.overseas.navi/com.kotei.overseas.navi.base.MainActivity}: viewVisibility=0 req=1920x1200 ty=1 d0 2025-09-01 15:04:13.025 30380-30380 VRI[MainAc...y]@44606a7 com.kotei.overseas.navi I registerCallbackForPendingTransactions 2025-09-01 15:04:13.034 30380-30480 VRI[MainAc...y]@44606a7 com.kotei.overseas.navi I mWNT: t=0xb400007b43d65a80 mBlastBufferQueue=0xb400007b43fee100 fn= 194 HdrRenderState mRenderHdrSdrRatio=1.0 caller= android.view.ViewRootImpl$9.onFrameDraw:6276 android.view.ViewRootImpl$3.onFrameDraw:2440 android.view.ThreadedRenderer$1.onFrameDraw:761 2025-09-01 15:04:14.008 30380-30614 FileUtils com.kotei.overseas.navi E 解压失败: KVM_Navi_EU_148_1.zip java.lang.InterruptedException at java.util.concurrent.FutureTask.awaitDone(FutureTask.java:418) at java.util.concurrent.FutureTask.get(FutureTask.java:190) at com.kotei.overseas.navi.update.FileUtils.extractZipWithProgress(FileUtils.java:293) at com.kotei.overseas.navi.update.USBOfflineUpdater$UpdateTask.doInBackground(USBOfflineUpdater.java:772) at com.kotei.overseas.navi.update.USBOfflineUpdater$UpdateTask.doInBackground(USBOfflineUpdater.java:624) at android.os.AsyncTask$3.call(AsyncTask.java:394) at java.util.concurrent.FutureTask.run(FutureTask.java:264) at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:305) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:644) at java.lang.Thread.run(Thread.java:1012) 2025-09-01 15:04:16.008 30380-30380 VRI[MainAc...y]@44606a7 com.kotei.overseas.navi I call setFrameRateCategory for touch hint category=no preference, reason=boost timeout, vri=VRI[MainActivity]@44606a7 2025-09-01 15:04:17.700 30380-30380 VRI[MainAc...y]@44606a7 com.kotei.overseas.navi I onDisplayChanged oldDisplayState=2 newDisplayState=2 2025-09-01 15:04:24.606 30380-30380 VRI[MainAc...y]@44606a7 com.kotei.overseas.navi I onDisplayChanged oldDisplayState=2 newDisplayState=2
最新发布
09-02
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值