質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.02%

Androidでのボタン処理

受付中

回答 1

投稿

  • 評価
  • クリップ 0
  • VIEW 2,333
退会済みユーザー

退会済みユーザー

前提・実現したいこと

Androidスマートフォンで、STARTボタンをタップすると2秒後に画面上に加速度センサーの値を表示し、STOPボタンを押すと表示を止める、ということをしようとしています。

ちなみに表示中の値はCSVで出力する予定です。

発生している問題・エラーメッセージ

STARTボタンを押すと、ちゃんと2秒たってから表示が始まるのですが、
STOPを押しても一瞬止まった後すぐ勝手に表示が再開されてしまいます。

おそらく0にしたbutton_flagが、また勝手に1になってしまっているのだと思いますが、
どうすれば『STARTを押した2秒後に1、STOPを押したら0、そしてそのまま』
というようにできますか?

ソースコード

protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        manager = (SensorManager)this.getSystemService(SENSOR_SERVICE);
        accSensor = this.manager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
        Button start_btn = (Button) findViewById(R.id.button);
        Button stop_btn = (Button) findViewById(R.id.button2);

        start_btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mHandler.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        button_flag = 1;
                        mHandler.postDelayed(this, 2000);
                    }
                },2000); // 2秒後に処理
            }
        });

        stop_btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                button_flag = 0;
            }
        });

        mX = (TextView)this.findViewById(R.id.textView);
        mY = (TextView)this.findViewById(R.id.textView4);
        mZ = (TextView)this.findViewById(R.id.textView6);

    }

その他

一部ですが、よろしくお願いします。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

0

まず、なぜ勝手に戻るかというと、

  1. STARTでHandlerに渡されるRunnableは、button_flagを1にしたあと、自身を再び2秒後に実行するようHandlerに入れる。
  2. STOPを押したところで前回のRunnableが入れられてから2秒後には再びRunnableが実行され、button_flagを1にして自身をHandlerに入れる。以下同じ動作を続ける。

という動きになっているからです。これを解消するためには、Runnableを変数に保持しておいて、止めるときにHandlerのremoveCallbacks(Runnable)にそれを渡す必要があるのではないでしょうか。

まどろっこしいのでコード全部書き直しました。

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    manager = (SensorManager)this.getSystemService(SENSOR_SERVICE);
    accSensor = this.manager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
    Button start_btn = (Button) findViewById(R.id.button);
    Button stop_btn = (Button) findViewById(R.id.button2);

    final Runnable r = new Runnable(){
        @Override
            public void run() {
            button_flag = 1;
            mHandler.postDelayed(this, 2000);
        }
    };

    start_btn.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            mHandler.postDelayed(r ,2000); // 2秒後に処理
        }
    });

    stop_btn.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            //Handlerにセットしている上のRunnableを除去
            mHandler.removeCallbacks(r);
            button_flag = 0;
        }
    });

    mX = (TextView)this.findViewById(R.id.textView);
    mY = (TextView)this.findViewById(R.id.textView4);
    mZ = (TextView)this.findViewById(R.id.textView6);

}

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/02/01 00:55 編集

    よく見たらコメントのコードがおかしいですね…
    質問で掲載している最初のコードから以下の修正をしてください。
    1. start_btn.setOnClickListenerの直前にfinal Runnable r = ~を入れる
    2. start_btn.setOnClickListenerの中、onClickでmHandler.postDelayedに渡しているnew Runnable(){~}をrに変える↓(追記:ここ間違えてました)
    public void onClick(View v) {
    mHandler.postDelayed(r, 2000);
    }
    3. stop_btn.setOnClickListenerの中、onClickの中にmHandler.removeCallbacks(r);を追加

    キャンセル

  • 2016/02/01 01:13

    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    manager = (SensorManager)this.getSystemService(SENSOR_SERVICE);
    accSensor = this.manager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
    Button start_btn = (Button) findViewById(R.id.button);
    Button stop_btn = (Button) findViewById(R.id.button2);

    final Runnable r = new Runnable();
    start_btn.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
    mHandler.postDelayed(new Runnable() {
    @Override
    public void run() {
    button_flag = 1;
    mHandler.postDelayed(r, 2000);
    }
    };
    }
    });

    stop_btn.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
    mHandler.removeCallbacks(r);
    button_flag = 0;
    }
    });


    mX = (TextView)this.findViewById(R.id.textView);
    mY = (TextView)this.findViewById(R.id.textView4);
    mZ = (TextView)this.findViewById(R.id.textView6);
    }



    こういうことですか?
    2番がよくわかりませんでした。

    現在『final Runnable r = new Runnable();』の行の右側と
    『mHandler.postDelayed(r, 2000);』の2行下の『};』にエラーが出ています。

    前者は『Runnable is abstract;cannot be instantiated』
    後者は『")" expected』です。

    キャンセル

  • 2016/02/01 01:19

    なぜ私が書いたとおりに書いてくれないのでしょうか?
    前者は私が回答で書いたとおりにfinal Runnable r = ~ を宣言すればいいだけです。あなたの元のコードでpostDelayedに渡している匿名クラスのインスタンスをそのまま変数化しているだけです。
    後者は、もともと匿名クラスで宣言していたインスタンスを変数化したので、その変数を渡しているだけです。書き方もコメントそのままです。と言うか置き換えている場所が違います。↓をそのまま書いてください。
    start_btn.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
    mHandler.postDelayed(r ,2000); // 2秒後に処理
    }
    });

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.02%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる