I've searched the internet far and wide about getting the UI to update in real-time in Android to no avail. I implemented an AysncTask class as most of the other posts suggested, but it's still not updating my UI in real-time like I want. It only updates after the program is done running. I've even been getting the "Skipped n frames. The application may be doing too much work in its main thread." error, which I don't understand because I'm trying to do these updates in the UI thread. About 5 seconds into running my program the screen turns black and stays like that until its done finishing. Any help would be much appreciated as I've been pulling my hair out on this one for awhile Here's my code.
EDIT: Solved. Removed the Thread.sleep(n) from my UI thread and added it to my AsyncTask. Thanks everyone!
Main class:
public class Home extends Activity {
// Declare objects
Button turingB, socratesB, voltaireB, descartesB, platoB;
int[] eating, thinking, hungry;
Philosopher socrates, turing, voltaire, descartes, plato;
Philosopher[] philosophers;
Chopstick[] chopsticks;
TextView info;
String value;
Context context;
int toastLength;
boolean turingHungry, socratesHungry, voltaireHungry, descartesHungry, platoHungry;
String running;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home);
// Instantiate objects (keep track of each button individually
context = getApplicationContext();
toastLength = Toast.LENGTH_SHORT;
info = (TextView) findViewById(R.id.textView1);
info.setText("Click Start to begin!");
socratesB = (Button) findViewById(R.id.button1);
descartesB = (Button) findViewById(R.id.button5);
platoB = (Button) findViewById(R.id.button4);
voltaireB = (Button) findViewById(R.id.button3);
turingB = (Button) findViewById(R.id.button2);
running = "false";
// Set all philosophers to thinking (blue)
// socratesB.setBackgroundColor(Color.BLUE);
// descartesB.setBackgroundColor(Color.BLUE);
// platoB.setBackgroundColor(Color.BLUE);
// voltaireB.setBackgroundColor(Color.BLUE);
// turingB.setBackgroundColor(Color.BLUE);
turingHungry = false;
socratesHungry = false;
voltaireHungry = false;
descartesHungry = false;
platoHungry = false;
//Button platoTempButton = (Button) findViewById(R.id.button4);
// Listen for buttons
OnClickListener pBtn = new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
platoHungry = true;
}
};
//platoTempButton.setOnClickListener(pBtn);
OnClickListener tBtn = new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
turingHungry = true;
}
};
OnClickListener sBtn = new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
socratesHungry = true;
}
};
OnClickListener vBtn = new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
voltaireHungry = true;
}
};
OnClickListener dBtn = new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
descartesHungry = true;
}
};
platoB.setOnClickListener(pBtn);
turingB.setOnClickListener(tBtn);
socratesB.setOnClickListener(sBtn);
voltaireB.setOnClickListener(vBtn);
descartesB.setOnClickListener(dBtn);
// Set arrays to count time spent eating, thinking, hungry
eating = new int[5];
thinking = new int[5];
hungry = new int[5];
// Create the chopsticks
chopsticks = new Chopstick[5];
for (int i = 0; i < 5; i ++)
{
chopsticks[i] = new Chopstick(i);
}
for (Chopstick chop: chopsticks)
{
chop.available = true;
}
// Create the philosophers
philosophers = new Philosopher[5];
philosophers[0] = new Philosopher(0, chopsticks[0], chopsticks[1], "Plato", platoB);
philosophers[1] = new Philosopher(1, chopsticks[1], chopsticks[2], "Turing", turingB);
philosophers[2] = new Philosopher(2, chopsticks[2], chopsticks[3], "Socrates", socratesB);
philosophers[3] = new Philosopher(3, chopsticks[3], chopsticks[4], "Voltaire", voltaireB);
philosophers[4] = new Philosopher(4, chopsticks[4], chopsticks[0], "Descartes", descartesB);
// Get sim time from user
AlertDialog.Builder alert = new AlertDialog.Builder(this);
alert.setTitle("Simulation Time");
alert.setMessage("Please length of time for the simulation to run (in seconds)");
final EditText input = new EditText(this);
alert.setView(input);
alert.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
value = String.valueOf(input.getText());
}
});
alert.show();
// Get info
Bundle extras = getIntent().getExtras();
if (extras != null)
{
running = extras.getString("runApp");
value = extras.getString("numToRun");
}
// Run app
if (running.equals("true"))
{
System.out.println("RUNNING!!!");
run(value);
}
}
public void run(String length)
{
int num = Integer.parseInt(length);
// Run num times
for (int i = 0; i < num; i++)
{
try {
// Pass current index, and data arrays to step method
step(i, eating, thinking, hungry);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
// Print out some data
for (int j = 0; j < 5; j++)
{
System.out.println("Philosopher " + j + " ate: " + eating[j]);
System.out.println("Philosopher " + j + " thought: " + thinking[j]);
System.out.println("Philosopher " + j + " was hungry: " + hungry[j]);
}
running = "false";
}
// Run simulation n times (n specified by the user)
public void startSim(View v)
{
Intent my_intent = new Intent(this, Home.class);
my_intent.putExtra("runApp", "true");
my_intent.putExtra("numToRun", value);
startActivity(my_intent);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.home, menu);
return true;
}
// Reset simulation
public void reset(View v)
{
Intent my_intent = new Intent(this, Home.class);
startActivity(my_intent);
}
// Return hunger status of philosopher
public boolean isHungry(String name) {
if (name.equals("Voltaire"))
return voltaireHungry;
else if (name.equals("Socrates"))
return socratesHungry;
else if (name.equals("Plato"))
return platoHungry;
else if (name.equals("Turing"))
return turingHungry;
else if (name.equals("Descartes"))
return descartesHungry;
else
return false;
}
// Step method for simulation
// Takes the current index and each of the data arrays
public void step(int i, int[] eating, int[] thinking, int[] hungry) throws InterruptedException
{
// Make random number
Random randomGenerator = new Random();
int num = randomGenerator.nextInt(10);
// Randomly set a philosopher isFull to false (hungry) (10% chance for each to become hungry if not specified by the user)
if (isHungry(philosophers[0].name))
philosophers[0].isFull = false;
if (num == 1 || isHungry(philosophers[1].name))
philosophers[1].isFull = false;
if (num == 2 || isHungry(philosophers[2].name))
philosophers[2].isFull = false;
if (num == 3 || isHungry(philosophers[3].name))
philosophers[3].isFull = false;
if (num == 4 || isHungry(philosophers[4].name))
philosophers[4].isFull = false;
// For each philosopher
for (Philosopher phil: philosophers)
{
// Print current info
System.out.println("PHIL: " + phil.name + " NUM: " + num + " RIGHT: " + phil.rightChopstick.available + " LEFT: " + phil.leftChopstick.available);
// Temp id var
int tempId = phil.id;
// If philosopher is hungry, try to eat
if (phil.isFull == false)
{
// Try to eat only if both chopsticks are available
if (phil.rightChopstick.pickUp(phil.name) && phil.leftChopstick.pickUp(phil.name))
{
// Change button color
new Background(phil.button).execute((long) 1);
//Toast.makeText(context, phil.name + " is eating.", toastLength).show();
// Increment time spent eating
eating[tempId]++;
}
// Check to see if the philosopher is already eating (has both chopsticks)
else if (phil.rightChopstick.who.equals(phil.name) && phil.leftChopstick.who.equals(phil.name))
{
//Toast.makeText(context, phil.name + " is eating.", toastLength).show();
new Background(phil.button).execute((long) 1);
// Increment eating
eating[tempId]++;
// 30% chance to stop eating
if (num >= 5 && num <=7)
{
// Put down chopsticks
phil.rightChopstick.putDown();
phil.leftChopstick.putDown();
// Stop eating
phil.isFull = true;
}
}
// Hungry
else
{
// Change button color
new Background(phil.button).execute((long) 3);
//Toast.makeText(context, phil.name + " is hungry.", toastLength).show();
// Increment time spent hungry
hungry[tempId]++;
}
}
// Thinking
else
{
new Background(phil.button).execute((long) 2);
//Toast.makeText(context, phil.name + " is thinking.", toastLength).show();
// Increment time spent thinking
thinking[tempId]++;
}
Thread.sleep(1000);
}
// Make each step count as 1 second (1000 miliseconds)
System.out.println("--------------------------------------------------------------");
Thread.sleep(5000);
}
}
Background class (AsyncTask):
public class Background extends AsyncTask<Long, Void, Void>
{
// Variables
String color;
Button button;
public Background(Button button)
{
this.button = button;
}
@Override
protected Void doInBackground(Long... params) {
// Get which color the button needs to be
try
{
// Change the color based on the value passed in
if (params[0] == 3)
{
color = "RED";
}
else if (params[0] == 2)
{
color = "BLUE";
}
else if (params[0] == 1)
{
color = "GREEN";
}
}
catch (Exception e)
{
e.printStackTrace();
}
return null;
}
@Override
protected void onPostExecute(Void result) {
// Set button to that color
System.out.println("Updating color in real time...");
button.setBackgroundColor(Color.parseColor(color));
}
@Override
protected void onPreExecute() {
}
@Override
protected void onProgressUpdate(Void... values) {
}
}