Utiliser Timer sous Android

Résolu/Fermé
matrix124 Messages postés 91 Date d'inscription mardi 3 novembre 2009 Statut Membre Dernière intervention 12 décembre 2013 - 22 mai 2013 à 18:18
scinarf Messages postés 1098 Date d'inscription samedi 18 novembre 2006 Statut Membre Dernière intervention 25 septembre 2014 - 28 mai 2013 à 22:08
Bonjour j'aurais besoin d'aide,
Je suis débutant en programmation et j'essaye de réaliser un mini jeu. Pour ça j'aurais besoin de modifier les coordonnées d'un bloc pour qu'il se déplace. Pour cela je crois qu'il faut utiliser un Timer mais je n'arrive pas à le mettre en place. Voici la classe qui ne fonctionne pas comme je l'aimerais.
public class Bloc {
	
    int pX=775;
    int pY=265;
	
    private RectF mRectangle = null;
    

    public RectF getRectangle() {
        return mRectangle;
    }
    

    Timer t = new Timer();
    t.scheduleAtFixedRate(new Action(),1000,600);
    
    class Action extends TimerTask{
    	public void run(){

    	pX--;
                }
    	}



    public Bloc() {
    	
    	this.mRectangle = new RectF(pX,pY,pX+25,pY+25);

    }
}

Voici l'eereur qu'eclipse m'indique au niveau du t.scheduleAt....
Multiple markers at this line
- Syntax error on token ")", invalid
ArgumentList
- Syntax error on token "(", = expected
- Syntax error on token(s), misplaced
construct(s)

Merci de votre aide.
Bonne soirée.
A voir également:

15 réponses

scinarf Messages postés 1098 Date d'inscription samedi 18 novembre 2006 Statut Membre Dernière intervention 25 septembre 2014 252
23 mai 2013 à 16:23
Bonjour,

Alors je vois pas trop ce que vous souhaitez faire ... beaucoup de choses étrange !

Pour récupérer le temps sous Android il faut utiliser System.currentTimeMillis ()

Après pour faire lancer un évènement au bout d'un certain faire faire
long MyFuturAction = System.currentTimeMillis () + Delai;
while (System.currentTimeMillis ()< MyFuturAction )
//Do action après l'attente.

Plus d'info ici : https://developer.android.com/reference/java/lang/System.html#currentTimeMillis%28%29
Doc officielle de Android, ne pas hésiter à l'utiliser

Après êtes vous obligé d'utiliser des Inner Class (Class définie directement dans le même .java qu'une autre Class) ? Je trouve que ça rend le code complétement illisible !

Pour faire déplacer un objet sur l'écran type Drawable ou Bitmap, je conseil d'utiliser un Thread associé à un handler qui est beaucoup plus claire et plus propre à mon avis.

Si vous avez des questions sur comment faire, je vous invite à les poser.
1
matrix124 Messages postés 91 Date d'inscription mardi 3 novembre 2009 Statut Membre Dernière intervention 12 décembre 2013 56
Modifié par matrix124 le 24/05/2013 à 14:21
Bonjour,

Tout d'abord merci de votre réponse.

Etant vraiment débutant je sais que mon code est mauvais. Cependant je n'ai pas vraiment eu le temps d'apprendre a bien me servir du java car il s'agit d'un projet que je devrais présenté pour le Baccalauréat dans le cadre de l'option Informatique et Sciences du Numérique. De plus je n'ai reçu aucune formation.

Concernant mon application, en réalité, je souhaite exécuter une certaine action toutes les 50 ms par exemple et non connaitre le temps avec un currentTimeMillis. Pour ce qui est du Thread associé à un handler je n'ai alors vraiment aucune idée de comment pour le mettre en place.

Je souhaiterais savoir comment puis je mettre en mouvement des blocs comme dans ce mini-jeu (Line Runner): https://play.google.com/store/apps/details?id=com.djinnworks.linerunnerfree&hl=fr

Cependant n'ayant aucune idée de comment faire j'ai cru qu'il serais bon d'utiliser un Timer mais a priori cette technique ne semble pas appropriée. Si vous pouviez me réorientez sur un façon plus appropriée de pouvoir faire défiler des blocs à l'écran comme dans le jeu, je vous en serait fort reconnaissant.

Merci d'avance.
0
scinarf Messages postés 1098 Date d'inscription samedi 18 novembre 2006 Statut Membre Dernière intervention 25 septembre 2014 252
24 mai 2013 à 14:36
Sachez qu'il n'y a aucun problème a être débutant ;) et il faut bien commencer un jour.

Je vois a peu près ce que vous souhaiter faire :

public class Bloc {

private final String TAG = "Bloc";

private int pX=775;
private int pY=265;
private int Repete;

private RectF mRectangle = null;

public Bloc()
{
mRectangle = new Rectangle(pX,pY,pX+10,pY+10);//Rectangle de 10 pixel

}

public void deplaceRect (int pas, int time)
{
while (Repete < 50)
{
mRectangle.set(mRectangle.left + pas, mRectangle.top + pas, mRectangle.right + pas, mRectangle.bottom + pas)
Repet +=1;
Try{
Thread.sleep(time);
}catch(Exception e)
{
Log.d(TAG, "Erreur sur thread sleep "+e);
}
}
}

public rectangle getRectangle()
{
return mRectangle;
}

}

Cette class permet de de créer un rectangle, une fois la méthode deplaceRect appelée, elle se repetera 50 et elle déplacera le rectangle du "pas" utiliser toutes les "time" fois

Ensuite il vous faut un objet à dessiner pour et dans la méthode deplacerect vous pouvez faire Objetadessiner.setBounds(mRectangle);
Objetadessiner.invalidate();

l'aobjet sera dessiné pendant 50 fois. (on peut changer le 50 an une autre condition du genre déplacer l'objetadessiner tant qu'il est pas sortie de l'écran ou durant un certain temps, ou si vous faite un jeu, tant uqe le joueur n'a pas perdu tout dépend de vos critères)

Ne pas hésiter si vous souhaitez plus d'informations
0
matrix124 Messages postés 91 Date d'inscription mardi 3 novembre 2009 Statut Membre Dernière intervention 12 décembre 2013 56
Modifié par matrix124 le 24/05/2013 à 15:30
Une fois de plus je souhaiterais vous remercier du temps que vous m'accorder et de votre soutien.

J'espère que vous ne penserez pas que je n'ai pas réfléchi ou que ce soit par fainéantise que je vous pose les questions suivantes.

J'ai bien compris l'ensemble du code que vous m'avez fourni à l'exception de Log.d(TAG, "Erreur sur thread sleep "+e); c'est pour cela que dans le code qui suit je l'ai mis en commentaire car eclipse m'affichait une erreur et je n'avais aucune idée de comment la résoudre.Pour ce qui concerne le pas et le temps j'ai pour l'instant mis des valeurs arbitraires que je modifierais plus tard en observant le résultat.

Il se trouve que pour réaliser mon mini-jeu j'ai utiliser une structure du site du zéro où je n'avais qu'à m'occuper de la méthode Draw. En voici une partie:
public class MainSurfaceView extends SurfaceView implements SurfaceHolder.Callback {

 Bloc b = new Bloc();

 @Override
 protected void onDraw(Canvas pCanvas) {
  // Dessinezici !
  pCanvas.drawColor(Color.WHITE);
  int width = getWidth();
  int largeur = width * 20 / 100;
  int mlargeur = width * 92 / 100;
  int height = getHeight();
  int hauteur = height * 60 / 100;
  int taille = height * 6 / 100;

  mPaint.setColor(Color.BLACK);
  pCanvas.drawRect(0, hauteur, width, hauteur + taille, mPaint);

  pCanvas.drawRect(b.getRectangle(), mPaint);

  mPaint.setColor(Color.RED);
  pCanvas.drawRect(largeur, hauteur - taille, largeur + taille, hauteur,mPaint);

 }


Seulement vous avez mentionné "Objetadessiner.setBounds(mRectangle); Objetadessiner.invalidate(); ", et là encore je ne comprends pas vraiment de quoi il s'agit. Si vous pouviez m'éclairer afin que je comprenne comment je vais pouvoir afficher ce Bloc qui se déplace.
Merci.
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
scinarf Messages postés 1098 Date d'inscription samedi 18 novembre 2006 Statut Membre Dernière intervention 25 septembre 2014 252
24 mai 2013 à 17:23
Pas de soucis, je sais que ca peut paraitre assez obscure au début.

Par contre j'suis pas toujours d'accord avec le site du zéro, je trouve qu'il complique les choses les plus simples ... comme par exemple ici.

Quel forme souhaitez vous dessiner un simple carré pour le début ? ça vous va ?

(il faudra peut être adapter le nom du Package)
On va procéder en deux fichiers .java différents c'est beaucoup plus claire :

Le premier qui contient la MainActivity et qui se nomme de manière évidente MainActivity.java (lorsque vous le créerez)

package com.example.testshape;

import android.os.Bundle;
import android.app.Activity;


public class MainActivity extends Activity
{
private myView v;

@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
v = new myView(this);
setContentView(v);
}

}

le second qui contient ma vue (View) avec un Drawable un objet qui permet d'être tracé sur l'écran
(la encore il faudra peut être changer le nom du package) . Se fichier se nomme myView.java
pour tester sur mon HTC désire j'ai modifié les valeurs initiales de pX et pY

package com.example.testshape;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Rect;
import android.graphics.drawable.ShapeDrawable;
import android.graphics.drawable.shapes.RectShape;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;

public class myView extends View
{
private final String TAG = "MyView";
private ShapeDrawable Sd =null;
private RectShape RS = null;
private int pX=100;
private int pY=100;
private int Repete;
private Rect mRectangle = null;

public myView(Context context)
{
// TODO Auto-generated constructor stub
super(context);
RS = new RectShape();
Sd = new ShapeDrawable(RS);
Sd.getPaint().setColor(Color.BLUE);
this.setBackgroundColor(0xff000000);
mRectangle = new Rect(pX,pY,pX+20,pY+20);//Rectangle de 10 pixel
Sd.setBounds(mRectangle);
invalidate();
}
public myView(Context context, AttributeSet attrs)
{
super(context, attrs);
// TODO Auto-generated constructor stub
}

public myView(Context context, AttributeSet attrs, int defStyle)
{
super(context, attrs, defStyle);
// TODO Auto-generated constructor stub
}

public void deplaceRect (int pas, int time)
{
while (Repete < 50)
{
mRectangle.set(mRectangle.left + pas, mRectangle.top + pas, mRectangle.right + pas, mRectangle.bottom + pas);
Sd.setBounds(mRectangle);
invalidate();
Repete +=1;
try{
Thread.sleep(time);
}
catch(Exception e)
{
Log.d(TAG, "Erreur sur thread sleep "+e);
}
}
}

@Override
public void onDraw(Canvas canvas)
{
Sd.draw(canvas);
}
}

Invalidate est utilisé pour forcer le Thread UI à redessiner les objets à l'écran. Pour utiliser la méthode deplaceRect il suffit de placer cette ligne dans le main activity après le setContentView(v)

v.deplaceRect(5,15);

Le temps est en Milleseconds donc vous ne verrez pas grand chose avec 15 mais faites des tests.
0
matrix124 Messages postés 91 Date d'inscription mardi 3 novembre 2009 Statut Membre Dernière intervention 12 décembre 2013 56
24 mai 2013 à 18:38
Merci, cependant après plusieurs tests sur mon téléphone et mon émulateur je n'obtient pas une animation mais seulement un carré bleu qui s'affiche sur un fond noir.
C'est pour ça que je me demandais si le code marchais sur votre htc desire car moi si j'augmente le temps dans le thread.sleep il met juste plus de temps à m'afficher le résultat du déplacement. Cela se traduit par un écran blanc pendant plusieurs secondes puis l'affichage du carré bleu sur le fond noir.
Je penses que je devrais vous laisser tranquille pour aujourd'hui au moins.
Merci et bonne soirée.
0
scinarf Messages postés 1098 Date d'inscription samedi 18 novembre 2006 Statut Membre Dernière intervention 25 septembre 2014 252
24 mai 2013 à 19:09
Pour que l animation se lance il faut ajouter :

V.deplace(5,100) après l appel à la méthode setcontentview(v)
0
matrix124 Messages postés 91 Date d'inscription mardi 3 novembre 2009 Statut Membre Dernière intervention 12 décembre 2013 56
Modifié par matrix124 le 24/05/2013 à 19:15
Oui, c'est bon elle y est déjà et pourtant rien ne se passe.
0
scinarf Messages postés 1098 Date d'inscription samedi 18 novembre 2006 Statut Membre Dernière intervention 25 septembre 2014 252
24 mai 2013 à 19:45
Alors le mieux est de faire une activation sur le click d'un bouton pourquoi pas le bouton Menu je vais mettre ca au point
0
matrix124 Messages postés 91 Date d'inscription mardi 3 novembre 2009 Statut Membre Dernière intervention 12 décembre 2013 56
24 mai 2013 à 20:41
D'accord, moi je vais continuez quelques trucs sur mon application car il me reste encore beaucoup de travail.
0
scinarf Messages postés 1098 Date d'inscription samedi 18 novembre 2006 Statut Membre Dernière intervention 25 septembre 2014 252
24 mai 2013 à 21:09
Je regarde ça de plus pret ce week end si vous ouvez attendre jusqu'a la.
0
matrix124 Messages postés 91 Date d'inscription mardi 3 novembre 2009 Statut Membre Dernière intervention 12 décembre 2013 56
24 mai 2013 à 21:13
Bien sur, et bonne soirée.
0
scinarf Messages postés 1098 Date d'inscription samedi 18 novembre 2006 Statut Membre Dernière intervention 25 septembre 2014 252
27 mai 2013 à 08:25
Bonjour, bien reposé ? Je reviens vers vous avec quelques questions.

Quel genre interaction avec l'utilisateur souhaitez vous ? un bouton Start pour lancer l'animation ca vous va ? ou juste en touchant l'écran (peut importe ou)?
0
matrix124 Messages postés 91 Date d'inscription mardi 3 novembre 2009 Statut Membre Dernière intervention 12 décembre 2013 56
27 mai 2013 à 22:31
Bonsoir en touchant l'écran ça serait parfait.
0
scinarf Messages postés 1098 Date d'inscription samedi 18 novembre 2006 Statut Membre Dernière intervention 25 septembre 2014 252
28 mai 2013 à 11:12
Voila j'ai fais un truc qui fonctionne et qui a le mérite d'être super propre !

Quelques conventions que j'utilise :

-1 Class = 1 fichier Java donc pas Inner Class
-Chaque objet dispose de son destructeur pour éviter les pertes de mémoires importantes (non gérées par le GC)
-J'ai commenté le code pour que chaque objet soit bien explicite et chaque ligne soit compréhensible.

MainActivity
package com.example.testshape;



import android.app.Activity;
import android.os.Bundle;
import android.view.Display;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;


public class MainActivity extends Activity implements OnTouchListener
{
private myView v=null;
private Display display=null;//Récupération de la taille de l'écran pour adapter le programme à toutes les tailles

@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
display = this.getWindowManager().getDefaultDisplay();
v = new myView(this, display);
setContentView(v);
}

//Action à effectuer lorsque l'on pose le doigt sur l'écran
//Deux actions identifier, la pose d'un doigt et le mouvement d'un doigt
@Override
public boolean onTouch(View arg0, MotionEvent event)
{
// TODO Auto-generated method stub
int action = event.getAction();
if ( action == MotionEvent.ACTION_DOWN | action == MotionEvent.ACTION_MOVE)
{
v.onTouchEvent(event);
}
return true;
}

//Destructeur pour éviter les leak of memory
@Override
public void onDestroy()
{
v.onDestroy();
v = null;
super.onDestroy();
}

}


MyView


package com.example.testshape;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Rect;
import android.graphics.drawable.ShapeDrawable;
import android.graphics.drawable.shapes.RectShape;
import android.util.AttributeSet;
import android.util.Log;
import android.view.Display;
import android.view.MotionEvent;
import android.view.View;

public class myView extends View
{

private final String TAG = "MyView";//Permet d'identifier l'activité dans les log
private ShapeDrawable Sd =null;//L'objet qui est dessiné

private int pX=100;//Position X au lancement du programme
private int pY=100;//Position Y au lancement du programme
private Rect mRectangle = null;//Rectange qui est utlisé pour la position intiale
private Movement myAnimation=null;//Thread responsable de l'animation du ShapeDrawable
private Display D=null;

public myView(Context context, Display d) //Constructeur
{
// TODO Auto-generated constructor stub
super(context);
Sd = new ShapeDrawable(new RectShape());
Sd.getPaint().setColor(Color.BLUE);
this.setBackgroundColor(0xff000000);
mRectangle = new Rect(pX,pY,pX+20,pY+20);//Rectangle de 10 pixel
Sd.setBounds(mRectangle);
D = d;
myAnimation = new Movement(this, d);
}
public myView(Context context, AttributeSet attrs) //Constructeur non utilisé
{
super(context, attrs);
// TODO Auto-generated constructor stub
}

public myView(Context context, AttributeSet attrs, int defStyle) //Constructeur non utilisé
{
super(context, attrs, defStyle);
// TODO Auto-generated constructor stub
}

//Méthode appelée pour dessiner (ou actualiser) l'écran
@Override
public void onDraw(Canvas canvas)
{
Log.d(TAG, "Draw called"); //Log visible dans le LogCat
Sd.draw(canvas); //On redessine le ShapeDrawable
}

//Méthode appelée lors de l'appuye sur l'écran
@Override
public boolean onTouchEvent(MotionEvent event)
{
if (!myAnimation.getStatut()) myAnimation.start();//Si le Thread n'est pas lancé alors on le lance
else if (myAnimation.getfinish())//Si le Thread a été lancé et si il est finie alors on en recré un
{
myAnimation.onDestroy();
myAnimation = null;
myAnimation = new Movement(this,D);
}
return true;

}

//Getter pour récupérer le ShapeDrawable
public ShapeDrawable getShapeDrawable()
{
return Sd;
}

//Destructeur appelé automatiquement pour ne pas que de référence ou pointeur reste non null lors de la fermeture de l'activity
public void onDestroy()
{
myAnimation.onDestroy();
myAnimation = null;
mRectangle = null;
Sd = null;
}
}


movement

package com.example.testshape;

import android.graphics.drawable.ShapeDrawable;
import android.util.Log;
import android.view.Display;

public class Movement extends Thread
{
private final String TAG ="MovementThread";
private final int INVALIDATE = 0;
private int Width = 0;
private int X_ini = 0;
private int Y_ini = 100;
private ShapeDrawable SD = null;
private sdhandler UIHandler = null;
private boolean Start = false;
private boolean finish = false;

public Movement(myView v, Display d)
{
SD = v.getShapeDrawable();//On récupère le Drawable de la vue créée dans la mainActivity
SD.setBounds(X_ini,Y_ini,X_ini + 20,Y_ini + 20);//pour les besoins du Thread on replace le ShapeDrawable sur le bord droit de l'écran
Width = d.getWidth();
UIHandler = new sdhandler(v);
UIHandler.sendEmptyMessage(INVALIDATE);//On déssine une première fois le ShapeDrawable
}

//Méthode qui permet d'exécuter du code en parallèle (et non en séquentielle)
public void run()
{
Start = true;//On informe le programme que le Thread est déjà lancé pour ne pas le lancer deux fois
while (SD.getBounds().right < Width)//Critère d'arrêt tant que on n'a pas atteint le bord droit, peut être changer
{
//Un Thread n'a pas la possibilité de changer l'interface graphique c'est pourqui on appel un Handler qui lui est exécuté sur le Thread principal
//Donc possibilité de changer l'interface Graphique
UIHandler.sendEmptyMessage(INVALIDATE);//On communique avec le Handler en envoyer des Message de type int
try {
Thread.sleep(100);//On attend 0.1 Secondes que ShapeDrawable soit redéssiné peut être modifié pour plus de réactivité
} catch (InterruptedException e) {
// TODO Auto-generated catch block
Log.d(TAG,"Erreur Sleep " + e);//Récupéretaion d'erreur et d'intérption sur le Thread.sleep obligatoire
break;
}
}
finish = true;
}

//Getter pour le Statut du Thread
public boolean getStatut()
{
return Start;
}
//Getter pour savoir si le Thread est terminé
public boolean getfinish()
{
return finish;
}

//Destructeur
public void onDestroy()
{
UIHandler.onDestroy();
UIHandler = null;
SD = null;
}
}


Handler

package com.example.testshape;

import android.graphics.drawable.ShapeDrawable;
import android.os.Handler;

//Le Handler permet d'intéragir sur les éléments du Thread Principal appelé Thread UI
public class sdhandler extends Handler
{

private myView mv=null;
private ShapeDrawable SD=null;

//Constructeur
public sdhandler(myView v)
{
mv = v;
SD = mv.getShapeDrawable();
}

//Méthode permettant la communication entre le Thread et le Handler
public void handleMessage(android.os.Message msg)
{
switch (msg.what)
{
case 0:
{
SD.setBounds(SD.getBounds().left + 10,SD.getBounds().top +10,SD.getBounds().right +10,SD.getBounds().bottom +10 );//On déplace le ShapeDrawable
mv.invalidate();//On Demande à Actualiser l'écran
break;
}
default :
break;
}
}

//Destructeuur
public void onDestroy()
{
mv = null;
SD = null;
}
}

Si vous avez des questions pas de soucis.
0
scinarf Messages postés 1098 Date d'inscription samedi 18 novembre 2006 Statut Membre Dernière intervention 25 septembre 2014 252
28 mai 2013 à 11:17
Le nom des fichiers Java doit être le même que le nom des class déclarées

Soit :
MainActivity
myView
movement
sdhandler
0
matrix124 Messages postés 91 Date d'inscription mardi 3 novembre 2009 Statut Membre Dernière intervention 12 décembre 2013 56
Modifié par matrix124 le 28/05/2013 à 18:05
Magnifique, ça marche à merveille! Merci énormément pour tout ce que vous avez pu faire pour m'aider c'est vraiment génial et c'est exactement le rendu que j'espérais obtenir.
C'est vraiment très bien détaillé grâce aux nombreux commentaires que vous avez pu laisser. Merci encore.
0
scinarf Messages postés 1098 Date d'inscription samedi 18 novembre 2006 Statut Membre Dernière intervention 25 septembre 2014 252
Modifié par scinarf le 28/05/2013 à 22:12
Après à vous de faire le reste ;)

Mais n'hésitez à me recontacter sur ce forum, je passe régulièrement. Et à partir cela vous pouvez faire pas mal de choses pour vous amuser.

Pensez à changer le statut du topic en résolu ;)
0