如何在片段中为计时器启动新线程
How to start new thread for chronometer in fragment
我正在制作一个计时器应用程序。它在我的旧设备上明显滞后,但在新设备上却没有那么多。所以经过研究,我明白我必须创建一个新线程并从中更新 UI 线程。但无论如何我都无法摆脱这种滞后。
这里是精简为重要组件的计时器片段。任何帮助,将不胜感激。谢谢
public class ChronometerFragment 扩展片段 {
private static final String TAG = "ChronometerFragment";
private Button btnRestart,btnStartStop;
private TextView time;
private int currentTime;
private long startTime = 0L;
private Handler customHandler = new Handler();
long timeInMilliseconds = 0L;
long timeSwapBuff = 0L;
long updatedTime = 0L;
private int running = 0;
私人时间转换器时间转换器;
CycleDataListener 回调;
DecimalFormat df = new DecimalFormat("#.#####");
public ChronometerFragment(){}
public interface CycleDataListener{
void fragmentDataUpdate(Bundle bundle);
}
@Override
public void onAttach(@NonNull Context context) {
super.onAttach(context);
callback = (CycleDataListener)getActivity();
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
final View view = inflater.inflate(R.layout.fragment_chronometer,container,false);
initWidgets(view);
view.setKeepScreenOn(true);
df.setRoundingMode(RoundingMode.CEILING);
timeConverter = new TimeConverter();
btnRestart.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.d(TAG, "onClick: button restart" );
resetTime();
}
});
btnStartStop.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.d(TAG, "onClick: button startStop");
btnStartStop.performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY);
if(running == 0){
running = 1;
btnStartStop.setText(R.string.stop);
startTime = SystemClock.uptimeMillis();
customHandler.postDelayed(updateTimerThread, 0);
}else{
running = 0;
btnStartStop.setText(R.string.start);
timeSwapBuff += timeInMilliseconds;
customHandler.removeCallbacks(updateTimerThread);
}
}
});
return view;
}
@Override
public void onSaveInstanceState(@NonNull Bundle outState) {
super.onSaveInstanceState(outState);
}
private Runnable updateTimerThread = new Runnable() {
@Override
public void run() {
timeInMilliseconds = SystemClock.uptimeMillis() - startTime;
updatedTime = timeSwapBuff + timeInMilliseconds;
timeConverter.setUpTime(updatedTime);
time.setText(timeConverter.getTimeStringFormat());
customHandler.postDelayed(this, 0);
}
};
/**
* *********************helper methods**********************
*/
private void resetTime(){
running = 0;
btnStartStop.setText(R.string.start);
timeSwapBuff += timeInMilliseconds;
startTime = 0L;
timeInMilliseconds = 0L;
timeSwapBuff = 0L;
updatedTime = 0L;
customHandler.removeCallbacks(updateTimerThread);
time.setText("00:00:00:000");
}
private void initWidgets(View v){
btnRestart = v.findViewById(R.id.restart_button);
btnStartStop = v.findViewById(R.id.start_stop_button);
time = v.findViewById(R.id.currentTime);
}
}
此行导致滞后。您几乎立即在主线程上发布了 runnable。
customHandler.postDelayed(this, 0);
改为
customHandler.postDelayed(this, 10);
最好的解决方案是只使用主处理程序来更新 UI。时间计算和转换应由与 HandlerThread
关联的后台处理程序处理,以避免 UI 阻塞。
private Handler mainHandler = new Handler(Looper.getMainLooper());
private HandlerThread handlerThread = new HandlerThread("MyHandlerThread");
private Handler backgroundHandler;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
handlerThread.start();
backgroundHandler = new Handler(handlerThread.getLooper());
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
...
btnStartStop.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.d(TAG, "onClick: button startStop");
btnStartStop.performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY);
if (running == 0){
running = 1;
btnStartStop.setText(R.string.stop);
startTime = SystemClock.uptimeMillis();
backgroundHandler.post(updateTimerThread);
} else {
running = 0;
btnStartStop.setText(R.string.start);
timeSwapBuff += timeInMilliseconds;
backgroundHandler.removeCallbacks(updateTimerThread);
}
}
});
}
private Runnable updateTimerThread = new Runnable() {
@Override
public void run() {
timeInMilliseconds = SystemClock.uptimeMillis() - startTime;
updatedTime = timeSwapBuff + timeInMilliseconds;
timeConverter.setUpTime(updatedTime);
final String timeWithFormat = timeConverter.getTimeStringFormat();
mainHandler.post(() -> time.setText(timeWithFormat);)
backgroundHandler.postDelayed(this, 10);
}
};
@Override
public void onDestroy() {
handlerThread.quitSafely();
super.onDestroy()
}
我正在制作一个计时器应用程序。它在我的旧设备上明显滞后,但在新设备上却没有那么多。所以经过研究,我明白我必须创建一个新线程并从中更新 UI 线程。但无论如何我都无法摆脱这种滞后。
这里是精简为重要组件的计时器片段。任何帮助,将不胜感激。谢谢
public class ChronometerFragment 扩展片段 { private static final String TAG = "ChronometerFragment";
private Button btnRestart,btnStartStop;
private TextView time;
private int currentTime;
private long startTime = 0L;
private Handler customHandler = new Handler();
long timeInMilliseconds = 0L;
long timeSwapBuff = 0L;
long updatedTime = 0L;
private int running = 0;
私人时间转换器时间转换器; CycleDataListener 回调;
DecimalFormat df = new DecimalFormat("#.#####");
public ChronometerFragment(){}
public interface CycleDataListener{
void fragmentDataUpdate(Bundle bundle);
}
@Override
public void onAttach(@NonNull Context context) {
super.onAttach(context);
callback = (CycleDataListener)getActivity();
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
final View view = inflater.inflate(R.layout.fragment_chronometer,container,false);
initWidgets(view);
view.setKeepScreenOn(true);
df.setRoundingMode(RoundingMode.CEILING);
timeConverter = new TimeConverter();
btnRestart.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.d(TAG, "onClick: button restart" );
resetTime();
}
});
btnStartStop.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.d(TAG, "onClick: button startStop");
btnStartStop.performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY);
if(running == 0){
running = 1;
btnStartStop.setText(R.string.stop);
startTime = SystemClock.uptimeMillis();
customHandler.postDelayed(updateTimerThread, 0);
}else{
running = 0;
btnStartStop.setText(R.string.start);
timeSwapBuff += timeInMilliseconds;
customHandler.removeCallbacks(updateTimerThread);
}
}
});
return view;
}
@Override
public void onSaveInstanceState(@NonNull Bundle outState) {
super.onSaveInstanceState(outState);
}
private Runnable updateTimerThread = new Runnable() {
@Override
public void run() {
timeInMilliseconds = SystemClock.uptimeMillis() - startTime;
updatedTime = timeSwapBuff + timeInMilliseconds;
timeConverter.setUpTime(updatedTime);
time.setText(timeConverter.getTimeStringFormat());
customHandler.postDelayed(this, 0);
}
};
/**
* *********************helper methods**********************
*/
private void resetTime(){
running = 0;
btnStartStop.setText(R.string.start);
timeSwapBuff += timeInMilliseconds;
startTime = 0L;
timeInMilliseconds = 0L;
timeSwapBuff = 0L;
updatedTime = 0L;
customHandler.removeCallbacks(updateTimerThread);
time.setText("00:00:00:000");
}
private void initWidgets(View v){
btnRestart = v.findViewById(R.id.restart_button);
btnStartStop = v.findViewById(R.id.start_stop_button);
time = v.findViewById(R.id.currentTime);
}
}
此行导致滞后。您几乎立即在主线程上发布了 runnable。
customHandler.postDelayed(this, 0);
改为
customHandler.postDelayed(this, 10);
最好的解决方案是只使用主处理程序来更新 UI。时间计算和转换应由与 HandlerThread
关联的后台处理程序处理,以避免 UI 阻塞。
private Handler mainHandler = new Handler(Looper.getMainLooper());
private HandlerThread handlerThread = new HandlerThread("MyHandlerThread");
private Handler backgroundHandler;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
handlerThread.start();
backgroundHandler = new Handler(handlerThread.getLooper());
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
...
btnStartStop.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.d(TAG, "onClick: button startStop");
btnStartStop.performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY);
if (running == 0){
running = 1;
btnStartStop.setText(R.string.stop);
startTime = SystemClock.uptimeMillis();
backgroundHandler.post(updateTimerThread);
} else {
running = 0;
btnStartStop.setText(R.string.start);
timeSwapBuff += timeInMilliseconds;
backgroundHandler.removeCallbacks(updateTimerThread);
}
}
});
}
private Runnable updateTimerThread = new Runnable() {
@Override
public void run() {
timeInMilliseconds = SystemClock.uptimeMillis() - startTime;
updatedTime = timeSwapBuff + timeInMilliseconds;
timeConverter.setUpTime(updatedTime);
final String timeWithFormat = timeConverter.getTimeStringFormat();
mainHandler.post(() -> time.setText(timeWithFormat);)
backgroundHandler.postDelayed(this, 10);
}
};
@Override
public void onDestroy() {
handlerThread.quitSafely();
super.onDestroy()
}