好吧,我遇到了一个我似乎无法解决的问题,并且正在寻找一些帮助或替代解决方案。我正在制作一个应用程序,简而言之,它允许您使用多个秒表(想想赛道会,游泳比赛,体育课等)。我有基本的功能,但似乎不能暂停我用作秒表的runnables。我正在使用listview,当我尝试使用wait / notify停止(暂停)runnable时,整个活动会冻结并最终崩溃。
我正在使用此方法暂停此答案中的runnables:https://stackoverflow.com/a/6776463/1642831 这是使用runnables作为列表视图项,还是实际暂停runnables的问题?是可以修复还是有更好的方法来模拟秒表功能?提前致谢
Stopwatch.java
import android.os.Handler;
import android.os.SystemClock;
import android.widget.TextView;
public class Stopwatch implements Runnable{
private long startTime;
private long timeInMillis = 0L;
private long timeSwap = 0L;
private long totalTime = 0L;
private long lastTime = 0L;
private long lastSplit = 0L;
private boolean startTimeSet = false;
private String currentTime = "00:00:00";
private TextView totalTimeText;
private TextView lastTimeText;
private TextView lastSplitText;
private Handler handler;
private boolean paused = false;
private Object pauseLock;
public Stopwatch(TextView totalTimeText, TextView lastTimeText, TextView lastSplitText) {
this.handler = new Handler();
pauseLock = new Object();
this.totalTimeText = totalTimeText;
this.lastTimeText = lastTimeText;
this.lastSplitText = lastSplitText;
}
@Override
public void run() {
if(!startTimeSet) {
startTime = SystemClock.uptimeMillis();
startTimeSet = true;
}
timeInMillis = SystemClock.uptimeMillis() - startTime;
totalTime = timeSwap + timeInMillis;
totalTimeText.setText(TimeHelpers.millisToStringTime(totalTime));
handler.postDelayed(this, 0);
synchronized (pauseLock) {
while (paused) {
try {
pauseLock.wait();
} catch (InterruptedException e) {
}
}
}
}
public void split() {
lastSplit = getTotalTime() - lastTime;
lastTime = getTotalTime();
lastSplitText.setText(TimeHelpers.millisToStringTime(lastSplit));
lastTimeText.setText(TimeHelpers.millisToStringTime(lastTime));
}
public String getCurrentTime() {
return currentTime;
}
public long getTimeSwap() {
return timeSwap;
}
public void setTimeSwap(long timeSwap) {
this.timeSwap = timeSwap;
}
public long getTimeInMillis() {
return timeInMillis;
}
public long getTotalTime() {
return totalTime;
}
public void toggleStartTimeSet() {
startTimeSet = !startTimeSet;
}
public void pause() {
synchronized (pauseLock) {
paused = true;
}
}
public void resume() {
synchronized (pauseLock) {
paused = false;
pauseLock.notify();
}
}
}
包含listview
的AthleteActivity.javaimport java.util.ArrayList;
import java.util.Calendar;
import android.os.Bundle;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.view.Gravity;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.TextView;
public class AthletesActivity extends Activity {
private ArrayList<Athlete> athletes;
private AthletesAdapter athletesAdapter;
private Button startStopAllButton;
private Button splitResetAllButton;
private ListView lv;
private ButtonStates splitResetState;
private ButtonStates startStopState;
private boolean running;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
setContentView(R.layout.activity_athletes);
athletes = new ArrayList<Athlete>();
startStopState = ButtonStates.START;
running = false;
splitResetState = ButtonStates.RESET;
athletesAdapter = new AthletesAdapter(this,athletes);
startStopAllButton = (Button) findViewById(R.id.btnStartStopAll);
splitResetAllButton = (Button) findViewById(R.id.btnSplitResetAll);
startStopAllButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
switch (startStopState) {
case START:
startStopState = ButtonStates.STOP;
startStopAllButton.setText("Stop All");
splitResetState = ButtonStates.SPLIT;
splitResetAllButton.setText("Split All");
for(Athlete athlete : athletes) {
if(athlete.getPaused()) {
athlete.resume();
}
else athlete.start();
}
break;
case STOP:
startStopState = ButtonStates.START;
startStopAllButton.setText("Start All");
splitResetState = ButtonStates.RESET;
splitResetAllButton.setText("Reset All");
for(Athlete athlete : athletes) {
athlete.pause();
}
break;
}
}
});
splitResetAllButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
switch(splitResetState) {
case SPLIT:
for(Athlete athlete : athletes) {
athlete.split();
}
break;
case RESET:
break;
}
}
});
lv = (ListView)findViewById(R.id.athleteList);
lv.setAdapter(athletesAdapter);
lv.setDivider(new ColorDrawable(0xff33b5e5));
lv.setDividerHeight(3);
lv.setBackgroundColor(0x222222);
//set meet name
Intent intent = getIntent();
String eventName = intent.getStringExtra("Event");
TextView eventNameText = (TextView) findViewById(R.id.event_name_athletes);
eventNameText.setText(eventName);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu items for use in the action bar
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.athletes, menu);
return super.onCreateOptionsMenu(menu);
}
@Override
public void onBackPressed() {
super.onBackPressed();
overridePendingTransition(R.anim.left_to_right, R.anim.right_to_left);
}
public boolean onOptionsItemSelected(MenuItem item) {
// Handle presses on the action bar items
switch (item.getItemId()) {
case R.id.action_newAthlete:
athletes.add(new Athlete("Athlete Name"));
athletesAdapter.notifyDataSetChanged();
//openNewAthleteDialog();
return true;
case R.id.action_discardAthlete:
if(!athletes.isEmpty()) {
//openDiscardEventDialog();
}
return true;
default:
return super.onOptionsItemSelected(item);
}
}
public void openNewAthleteDialog() {
AlertDialog.Builder builder = new AlertDialog.Builder(AthletesActivity.this, AlertDialog.THEME_HOLO_DARK);
// Setting Dialog Title
builder.setTitle("New Athlete");
// Setting Dialog Message
builder.setMessage("Enter Meet Name:");
final EditText input = new EditText(AthletesActivity.this);
input.setTextColor(Color.WHITE);
input.setHint("Athlete Name");
LinearLayout layout = new LinearLayout(this);
layout.setOrientation(LinearLayout.VERTICAL);
LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.WRAP_CONTENT);
lp.setMargins(30, 0, 30, 0);
layout.addView(input, lp);
builder.setView(layout);
// Setting Positive "Yes" Button
builder.setPositiveButton("Add",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog,int which) {
athletes.add(new Athlete(input.getText().toString()));
athletesAdapter.notifyDataSetChanged();
}});
// Setting Negative "NO" Button
builder.setNegativeButton("Cancel",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
// Write your code here to execute after dialog
dialog.cancel();
}
});
// closed
// Showing Alert Message
AlertDialog dialog = builder.show();
TextView messageText = (TextView)dialog.findViewById(android.R.id.message);
messageText.setGravity(Gravity.CENTER);
dialog.show();
}
}
AthletesAdapter.java - listview适配器
import java.util.ArrayList;
import java.util.Calendar;
import android.content.Context;
import android.os.Handler;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
public class AthletesAdapter extends ArrayAdapter<Athlete>{
private final Context context;
private final ArrayList<Athlete> athletes;
public AthletesAdapter(Context context, ArrayList<Athlete> athletes) {
super(context, R.layout.list_athletes, athletes);
this.context = context;
this.athletes= athletes;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View rowView = inflater.inflate(R.layout.list_athletes, parent, false);
final int i = position;
rowView.setBackgroundColor(0x222222);
final AutoResizeEditTextView athleteNameText = (AutoResizeEditTextView) rowView.findViewById(R.id.athlete_name);
athleteNameText.setEnabled(true);
athleteNameText.setFocusableInTouchMode(true);
athleteNameText.setFocusable(true);
athleteNameText.setMovementMethod(null);
athleteNameText.setText(athletes.get(position).getAthleteName());
athleteNameText.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence charSequence, int i, int i2, int i3) {
}
@Override
public void onTextChanged(CharSequence charSequence, int i, int i2, int i3) {
}
@Override
public void afterTextChanged(Editable editable) {
athletes.get(i).setAthleteName(editable.toString());
athleteNameText.setCursorVisible(false);
}
});
TextView totalTimeText = (TextView) rowView.findViewById(R.id.main_time);
TextView lastSplitText = (TextView) rowView.findViewById(R.id.split_time);
TextView lastTimeText = (TextView) rowView.findViewById(R.id.second_time);
athletes.get(position).setTextViews(totalTimeText, lastTimeText, lastSplitText);
final Button startStopButton = (Button) rowView.findViewById(R.id.btnstartStop);
final Button splitResetButton = (Button) rowView.findViewById(R.id.btnSplitReset);
startStopButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Athlete athlete = athletes.get(i);
switch(athlete.getStartStopButtonState()) {
case START:
athlete.setStartStopButtonState(ButtonStates.STOP);
startStopButton.setText("Stop");
athlete.setSplitResetButtonState(ButtonStates.SPLIT);
splitResetButton.setText("Split");
if(athlete.getPaused()) {
athlete.resume();
}
else {
athlete.start();
}
break;
case STOP:
athlete.setStartStopButtonState(ButtonStates.START);
startStopButton.setText("Start");
athlete.setSplitResetButtonState(ButtonStates.RESET);
splitResetButton.setText("Reset");
athlete.pause();
break;
}
}
});
splitResetButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Athlete athlete = athletes.get(i);
switch(athlete.getSplitResetButtonState()) {
case SPLIT:
athlete.split();
break;
case RESET:
break;
}
}
});
return rowView;
}
}
Athlete.java
import android.os.Handler;
import android.widget.TextView;
public class Athlete {
private String athleteName;
private Stopwatch sw;
private Handler swHandler;
private TextView totalTimeText;
private boolean paused = false;
private boolean running = false;
private ButtonStates startStopButtonState;
private ButtonStates splitResetButtonState;
public Athlete(String athleteName) {
this.athleteName = athleteName;
startStopButtonState = ButtonStates.START;
splitResetButtonState = ButtonStates.RESET;
}
public String getAthleteName() {
return athleteName;
}
public void setAthleteName(String athleteName) {
this.athleteName = athleteName;
}
public void setStopwatch(Stopwatch sw) {
this.sw = sw;
}
public Stopwatch getStopwatch() {
return sw;
}
public void start() {
sw.run();
running = true;
}
public void split() {
sw.split();
}
public void setTextViews(TextView totalTimeText, TextView lastTimeText, TextView splitTimeText) {
this.totalTimeText = totalTimeText;
setStopwatch(new Stopwatch(totalTimeText, lastTimeText, splitTimeText));
}
public void pause() {
this.paused = true;
sw.pause();
}
public void resume() {
this.paused = false;
sw.resume();
}
public boolean getPaused() {
return paused;
}
public ButtonStates getStartStopButtonState() {
return startStopButtonState;
}
public void setStartStopButtonState(ButtonStates state) {
this.startStopButtonState = state;
}
public ButtonStates getSplitResetButtonState() {
return splitResetButtonState;
}
public void setSplitResetButtonState(ButtonStates state) {
this.splitResetButtonState = state;
}
private boolean getRunning() {
return running;
}
}