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 で発生する可能性のある問題の 1 つは、スレッド化の問題です。そのタイマー タスクは、Android UI で使用されるメイン スレッドとは別のスレッドで実行されます。Android ウィジェットやその他のインスタンス変数に触れていると、スレッド セーフの問題が発生し、それを行おうとすると Android が例外をスローすることがよくあります。したがって、このような別のスレッドを作成するよりもうまくいく可能性があるかどうかは、そのスレッドで何を達成しようとしているのかということになります。通常、メイン スレッドで定期的にタスクを実行するには、このようにタイマーを使用するのではなく、ハンドラーを使用します。これは、スレッドの問題が発生するためです。

アップデート:

今説明した内容で深刻なスレッド セーフの問題が確認されました。スレッド セーフとは、2 つのスレッドが同じメモリ位置に対して同時に読み取り/書き込みを行う可能性があることを意味します。それは大きな問題です。実際、あなた自身の承認により、あなたの StringBuilder インスタンスはタイマー スレッドとボタン コールバックの間で共有されます。つまり、その StringBuilder を読み取ることでスレッド セーフの問題が発生することは間違いありません。

これを行うと、予測できない問題が常に発生し、ユーザーが操作したときにコードが安定することはありません。まず、別のスレッドから GPS を読み取る必要はありません。なぜなら、LocationManager は、変更されるたびに定期的に呼び出しを行うからです。呼び出されたときに StringBuilder または ArrayList に追加するだけです。GPS コールバックはメイン スレッドで実行されるため、その変数を変更すると同時にその変数を読み取るボタン ロジックが発生する可能性はありません。

そのタイマーをコードから削除し、メイン スレッドを使用してすべての作業を行う必要があります。または、データ構造へのアクセスを同期する必要があります。Android で発生するコールバックのほとんどは、メイン スレッドで実行されます。したがって、履歴値を記録するロジックを、タイマーではなくデータ構造に移動するだけで問題ありません。記録しようとしているものとは別に GPS を記録する必要があるかもしれませんが、ボタン クリック ハンドラでそれらを文字列にフォーマットできます。

NPE はファイルの 94 行目にあります。ソースコードの行番号を知らなければ、私たちはあなたを助けることができません. しかし、これらは、スレッド セーフティの問題が発生したときに遭遇するタイプの問題です。そして、彼らはあなたを夢中にさせるので、私の警告に頭を悩ませ、スレッド化とそれを安全に制御することについてもっと学ぶことは理にかなっています.

于 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 に view(R.layout.main) が設定されていて、関数 addListenerOnButton() がメイン レイアウトを認識していないため、上記の行は oncreate() にある必要があります。

于 2012-04-19T02:01:19.353 に答える