Pergunta

I am writing a simple android application to demonstrate wait() and notify() methods. The application contain 1 button and 1 textView, the textView will show a timer and button will show a dialog contain 2 buttons. now what i want to do is whenever i press the the dialog button, the time pause and whenever i resume by pressing the resume button within the dialoug the time continue and so on.

Here is my code:

public class MainActivity extends Activity implements OnClickListener{

Timer t;
int count = 0;

Button b;
TextView tv;

Thread thread;

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

    b = (Button) findViewById(R.id.button1);
    tv = (TextView) findViewById(R.id.textView1);

    t = new Timer();
    t.scheduleAtFixedRate(new TimerTask() {

        @Override
        public void run() {
            // TODO Auto-generated method stub
            runOnUiThread(new Runnable() {
                public void run() {
                tv.setText(String.valueOf(count));
                count++;
                }
            });
        }
    }, 1000, 1000);

    b.setOnClickListener(this);


}


@Override
public void onClick(View v) {
    // TODO Auto-generated method stub

    synchronized (MainActivity.this)
    {
        try {
            wait();
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    final Dialog d = new Dialog(this);
    d.setTitle("Pause Menu");
    d.setContentView(R.layout.pausemenu);
    Button b1 = (Button) d.findViewById(R.id.Resume);
    Button b2 = (Button) d.findViewById(R.id.Main);

    b1.setOnClickListener(new OnClickListener() {

        @Override
        public void onClick(View v) {
            // TODO Auto-generated method stub
            d.cancel();
            thread = new Thread()
            {
                public void run()
                {
                    synchronized (MainActivity.this) {
                        try {
                            wait(1000);

                        }catch (Exception e) {
                            // TODO: handle exception
                        }

                        notify();
                    }
                }
            };
        }
    });

    b2.setOnClickListener(new OnClickListener() {

        @Override
        public void onClick(View v) {
            // TODO Auto-generated method stub
            d.cancel();
        }
    });
    d.show();

}
}

and here is the logcat:

06-09 08:07:55.066: E/AndroidRuntime(635): FATAL EXCEPTION: main
06-09 08:14:43.946: E/AndroidRuntime(664): FATAL EXCEPTION: main
06-09 08:14:43.946: E/AndroidRuntime(664): java.lang.NullPointerException
06-09 08:14:43.946: E/AndroidRuntime(664):  
at com.example.timerwithnotify.MainActivity.onClick(MainActivity.java:58)
06-09 08:14:43.946: E/AndroidRuntime(664):       
at  android.view.View.performClick(View.java:2408)
06-09 08:14:43.946: E/AndroidRuntime(664):  
at android.view.View$PerformClick.run(View.java:8816)
06-09 08:14:43.946: E/AndroidRuntime(664):  
at android.os.Handler.handleCallback(Handler.java:587)
 06-09 08:14:43.946: E/AndroidRuntime(664):     
at android.os.Handler.dispatchMessage(Handler.java:92)
06-09 08:14:43.946: E/AndroidRuntime(664):  at android.os.Looper.loop(Looper.java:123)
06-09 08:14:43.946: E/AndroidRuntime(664):  
at android.app.ActivityThread.main(ActivityThread.java:4627)
06-09 08:14:43.946: E/AndroidRuntime(664):  
at java.lang.reflect.Method.invokeNative(Native Method)
06-09 08:14:43.946: E/AndroidRuntime(664):  
at java.lang.reflect.Method.invoke(Method.java:521)
06-09 08:14:43.946: E/AndroidRuntime(664):  
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:868)
06-09 08:14:43.946: E/AndroidRuntime(664):  
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:626)

please show me in code how to fix this, im still a noob :D. Thank you for your time and consideration.

Foi útil?

Solução

Not sure what you are trying to do. You can use the below for reference.

If you implement Thread or HandlerThread, be sure that your UI thread does not block while waiting for the worker thread to complete—do not call Thread.wait() or Thread.sleep().

Check this developer.android.com/training/articles/perf-anr.html

You should not block your main ui thread. Instead of a timer you can use a 'Handler'

You can start and stop a timer on button click. You can reschedule your timer with the count value. You need to take care of orientation change as activity is destroyed and recreated. The value of count we will be re-initialized.

MainActivity.java

public class MainActivity extends Activity implements OnClickListener{

Timer t;
int count = 0;
boolean isDone = true;
Button b;
TextView tv;

Thread thread;

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

    b = (Button) findViewById(R.id.button1);
    tv = (TextView) findViewById(R.id.textView1);

    t = new Timer();
    t.scheduleAtFixedRate(new TimerTask() {

        @Override
        public void run() {
            // TODO Auto-generated method stub
            runOnUiThread(new Runnable() {
                public void run() {
                tv.setText(String.valueOf(count));
                if(isDone)
                count++;

                }
            });
        }
    }, 1000, 1000);

    b.setOnClickListener(this);


}


@Override
public void onClick(View v) {
    // TODO Auto-generated method stu

    final Dialog d = new Dialog(MainActivity.this);
    d.setTitle("Pause Menu");
    d.setContentView(R.layout.pausemenu);
    Button b1 = (Button) d.findViewById(R.id.button1);
    Button b2 = (Button) d.findViewById(R.id.button2);

    b1.setOnClickListener(new OnClickListener() {

        @Override
        public void onClick(View v) {
            // TODO Auto-generated method stub
            t.cancel();
            d.dismiss();

        }
    });

    b2.setOnClickListener(new OnClickListener() {

        @Override
        public void onClick(View v) {
            // TODO Auto-generated method stub
            if(isDone)
            {
                t.cancel();
                isDone=false;
            }
            t = new Timer();
             t.scheduleAtFixedRate(new TimerTask() {

                    @Override
                    public void run() {
                        // TODO Auto-generated method stub
                        runOnUiThread(new Runnable() {
                            public void run() {
                            tv.setText(String.valueOf(count));
                            count++;
                            }
                        });
                    }
                }, 1000, 1000);
             d.dismiss();
        }
    });
    d.show();

}
}

main.xml

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

    <TextView
        android:id="@+id/textView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_centerVertical="true"
       android:textSize="20sp"
        android:text="TextView" />

    <Button
        android:id="@+id/button1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_alignRight="@+id/textView1"
        android:layout_marginBottom="21dp"
        android:text="Button" />

</RelativeLayout>

pausemenu.xml

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

    <Button
        android:id="@+id/button1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_alignParentLeft="true"
        android:layout_marginBottom="118dp"
        android:layout_marginLeft="51dp"
        android:text="Stop" />

    <Button
        android:id="@+id/button2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignBaseline="@+id/button1"
        android:layout_alignBottom="@+id/button1"
        android:layout_marginLeft="32dp"
        android:layout_toRightOf="@+id/button1"
        android:text="Start" />

</RelativeLayout>

Edit:

Using Handler

    Handler m_handler;
    Runnable m_handlerTask ; 
     m_handlerTask = new Runnable()
{
     @Override 
     public void run() {
         if(isDone)
         {
          tv.setText(""+count);
          count++;
          m_handler.postDelayed(m_handlerTask, 1000);
         }
        //  m_handler.removeCallbacks(m_handlerTask);
     }
};
m_handlerTask.run();    

You should stop the timer and cancel the handler when not required.

Call t.cancel() if your using timer and use m_handler.removeCallbacks(m_handlerTask) to stop the handler

Outras dicas

In your code

   public void onClick(View v) {
        synchronized (MainActivity.this)
        {
            try {
                wait();

Never suspend the Android GUI thread with the wait statement. Pausing this thread would make all GUI to stop responding to your inputs, and Android operating system may close the program automatically after detecting the situation.

Also, a thread only starts after you call the start method that you never do. Finally you seems calling wait and notify on the thread itself (inner class) but no code elsewhere calls notify so that thread would stall permanently. Of course, this is surely less a problem if you never even start it.

I would suggest you to read some good tutorial on multithreading.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top