子线程不显示Toast?Handler构造函数抛异常
Handler不仅在ANR过程中有用到Toast中也用到了Handler。代码如下publicclassMainActivityextendsAppCompatActivity{OverrideprotectedvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);newThread(newRunnable(){Overridepublicvoidrun(){Toast.makeText(MainActivity.this,子线程,Toast.LENGTH_SHORT).show();}}).start();}}运行安装Logcat里面显示了异常如下Process: com.exp.cpdemo, PID: 1961 java.lang.RuntimeException: Cant create handler inside thread that has not called Looper.prepare() at android.os.Handler.init(Handler.java:200) at android.os.Handler.init(Handler.java:114) at android.widget.Toast$TN$2.init(Toast.java:336) at android.widget.Toast$TN.init(Toast.java:336) at android.widget.Toast.init(Toast.java:103) at android.widget.Toast.makeText(Toast.java:256) at com.exp.cpdemo.MainActivity$1.run(MainActivity.java:40) at java.lang.Thread.run(Thread.java:761)设备是Android 7.1 系统对应源码/frameworks/base/core/java/android/widget/Toast.java为什么会抛出这个异常异常是从makeText()方法抛出的先看Toast.makeText()方法开始看publicstaticToastmakeText(Contextcontext,CharSequencetext,Durationintduration){ToastresultnewToast(context);LayoutInflaterinflate(LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);Viewvinflate.inflate(com.android.internal.R.layout.transient_notification,null);TextViewtv(TextView)v.findViewById(com.android.internal.R.id.message);tv.setText(text);result.mNextViewv;result.mDurationduration;returnresult;}这行代码Toast result new Toast(context);new 了一个Toast对象。异常就是这里抛出的。看看Toast构造器里面的代码逻辑publicToast(Contextcontext){mContextcontext;mTNnewTN(context.getPackageName());mTN.mYcontext.getResources().getDimensionPixelSize(com.android.internal.R.dimen.toast_y_offset);mTN.mGravitycontext.getResources().getInteger(com.android.internal.R.integer.config_toastDefaultGravity);}从错误栈里可知这行mTN new TN(context.getPackageName());出了问题。这行代码初始化了一个TN对象。继续看TN这个类privatestaticclassTNextendsITransientNotification.Stub{......finalHandlermHandlernewHandler(){OverridepublicvoidhandleMessage(Messagemsg){...}};TN(StringpackageName){...}...}根据错误栈出异常的是final Handler mHandler new Handler() {...}TN是Toast的静态内部类。在生成TN对象时成员变量mHandler赋值逻辑执行调用了Handler的默认构造函数。接着看Android 7.1 Handler的源码/frameworks/base/core/java/android/os/Handler.java看看构造函数是怎么抛出异常的。如下publicHandler(){this(null,false);}publicHandler(Callbackcallback,booleanasync){if(FIND_POTENTIAL_LEAKS){finalClass?extendsHandlerklassgetClass();if((klass.isAnonymousClass()||klass.isMemberClass()||klass.isLocalClass())(klass.getModifiers()Modifier.STATIC)0){Log.w(TAG,The following Handler class should be static or leaks might occur: klass.getCanonicalName());}}mLooperLooper.myLooper();if(mLoopernull){thrownewRuntimeException(Cant create handler inside thread that has not called Looper.prepare());}mQueuemLooper.mQueue;mCallbackcallback;mAsynchronousasync;}果然在Handler的两参数构造方法中抛出了上面看到的异常。怎么解决知道了原因添加两行代码就好了如下publicclassMainActivityextendsAppCompatActivity{OverrideprotectedvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);newThread(newRunnable(){Overridepublicvoidrun(){Looper.prepare();Toast.makeText(MainActivity.this,子线程,Toast.LENGTH_SHORT).show();Looper.loop();}}).start();}}Toast显示成功了。