2017-02-22 42 views
2

我正在使用Android计算器应用程序,它不使用任何基于计时器的Android内置类,而是使用处理程序和线程来更新UI。我不确定是否存在逻辑问题,但无论出于何种原因,当我设置时间并点击“开始”按钮时,屏幕上根本没有任何反应。有针对性的TextView不会像应该那样降低。再次,我可能做了一个简单的错误(或几个),但我张贴我的Java和XML文件供大家看看。预先感谢您的回复。Android计算器上的开始按钮问题

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> 

回答

1

有几件事情在你的代码怎么回事。我不会试图解决所有问题,而只是为了让你的代码能够应付它。我复制了&尝试了你的代码&它实际上改变了我的显示。我跳过你的时间选择器对话框&只需设置sec=20开始。如果您的显示屏没有任何更改,显示屏是否从时间选择器开始设置?

无论如何,首先让我们来谈谈调试。一种方法是将Log语句放入代码中。通过把这个在文件的顶部

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())。就像你现在所做的那样,你有2个线程正在运行,并且你的计数器每秒钟都会下降两次。

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

最后,txtSeconds.setText(sec + "");不是一个很好的使用setText()的方法(它可能对Log消息是确定的,但最好习惯于以其他方式使用文本)。有超过1种好的方法来显示文本,但对于这种情况,您需要特殊的格式。那就是你希望你的显示器显示每个数字“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()

temp_sec = newVal; 
在positiveButton onClick()

现在,你必须

sec = temp_sec; 
+0

哇!非常感谢!我仍然习惯于使用日志消息。所以非常感谢提示和其他内容。回到现在应用这些并找到问题的根源。 –

+0

哦,还有一件事,你说它确实更新了显示器,当值没有设置数字选择器时,是吗? –

+0

这是正确的。我很懒,不想处理数字选择器,所以我只是把它放在文件'private int hrs = 0,min = 0,sec = 20;' – Gary99