非UI线程可不可以更新UI(二)

来源:互联网 发布:淘宝资产拍卖 编辑:程序博客网 时间:2024/04/30 13:32

上篇文章提到因为ViewRootImpl会在线程更新UI时检查当前线程是不是创建它的线程,子线程可以在ViewRootImpl未创建的时候尽行更新UI。下面我们来看另外一种可以在子线程更新UI的办法。

既然ViewRootImpl的checkThread方法只会检查当前更新UI的线程是不是创建它的线程。那么可不可以在子线程中构建自己的ViewRootImpl,这样在子线程中更新UI就应该不会报下面的错误:
Only the original thread that created a view hierarchy can touch its views.
这里写图片描述

由于ViewRootImpl对象的创建在WindowManager调用addView方法时创建的。所以下面我们用windowManager在子线程中创建自己的视图。

UnUIThread.java

public class UnUIThread extends Thread {    private String TAG = "looper";    private Looper mLooper = null;    TextView tv_thread;//要添加的textView    WindowManager wManager;    private Context mContext;    private Handler threadHandler;    public UnUIThread(Context context){        mContext = context;    }    public void run() {        Looper.prepare();        synchronized (this) {            mLooper = Looper.myLooper();            notifyAll();        }        createUI();        if(threadHandler==null){            threadHandler = new Handler(Looper.myLooper()){                @Override                public void handleMessage(Message msg) {                    // TODO Auto-generated method stub                    super.handleMessage(msg);                    tv_thread.setText(msg.obj.toString());                    if(msg.arg1==2){                        getmLooper().quit();                    }                    if(msg.arg1==3){                        wManager.removeView(tv_thread);                    }                }            };        }        Looper.loop();    }    public void createUI() {        try {            Thread.sleep(500);        } catch (InterruptedException e) {            e.printStackTrace();        }        tv_thread = new TextView(mContext);        tv_thread.setTextColor(0xFF000000);        tv_thread.setText("UNUIThread");        wManager = (WindowManager) mContext.getApplicationContext().getSystemService(Context.WINDOW_SERVICE);        WindowManager.LayoutParams mParams = new WindowManager.LayoutParams();        mParams.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;        mParams.format = PixelFormat.TRANSLUCENT;        mParams.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;        mParams.width = 400;        mParams.height = 100;        mParams.alpha = 1.0f;        mParams.gravity=Gravity.BOTTOM;        wManager.addView(tv_thread, mParams);    }    public void updateUI(){        Message msg = new Message();        msg.arg1 =1;        msg.obj = String.valueOf(System.currentTimeMillis());        threadHandler.sendMessage(msg);    }    public void stopLoop(){        if(mLooper==null){            Toast.makeText(mContext, "mLooper", Toast.LENGTH_LONG).show();        }        Message msg = new Message();        msg.arg1 =2;        msg.obj = String.valueOf(System.currentTimeMillis());        threadHandler.sendMessage(msg);    }    public void removeUI(){        if(mLooper==null){            Toast.makeText(mContext, "mLooper", Toast.LENGTH_LONG).show();        }        Message msg = new Message();        msg.arg1 =3;        msg.obj = String.valueOf(System.currentTimeMillis());        threadHandler.sendMessage(msg);    }    public Looper getmLooper()    {        if(mLooper!=null){            return mLooper;        }else        {            synchronized (this){                try {                    while (isAlive()&& mLooper==null){                        wait();                    }                } catch (InterruptedException e) {                    e.printStackTrace();                }            }            return mLooper;        }    }}

Activity.java

public class SecondActivity extends ActionBarActivity {    private Button btn_create;//创建UI    private Button btn_change;//改变UI显示    private Button btn_remove;//移除UI    private Button btn_stop;//停止子线程消息循环    public void autoLoad_activity_second() {        btn_create = (Button) findViewById(R.id.btn_create);        btn_change = (Button) findViewById(R.id.btn_change);        btn_remove = (Button) findViewById(R.id.btn_remove);        btn_stop = (Button) findViewById(R.id.btn_stop);    }    private UnUIThread unUIThread = new UnUIThread(this);    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_second);        autoLoad_activity_second();        btn_create.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                if(unUIThread.getState()==Thread.State.NEW){                    unUIThread.start();                }else{                    unUIThread = new UnUIThread(SecondActivity.this);                    unUIThread.start();                }                if(unUIThread!=null&&!unUIThread.isAlive()){                }            }        });        btn_remove.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                if(unUIThread==null){                    return;                }                unUIThread.removeUI();            }        });        btn_stop.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                if(unUIThread==null){                    return;                }                unUIThread.stopLoop();            }        });        btn_change.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                if(unUIThread==null){                    return;                }                unUIThread.updateUI();            }        });    }}

效果:
这里写图片描述

Android UI相关的操作不管是在主线程还是子线程都必须依赖Looper,Handler,Message。所以必须在子线程中构建自己的消息循环机制。通过Handler机制对UI进行更新。相关原理请看http://blog.csdn.net/innost/article/details/6055793

另外由于小米系列手机对Android权限进行了限制,所以使用小米手机测试时,必须开启浮窗权限。

0 0
原创粉丝点击