【问题标题】:postInvalidate() not working with non-ui ThreadpostInvalidate() 不适用于非 ui 线程
【发布时间】:2014-02-12 15:03:26
【问题描述】:

我正在使用自定义视图来绘制游戏内容,并且我使用 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 方法,我需要重新绘制画布。我已经考虑了几个月,而且我也是编程新手。所以请指导我并建议我是否有有没有其他更好的方法来做我需要的事情。谢谢。

【问题讨论】:

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


    【解决方案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();
    
           }
     });
    

    【讨论】:

    • 我试过了,它不起作用。无效被忽略:(
    【解决方案2】:

    我刚刚遇到了完全相同的问题。

    对我来说,解决方法是使用 onCreate() 中的 findViewById(),而不是调用构造函数。

    添加

    android:id="@+id/custom_view"
    

    到您的 XML,并且

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

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

    在调用 setContentView() 之后 执行此操作。

    Android 有无数这样的静默故障模式。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-11-04
      • 2021-12-02
      相关资源
      最近更新 更多