View von anderer Klasse repainten

  • Antworten:8
  • Bentwortet
dwjiidnsw
  • Forum-Beiträge: 58

25.05.2018, 14:18:25 via Website

Hallo,
ich möchte von einer Klasse eine View repainten. Der Timer läuft zwar aber die View wird nicht neugezeichnet.

public class MyView extends SurfaceView{

private MainActivity mainActivity;
private Random random = new Random();
private static  MyView Instance;

public MyView(Context context) {
super(context);
mainActivity = (MainActivity)context;

}

 public final static MyView getInstance(Context context) {
if(Instance==null) {
    Instance = new MyView(context);
}
return Instance;
}

 @Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    setBackgroundColor(Color.argb(random.nextInt(255),random.nextInt(255),
            random.nextInt(255),random.nextInt(255)));
  }
}


 public class MyThread implements SurfaceHolder.Callback {

private Timer timer = new Timer();
private MainActivity mainActivity;
private MyView myView;
private TimerThread timerThread = new TimerThread();

public MyThread(Context context) {
   mainActivity = (MainActivity) context;
   myView = MyView.getInstance(context);
   timer.schedule(timerThread,50,50);
 }

class TimerThread extends TimerTask {

    @Override
    public void run() {
        mainActivity.runOnUiThread(new TimerTask() {
            @Override
            public void run() {
                Log.v("Log","Timer run");
                myView.invalidate();
            }
        });
     }
  }

Woran liegt das, dass die View nicht neugezeichnet wird?

— geändert am 25.05.2018, 14:41:19

Kommentieren
Beste Antwort
Jokel
  • Forum-Beiträge: 1.527

26.05.2018, 17:43:32 via Website

Dein Code funktioniert, wenn du statt von „SurfaceView“ nur von View erbst.

In deiner Java Klasse ebst du auch nur von "JFrame" was in etwa das gleiche wie "View" ist.

Wieso Implements du das „SurfaceHolder.Callback“ in die „MyThread“ Klasse?
Das wird dort gar nicht gebraucht.
Wenn dann must du es in deiner MyView Klasse Implementiren wenn die von „SurfaceView“ erbt. Dann must du auch die drei Methoden überschreiben und vorallem die „surfaceCreated“ benutzen.

Denke du schaust dir das mit dem SurfaceView nochmal an. So wie du es hattest wird die onDraw nie aufgerufen ob das nun eine Singleton Klasse ist oder nicht.

public class MyView extends View {

private MainActivity mainActivity;
private Random random = new Random();
private static  MyView Instance;

public MyView(Context context) {
    super(context);
    mainActivity = (MainActivity)context;

}

public final static MyView getInstance(Context context) {
    if(Instance==null) {
        Instance = new MyView(context);

    }
    return Instance;
}

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    canvas.drawARGB(255,random.nextInt(255),random.nextInt(255),random.nextInt(255));
}

}

public class MyThread {

private Timer timer = new Timer();
private MainActivity mainActivity;
private MyView myView;
private TimerThread timerThread = new TimerThread();

public MyThread(Context context) {
    mainActivity = (MainActivity) context;
    myView = MyView.getInstance(context);
    timer.schedule(timerThread, 50, 50);
 }

class TimerThread extends TimerTask {

    @Override
    public void run() {
        mainActivity.runOnUiThread(new TimerTask() {
            @Override
            public void run() {
               myView.invalidate();
            }
        });
    }
}

— geändert am 26.05.2018, 23:27:12

Hilfreich?
dwjiidnsw
Kommentieren
Pascal P.
  • Admin
  • Forum-Beiträge: 11.286

25.05.2018, 14:24:53 via App

Warum machst du im Rahmen nOnUiThread einen TimerTask statt einen Runnable?
Das müsste eine Runnable sein, dann dürfte es gehen.

LG Pascal //It's not a bug, it's a feature. :) ;)

Hilfreich?
dwjiidnsw
Kommentieren
dwjiidnsw
  • Forum-Beiträge: 58

25.05.2018, 15:13:28 via Website

Wenn ich jetzt eine Runnable verwende, wird gar nichts mehr ausgegeben:

 Thread t = new Thread(new RunnableThread());

 public MyThread(Context context) {
   mainActivity = (MainActivity) context;
   myView = MyView.getInstance(context);     
   t.start();
}

 class RunnableThread implements Runnable {

    @Override
    public void run() {
        mainActivity.runOnUiThread(new Runnable() {
            @Override
            public void run() {
                Log.v("Log","Runnable run");
                myView.invalidate();
            }
        });
     }
   }

Wieso ist es den besser eine Runnable zu verwenden? Ich hatte schon öfter einen Timer verwendet, wo es auch geklappt hat.

— geändert am 25.05.2018, 15:13:53

Hilfreich?
Kommentieren
Jokel
  • Forum-Beiträge: 1.527

25.05.2018, 16:15:31 via Website

Hallo
Also meiner Meinung nach ist das setzen der Hintergrundfarbe in deiner onDraw falsch.
setBackgroundColor ist eine Methode von View , du benutzt aber gar keine View.
Selbst wenn es eine Methode von Canvas wäre musst du auch ein Objekt benuten nur die Methode geht nicht. Ohne Objekt müsstest du von der Klasse erben.
"view.setBackgroundColor(...);"

Für das Canvas sollte es die "drawARGB(int a, int r, int g, int b)" Methode sein.

also
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawARGB(random.nextInt(255),random.nextInt(255),
random.nextInt(255),random.nextInt(255));
}

https://developer.android.com/reference/android/graphics/Canvas

— geändert am 25.05.2018, 17:05:15

Hilfreich?
dwjiidnsw
Kommentieren
dwjiidnsw
  • Forum-Beiträge: 58

25.05.2018, 23:07:43 via Website

Hallo,
ich verwende jetzt das canvas.drawArgb(), aber jetzt bleibt der Bildschirm die ganze Zeit schwarz.
Ich habe noch einen Log in die onDraw() Methode gepackt und anscheinend wird die onDraw() Methode gar nicht aufgerufen, es wird also nichts neugezeichnet

Hilfreich?
Kommentieren
Jokel
  • Forum-Beiträge: 1.527

26.05.2018, 10:14:35 via Website

Hallo
Bezug nehmen auf deinen ersten geposteten Code.

Wie und wo starttest du deinen Thread?
Wenn ich es richtig verstehe willst du mit Hilfe des Thread und Timer das neu Zeichen veranlassen.

Was mir noch in deinen Code auffällt ist.
In der Klasse TimerThread willst du das Neuzeichen anstoßen.
In Zeile 50 „myView.invalidate();“ wo wird die Variable „myView“ erstellt und instanziiert?
Die in der Klasse MyThread erstellte Variable ist in der TimerThread Klasse nicht sichtbar.
Oder hast du da eine Globale Variable?
Wenn nicht währe es klar das die onDraw nicht aufgerufen wird.

Auch würde ich erstmal bei der Hintergrundfarbe die Transparenz (Alphakanal) auf 255 setzen, denn es könnte sein das die zufällig immer sehr niedrig und somit unsichtbar ist.
canvas.drawARGB(255,random.nextInt(255),random.nextInt(255),random.nextInt(255));.

Verstehe auch nicht so richtig was das mit der „getInstance(Context context)“ Mdethode soll.
Du speicherst da nicht die Instanz der eigenen Klasse sondern erzeugst eine neue. Von dir selber.

Hilfreich?
Kommentieren
Pascal P.
  • Admin
  • Forum-Beiträge: 11.286

26.05.2018, 12:09:53 via App

Andere Frage: Wieso überhaupt ein Thread wenn du in diesem wieder nur runOnUiThread machst?
Da reicht dann doch auch ein Handler#postDelayed

LG Pascal //It's not a bug, it's a feature. :) ;)

Hilfreich?
dwjiidnsw
Kommentieren
dwjiidnsw
  • Forum-Beiträge: 58

26.05.2018, 13:16:48 via Website

@Pascal P.
Ich bin noch relativ neu in der Android Programmierung und habe noch nie von PostDelayed gehört, werde ich mir aber mal anschauene.

@Jokel
Das Beispiel ist etwas sinnlos, ich wollte daran nur zeigen was nicht klappt.
MyView wollte ich als Singleton machen, damit ich dann nur ein Objekt davon habe und es von einer anderen Klasse repainten kann. Hier ist noch meine MainActivity:

@Override
 protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    MyView mv = MyView.getInstance(this);
   RelativeLayout.LayoutParams params = new 
  RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT,
  RelativeLayout.LayoutParams.MATCH_PARENT);
   mv.setLayoutParams(params);
   RelativeLayout layout = (RelativeLayout) findViewById(R.id.relativeLayout);
   layout.addView(mv);
   MyThread myThread = new MyThread(this);
}

Edit:
Nur mit Java und eclipse habe ich es so gemacht und da funktioniert es:

   public class AnimationView extends JFrame {

private static AnimationView Instance;
private ArrayList<Color> colorList = new ArrayList<Color>();
private Random random = new Random();

public final static AnimationView getInstance() {
    if(Instance==null) {
        Instance = new AnimationView();
    }       
    return Instance;
}

private AnimationView() {
    setSize(300,300);
    colorList.add(Color.BLUE);
    colorList.add(Color.GREEN);
    colorList.add(Color.RED);
    setVisible(true);
}

@Override public void paint(Graphics g) {   
    int tmp= random.nextInt(3);     
    this.getContentPane().setBackground(colorList.get(tmp));
}   
 }

 public class AnimationThread {

private AnimationView av;
private Timer timer = new Timer();

public AnimationThread() {
    av = AnimationView.getInstance();
    timer.schedule(new MyThread(),50,100);
}

class MyThread extends TimerTask {
    @Override
    public void run() {                 
        av.repaint();
    }       
}

public static void main(String[] args) {
    new AnimationThread();
}   
 }

— geändert am 26.05.2018, 14:03:26

Hilfreich?
Kommentieren
Beste Antwort
Jokel
  • Forum-Beiträge: 1.527

26.05.2018, 17:43:32 via Website

Dein Code funktioniert, wenn du statt von „SurfaceView“ nur von View erbst.

In deiner Java Klasse ebst du auch nur von "JFrame" was in etwa das gleiche wie "View" ist.

Wieso Implements du das „SurfaceHolder.Callback“ in die „MyThread“ Klasse?
Das wird dort gar nicht gebraucht.
Wenn dann must du es in deiner MyView Klasse Implementiren wenn die von „SurfaceView“ erbt. Dann must du auch die drei Methoden überschreiben und vorallem die „surfaceCreated“ benutzen.

Denke du schaust dir das mit dem SurfaceView nochmal an. So wie du es hattest wird die onDraw nie aufgerufen ob das nun eine Singleton Klasse ist oder nicht.

public class MyView extends View {

private MainActivity mainActivity;
private Random random = new Random();
private static  MyView Instance;

public MyView(Context context) {
    super(context);
    mainActivity = (MainActivity)context;

}

public final static MyView getInstance(Context context) {
    if(Instance==null) {
        Instance = new MyView(context);

    }
    return Instance;
}

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    canvas.drawARGB(255,random.nextInt(255),random.nextInt(255),random.nextInt(255));
}

}

public class MyThread {

private Timer timer = new Timer();
private MainActivity mainActivity;
private MyView myView;
private TimerThread timerThread = new TimerThread();

public MyThread(Context context) {
    mainActivity = (MainActivity) context;
    myView = MyView.getInstance(context);
    timer.schedule(timerThread, 50, 50);
 }

class TimerThread extends TimerTask {

    @Override
    public void run() {
        mainActivity.runOnUiThread(new TimerTask() {
            @Override
            public void run() {
               myView.invalidate();
            }
        });
    }
}

— geändert am 26.05.2018, 23:27:12

Hilfreich?
dwjiidnsw
Kommentieren