zoukankan      html  css  js  c++  java
  • Toast,AlertDialog的误解

    在一般的软件开发中,子线程中是不能更改UI主线程中创建的UI控件的。之前的理解是Toast也不能在子线程中创建。事实上并不是这样子的。

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        new Thread(new Runnable(){
            @Override
            public void run() {
                // TODO Auto-generated method stub
                Toast.makeText(MainActivity.this, "test", Toast.LENGTH_LONG).show();
            }}).start();
    }

    在Activity的onCreate中写入以上代码运行。LogCat中会抱错

    java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()

    不看这个错误信息第一反应肯定是UI控件不能在子线程调用
    事实上并不是这样的

    我们可以查看Toast的源码

    public Toast(Context context) {
            mContext = context;
            mTN = new TN();
            mTN.mY = context.getResources().getDimensionPixelSize(
                    com.android.internal.R.dimen.toast_y_offset);
        }
        
        /**
         * Show the view for the specified duration.
         */
    public void show() {
        if (mNextView == null) {
            throw new RuntimeException("setView must have been called");
        }
    
        INotificationManager service = getService();
        String pkg = mContext.getPackageName();
        TN tn = mTN;
        tn.mNextView = mNextView;
        try {
            service.enqueueToast(pkg, tn, mDuration);
        } catch (RemoteException e) {
                // Empty
        }
    }

    看这个mTN = new TN();构造函数

    final Handler mHandler = new Handler();    

    Handler的构造函数

    public Handler(Callback callback, boolean async) {
           ...
            mLooper = Looper.myLooper();
            if (mLooper == null) {
                throw new RuntimeException(
                    "Can't create handler inside thread that has not called Looper.prepare()");
            }
           ...
        }

    而Looper.myLooper()

     /**
         * Return the Looper object associated with the current thread.  Returns
         * null if the calling thread is not associated with a Looper.
         */
        public static Looper myLooper() {
            return sThreadLocal.get();
        }

    android中的子线程默认ThreadLocal中未设置Looper,所有会抛出这个异常,至于Looper是啥,可以参考我另一篇文章:http://www.cnblogs.com/cqcmdwym/archive/2013/05/12/3074138.html

    解决方法

    new Thread(new Runnable(){
        @Override
        public void run() {
            // TODO Auto-generated method stub
            Looper.prepare();
            Toast.makeText(MainActivity.this, "test", Toast.LENGTH_LONG).show();
            Looper.loop();
    }}).start();

    或者在主线程中声明一个Handler,然后在run方法中hanlder.post(new Runnable(){})一下。

    同样AlertDialog也是如此,他包含一个AlertController字段,其内部也需要创建一个Handler.

    参考网址:http://www.oschina.net/question/163910_31439

  • 相关阅读:
    工具函数(代码块的大小,代码块起始地址,提升进程权限)
    在共享DLL中使用MFC 和在静态库中使用MFC的区别
    虚拟机检测绕过总结--不定时更新
    OSGI原形(.NET)
    iOS开发技术分享(1)— iOS本地数据存储
    将JSON映射为实体对象(iOS篇)
    灵活的路由(上)
    github开源项目
    EF里查看/修改实体的当前值、原始值和数据库值以及重写SaveChanges方法记录实体状态
    实体能否处于非法状态
  • 原文地址:https://www.cnblogs.com/cqcmdwym/p/3280867.html
Copyright © 2011-2022 走看看