2010-12-13 72 views
1

Cette question concerne l'utilisation du SDK Google Android dans le langage de programmation Java.L'émulateur Android se bloque lors de l'utilisation simultanée

Ma question pourrait se résumer à: Pourquoi ce code provoque-t-il le crash de l'émulateur Android?

J'ai lutté pendant quelques jours avec la concurrence liée à la mise en place de différents threads pour une application de jeu. J'ai fait beaucoup de variations, mais elles ont toutes échoué. À ce stade, je veux juste obtenir une configuration concurrente de base allant. Le pire, c'est que c'est l'émulateur qui tombe en panne, donc DDMS ne rapporte rien; Par conséquent, je ne sais vraiment pas où est la question.

Le code suivant montre une activité (classe Main), appelée classe SceneManager, qui crée un thread à utiliser pour les éléments de logique de jeu. Une troisième classe, StatusChannel, est (sera) utilisée pour communiquer les informations d'état entre les différents threads (Eventuellement, il y aura aussi un thread de rendu OpenGL).

L'émulateur se bloque à différents moments. Cela peut durer 20 secondes ou 5 minutes.

setContentView (R.layout.main) dans la classe Activity uniquement la disposition de base définie qu'Eclipse crée.

J'ai commenté sur l'utilisation du nœud (créée dans la classe d'activité et accessible à SceneManager)

J'ai installé des versions sdk 1.5 à 2.3 - L'application actuelle vise à 2.1

Le problème a quelque chose à voir avec la classe SceneManager. Je suis particulièrement méfiant de la méthode run().

Voici les 3 classes.

Désolé pour la longueur du code.

public class Main extends Activity { 
private SceneManager mSceneManager; 
private volatile Node mSceneGraph = new Node(); 
private volatile Status mStatusChannel = new Status(); 

    /** Called when the activity is first created. */ 
    @Override 
    public void onCreate(Bundle savedInstanceState) { 
    Log.d("-- Main", "onCreate()"); 
     super.onCreate(savedInstanceState);  

     setContentView(R.layout.main); 

     // Holds the scene assets, such as the stage, 
     // the agents, camera, etc. 
     mSceneManager = new SceneManager(mSceneGraph, mStatusChannel);  
     mSceneManager.onCreate(); 
    } 

    @Override 
    protected void onResume() { 
    Log.d("-- Main", "onResume()");  
     super.onResume(); 
    mSceneManager.onResume();     
    }  

    @Override 
    protected void onPause() { 
    Log.d("-- Main", "onPause()");  
     super.onPause(); 
     mSceneManager.onPause();   
    } 

    @Override 
    protected void onDestroy() { 
    Log.d("-- Main", "onDestroy()"); 
     super.onDestroy(); 
     mSceneManager.onDestroy(); 
    }  
} 




public class SceneManager implements Runnable{ 
private Thread mThread; 
private volatile Status mStatusChannel; 
private volatile Node mSceneGraph; 

private volatile long mMillis = 0; 
private volatile PrepareVisitor mPrepareVisitor; 
private volatile int mStatus = Status.UNKNOWN_STATUS; 

SceneManager(Node sceneGraph, Status statusChannel) { 
    mPrepareVisitor = new PrepareVisitor(); 
    mStatusChannel = statusChannel; 
    mSceneGraph = sceneGraph; 
     mMillis = SystemClock.uptimeMillis(); 
    mThread = new Thread(this); 
    mThread.setName("LogicThread"); 
    mStatusChannel.setSceneManagerStatus(Status.READY_STATUS); 
} 

public void onCreate() { 
    Log.d("-- SceneManager", "onCreate()..."); 
    // This will start the thread in a paused state. 
    mThread.start(); 
} 

public void onResume() { 
    Log.d("-- SceneManager", "onResume()..."); 

    // Unpause the status manager, if it is currently paused. 
    if (mStatusChannel.getSceneManagerStatus() == Status.PAUSED_STATUS) { 
    mStatusChannel.setSceneManagerStatus(Status.READY_STATUS); 
    } 
} 

public void onPause() { 
    Log.d("-- SceneManager", "onPause()..."); 
    if (mStatusChannel.getSceneManagerStatus() != Status.UNKNOWN_STATUS) { 
    mStatusChannel.setSceneManagerStatus(Status.PAUSED_STATUS); 
    } 
} 

public void onDestroy() { 
    mStatusChannel.setSceneManagerStatus(Status.QUIT_STATUS); 
    try { 
    mThread.join(); 
    } 
    catch (InterruptedException e) { 
    Log.d("-- SceneManager", "InterruptedException"); 
    } 
} 

/** 
    * This method should not be called by clients of this class. 
    */ 
@Override 
public void run() { 
    Log.d("-- SceneManager", "Called..."); 

    // Main logic loop. 
    outer: while (true) { 

    // How much time has elapsed since last call. 
    long timeDelta = SystemClock.uptimeMillis() - mMillis; 

    switch (mStatus) { 
    case Status.READY_STATUS: 
    //mPrepareVisitor.go(mSceneGraph, timeDelta); 
    break; 
    case Status.PAUSED_STATUS: 
    break; 
    case Status.QUIT_STATUS: 
    break outer;  
    case Status.UNKNOWN_STATUS: 
    int renderStatus = mStatusChannel.getRendererStatus();  
    if (renderStatus == Status.READY_STATUS) { 
    mStatusChannel.setSceneManagerStatus(Status.READY_STATUS); 
    } 
    break; 
    } 

    mStatus = mStatusChannel.getSceneManagerStatus(); 

     // Update the time. 
    mMillis = SystemClock.uptimeMillis(); 
    } 
} 
} 


public class Status { 

/* Generic Statuses */ 
public final static int UNKNOWN_STATUS = 0; 
public final static int READY_STATUS = 1; 
public final static int PAUSED_STATUS = 2; 
public final static int QUIT_STATUS = 3; 

/* Current statuses values */ 
private int mSceneManagerStatus = UNKNOWN_STATUS ; 
private int mRendererStatus = UNKNOWN_STATUS ; 


public synchronized int getSceneManagerStatus() { 
    return mSceneManagerStatus; 
} 

public synchronized int getRendererStatus() { 
    return mRendererStatus; 
} 

public synchronized void setSceneManagerStatus(int status) { 
    mSceneManagerStatus = status; 
} 

public synchronized void setRendererStatus(int status) { 
    mRendererStatus = status; 
} 
} 

- EDIT -

This issue happens even with something as simple as this: 

public class ThreadActivity extends Activity { 
    private Booboo mBooboo; 

    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.main); 

     mBooboo = new Booboo(); 
     mBooboo.onCreate(); 
    } 
} 

public class Booboo implements Runnable { 
     private Thread mThread; 

     Booboo() { 
       mThread = new Thread(this, "SceneManagerThread");  
     } 

     public void onCreate() { 
       Log.d("Booboo", "Thread started"); 
       mThread.start(); 
     } 

     @Override 
     public void run() { 
       while (true) {} 
     } 
} 

Je sais que la première réaction est de dire qu'il est le while (true) {}. Rappelez-vous juste que c'est un exemple artificiel pour montrer le problème. Dans mon propre code, je fais l'activité de cycle de vie comme décrit dans les documents. Le problème est que l'émulateur se bloque après un certain temps dans une boucle infinie comme ça, si vous avez des conditions de pause ou non.

+1

Lorsque vous dites que l'émulateur se bloque, voulez-vous dire que l'émulateur se bloque ou que votre application plante, les journaux de l'accident? – aronp

Répondre

0

Vous souhaitez probablement examiner AsyncTask. Il y a un grand article ici: http://android-developers.blogspot.com/2009/05/painless-threading.html

+0

Bien que les AsyncTasks soient très utiles, ils ne constituent pas la réponse finale à tous les problèmes de thread. Parfois, un thread est la bonne voie à suivre, et dans ce cas, AsyncTasks ne sera pas très utile. – kabuko