Avoid memory leak by by non-static Handler inner classes

bug: 4901934
Change-Id: I870ab2e621ef3640a84468f09c074cdd726dc963
main
Ken Wakasa 2011-06-25 03:54:11 +09:00
parent e7de39ac42
commit 4f0d290c5d
6 changed files with 122 additions and 51 deletions

View File

@ -18,7 +18,6 @@ package com.android.inputmethod.accessibility;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.inputmethodservice.InputMethodService; import android.inputmethodservice.InputMethodService;
import android.os.Handler;
import android.os.Looper; import android.os.Looper;
import android.os.Message; import android.os.Message;
import android.text.TextUtils; import android.text.TextUtils;
@ -26,6 +25,7 @@ import android.view.inputmethod.ExtractedText;
import android.view.inputmethod.ExtractedTextRequest; import android.view.inputmethod.ExtractedTextRequest;
import com.android.inputmethod.latin.R; import com.android.inputmethod.latin.R;
import com.android.inputmethod.latin.StaticInnerHandlerWrapper;
public class AccessibleInputMethodServiceProxy implements AccessibleKeyboardActionListener { public class AccessibleInputMethodServiceProxy implements AccessibleKeyboardActionListener {
private static final AccessibleInputMethodServiceProxy sInstance = private static final AccessibleInputMethodServiceProxy sInstance =
@ -42,18 +42,20 @@ public class AccessibleInputMethodServiceProxy implements AccessibleKeyboardActi
private AccessibilityHandler mAccessibilityHandler; private AccessibilityHandler mAccessibilityHandler;
private class AccessibilityHandler extends Handler { private static class AccessibilityHandler
extends StaticInnerHandlerWrapper<AccessibleInputMethodServiceProxy> {
private static final int MSG_NO_HOVER_SELECTION = 0; private static final int MSG_NO_HOVER_SELECTION = 0;
public AccessibilityHandler(Looper looper) { public AccessibilityHandler(AccessibleInputMethodServiceProxy outerInstance,
super(looper); Looper looper) {
super(outerInstance, looper);
} }
@Override @Override
public void handleMessage(Message msg) { public void handleMessage(Message msg) {
switch (msg.what) { switch (msg.what) {
case MSG_NO_HOVER_SELECTION: case MSG_NO_HOVER_SELECTION:
notifyNoHoverSelection(); getOuterInstance().notifyNoHoverSelection();
break; break;
} }
} }
@ -82,7 +84,7 @@ public class AccessibleInputMethodServiceProxy implements AccessibleKeyboardActi
private void initInternal(InputMethodService inputMethod, SharedPreferences prefs) { private void initInternal(InputMethodService inputMethod, SharedPreferences prefs) {
mInputMethod = inputMethod; mInputMethod = inputMethod;
mAccessibilityHandler = new AccessibilityHandler(inputMethod.getMainLooper()); mAccessibilityHandler = new AccessibilityHandler(this, inputMethod.getMainLooper());
} }
/** /**

View File

@ -19,6 +19,7 @@ package com.android.inputmethod.deprecated.voice;
import com.android.inputmethod.latin.EditingUtils; import com.android.inputmethod.latin.EditingUtils;
import com.android.inputmethod.latin.LatinImeLogger; import com.android.inputmethod.latin.LatinImeLogger;
import com.android.inputmethod.latin.R; import com.android.inputmethod.latin.R;
import com.android.inputmethod.latin.StaticInnerHandlerWrapper;
import android.content.ContentResolver; import android.content.ContentResolver;
import android.content.Context; import android.content.Context;
@ -26,7 +27,6 @@ import android.content.Intent;
import android.content.res.Configuration; import android.content.res.Configuration;
import android.os.Build; import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.os.Handler;
import android.os.Message; import android.os.Message;
import android.os.Parcelable; import android.os.Parcelable;
import android.speech.RecognitionListener; import android.speech.RecognitionListener;
@ -132,13 +132,20 @@ public class VoiceInput implements OnClickListener {
private final static int MSG_RESET = 1; private final static int MSG_RESET = 1;
private final Handler mHandler = new Handler() { private final UIHandler mHandler = new UIHandler(this);
private static class UIHandler extends StaticInnerHandlerWrapper<VoiceInput> {
public UIHandler(VoiceInput outerInstance) {
super(outerInstance);
}
@Override @Override
public void handleMessage(Message msg) { public void handleMessage(Message msg) {
if (msg.what == MSG_RESET) { if (msg.what == MSG_RESET) {
mState = DEFAULT; final VoiceInput voiceInput = getOuterInstance();
mRecognitionView.finish(); voiceInput.mState = DEFAULT;
mUiListener.onCancelVoice(); voiceInput.mRecognitionView.finish();
voiceInput.mUiListener.onCancelVoice();
} }
} }
}; };

View File

@ -30,7 +30,6 @@ import android.graphics.Rect;
import android.graphics.Region.Op; import android.graphics.Region.Op;
import android.graphics.Typeface; import android.graphics.Typeface;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.os.Message; import android.os.Message;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.util.Log; import android.util.Log;
@ -53,6 +52,7 @@ import com.android.inputmethod.keyboard.internal.PointerTrackerQueue;
import com.android.inputmethod.keyboard.internal.SwipeTracker; import com.android.inputmethod.keyboard.internal.SwipeTracker;
import com.android.inputmethod.latin.LatinImeLogger; import com.android.inputmethod.latin.LatinImeLogger;
import com.android.inputmethod.latin.R; import com.android.inputmethod.latin.R;
import com.android.inputmethod.latin.StaticInnerHandlerWrapper;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
@ -193,9 +193,9 @@ public class KeyboardView extends View implements PointerTracker.UIProxy {
private static final String KEY_LABEL_REFERENCE_CHAR = "M"; private static final String KEY_LABEL_REFERENCE_CHAR = "M";
private final int mKeyLabelHorizontalPadding; private final int mKeyLabelHorizontalPadding;
private final UIHandler mHandler = new UIHandler(); private final UIHandler mHandler = new UIHandler(this);
class UIHandler extends Handler { public static class UIHandler extends StaticInnerHandlerWrapper<KeyboardView> {
private static final int MSG_SHOW_KEY_PREVIEW = 1; private static final int MSG_SHOW_KEY_PREVIEW = 1;
private static final int MSG_DISMISS_KEY_PREVIEW = 2; private static final int MSG_DISMISS_KEY_PREVIEW = 2;
private static final int MSG_REPEAT_KEY = 3; private static final int MSG_REPEAT_KEY = 3;
@ -205,34 +205,40 @@ public class KeyboardView extends View implements PointerTracker.UIProxy {
private boolean mInKeyRepeat; private boolean mInKeyRepeat;
public UIHandler(KeyboardView outerInstance) {
super(outerInstance);
}
@Override @Override
public void handleMessage(Message msg) { public void handleMessage(Message msg) {
final KeyboardView keyboardView = getOuterInstance();
final PointerTracker tracker = (PointerTracker) msg.obj; final PointerTracker tracker = (PointerTracker) msg.obj;
switch (msg.what) { switch (msg.what) {
case MSG_SHOW_KEY_PREVIEW: case MSG_SHOW_KEY_PREVIEW:
showKey(msg.arg1, tracker); keyboardView.showKey(msg.arg1, tracker);
break; break;
case MSG_DISMISS_KEY_PREVIEW: case MSG_DISMISS_KEY_PREVIEW:
mPreviewText.setVisibility(View.INVISIBLE); keyboardView.mPreviewText.setVisibility(View.INVISIBLE);
break; break;
case MSG_REPEAT_KEY: case MSG_REPEAT_KEY:
tracker.onRepeatKey(msg.arg1); tracker.onRepeatKey(msg.arg1);
startKeyRepeatTimer(mKeyRepeatInterval, msg.arg1, tracker); startKeyRepeatTimer(keyboardView.mKeyRepeatInterval, msg.arg1, tracker);
break; break;
case MSG_LONGPRESS_KEY: case MSG_LONGPRESS_KEY:
openMiniKeyboardIfRequired(msg.arg1, tracker); keyboardView.openMiniKeyboardIfRequired(msg.arg1, tracker);
break; break;
case MSG_LONGPRESS_SHIFT_KEY: case MSG_LONGPRESS_SHIFT_KEY:
onLongPressShiftKey(tracker); keyboardView.onLongPressShiftKey(tracker);
break; break;
} }
} }
public void showKeyPreview(long delay, int keyIndex, PointerTracker tracker) { public void showKeyPreview(long delay, int keyIndex, PointerTracker tracker) {
final KeyboardView keyboardView = getOuterInstance();
removeMessages(MSG_SHOW_KEY_PREVIEW); removeMessages(MSG_SHOW_KEY_PREVIEW);
if (mPreviewText.getVisibility() == VISIBLE || delay == 0) { if (keyboardView.mPreviewText.getVisibility() == VISIBLE || delay == 0) {
// Show right away, if it's already visible and finger is moving around // Show right away, if it's already visible and finger is moving around
showKey(keyIndex, tracker); keyboardView.showKey(keyIndex, tracker);
} else { } else {
sendMessageDelayed( sendMessageDelayed(
obtainMessage(MSG_SHOW_KEY_PREVIEW, keyIndex, 0, tracker), delay); obtainMessage(MSG_SHOW_KEY_PREVIEW, keyIndex, 0, tracker), delay);

View File

@ -21,7 +21,6 @@ import android.content.res.Resources;
import android.content.res.TypedArray; import android.content.res.TypedArray;
import android.graphics.Color; import android.graphics.Color;
import android.graphics.Typeface; import android.graphics.Typeface;
import android.os.Handler;
import android.os.Message; import android.os.Message;
import android.text.Spannable; import android.text.Spannable;
import android.text.SpannableString; import android.text.SpannableString;
@ -95,23 +94,28 @@ public class CandidateView extends LinearLayout implements OnClickListener, OnLo
private boolean mShowingAutoCorrectionInverted; private boolean mShowingAutoCorrectionInverted;
private boolean mShowingAddToDictionary; private boolean mShowingAddToDictionary;
private final UiHandler mHandler = new UiHandler(); private final UiHandler mHandler = new UiHandler(this);
private class UiHandler extends Handler { private static class UiHandler extends StaticInnerHandlerWrapper<CandidateView> {
private static final int MSG_HIDE_PREVIEW = 0; private static final int MSG_HIDE_PREVIEW = 0;
private static final int MSG_UPDATE_SUGGESTION = 1; private static final int MSG_UPDATE_SUGGESTION = 1;
private static final long DELAY_HIDE_PREVIEW = 1000; private static final long DELAY_HIDE_PREVIEW = 1000;
private static final long DELAY_UPDATE_SUGGESTION = 300; private static final long DELAY_UPDATE_SUGGESTION = 300;
public UiHandler(CandidateView outerInstance) {
super(outerInstance);
}
@Override @Override
public void dispatchMessage(Message msg) { public void dispatchMessage(Message msg) {
final CandidateView candidateView = getOuterInstance();
switch (msg.what) { switch (msg.what) {
case MSG_HIDE_PREVIEW: case MSG_HIDE_PREVIEW:
hidePreview(); candidateView.hidePreview();
break; break;
case MSG_UPDATE_SUGGESTION: case MSG_UPDATE_SUGGESTION:
updateSuggestions(); candidateView.updateSuggestions();
break; break;
} }
} }

View File

@ -29,7 +29,6 @@ import android.inputmethodservice.InputMethodService;
import android.media.AudioManager; import android.media.AudioManager;
import android.net.ConnectivityManager; import android.net.ConnectivityManager;
import android.os.Debug; import android.os.Debug;
import android.os.Handler;
import android.os.IBinder; import android.os.IBinder;
import android.os.Message; import android.os.Message;
import android.os.SystemClock; import android.os.SystemClock;
@ -206,9 +205,9 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
private CharSequence mEnteredText; private CharSequence mEnteredText;
public final UIHandler mHandler = new UIHandler(); public final UIHandler mHandler = new UIHandler(this);
public class UIHandler extends Handler { public static class UIHandler extends StaticInnerHandlerWrapper<LatinIME> {
private static final int MSG_UPDATE_SUGGESTIONS = 0; private static final int MSG_UPDATE_SUGGESTIONS = 0;
private static final int MSG_UPDATE_OLD_SUGGESTIONS = 1; private static final int MSG_UPDATE_OLD_SUGGESTIONS = 1;
private static final int MSG_UPDATE_SHIFT_STATE = 2; private static final int MSG_UPDATE_SHIFT_STATE = 2;
@ -218,42 +217,50 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
private static final int MSG_SPACE_TYPED = 6; private static final int MSG_SPACE_TYPED = 6;
private static final int MSG_SET_BIGRAM_PREDICTIONS = 7; private static final int MSG_SET_BIGRAM_PREDICTIONS = 7;
public UIHandler(LatinIME outerInstance) {
super(outerInstance);
}
@Override @Override
public void handleMessage(Message msg) { public void handleMessage(Message msg) {
final KeyboardSwitcher switcher = mKeyboardSwitcher; final LatinIME latinIme = getOuterInstance();
final KeyboardSwitcher switcher = latinIme.mKeyboardSwitcher;
final LatinKeyboardView inputView = switcher.getKeyboardView(); final LatinKeyboardView inputView = switcher.getKeyboardView();
switch (msg.what) { switch (msg.what) {
case MSG_UPDATE_SUGGESTIONS: case MSG_UPDATE_SUGGESTIONS:
updateSuggestions(); latinIme.updateSuggestions();
break; break;
case MSG_UPDATE_OLD_SUGGESTIONS: case MSG_UPDATE_OLD_SUGGESTIONS:
mRecorrection.fetchAndDisplayRecorrectionSuggestions(mVoiceProxy, mCandidateView, latinIme.mRecorrection.fetchAndDisplayRecorrectionSuggestions(
mSuggest, mKeyboardSwitcher, mWord, mHasUncommittedTypedChars, latinIme.mVoiceProxy, latinIme.mCandidateView,
mLastSelectionStart, mLastSelectionEnd, mSettingsValues.mWordSeparators); latinIme.mSuggest, latinIme.mKeyboardSwitcher, latinIme.mWord,
latinIme.mHasUncommittedTypedChars, latinIme.mLastSelectionStart,
latinIme.mLastSelectionEnd, latinIme.mSettingsValues.mWordSeparators);
break; break;
case MSG_UPDATE_SHIFT_STATE: case MSG_UPDATE_SHIFT_STATE:
switcher.updateShiftState(); switcher.updateShiftState();
break; break;
case MSG_SET_BIGRAM_PREDICTIONS: case MSG_SET_BIGRAM_PREDICTIONS:
updateBigramPredictions(); latinIme.updateBigramPredictions();
break; break;
case MSG_VOICE_RESULTS: case MSG_VOICE_RESULTS:
mVoiceProxy.handleVoiceResults(preferCapitalization() latinIme.mVoiceProxy.handleVoiceResults(latinIme.preferCapitalization()
|| (switcher.isAlphabetMode() && switcher.isShiftedOrShiftLocked())); || (switcher.isAlphabetMode() && switcher.isShiftedOrShiftLocked()));
break; break;
case MSG_FADEOUT_LANGUAGE_ON_SPACEBAR: case MSG_FADEOUT_LANGUAGE_ON_SPACEBAR:
if (inputView != null) { if (inputView != null) {
inputView.setSpacebarTextFadeFactor( inputView.setSpacebarTextFadeFactor(
(1.0f + mSettingsValues.mFinalFadeoutFactorOfLanguageOnSpacebar) / 2, (1.0f + latinIme.mSettingsValues.
mFinalFadeoutFactorOfLanguageOnSpacebar) / 2,
(LatinKeyboard)msg.obj); (LatinKeyboard)msg.obj);
} }
sendMessageDelayed(obtainMessage(MSG_DISMISS_LANGUAGE_ON_SPACEBAR, msg.obj), sendMessageDelayed(obtainMessage(MSG_DISMISS_LANGUAGE_ON_SPACEBAR, msg.obj),
mSettingsValues.mDurationOfFadeoutLanguageOnSpacebar); latinIme.mSettingsValues.mDurationOfFadeoutLanguageOnSpacebar);
break; break;
case MSG_DISMISS_LANGUAGE_ON_SPACEBAR: case MSG_DISMISS_LANGUAGE_ON_SPACEBAR:
if (inputView != null) { if (inputView != null) {
inputView.setSpacebarTextFadeFactor( inputView.setSpacebarTextFadeFactor(
mSettingsValues.mFinalFadeoutFactorOfLanguageOnSpacebar, latinIme.mSettingsValues.mFinalFadeoutFactorOfLanguageOnSpacebar,
(LatinKeyboard)msg.obj); (LatinKeyboard)msg.obj);
} }
break; break;
@ -263,7 +270,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
public void postUpdateSuggestions() { public void postUpdateSuggestions() {
removeMessages(MSG_UPDATE_SUGGESTIONS); removeMessages(MSG_UPDATE_SUGGESTIONS);
sendMessageDelayed(obtainMessage(MSG_UPDATE_SUGGESTIONS), sendMessageDelayed(obtainMessage(MSG_UPDATE_SUGGESTIONS),
mSettingsValues.mDelayUpdateSuggestions); getOuterInstance().mSettingsValues.mDelayUpdateSuggestions);
} }
public void cancelUpdateSuggestions() { public void cancelUpdateSuggestions() {
@ -277,7 +284,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
public void postUpdateOldSuggestions() { public void postUpdateOldSuggestions() {
removeMessages(MSG_UPDATE_OLD_SUGGESTIONS); removeMessages(MSG_UPDATE_OLD_SUGGESTIONS);
sendMessageDelayed(obtainMessage(MSG_UPDATE_OLD_SUGGESTIONS), sendMessageDelayed(obtainMessage(MSG_UPDATE_OLD_SUGGESTIONS),
mSettingsValues.mDelayUpdateOldSuggestions); getOuterInstance().mSettingsValues.mDelayUpdateOldSuggestions);
} }
public void cancelUpdateOldSuggestions() { public void cancelUpdateOldSuggestions() {
@ -287,7 +294,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
public void postUpdateShiftKeyState() { public void postUpdateShiftKeyState() {
removeMessages(MSG_UPDATE_SHIFT_STATE); removeMessages(MSG_UPDATE_SHIFT_STATE);
sendMessageDelayed(obtainMessage(MSG_UPDATE_SHIFT_STATE), sendMessageDelayed(obtainMessage(MSG_UPDATE_SHIFT_STATE),
mSettingsValues.mDelayUpdateShiftState); getOuterInstance().mSettingsValues.mDelayUpdateShiftState);
} }
public void cancelUpdateShiftState() { public void cancelUpdateShiftState() {
@ -297,7 +304,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
public void postUpdateBigramPredictions() { public void postUpdateBigramPredictions() {
removeMessages(MSG_SET_BIGRAM_PREDICTIONS); removeMessages(MSG_SET_BIGRAM_PREDICTIONS);
sendMessageDelayed(obtainMessage(MSG_SET_BIGRAM_PREDICTIONS), sendMessageDelayed(obtainMessage(MSG_SET_BIGRAM_PREDICTIONS),
mSettingsValues.mDelayUpdateSuggestions); getOuterInstance().mSettingsValues.mDelayUpdateSuggestions);
} }
public void cancelUpdateBigramPredictions() { public void cancelUpdateBigramPredictions() {
@ -309,23 +316,26 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
} }
public void startDisplayLanguageOnSpacebar(boolean localeChanged) { public void startDisplayLanguageOnSpacebar(boolean localeChanged) {
final LatinIME latinIme = getOuterInstance();
removeMessages(MSG_FADEOUT_LANGUAGE_ON_SPACEBAR); removeMessages(MSG_FADEOUT_LANGUAGE_ON_SPACEBAR);
removeMessages(MSG_DISMISS_LANGUAGE_ON_SPACEBAR); removeMessages(MSG_DISMISS_LANGUAGE_ON_SPACEBAR);
final LatinKeyboardView inputView = mKeyboardSwitcher.getKeyboardView(); final LatinKeyboardView inputView = latinIme.mKeyboardSwitcher.getKeyboardView();
if (inputView != null) { if (inputView != null) {
final LatinKeyboard keyboard = mKeyboardSwitcher.getLatinKeyboard(); final LatinKeyboard keyboard = latinIme.mKeyboardSwitcher.getLatinKeyboard();
// The language is always displayed when the delay is negative. // The language is always displayed when the delay is negative.
final boolean needsToDisplayLanguage = localeChanged final boolean needsToDisplayLanguage = localeChanged
|| mSettingsValues.mDelayBeforeFadeoutLanguageOnSpacebar < 0; || latinIme.mSettingsValues.mDelayBeforeFadeoutLanguageOnSpacebar < 0;
// The language is never displayed when the delay is zero. // The language is never displayed when the delay is zero.
if (mSettingsValues.mDelayBeforeFadeoutLanguageOnSpacebar != 0) { if (latinIme.mSettingsValues.mDelayBeforeFadeoutLanguageOnSpacebar != 0) {
inputView.setSpacebarTextFadeFactor(needsToDisplayLanguage ? 1.0f inputView.setSpacebarTextFadeFactor(needsToDisplayLanguage ? 1.0f
: mSettingsValues.mFinalFadeoutFactorOfLanguageOnSpacebar, keyboard); : latinIme.mSettingsValues.mFinalFadeoutFactorOfLanguageOnSpacebar,
keyboard);
} }
// The fadeout animation will start when the delay is positive. // The fadeout animation will start when the delay is positive.
if (localeChanged && mSettingsValues.mDelayBeforeFadeoutLanguageOnSpacebar > 0) { if (localeChanged
&& latinIme.mSettingsValues.mDelayBeforeFadeoutLanguageOnSpacebar > 0) {
sendMessageDelayed(obtainMessage(MSG_FADEOUT_LANGUAGE_ON_SPACEBAR, keyboard), sendMessageDelayed(obtainMessage(MSG_FADEOUT_LANGUAGE_ON_SPACEBAR, keyboard),
mSettingsValues.mDelayBeforeFadeoutLanguageOnSpacebar); latinIme.mSettingsValues.mDelayBeforeFadeoutLanguageOnSpacebar);
} }
} }
} }
@ -333,7 +343,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
public void startDoubleSpacesTimer() { public void startDoubleSpacesTimer() {
removeMessages(MSG_SPACE_TYPED); removeMessages(MSG_SPACE_TYPED);
sendMessageDelayed(obtainMessage(MSG_SPACE_TYPED), sendMessageDelayed(obtainMessage(MSG_SPACE_TYPED),
mSettingsValues.mDoubleSpacesTurnIntoPeriodTimeout); getOuterInstance().mSettingsValues.mDoubleSpacesTurnIntoPeriodTimeout);
} }
public void cancelDoubleSpacesTimer() { public void cancelDoubleSpacesTimer() {

View File

@ -0,0 +1,42 @@
/*
* Copyright (C) 2011 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.inputmethod.latin;
import android.os.Handler;
import android.os.Looper;
import java.lang.ref.WeakReference;
public class StaticInnerHandlerWrapper<T> extends Handler {
final private WeakReference<T> mOuterInstanceRef;
public StaticInnerHandlerWrapper(T outerInstance) {
super();
if (outerInstance == null) throw new NullPointerException("outerInstance is null");
mOuterInstanceRef = new WeakReference<T>(outerInstance);
}
public StaticInnerHandlerWrapper(T outerInstance, Looper looper) {
super(looper);
if (outerInstance == null) throw new NullPointerException("outerInstance is null");
mOuterInstanceRef = new WeakReference<T>(outerInstance);
}
public T getOuterInstance() {
return mOuterInstanceRef.get();
}
}