我正在开发一款Android计算器应用,不使用Android中的任何内置基于计时器的类,而是使用处理程序和线程来更新UI。我不确定我的逻辑是否存在问题,但无论出于何种原因,当我设置时间并点击“开始”按钮时,屏幕上根本没有任何问题。目标TextView不会减少。再说一次,我可能犯了一个简单的错误(或者一些错误),但是我发布了我的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>
答案 0 :(得分:1)
您的代码中发生了一些事情。我不会试图解决所有这些问题,只是为了让你的代码能够做到应有的事情。我复制了&amp;试过你的代码&amp;它实际上改变了我的显示。我跳过你的时间选择器对话框&amp;只需设置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);
拥有这些日志消息可以帮助您了解您的计划已完成的工作&amp;什么没有,加上向你展示一些变量值。你也可以使用我现在不会进入的调试器。
现在为你的代码。 onStart()
是一种生命周期方法。你不应该自己打电话。重命名您的方法(可能类似于onStartButton()
)。正如你现在所做的那样,你有2个线程运行实例,你的计数器每秒都会下降两次。
在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.其他有用的格式化器是32位十六进制的“%08x”或“%。2f”,它将显示限制在小数点后的2位,如显示美元和美分。
所以,这些都不会解决你的帖子中的问题,但是它们会使你的最终代码更接近它所需要的。正如我所说,你的代码更新了我的显示(不使用时间选择器)。您可以先将sec
设置为固定数字,然后点击“开始”按钮查看会发生什么。如果你的时间选择器有问题,你可以使用日志消息来追踪错误和解决它们。
修改强>
所以你的计时器没有启动会发生什么,当你更改数字选择器中的显示时,你没有设置基础变量(sec
等)。定义一些变量用作临时存储( temp_sec
等)然后在onValueChange()
,
temp_sec = newVal;
现在在您的positiveButton onClick()
中,您将拥有
sec = temp_sec;