简体   繁体   中英

Android Timers Crashing On Cancel

I have a timer running that then goes off and does a few things and the timer starts fine.

What I then want to do is click a button, then have that create an email. Everything is working, apart from when clicking the button when the timer is running, the application is crashing. When trying to cancel the timer when hitting the button, that also crashes the application.

Any help would be appreciated.

Here's the code snippet:

public class myApplication extends Activity {
    StringBuilder str;
    Timer t;
    Button mailbutton;

    public void onCreate(Bundle savedInstanceState) {

        final StringBuilder str = new StringBuilder(1000);
        super.onCreate(savedInstanceState);


        setContentView(R.layout.main);

        addListenerOnButton();


        TimerTask task = new TimerTask() {

            @Override
            public void run() 
            {
            /// do stuff here
            }
        }

        t = new Timer();
        t.schedule(task,2000,2000);

    } 


    public void addListenerOnButton() {

        mailbutton = (Button) findViewById(R.id.emailbutton);

        mailbutton.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View arg0) {

                t.cancel();

                Intent i = new Intent(Intent.ACTION_SEND);
                i.setType("text/plain");
                i.putExtra(Intent.EXTRA_EMAIL  , new String[]{"email@domain.com"});
                i.putExtra(Intent.EXTRA_SUBJECT, "subject");
                i.putExtra(Intent.EXTRA_TEXT   , str.toString());
                try {
                    startActivity(Intent.createChooser(i, "Send mail"));
                } catch (android.content.ActivityNotFoundException ex) {
                }
            }
        });
    }
}

LogCat output:

04-19 09:13:11.143: W/dalvikvm(12613): threadid=1: thread exiting with uncaught exception (group=0x40c421f8)
04-19 09:13:11.148: E/AndroidRuntime(12613): FATAL EXCEPTION: main
04-19 09:13:11.148: E/AndroidRuntime(12613): java.lang.NullPointerException
04-19 09:13:11.148: E/AndroidRuntime(12613):    at uk.co.application.applicationActivity$2.onClick(applicationActivity.java:94)
04-19 09:13:11.148: E/AndroidRuntime(12613):    at android.view.View.performClick(View.java:3591)
04-19 09:13:11.148: E/AndroidRuntime(12613):    at android.view.View$PerformClick.run(View.java:14263)
04-19 09:13:11.148: E/AndroidRuntime(12613):    at android.os.Handler.handleCallback(Handler.java:605)
04-19 09:13:11.148: E/AndroidRuntime(12613):    at android.os.Handler.dispatchMessage(Handler.java:92)
04-19 09:13:11.148: E/AndroidRuntime(12613):    at android.os.Looper.loop(Looper.java:137)
04-19 09:13:11.148: E/AndroidRuntime(12613):    at android.app.ActivityThread.main(ActivityThread.java:4507)
04-19 09:13:11.148: E/AndroidRuntime(12613):    at java.lang.reflect.Method.invokeNative(Native Method)
04-19 09:13:11.148: E/AndroidRuntime(12613):    at java.lang.reflect.Method.invoke(Method.java:511)
04-19 09:13:11.148: E/AndroidRuntime(12613):    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:790)
04-19 09:13:11.148: E/AndroidRuntime(12613):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:557)
04-19 09:13:11.148: E/AndroidRuntime(12613):    at dalvik.system.NativeStart.main(Native Method)

What exactly is the purpose of this timer? I can't imagine what you'd be using it for with it constantly repeating to run every 2 seconds. One thing you could be running into is threading issues with Android. That timer task runs on a different thread than the main thread used by the Android UI. If you are touching android widgets or other instance variables then you'll end up with thread safety problems, and Android will often throw exceptions if you try to do that. So it comes down to what you are trying to accomplish with that thread as to what might work better than creating another thread like this. Typically we'd use a Handler to run a task on the main thread periodically rather than using a Timer like this because of the threading issues it introduces.

Update:

You just confirmed a serious thread safety issue in what you just described. What I mean by thread safety is you have the potential for two threads to read/write to the same memory location at the same time. That is a big problem. In fact, by your own admission, your StringBuilder instance is shared between the timer thread and button callback which means you most certainly have a thread safety problem from reading that StringBuilder.

You are going to have constant unpredictable problems doing that, and your code will never be stable when operated by users. First there is no reason to read GPS from another thread since the LocationManager will call you periodically as it changes. Just simply append that onto the a StringBuilder or ArrayList when it's called. The GPS callback runs on the main thread so there is no chance for the button logic that reads that variable to occur at the same time as modifying that variable.

You need to remove that timer from your code, and use the main thread to do all of your work. Or you'll have to synchronize access to your data structures. Most of the callbacks that occur in Android run on the main thread. So if you'll just move the logic of recording the historical values into a data structure(s) there, instead of in your timer, you'll be fine. You might have to record GPS separately from whatever else your are trying to record, but you can then format them into your String in the button click handler.

Your NPE is on line 94 of your file. Without knowing line numbers to source code we can't help you. But these are the types of problems you'll encounter when you have Thread safety issues. And they'll drive you crazy so it makes sense to head my warning, and learn more about threading and controlling it safely.

   mailbutton = (Button) findViewById(R.id.emailbutton);

        mailbutton.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View arg0) {

                t.cancel();

                Intent i = new Intent(Intent.ACTION_SEND);
                i.setType("text/plain");
                i.putExtra(Intent.EXTRA_EMAIL  , new String[]{"email@domain.com"});
                i.putExtra(Intent.EXTRA_SUBJECT, "subject");
                i.putExtra(Intent.EXTRA_TEXT   , str.toString());
                try {
                    startActivity(Intent.createChooser(i, "Send mail"));
                } catch (android.content.ActivityNotFoundException ex) {
                }
            }
        });

the above line must be in oncreate() because you have a view(R.layout.main) set in oncreate and you function addListenerOnButton() doesn't know about main layout.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM