Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/elixir/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java Android:更新窗口内部视图的线程_Java_Android_Multithreading_Canvas - Fatal编程技术网

Java Android:更新窗口内部视图的线程

Java Android:更新窗口内部视图的线程,java,android,multithreading,canvas,Java,Android,Multithreading,Canvas,我有一个服务,它可以使用包含自定义视图的系统警报窗口在所有应用程序的顶部绘制一个画布 我正在尝试使用调用Canvas.draw(…)和postInvalidate()的Thread来设置Canvas对象的动画-我希望这样可以在屏幕上“移动”形状。它不起作用 我尝试将自定义的视图放入视图组容器中,并将其添加到WindowManager对象中-基于以下帖子: 画布对象位置不变-我做错了什么? 这是我的密码 CursorService.java public class CursorSer

我有一个
服务
,它可以使用包含自定义
视图的
系统警报窗口
在所有应用程序的顶部绘制一个
画布

我正在尝试使用调用
Canvas.draw(…)
postInvalidate()
Thread
来设置
Canvas
对象的动画-我希望这样可以在屏幕上“移动”形状。它不起作用

我尝试将自定义的
视图
放入
视图组
容器中,并将其添加到
WindowManager
对象中-基于以下帖子:

画布对象位置不变-我做错了什么?

这是我的密码

CursorService.java

    public class CursorService extends Service {

    private WindowManager windowManager;
    private ViewGroup cursorContainer;
    private Cursor cursor;

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }


    public void onCreate() {
        super.onCreate();

       go();
    }

    public void go(){

        windowManager = (WindowManager) getSystemService(WINDOW_SERVICE);

        WindowManager.LayoutParams params = new WindowManager.LayoutParams(
                WindowManager.LayoutParams.WRAP_CONTENT,
                WindowManager.LayoutParams.WRAP_CONTENT,
                WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY,
                WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE,
                PixelFormat.TRANSLUCENT
        );

        cursor = new Cursor(this);
        cursorContainer = new LinearLayout(this);
        cursorContainer.addView(cursor);
        windowManager.addView(cursorContainer, params);


        new Thread(new Runnable() {
            @Override
            public void run() {
                    cursor.x+=1;
                    cursor.y+=1;
                    cursor.radius=100;
               }
        }).start();
    }


    public void onDestroy() {
        super.onDestroy();
        if (cursorContainer!=null) windowManager.removeView(cursorContainer);
    }
}
public class Cursor extends View {

    public float x;
    public float y;
    public float radius;
    public Paint paint;

    public Cursor(Context context) {
        super(context);

        x=0;
        y=0;
        radius=0;
        paint=new Paint();
        paint.setColor(Color.RED);

        new Thread(new Runnable() {
            public void run() {
                while (true){
                    try{
                        Thread.sleep(100);
                        postInvalidate();
                    } catch (InterruptedException e){
                        e.printStackTrace();
                    }
                }
            }
        }).start();
    }

    @Override
    protected void onDraw(Canvas canvas){
        canvas.drawCircle(x, y, radius, paint);
    }
}
Cursor.java

    public class CursorService extends Service {

    private WindowManager windowManager;
    private ViewGroup cursorContainer;
    private Cursor cursor;

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }


    public void onCreate() {
        super.onCreate();

       go();
    }

    public void go(){

        windowManager = (WindowManager) getSystemService(WINDOW_SERVICE);

        WindowManager.LayoutParams params = new WindowManager.LayoutParams(
                WindowManager.LayoutParams.WRAP_CONTENT,
                WindowManager.LayoutParams.WRAP_CONTENT,
                WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY,
                WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE,
                PixelFormat.TRANSLUCENT
        );

        cursor = new Cursor(this);
        cursorContainer = new LinearLayout(this);
        cursorContainer.addView(cursor);
        windowManager.addView(cursorContainer, params);


        new Thread(new Runnable() {
            @Override
            public void run() {
                    cursor.x+=1;
                    cursor.y+=1;
                    cursor.radius=100;
               }
        }).start();
    }


    public void onDestroy() {
        super.onDestroy();
        if (cursorContainer!=null) windowManager.removeView(cursorContainer);
    }
}
public class Cursor extends View {

    public float x;
    public float y;
    public float radius;
    public Paint paint;

    public Cursor(Context context) {
        super(context);

        x=0;
        y=0;
        radius=0;
        paint=new Paint();
        paint.setColor(Color.RED);

        new Thread(new Runnable() {
            public void run() {
                while (true){
                    try{
                        Thread.sleep(100);
                        postInvalidate();
                    } catch (InterruptedException e){
                        e.printStackTrace();
                    }
                }
            }
        }).start();
    }

    @Override
    protected void onDraw(Canvas canvas){
        canvas.drawCircle(x, y, radius, paint);
    }
}

由于要从一个单独的线程更改
x
y
radius
,因此应该使它们不稳定。否则,视图(在UI线程上)将看不到您(从后台线程)对这些变量所做的更改


首先,在runnable中需要smth,比如
while(true){}
循环,因为在代码中
postInvalidate()
方法只调用一次

但最好在
onDraw
中调用
invalidate()
方法,并使用当前时间计算圆的位置

public class Cursor extends View {    
    public Cursor(Context context) {
        super(context);
        startTime = System.currentTimeMills();
    }

    @Override
    protected void onDraw(Canvas canvas){
        long delta = System.currentTimeMills() - startTime;
        // ... calculate x and y using delta
        canvas.drawCircle(x, y, radius, paint);
        invalidate();
    }
}

抱歉,恐怕这没有什么区别-我似乎没有得到
NullPointerException
线程之间没有竞争条件,因此volatile在这里真的什么都不做堆栈跟踪表明您正在调用
invalidate
,但您发布的代码正在调用
postInvalidate
。您必须调用
postInvalidate
以使来自不同线程的视图无效。我编辑了该帖子-结果表明根本没有任何错误!我在runnable中使用了
while(true){}
循环,它可以工作!我如何使用delta time计算x和y呢?例如@calcha3991,你希望你的圆在一秒钟内以x轴移动100dp。所以一毫秒内有0.1dp的圆周速度。因此,任何时刻的位置x都是x=起始位置+增量*速度;若你们想让圆停在某个点上,你们可以检查(x>maxPosition)x=maxPosition;等等