0

Earlier I was having an issue where going to my main activity (ColorMatch.java) from my splash page activity caused the program to get indefinitely stuck on a black screen. I found this was due to the run() method called in my onCreate in my main activity. I've tried commenting out certain things to see if it works, but as long as run() is called in my onCreate it automatically goes to black screen, without even giving an error for me to troubleshoot with. What could be causing this issue?

My ClassMatch.java:

package com.example.ali.colormatch;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.os.Bundle;
import android.app.Activity;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;
import java.util.Random;

public class ColorMatch extends AppCompatActivity {

int answer; //1 = red, 2 = blue, 3 = green, 4 = yellow
TextView textView3, textView2;
int count = 0;
volatile boolean playing = true;
private long timeThisFrame;
private Button testButton;
long fps;
int score;
int correctAnswer;
boolean matchColor = true, matchText = false;
long startFrameTime;
boolean firstTime = true;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_color_match);
    textView3 = (TextView) findViewById(R.id.textView3);
    textView2 = (TextView) findViewById(R.id.textView2);

    run();
}

public void run() {
    while (playing) {

        startFrameTime = System.currentTimeMillis();

        if (firstTime){
            generateNewWord();
            firstTime = false;
        }

        if (answer == correctAnswer){
            score++;
            count++;
            generateNewWord();}
        //else {
         //   quit();
       // }


        if (count % 5 == 0){
                if (matchColor) {
                    textView3.setText(getString(R.string.gameSetting2)); // might need to add context with this - check http://stackoverflow.com/questions/10698945/reference-string-resource-from-code
                    matchColor = true;
                    matchText = false;
                }
                else if (matchText){
                    textView3.setText(getString(R.string.gameSetting1));
                    matchText = true;
                    matchColor = false;
                }
            }
        }

        //draw();
        timeThisFrame = System.currentTimeMillis() - startFrameTime;
        if (timeThisFrame > 0) {
            fps = 1000 / timeThisFrame;
        }

    }

public void generateNewWord(){

    //randomly select between red, green, blue, yellow
    Random rand = new Random();
    int randomInt1 = rand.nextInt(4) + 1; // assigns randomInt a value between 1 - 4
    int randomInt2 = rand.nextInt(4) + 1;

    if (randomInt1 ==1){
        textView3.setText(R.string.Red);
    }
    else if (randomInt1 ==2){
        textView3.setText(R.string.Green);
    }
    else if (randomInt1 == 3){
        textView3.setText(R.string.Blue);
    }
    else if (randomInt1 == 4){
        textView3.setText(R.string.Yellow);
    }


    //randomly select hex codes between rgby
    if (randomInt2 ==1){
        textView3.setTextColor(0xffcc0000);
    }
    else if (randomInt2 ==2){
        textView3.setTextColor(0xff669900);
    }
    else if (randomInt2 == 3){
        textView3.setTextColor(0xff000080);
    }
    else if (randomInt2 == 4){
        textView3.setTextColor(0xffffff00);
    }


   if (matchColor) {
        correctAnswer = randomInt2;
    }
    else if(matchText){
        correctAnswer = randomInt1;
    }

}
public void quit(){

}


public void sendBlue(View view){
    answer = 2;
}
public void sendRed(View view){
    answer = 1;
}
public void sendYellow(View view){
    answer = 4;
}
public void sendGreen(View view){
    answer = 3;
}


}

The activity_color_match.xml file that it uses:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"

xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_color_match"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.example.ali.colormatch.ColorMatch">

<TextView

    android:text="@string/matchText"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:id="@+id/textView3"
    android:textAppearance="@style/TextAppearance.AppCompat.Body2"
    android:layout_alignParentTop="true"
    android:layout_centerHorizontal="true" />

<TextView
    android:text="@string/mainColor"
    android:id="@+id/textView2"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:gravity="center_horizontal"
    android:textColor="@android:color/background_dark"
    android:textSize="100dp"
    android:layout_marginBottom="104dp"
    android:textAppearance="@style/TextAppearance.AppCompat.Display3"
    android:layout_above="@+id/button3"
    android:layout_centerHorizontal="true" />

<Button
    android:layout_width="150dp"
    android:layout_height="60dp"
    android:id="@+id/button"
    android:background="#000080"
    android:onClick="sendBlue"
    android:layout_alignParentBottom="true"
    android:layout_alignParentLeft="true"
    android:layout_alignParentStart="true" />

<Button
    android:layout_height="60dp"
    android:id="@+id/button2"
    android:background="@color/yellow"
    android:elevation="0dp"
    android:layout_width="150dp"
    android:onClick="sendYellow"
    android:layout_alignParentBottom="true"
    android:layout_alignParentRight="true"
    android:layout_alignParentEnd="true" />

<Button
    android:layout_width="150dp"
    android:layout_height="60dp"
    android:id="@+id/button3"
    android:background="@android:color/holo_red_dark"
    android:onClick="sendRed"
    android:layout_above="@+id/button"
    android:layout_alignParentLeft="true"
    android:layout_alignParentStart="true"
    android:layout_marginBottom="19dp" />

<Button
    android:layout_width="150dp"
    android:layout_height="60dp"
    android:id="@+id/button4"
    android:background="@android:color/holo_green_dark"
    android:onClick="sendGreen"
    android:layout_alignParentRight="true"
    android:layout_alignParentEnd="true"
    android:layout_alignBottom="@+id/button3" />


</RelativeLayout>

For completion's sake, though I think it's probably irrelevant, here's my MainActivity.java. It seems to be working as I would like:

package com.example.ali.colormatch;

import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;


public class MainActivity extends AppCompatActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.splash_page);
}

public void onSplashPageClick(View view){
    Intent intent = new Intent(MainActivity.this, ColorMatch.class);
    startActivity(intent);
}

public void onQuitClick(View view){
    finish();
}
}

I am using a Nexus 5 to launch my app and debug. Thank you.

Johnny
  • 103
  • 1
  • 13
  • `onCreate()` never returns cause `playing` in the `run()` method is `true` resulting in an infinite loop. Since `onCreate()` can't return the rest of the `Activity`'s lifecycle methods cannot be invoked. As a result, `onResume()` won't return, the UI won't be drawn, black screen is up. You should move the `while` loop logic in a background thread and post results to the main one. – Onik Oct 15 '16 at 03:17
  • You were right! I disabled the while(playing) loop and it worked. This is my first time coding in Android with only experience in java so that loop to me was a foundation that I didn't realize could be an issue. I've messing around with that while (playing) loop currently, right now the text loads so I just need to find a way to have it refresh. – Johnny Oct 15 '16 at 03:55

2 Answers2

0

I think you can create a thread in onCreate(), and put the method 'run()' to this thread.

try it:

           new Thread(new Runnable() {
                @Override
                public void run() {
                    ColorMatch.this.run();
                }
            }).start();

** Edit **

The reason is you do too many thing in the ui thread (main thread) when onCreate, and if you waste too many time in onCreate method, it will be ANR(Activity Not Responding), you need to put the task that waste time in background thread. And it will avoid the black screen when activity onCreate.

Takuma Lee
  • 1
  • 1
  • 1
  • `AsyncTask` is the standard way to do that in Android, at least for relatively short operations. – nasch Oct 15 '16 at 03:31
  • He does not block the UI thread, it's still running. Also the way you suggest will fail, because in the `run()` method widgets are "touched". – Onik Oct 15 '16 at 03:33
  • Yes AsyncTask is the standard way :). – Takuma Lee Oct 15 '16 at 03:41
  • OK I wrong, yes it's still running. :(, I try to edit this. – Takuma Lee Oct 15 '16 at 03:42
  • Black screen and ANR are 2 different things. The app doesn't crash, he's got no ANR, because UI thread isn't blocked. – Onik Oct 15 '16 at 03:50
  • But if the app not go next lifecycle onResume, it will be ANR, doesn't it? – Takuma Lee Oct 15 '16 at 03:53
  • Likely, if `onCreate()` can't return for a long enough time. – Onik Oct 15 '16 at 04:01
  • Yes, that's I mean. I think my description is not correct probably. – Takuma Lee Oct 15 '16 at 04:10
  • @Onik - you mentioned moving the while loop to a background thread and posting the results back to the main one. I tried using Takuma's code snippet here but it did not work. Why does that not work to move it to another thread? Also, possibly a very silly question, but when you mentioned moving it to a background thread did you mean an actual new Thread? – Johnny Oct 15 '16 at 05:24
  • @Ali hmm... sorry I lose the `start()` method to start the thread.. I edit the answer, can you try again? – Takuma Lee Oct 15 '16 at 06:41
  • @TakumaLee So your thread works, but as I feared not with the original while loop I used; with that it gives this error: android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views. – Johnny Oct 15 '16 at 07:00
  • Yes, I think your error like this: `textView3.setText(getString(R.string.gameSetting2));` The reason is ui changed need on ui thread, but now is create a new thread, so this is need to be put in ui thread, not back thread, so you need to separate it. – Takuma Lee Oct 15 '16 at 07:02
0

Hey If you are still looking for a way to refresh the view time to time then you can use Timer.

Look into this answer here https://stackoverflow.com/a/18353754/2311117. this explains how to use timer.

For more information about Timer and TimerTask.

Community
  • 1
  • 1
Shivansh
  • 906
  • 12
  • 25
  • I am planning on adding a timer to limit how long the user has to click on a button, so it seems I will be able to use Timer for that. However, I need the run() method to occur every time the user clicks on a button; if the answer's right, it'll generate a new word and refresh the timer, if it's wrong the program will stop. – Johnny Oct 15 '16 at 04:35
  • you can use `Timer.start` and `Timer.cancel` for that to start/stop the timer. as far as i understand this you need something to refresh view until user takes some action. – Shivansh Oct 15 '16 at 04:58