1

I'm working on an android Quiz app with connection to a server over a socket. On the client side (Android device) I check in a while loop the answers which are given by a server (Java server). The connection and the receiving of the answer all goes good. The problem is that in my class to check for answers there's a bug. To give more information I will include a part of the code here:

public void startClient(){

    checkValue = new Thread(new Runnable(){
        @Override
        public void run() {     
            try
            {
                final int PORT = 4444;
                final String HOST = "192.168.1.118";
                Socket SOCK = new Socket(HOST, PORT);
                Log.e("success", "You connected to: " + HOST);

                quizClient = new QuizClient(SOCK);

                //Send the groupname to the list
                PrintWriter OUT = new PrintWriter(SOCK.getOutputStream());
                OUT.println(groupName);
                OUT.flush();

                Thread X = new Thread(quizClient);
                X.start();

                connected = true;


            }
            catch(Exception X)
            {
                Log.e("connection error", "Error: ", X);
            }       
        }
    });

    checkValue.start(); 

}

public void testvalue(){

    Thread thread = new Thread(new Runnable(){
        @Override
        public void run() {
            try {
                while(true){
                    if(message != null && !message.matches("")){
                        Thread.sleep(1000);
                        Log.e("receive", message);
                        buffer = message;
                        message = "";

                        Message msg = new Message();
                        String textTochange = buffer;
                        msg.obj = textTochange;
                        mHandler.sendMessage(msg);
                        Thread.sleep(3000);
                    }

                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    });

    thread.start();

}

Handler mHandler = new Handler() {
    @Override
    public void handleMessage(Message msg) {

        String text = (String)msg.obj;
        //call setText here

        //String[] myStringArray = new String[]; 
        value.clear();

        String[] items = text.split(";");
        for (String item : items)
        {
            value.add(item);
            Log.e("message", item);
            //System.out.println("item = " + item);
        }

        if(value.get(0).equals("1")){

            questionGroup.setVisibility(View.INVISIBLE);
            sendAnswer.setVisibility(View.INVISIBLE);
            answer.setVisibility(View.INVISIBLE);
            question.setText("");


            question.setText(value.get(2));
            rad1.setText(value.get(3));
            rad2.setText(value.get(4));
            rad3.setText(value.get(5));
            rad4.setText(value.get(6));

            questionGroup.setVisibility(View.VISIBLE);
            sendAnswer.setVisibility(View.VISIBLE);


        } else if (value.get(0).equals("2")){

            questionGroup.setVisibility(View.INVISIBLE);
            sendAnswer.setVisibility(View.INVISIBLE);
            answer.setVisibility(View.INVISIBLE);

            question.setText("");
            question.setText(value.get(2));
            answer.setVisibility(View.VISIBLE);
            sendAnswer.setVisibility(View.VISIBLE);


        } else
        {
            questionGroup.setVisibility(View.INVISIBLE);
            sendAnswer.setVisibility(View.INVISIBLE);
            answer.setVisibility(View.INVISIBLE);

            question.setText(text);
        }


    }
};

@Override
protected void onStop() 
{

    if (connected == true){
        try {
            quizClient.DISCONNECT();
        } catch (IOException e) {
            e.printStackTrace();
        }   
    }

    if(checkValue != null)
    {
        checkValue.interrupt();
    }

    super.onStop();
    closeApplication();

}

So I make a new instance of this class (where I actually check the incoming stream of data)

public class QuizClient implements Runnable {

//Globals 
Socket SOCK;
Scanner INPUT;
Scanner SEND = new Scanner(System.in);
PrintWriter OUT;

public QuizClient(Socket X)
{
    this.SOCK = X;
}

public void run()
{
    try
    {
        try
        {
            INPUT = new Scanner(SOCK.getInputStream());
            OUT = new PrintWriter(SOCK.getOutputStream());
            OUT.flush();
            CheckStream();
        }
        finally
        {
            SOCK.close();
        }
    }
    catch(Exception X)
    {
        Log.e("error", "error: ", X);
    }
}

public void DISCONNECT() throws IOException
{
    OUT.println("DISCONNECT");
    OUT.flush();
    SOCK.close();
}

public void CheckStream()
{
    while(true)
    {
        RECEIVE();
    }
}

public void RECEIVE()
{

    if(INPUT.hasNext())
    {
        String MESSAGE = INPUT.nextLine();

        if(MESSAGE.contains("#?!"))
        {

        }
        else
        {
            QuizActivity.message = MESSAGE;
            Log.e("test", MESSAGE);
        }
    }
}

public void SEND(String X)
{
    OUT.println(X);
    OUT.flush();
}
}

So the bug persist I think in the following class:

public void testvalue(){

    Thread thread = new Thread(new Runnable(){
        @Override
        public void run() {
            try {
                while(true){
                    if(message != null && !message.matches("")){
                        Thread.sleep(1000);
                        Log.e("receive", message);
                        buffer = message;
                        message = "";

What I do here is make a thread and check if the "message" is not equals at null. The message come from the other class:

public void RECEIVE()
{

    if(INPUT.hasNext())
    {
        String MESSAGE = INPUT.nextLine();

        if(MESSAGE.contains("#?!"))
        {

        }
        else
        {
            QuizActivity.message = MESSAGE;

Now most of the time this works good but there are 2 problems. When I go out of the page it disconnect from the server (works) I go back on the page and connect again to the server but this time I don't get any values on the screen (receiving is okj but for one of the other reason it does not go good in my handler). Also get an indexoutofboundexception after a time:

question.setText(value.get(2));

A second problem occurs some time while the program runs. There are moments that I also don't get a value on my interface while it correctly receive the input.

So my guess is that my solution of the thread to read in the values is not the best way to handle it. So now I ask to people with more experience what I can do to make this work without major problems? You need to know the connection works and I get the value in my QuizClient class. So the problem need to be in my main class.

My oncreate class:

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

    selectgroep = (Spinner) findViewById(R.id.groepen);
    questionGroup = (RadioGroup) findViewById(R.id.QuestionGroup);
    sendAnswer = (Button) findViewById(R.id.sendAnswer);

    rad1 = (RadioButton) findViewById(R.id.radio0);
    rad2 = (RadioButton) findViewById(R.id.radio1);
    rad3 = (RadioButton) findViewById(R.id.radio2);
    rad4 = (RadioButton) findViewById(R.id.radio3);

    answer = (EditText) findViewById(R.id.textanswer);

    questionGroup.setVisibility(View.INVISIBLE);
    sendAnswer.setVisibility(View.INVISIBLE);
    answer.setVisibility(View.INVISIBLE);


    try {
        connect();
    } catch (InterruptedException e) {
        e.printStackTrace();
    }

    //Code na het drukken op de knop
    startserver = (Button) findViewById(R.id.startserver);
    startserver.setOnClickListener(new OnClickListener() {

        @Override
        public void onClick(View v) {
            startClient();
            getID();
            testvalue();
        }

});

    sendAnswer.setOnClickListener(new OnClickListener() {

        @Override
        public void onClick(View v) {
            // Stuur antwoord door en sluit alles af 
            questionGroup.setVisibility(View.INVISIBLE);
            sendAnswer.setVisibility(View.INVISIBLE);
            answer.setVisibility(View.INVISIBLE);
            answer.setText("");

            rad1.setChecked(true);
            rad1.setText("");
            rad2.setText("");
            rad3.setText("");
            rad4.setText("");

            question.setText("Wachten op server ... ");

        }
    });

}

Thank you in advance, Thomas Thooft

  • what have you put in Oncreate of main class? – Metalhead1247 Sep 11 '13 at 10:15
  • I added the oncreate class in the post. – Thomas Thooft Sep 11 '13 at 10:39
  • `while(true){RECEIVE();}` you will create very much load here... busy waiting is no good idea. Better use timers if you want to check periodically. I dont know what fits best for you but also C2DM could be a proper solution, because then you dont need to constantly poll the server. – reox Sep 11 '13 at 10:45
  • also if you check `message != null && !message.matches("")``you dont have a else here. when the value is null or "", you will get busy waiting as well. (besides that synchronisation with sleep is not a favorite of mine. also you can use timers here or use a callback interface when the value of message has changed - but that really depends on what you aim for) – reox Sep 11 '13 at 10:53
  • you should use AsycTask so that busy tasks are not carried out on the main thread. – Metalhead1247 Sep 11 '13 at 10:55
  • The load is not really a problem here. It's a small application and only need to do some basic things. The message receive very well, that I can test to set an output. The problem is that my class who process it have a problem. So maybe I need to change the while loop in my main class because that's where I think it all goes wrong. – Thomas Thooft Sep 11 '13 at 10:58
  • So I would need to change the thread to a AsycTask ? – Thomas Thooft Sep 11 '13 at 10:59
  • Could you then please help me a bit how I can do this in my example. I'm pretty new in android programming. – Thomas Thooft Sep 11 '13 at 10:59
  • AsyncTasks are perfectly made for UI changing long running tasks. i think the problem might be that the testvalue thread is killed by the android system after the activity is left and never started again. I cant see that you stop it somewhere. – reox Sep 11 '13 at 11:04
  • check http://stackoverflow.com/questions/6964011/handler-vs-asynctask-vs-thread for the difference between thread and asynctask – reox Sep 11 '13 at 11:08

0 Answers0