0

我有一个正在运行的计时器,然后它会关闭并执行一些操作,并且计时器可以正常启动。

然后我想做的是单击一个按钮,然后让它创建一封电子邮件。一切正常,除了在计时器运行时单击按钮时,应用程序正在崩溃。当按下按钮时试图取消计时器时,这也会导致应用程序崩溃。

任何帮助,将不胜感激。

这是代码片段:

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 输出:

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)
4

2 回答 2

2

这个计时器的具体用途是什么?我无法想象你会用它来做什么,它会不断重复每 2 秒运行一次。您可能会遇到的一件事是 Android 的线程问题。该计时器任务在与 Android UI 使用的主线程不同的线程上运行。如果您正在触摸 android 小部件或其他实例变量,那么您最终会遇到线程安全问题,如果您尝试这样做,Android 经常会抛出异常。因此,归结为您尝试使用该线程完成的工作,以及比创建这样的另一个线程更好的方法。通常我们会使用 Handler 在主线程上定期运行任务,而不是像这样使用 Timer,因为它引入了线程问题。

更新:

您刚刚确认了您刚才描述的一个严重的线程安全问题。我所说的线程安全的意思是你有可能让两个线程同时读/写同一个内存位置。这是一个大问题。事实上,您自己承认,您的 StringBuilder 实例在计时器线程和按钮回调之间共享,这意味着您肯定会在读取该 StringBuilder 时遇到线程安全问题。

这样做你会经常遇到不可预知的问题,并且你的代码在用户操作时永远不会稳定。首先,没有理由从另一个线程读取 GPS,因为 LocationManager 会在它更改时定期调用您。只需在调用时将其附加到 StringBuilder 或 ArrayList 即可。GPS 回调在主线程上运行,因此读取该变量的按钮逻辑不可能在修改该变量的同时发生。

您需要从代码中删除该计时器,并使用主线程来完成所有工作。或者您必须同步对数据结构的访问。Android 中发生的大多数回调都在主线程上运行。因此,如果您只是将记录历史值的逻辑移动到那里的数据结构中,而不是在您的计时器中,那么您会没事的。您可能必须将 GPS 与您尝试记录的任何其他内容分开记录,但您可以在按钮单击处理程序中将它们格式化为您的字符串。

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.

于 2012-04-19T02:14:47.010 回答
0
   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) {
                }
            }
        });

上面的行必须在 oncreate() 中,因为您在 oncreate 中设置了 view(R.layout.main) 并且您的函数 addListenerOnButton() 不知道主布局。

于 2012-04-19T02:01:19.353 回答