我試圖用內部類與AsyncTask
工作。但我面臨着一個問題泄漏內存。所以我決定編寫一些測試代碼,以便找出問題所在。在下面的代碼中,我試圖運行一個從0到100計數的任務。比我在任務運行時離開活動。我得到了一個_InterruptedException_
和Activity
泄露(使用泄露金絲雀),然後我的應用程序被凍結,直到它墜毀。我不明白爲什麼,因爲任務被取消了,我留下了活動。運行時切換活動AsyncTask會泄漏內存嗎?
這裏是我的小示例代碼:
public class MainActivity extends AppCompatActivity {
TextView textView;
BackgroundTask _task;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = (TextView) findViewById(R.id.textView);
_task = new BackgroundTask(textView);
_task.execute();
}
@Override
protected void onPause() {
_task.cancel(true);
super.onPause();
}
@Override
protected void onResume() {
if (_task.isCancelled()){
_task = new BackgroundTask(textView);
_task.execute();
}
super.onResume();
}
private class BackgroundTask extends AsyncTask<Void, Integer, String> {
private WeakReference<TextView> _textView;
public BackgroundTask(TextView textView) {
this._textView = new WeakReference<TextView>(textView);
}
@Override
protected String doInBackground(Void... params) {
for (int i = 0; i <= 100; i++)
try {
Thread.sleep(1000);
publishProgress(i);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "DONE";
}
@Override
protected void onProgressUpdate(Integer... values) {
TextView textView = _textView.get();
if (textView != null) {
textView.setText(values[0] + " .");
}
Log.d("==> ",values[0]+" ");
}
@Override
protected void onPostExecute(String result) {
TextView textView = _textView.get();
if (textView != null) {
textView.setText(result);
}
//MainActivity.this.isFinishing();
}
}
}
這是我的日誌:
D/==>: 0
D/==>: 1
D/==>: 2
W/System.err: java.lang.InterruptedException
W/System.err: at java.lang.Thread.sleep(Native Method)
W/System.err: at java.lang.Thread.sleep(Thread.java:1031)
W/System.err: at java.lang.Thread.sleep(Thread.java:985)
W/System.err: at com.example.longluong.test_app.MainActivity$BackgroundTask.doInBackground(MainActivity.java:58)
W/System.err: at com.example.longluong.test_app.MainActivity$BackgroundTask.doInBackground(MainActivity.java:47)
W/System.err: at android.os.AsyncTask$2.call(AsyncTask.java:295)
W/System.err: at java.util.concurrent.FutureTask.run(FutureTask.java:237)
W/System.err: at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:234)
W/System.err: at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113)
W/System.err: at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588)
W/System.err: at java.lang.Thread.run(Thread.java:818)
I/art: Waiting for a blocking GC Explicit
I/art: Starting a blocking GC Explicit
I/art: Explicit concurrent mark sweep GC freed 343(27KB) AllocSpace objects, 0(0B) LOS objects, 82% free, 1267KB/7MB, paused 488us total 18.818ms
I/art: hprof: heap dump "/storage/emulated/0/Download/leakcanary-com.example.longluong.test_app/0a1c4ebe-238f-4156-a317-ed8d454de769_pending.hprof" starting...
I/art: hprof: heap dump completed (12MB) in 7.001s
D/LeakCanary: In com.example.longluong.test_app:1.0:1.
D/LeakCanary: * com.example.longluong.test_app.MainActivity has leaked:
D/LeakCanary: * GC ROOT thread java.lang.Thread.<Java Local> (named 'AsyncTask #1')
D/LeakCanary: * references com.example.longluong.test_app.MainActivity$BackgroundTask.this$0
D/LeakCanary: * leaks com.example.longluong.test_app.MainActivity instance
D/LeakCanary: * Retaining: 6.7 KB.
D/LeakCanary: * Reference Key: 4db87806-d761-42c8-a874-9682d7477106
D/LeakCanary: * Device: LENOVO Lenovo Lenovo TB2-X30F TB2-X30F
D/LeakCanary: * Android Version: 6.0.1 API: 23 LeakCanary: 1.5 00f37f5
D/LeakCanary: * Durations: watch=5055ms, gc=125ms, heap dump=7205ms, analysis=26304ms
D/LeakCanary: * Details:
D/LeakCanary: * Instance of java.lang.Thread
D/LeakCanary: | static NANOS_PER_MILLI = 1000000
D/LeakCanary: | static defaultUncaughtHandler = [email protected] (0x22c01180)
D/LeakCanary: | static count = 902
D/LeakCanary: | static MAX_PRIORITY = 10
D/LeakCanary: | static $staticOverhead = byte[48]@1873454545 (0x6faaa5d1)
D/LeakCanary: | static NORM_PRIORITY = 5
D/LeakCanary: | static MIN_PRIORITY = 1
D/LeakCanary: | contextClassLoader = [email protected] (0x22c02d80)
D/LeakCanary: | daemon = false
D/LeakCanary: | group = [email protected] (0x6f8e8818)
D/LeakCanary: | hasBeenStarted = true
D/LeakCanary: | id = 900
D/LeakCanary: | inheritableValues = null
D/LeakCanary: | interruptActions = [email protected] (0x22d84ba0)
D/LeakCanary: | localValues = [email protected] (0x22d84bc0)
D/LeakCanary: | lock = [email protected] (0x22c01100)
D/LeakCanary: | name = [email protected] (0x22d83340)
D/LeakCanary: | nativePeer = -1218480552
D/LeakCanary: | parkBlocker = null
D/LeakCanary: | parkState = 1
D/LeakCanary: | priority = 5
D/LeakCanary: | stackSize = 0
D/LeakCanary: | target = [email protected] (0x22c001f0)
D/LeakCanary: | uncaughtHandler = null
D/LeakCanary: | shadow$_klass_ = java.lang.Thread
D/LeakCanary: | shadow$_monitor_ = 0
D/LeakCanary: * Instance of com.example.longluong.test_app.MainActivity$BackgroundTask
D/LeakCanary: | static $staticOverhead = byte[16]@583275521 (0x22c41401)
D/LeakCanary: | static serialVersionUID = 0
D/LeakCanary: | static $change = null
D/LeakCanary: | _textView = [email protected] (0x22d69fa0)
D/LeakCanary: | this$0 = [email protected] (0x22c8d300)
D/LeakCanary: | mCancelled = [email protected] (0x22d6c1a0)
D/LeakCanary: | mFuture = [email protected] (0x22c020c0)
D/LeakCanary: | mStatus = [email protected] (0x6f924e30)
D/LeakCanary: | mTaskInvoked = [email protected] (0x22d6c1b0)
D/LeakCanary: | mWorker = [email protected] (0x22c01120)
D/LeakCanary: | shadow$_klass_ = com.example.longluong.test_app.MainActivity$BackgroundTask
D/LeakCanary: | shadow$_monitor_ = 0
D/LeakCanary: * Instance of com.example.longluong.test_app.MainActivity
D/LeakCanary: | static $staticOverhead = byte[16]@584134657 (0x22d13001)
D/LeakCanary: | static serialVersionUID = 0
D/LeakCanary: | static $change = null
D/LeakCanary: | _task = [email protected]8704 (0x22c001c0)
D/LeakCanary: | textView = [email protected] (0x22d07800)
D/LeakCanary: | mDelegate = [email protected] (0x22c0da60)
D/LeakCanary: | mEatKeyUpEvent = false
D/LeakCanary: | mResources = null
D/LeakCanary: | mThemeId = 2131230877
D/LeakCanary: | mCreated = true
D/LeakCanary: | mFragments = [email protected] (0x22d6c1c0)
D/LeakCanary: | mHandler = [email protected] (0x22d69fc0)
D/LeakCanary: | mMediaController = null
D/LeakCanary: | mNextCandidateRequestIndex = 0
D/LeakCanary: | mOptionsMenuInvalidated = false
D/LeakCanary: | mPendingFragmentActivityResults = [email protected] (0x22d69fe0)
D/LeakCanary: | mReallyStopped = true
D/LeakCanary: | mRequestedPermissionsFromFragment = false
D/LeakCanary: | mResumed = false
D/LeakCanary: | mRetaining = false
D/LeakCanary: | mStopped = true
D/LeakCanary: | mStartedActivityFromFragment = false
D/LeakCanary: | mStartedIntentSenderFromFragment = false
D/LeakCanary: | mActionBar = null
D/LeakCanary: | mActionModeTypeStarting = 0
D/LeakCanary: | mActivityInfo = android.content.pm.Activ[email protected] (0x22d66300)
D/LeakCanary: | mActivityTransitionState = [email protected] (0x22d41ec0)
D/LeakCanary: | mApplication = [email protected] (0x22d78040)
D/LeakCanary: | mCalled = true
D/LeakCanary: | mChangeCanvasToTranslucent = false
D/LeakCanary: | mChangingConfigurations = false
D/LeakCanary: | mComponent = [email protected] (0x22d6c1d0)
D/LeakCanary: | mConfigChangeFlags = 0
D/LeakCanary: | mCurrentConfig = [email protected] (0x22d6d100)
D/LeakCanary: | mDecor = null
D/LeakCanary: | mDefaultKeyMode = 0
D/LeakCanary: | mDefaultKeySsb = null
D/LeakCanary: | mDestroyed = true
D/LeakCanary: | mDoReportFullyDrawn = false
D/LeakCanary: | mEmbeddedID = null
D/LeakCanary: | mEnableDefaultActionBarUp = false
D/LeakCanary: | mEnterTransitionListener = [email protected] (0x6f8e9aa0)
D/LeakCanary: | mExitTransitionListener = [email protected] (0x6f8e9aa0)
D/LeakCanary: | mFinished = true
D/LeakCanary: | mFragments = [email protected] (0x22d6c1e0)
D/LeakCanary: | mHandler = [email protected] (0x22d78060)
D/LeakCanary: | mHasCurrentPermissionsRequest = false
D/LeakCanary: | mIdent = 115814648
D/LeakCanary: | mInstanceTracker = [email protected] (0x22d6c1f0)
D/LeakCanary: | mInstrumentation = [email protected] (0x22d37830)
D/LeakCanary: | mIntent = [email protected] (0x22d41f00)
D/LeakCanary: | mLastNonConfigurationInstances = null
D/LeakCanary: | mMainThread = [email protected] (0x22c03100)
D/LeakCanary: | mManagedCursors = [email protected] (0x22d78080)
D/LeakCanary: | mManagedDialogs = null
D/LeakCanary: | mMenuInflater = null
D/LeakCanary: | mParent = null
D/LeakCanary: | mReferrer = null
D/LeakCanary: | mResultCode = 0
D/LeakCanary: | mResultData = null
D/LeakCanary: | mResumed = false
D/LeakCanary: | mSearchEvent = null
D/LeakCanary: | mSearchManager = null
D/LeakCanary: | mStartedActivity = false
D/LeakCanary: | mStopped = true
D/LeakCanary: | mTemporaryPause = false
D/LeakCanary: | mTitle = [email protected] (0x22d780a0)
D/LeakCanary: | mTitleColor = 0
D/LeakCanary: | mTitleReady = true
D/LeakCanary: | mToken = [email protected] (0x22d780c0)
D/LeakCanary: | mTranslucentCallback = null
D/LeakCanary: | mUiThread = [email protected] (0x733cc258)
D/LeakCanary: | mVisibleBehind = false
D/LeakCanary: | mVisibleFromClient = true
D/LeakCanary: | mVisibleFromServer = true
D/LeakCanary: | mVoiceInteractor = null
D/LeakCanary: | mWindow = [email protected] (0x22c4c0a0)
D/LeakCanary: | mWindowAdded = true
D/LeakCanary: | mWindowManager = [email protected] (0x22d780e0)
D/LeakCanary: | mInflater = [email protected] (0x22d68340)
D/LeakCanary: | mOverrideConfiguration = null
D/LeakCanary: | mResources = [email protected] (0x22d37880)
D/LeakCanary: | mTheme = [email protected] (0x22d78100)
D/LeakCanary: | mThemeResource = 2131230877
D/LeakCanary: | mBase = [email protected] (0x22d66380)
D/LeakCanary: | shadow$_klass_ = com.example.longluong.test_app.MainActivity
D/LeakCanary: | shadow$_monitor_ = 1266075474
D/LeakCanary: * Excluded Refs:
D/LeakCanary: | Field: android.view.inputmethod.InputMethodManager.mNextServedView
D/LeakCanary: | Field: android.view.inputmethod.InputMethodManager.mServedView
D/LeakCanary: | Field: android.view.inputmethod.InputMethodManager.mServedInputConnection
D/LeakCanary: | Field: android.view.inputmethod.InputMethodManager.mCurRootView
D/LeakCanary: | Field: android.os.UserManager.mContext
D/LeakCanary: | Field: android.net.ConnectivityManager.sInstance
D/LeakCanary: | Field: android.view.Choreographer$FrameDisplayEventReceiver.mMessageQueue (always)
D/LeakCanary: | Thread:FinalizerWatchdogDaemon (always)
D/LeakCanary: | Thread:main (always)
D/LeakCanary: | Thread:LeakCanary-Heap-Dump (always)
D/LeakCanary: | Class:java.lang.ref.WeakReference (always)
D/LeakCanary: | Class:java.lang.ref.SoftReference (always)
D/LeakCanary: | Class:java.lang.ref.PhantomReference (always)
D/LeakCanary: | Class:java.lang.ref.Finalizer (always)
D/LeakCanary: | Class:java.lang.ref.FinalizerReference (always)
也許是因爲您使用的是來自Activity的View, – Jonas452
發佈錯誤代碼。你是否按下按鈕或回家離開活動? –
你想執行任何後臺任務,如果我移動到第二個活動,那麼該任務不應該被取消嗎? –