Java Android计算器上的开始按钮问题

Java Android计算器上的开始按钮问题,java,android,xml,Java,Android,Xml,我正在开发一个Android计算器应用程序,它不使用Android中任何内置的基于计时器的类,而是使用处理程序和线程来更新UI。我不确定我的逻辑是否有问题,但无论出于什么原因,当我设置时间并按下开始按钮时,屏幕上根本没有发生任何事情。目标文本视图并没有像应该的那样减少。再说一次,我可能犯了一些简单的错误(或几个),但我将发布我的java和xml文件供大家查看。提前感谢您的回复 TimerActivity.java package com.example.stins.intentsandtimer

我正在开发一个Android计算器应用程序,它不使用Android中任何内置的基于计时器的类,而是使用处理程序和线程来更新UI。我不确定我的逻辑是否有问题,但无论出于什么原因,当我设置时间并按下开始按钮时,屏幕上根本没有发生任何事情。目标文本视图并没有像应该的那样减少。再说一次,我可能犯了一些简单的错误(或几个),但我将发布我的java和xml文件供大家查看。提前感谢您的回复

TimerActivity.java

package com.example.stins.intentsandtimer;


import android.content.DialogInterface;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.NumberPicker;
import android.widget.TextView;
import android.os.Handler;
import android.os.Message;
import android.content.Context;
import android.os.Vibrator;



public class TimerActivity extends AppCompatActivity implements View.OnClickListener {
    TextView hours, minutes, seconds;
    Button numberPicker;
    private int hrs, min, sec;
    private boolean start;

    Handler timerHandler = new Handler(){

        /**
         * Handler for the timer class. It receives the onStart runnable to allow the textviews
         * to be updated. It checks to see if all textviews are empty and only updates them if
         * they follow the conditions of a traditional timer.  Including moving from 1 hour to 59 minutes.
         * The handler also sends the Vibrator function once the timer is complete.
         * @param msg
         */
        @Override
        public void handleMessage(Message msg){
            super.handleMessage(msg);
            TextView txtSeconds = (TextView) findViewById(R.id.textview_seconds);
            TextView txtMinutes = (TextView) findViewById(R.id.textview_minutes);
            TextView txtHours = (TextView) findViewById(R.id.textview_hours);
            int zeroCheck = Integer.parseInt(txtSeconds.getText().toString());

            if (zeroCheck > 0) {
                sec -= 1;
                txtSeconds.setText(sec + "");
            } else if (min > 0 && sec == 0) {
                min -= 1;
                txtMinutes.setText(min + "");
                sec = 59;
                txtSeconds.setText(sec + "");
            } else if (hrs > 0 && min == 0 && sec == 0) {
                hrs -= 1;
                txtHours.setText(hrs + "");
                min = 59;
                txtMinutes.setText(min + "");
                sec = 59;
                txtSeconds.setText(sec + "");
            } else {
                Vibrator v = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
                v.vibrate(1000);
            }
        }

    };


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_timer);
        this.setTitle("Timer");

        Button btnStart = (Button) findViewById(R.id.start_button);
        Button btnStop = (Button) findViewById(R.id.stop_button);
        Button btnReset = (Button) findViewById(R.id.reset_button);


        hours = (TextView) findViewById(R.id.textview_hours);
        numberPicker = (Button) findViewById(R.id.btn_set_hours);
        numberPicker.setOnClickListener(this);

        minutes = (TextView) findViewById(R.id.textview_minutes);
        numberPicker = (Button) findViewById(R.id.btn_set_minutes);
        numberPicker.setOnClickListener(this);

        seconds = (TextView) findViewById(R.id.textview_seconds);
        numberPicker = (Button) findViewById(R.id.btn_set_seconds);
        numberPicker.setOnClickListener(this);


        btnReset.setOnClickListener(new Button.OnClickListener() {
                                        public void onClick(View view) {
                                            TextView txtSeconds = (TextView) findViewById(R.id.textview_seconds);
                                            TextView txtMinutes = (TextView) findViewById(R.id.textview_minutes);
                                            TextView txtHours = (TextView) findViewById(R.id.textview_hours);
                                            sec = 0;
                                            min = 0;
                                            hrs = 0;
                                            txtSeconds.setText(sec+"");
                                            txtMinutes.setText(min+"");
                                            txtHours.setText(hrs+"");

                                        }
                                    }
        );

        btnStart.setOnClickListener(new Button.OnClickListener() {
                                        public void onClick(View view) {
                                            start = true;
                                            onStart();
                                        }
                                    }
        );

        btnStop.setOnClickListener(new Button.OnClickListener() {
                                       public void onClick(View view) {
                                           start = false;
                                       }
                                   }
        );


    }

    protected void onStart(){
        super.onStart();
        final Thread myThread = new Thread(new Runnable(){

            @Override
            public void run() {

                while (sec > 0 || min > 0 || hrs > 0) {
                    if(start) {
                        try {

                            Thread.sleep(1000);
                            timerHandler.sendMessage(timerHandler.obtainMessage());
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    else{

                    }
                }

            }

        });
        myThread.start();
    }




    public void onClick (View v){
        switch (v.getId()) {

            case R.id.btn_set_hours:
                hourPickerDialog();
                break;

            case R.id.btn_set_minutes:
                minutePickerDialog();
                break;

            case R.id.btn_set_seconds:
                secondPickerDialog();
                break;

            default:
                break;
        }


    }



    private void hourPickerDialog(){
        NumberPicker myNumberPicker = new NumberPicker(this);
        myNumberPicker.setMaxValue(99);
        myNumberPicker.setMinValue(0);
        NumberPicker.OnValueChangeListener myValChangedListener = new NumberPicker.OnValueChangeListener() {
            @Override
            public void onValueChange(NumberPicker picker, int oldVal, int newVal) {
                hours.setText(""+newVal);
            }
        };
        myNumberPicker.setOnValueChangedListener(myValChangedListener);
        AlertDialog.Builder builder =  new AlertDialog.Builder(this).setView(myNumberPicker);
        builder.setTitle("Set Hours");
        builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {

            }
        });
        builder.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {

            }
        });
        builder.show();


    }

    private void minutePickerDialog(){
        NumberPicker myNumberPicker = new NumberPicker(this);
        myNumberPicker.setMaxValue(59);
        myNumberPicker.setMinValue(0);
        NumberPicker.OnValueChangeListener myValChangedListener = new NumberPicker.OnValueChangeListener() {
            @Override
            public void onValueChange(NumberPicker picker, int oldVal, int newVal) {
                minutes.setText(""+newVal);
            }
        };
        myNumberPicker.setOnValueChangedListener(myValChangedListener);
        AlertDialog.Builder builder =  new AlertDialog.Builder(this).setView(myNumberPicker);
        builder.setTitle("Set Minutes");
        builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {

            }
        });
        builder.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {

            }
        });
        builder.show();


    }

    private void secondPickerDialog(){
        NumberPicker myNumberPicker = new NumberPicker(this);
        myNumberPicker.setMaxValue(59);
        myNumberPicker.setMinValue(0);
        NumberPicker.OnValueChangeListener myValChangedListener = new NumberPicker.OnValueChangeListener() {
            @Override
            public void onValueChange(NumberPicker picker, int oldVal, int newVal) {
                seconds.setText(""+newVal);
            }
        };
        myNumberPicker.setOnValueChangedListener(myValChangedListener);
        AlertDialog.Builder builder =  new AlertDialog.Builder(this).setView(myNumberPicker);
        builder.setTitle("Set Seconds");
        builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {

            }
        });
        builder.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {

            }
        });
        builder.show();


    }


}
activity_timer.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="match_parent"
              android:layout_height="match_parent"
              android:layout_margin="16dp"
              android:gravity="center_horizontal"
              android:orientation="vertical">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_weight="2"
        android:orientation="horizontal"
        android:gravity="center">

        <TextView
            android:id="@+id/textview_hours"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="16dp"
            android:text="00"
            android:textSize="70sp" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="16dp"
            android:text=":"
            android:textSize="70sp"/>

        <TextView
            android:id="@+id/textview_minutes"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="16dp"
            android:text="00"
            android:textSize="70sp" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="16dp"
            android:text=":"
            android:textSize="70sp"/>

        <TextView
            android:id="@+id/textview_seconds"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="16dp"
            android:text="00"
            android:textSize="70sp" />


    </LinearLayout>


    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center">

        <Button
            android:id="@+id/btn_set_hours"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Hours"/>

        <Button
            android:id="@+id/btn_set_minutes"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Minutes"/>

        <Button
            android:id="@+id/btn_set_seconds"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Seconds"/>



    </LinearLayout>

    <Button
        android:id="@+id/start_button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="16dp"
        android:layout_marginTop="16dp"
        android:background="?selectableItemBackgroundBorderless"
        android:text="@string/timer_start"
        style="@style/MyButton"
        />

    <Button
        android:id="@+id/stop_button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="16dp"
        android:layout_marginTop="16dp"
        android:background="?selectableItemBackgroundBorderless"
        android:text="@string/timer_stop"
        style="@style/MyButton"/>

    <Button
        android:id="@+id/reset_button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="16dp"
        android:background="?selectableItemBackgroundBorderless"
        android:text="@string/timer_reset"
        style="@style/MyButton"/>

</LinearLayout>

您的代码中有几个方面。我不会试图解决所有这些问题,只会解决一些问题,以使您的代码实现其应有的功能。我已经复制并尝试了你的代码&它实际上改变了我的显示。我跳过了时间选择器对话框&只需将
sec=20
设置为开始。如果您没有得到任何变化的显示,显示最初是否由时间选择器设置

不管怎样,首先让我们谈谈调试。一种方法是在代码中放入日志语句。首先把这个放在文件的顶部

private final static String TAG = "TimerActivity";
然后在代码中有如下内容:

// put this in the start button click listener
Log.d(TAG, "Start clicked");

// or this in handleMessage
Log.d(TAG, "handleMessage(), seconds = " + sec);
拥有这些日志消息可以帮助您了解程序做了什么和没有做什么,并向您显示一些变量值。你也可以使用调试器,我现在就不讲了

现在来看看你的代码
onStart()
是一种生命周期方法。你不应该自己称呼它。重命名您的方法(可能类似于
onStartButton()
)。现在,有两个线程实例正在运行,计数器每秒下降两次

handleMessage()
中,您有用于跟踪时间的变量(小时、分钟、秒),但也有从显示屏上的文本读取的
zeroCheck
。更好的做法是使用您已经保留的变量(
if(sec>0){sec-=1;…
)。我没有在这些条件的其余部分验证您的逻辑。一旦显示更新,我将留给您

最后,
txtSeconds.setText(sec+);
不是使用
setText()
的好方法(对于日志消息可能没问题,但最好习惯用其他方式使用文本)。有不止一种显示文本的好方法,但在本例中,您需要特殊格式。也就是说,您希望显示器为每个数字“00:09:07”而不是“0:9:7”显示前导0。您可以使用

txtSeconds.setText(String.format("%02d", sec));
这种方式始终提供2位显示,从0到59。其他有用的格式化程序有“%08x”表示32位十六进制,或“%.2f”表示将显示限制为小数点后2位,如用于显示美元和美分

因此,这些都不能解决您帖子中的问题,但它们会使您的最终代码更接近它所需要的。正如我所说,您的代码会按照我的方式更新显示(不使用时间选择器)。您可以先将
sec
设置为一个固定数字,然后点击“开始”按钮查看发生了什么。如果时间选择器中存在问题,您可以使用日志消息跟踪错误并修复它们

编辑:

因此,计时器没有启动的情况是,当您更改数字选择器中的显示时,您没有设置基础变量(
sec
等)。请定义一些用作临时存储的变量(
temp_sec
等),然后在
onValueChange()
中进行设置

现在,在您的positiveButton
onClick()
中,您将

sec = temp_sec;

哇!!非常感谢!我仍然习惯于使用日志消息。非常感谢这些提示和其他提示。现在回去应用这些并找到问题的根源。哦,还有一件事,你说它在没有设置数字选择器的情况下为你更新了显示,对吗?没错。我很懒&不想处理数字选择器,所以我只是将其放入文件
private int hrs=0,min=0,sec=20;
ah!好的。是的,我认为数字选择器可能会让我有点头疼。在实际添加这些对话框之前,我读了一段时间关于如何实现它们的内容,但是您知道我需要采取哪些进一步的步骤来实现吗那些由数字选择器设置的值实际上也开始更新了吗?非常感谢您的编辑,帮了我很大的忙!现在我只需要解决文本视图上的减少两倍问题。
sec = temp_sec;