2015-05-16 4 views
3

У меня есть Service, который может нарисовать Canvas поверх всех приложений, используя SYSTEM_ALERT_WINDOW, который содержит пользовательский View.Android: Thread to Update View Inside Window

Я пытаюсь оживить Canvas объект с помощью Thread, который вызывает Canvas.draw(...) и postInvalidate() - Я надеялся, что это будет «двигаться» форму по экрану. Это не работает.

Я попытался положить мой обычай View внутри ViewGroup контейнера и добавил это к WindowManager объекта - на основе следующих сообщений: положение объекта

Animate system alert type view

WindowManager with Animation (is it possible?)

Холст не изменяется - Что я делаю не так?

Вот мой код ...

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); 
    } 
} 

Cursor.java

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); 
    } 
} 
+0

Трассировка стека предполагает, что вы вызываете 'invalidate', но код, который вы отправили, вызывает' postInvalidate'. Вы должны вызвать 'postInvalidate', чтобы аннулировать представление из другого потока. – pathfinderelite

+0

Я отредактировал сообщение - оказывается, ошибок нет! – calcha3991

ответ

2

Прежде всего, вам нужно как-л while(true){} цикла в вашем работоспособным, потому что в вашем методе код postInvalidate() будет называться только один раз.

Но было бы намного лучше позвонить по телефону invalidate() в onDraw и рассчитать положение вашего круга, используя текущее время.

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(); 
    } 
} 
+0

Я использовал 'while (true) {} 'цикл в моем runnable, и он работает! Как бы вычислить x и y, используя дельта-время? – calcha3991

+0

@ calcha3991, например, вы хотите, чтобы ваш круг перемещался на 100dp по оси X за одну секунду. Таким образом, в миллисекундах скорость круга 0,1dp. Таким образом, положение x в любой момент времени будет равно x = startPosition + delta * speed; если вы хотите, чтобы круг в какой-то момент остановился, вы можете проверить, (x> maxPosition) x = maxPosition; и так далее. – Stepango

-1

Поскольку вы меняете x, y и radius от отдельный нить, вы должны сделать их неустойчивыми. В противном случае изменения, которые вы вносите в эти переменные (из фонового потока), не будут видны вашим представлением (в потоке пользовательского интерфейса).

public volatile float x; 
public volatile float y; 
public volatile float radius; 
+0

Извините, это не имеет никакого значения. Я боюсь. Кажется, я не получаю «NullPointerException» – calcha3991

+0

. Нет никаких условий гонки между потоками, поэтому volatile действительно ничего не делает здесь – Stepango