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;等等