postInvalidate()不使用非ui线程

时间:2014-02-12 15:03:27

标签: java android multithreading canvas android-custom-view

我正在使用自定义视图来绘制游戏内容,我使用xml布局中的按钮来启用或禁用使用单独线程绘制特定内容(矩形)。我设法让线程运行但是postInvalidate()我使用的方法被忽略。我也试过使用setWillNotDraw(false)。它没有工作。我已经压缩了我的代码,具体说明我有这个问题的代码部分。

activity_main.xml中

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/frm"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent" >

        <com.example.temp.Cview
            android:layout_width="match_parent"
            android:layout_height="match_parent" />



    </RelativeLayout>

        <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent" >

     <Button
         android:id="@+id/bMineDetector"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:layout_alignParentBottom="true"
         android:layout_alignParentLeft="true"
         android:text="Lock" />


     </RelativeLayout>
</FrameLayout>

这是我的MainActivity.java

package com.example.temp;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;



public class MainActivity extends Activity implements OnClickListener{

    Button b;
    Boolean lock=false;
    Cview v;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // TODO Auto-generated method stub
        super.onCreate(savedInstanceState);
        v=new Cview(this,null);
        setContentView(R.layout.activity_main);
        initialize();
    }

    private void initialize() {
        // TODO Auto-generated method stub
        b=(Button) findViewById(R.id.bMineDetector);
        lock=false;
        b.setOnClickListener(this);
    }

    public void updateViewStart(){
        v.onStart();
    }

    public void updateViewStop(){
        v.onPause();
    }

    @Override
    protected void onPause() {
        // TODO Auto-generated method stub
        super.onPause();
        if(v.isRunning==true)
        v.onPause();
    }

    @Override
    protected void onResume() {
        // TODO Auto-generated method stub
        super.onResume();
    }



    @Override
    public void onClick(View v) {
        // TODO Auto-generated method stub
        switch(v.getId()){
        case R.id.bMineDetector:
            if(lock==false){
                lock=true;
                updateViewStart();
                b.setText("UnLock");
            }else{
                lock=false;
                updateViewStop();
                b.setText("lock");
            }

            break;
        }
    }

}

在上面的类中,我设置了一个onClickListener,它有助于根据按钮的状态启动或停止一个单独的线程。这是我的自定义视图,我处理触摸事件并创建此线程。

Cview.java

package com.example.temp;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;



public class Cview extends View implements OnTouchListener,Runnable{

    Boolean isRunning=false,isLockMode=false;
    Context gameContext;
    Thread myThread=null;

    public Cview(Context context, AttributeSet attrs) {
        super(context, attrs);
        // TODO Auto-generated constructor stub
        gameContext=context;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        // TODO Auto-generated method stub
        super.onDraw(canvas);
        Log.d("INVALIDATE", "Invalidating");
        isLockMode=((MainActivity)gameContext).lock;
        if(isLockMode==true){
            canvas.drawRect(100, 100, 300, 300, null);
            //invalidate();
        }

    }

    @Override
    public void run() {
        // TODO Auto-generated method stub
        while(isRunning){
            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            isLockMode=((MainActivity)gameContext).lock;
            this.postInvalidate();
            Log.d("THREAD", "isRunning="+isRunning+";;isLockMode="+isLockMode);
            }
    }


    void onStart(){
        isRunning=true;
        myThread=new Thread(this);
        myThread.start();
        //Log.d("INVALIDATE", "onStart");
        //postInvalidate();
    }

    void onPause(){
        isRunning=false;
        while(true){
            try {
                myThread.join();
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            break;
        }
        myThread=null;
    }

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        // TODO Auto-generated method stub
        return true;
    }

}

请有人帮我解决这个问题。一旦执行run方法,我需要重绘画布。我已经考虑了几个月而且我也是编程的新手。所以请指导我并建议我,如果有的话是我做任何其他更好的方法。谢谢。

2 个答案:

答案 0 :(得分:1)

What is the difference between Android's invalidate() and postInvalidate() methods?中所述,当从其他线程使用postInvalidate时可能会出现一些问题。

我没有测试过这个并不是很好,但它可以帮助你(而不是this.postInvalidate();

((MainActivity) gameContext).runOnUiThread(new Runnable() {
       @Override
       public void run() {

           Cview.this.invalidate();

       }
 });

答案 1 :(得分:0)

我刚刚遇到了同样的问题。

我的修复是使用分配自定义视图 在onCreate()中查找ViewById(),而不是调用构造函数。

添加

android:id="@+id/custom_view"

到您的XML,

v = (Cview) findViewById(R.id.custom_view);

到你的onCreate()函数(并删除构造函数调用)。

在调用setContentView()之后执行

Android有这样的无声失败模式。