子线程不显示Toast?

文章详细分析了在Android子线程中使用Toast时抛出`CantcreatehandlerinsidethreadthathasnotcalledLooper.prepare()`异常的原因,跟踪了从`makeText`方法到`Handler`构造器的源码流程,并提供了解决方案,即在子线程中添加`Looper.prepare()`和`Looper.loop()`来确保消息循环的正确运行,从而成功显示Toast。
摘要由CSDN通过智能技术生成

Handler不仅在ANR过程中有用到,Toast中也用到了Handler。

代码如下:

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        new Thread(new Runnable() {
            @Override
            public void run() {
                Toast.makeText(MainActivity.this,"子线程",Toast.LENGTH_SHORT).show();
            }
        }).start();

    }
}

运行安装,Logcat里面显示了异常如下:

    Process: com.exp.cpdemo, PID: 1961
    java.lang.RuntimeException: Can't 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方法开始看:

    public static Toast makeText(Context context, CharSequence text, @Duration int duration) {
        Toast result = new Toast(context);

        LayoutInflater inflate = (LayoutInflater)
                context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        View v = inflate.inflate(com.android.internal.R.layout.transient_notification, null);
        TextView tv = (TextView)v.findViewById(com.android.internal.R.id.message);
        tv.setText(text);
        
        result.mNextView = v;
        result.mDuration = duration;

        return result;
    }

初始化了一个Toast对象。看看Toast构造器里面的代码逻辑:

    public Toast(Context context) {
        mContext = context;
        mTN = new TN(context.getPackageName());
        mTN.mY = context.getResources().getDimensionPixelSize(
                com.android.internal.R.dimen.toast_y_offset);
        mTN.mGravity = context.getResources().getInteger(
                com.android.internal.R.integer.config_toastDefaultGravity);
    }

初始化了一个TN对象。继续看TN这个类:

    private static class TN extends ITransientNotification.Stub {
		......
        final Handler mHandler = new Handler() {
            @Override
            public void handleMessage(Message msg) {
				...
            }
        };


        TN(String packageName) {
			...
        }
		
		...
	}

TN是Toast的静态内部类。在生成TN对象时,成员变量mHandler赋值逻辑执行,调用了Handler的默认构造器。接着看Android 7.1 Handler的源码:
/frameworks/base/core/java/android/os/Handler.java

    public Handler() {
        this(null, false);
    }

    public Handler(Callback callback, boolean async) {
        if (FIND_POTENTIAL_LEAKS) {
            final Class<? extends Handler> klass = getClass();
            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());
            }
        }

        mLooper = Looper.myLooper();
        if (mLooper == null) {
            throw new RuntimeException(
                "Can't create handler inside thread that has not called Looper.prepare()");
        }
        mQueue = mLooper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }

果然,在Handler的两参数构造方法中,抛出了上面看到的异常。

怎么解决?

知道了原因,添加两行代码就好了,如下:

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        new Thread(new Runnable() {
            @Override
            public void run() {
                Looper.prepare();
                Toast.makeText(MainActivity.this,"子线程",Toast.LENGTH_SHORT).show();
                Looper.loop();
            }
        }).start();

    }
}

Toast显示成功了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zhangjin1120

可靠的文章费时费力,希望支持

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值