Как насчет присоединиться к текущему counterThread
перед началом следующего нового потока.
Когда пользователь нажал кнопку остановки, мы можем остановиться и присоединиться к текущему counterThread
, чтобы заблокировать обработку события щелчка (основной поток) до текущие counterThread
остановки (только на несколько миллисекунд).
Затем мы можем обработать входящий щелчок по кнопке пуска и начать новый поток после того, как мы полностью остановили предыдущий.
Вот пример.
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private final static String LOG_TAG = "multithreadmenuupdate";
private Button mStartButton;
private Button mStopButton;
private Menu mMainMenu;
private CounterThread mCounterThread;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Initialize member fields
mStartButton = findViewById(R.id.startButton);
mStopButton = findViewById(R.id.stopButton);
mMainMenu = null;
mCounterThread = null;
// Set click listeners for buttons
mStartButton.setOnClickListener(this);
mStopButton.setOnClickListener(this);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
mMainMenu = menu;
getMenuInflater().inflate(R.menu.main, mMainMenu);
// must return true for the menu to be displayed
return true;
}
@Override
public void onClick(View v) {
switch(v.getId()) {
// Start button clicked?
case R.id.startButton:
// Thread is already running?
if(null != mCounterThread && !mCounterThread.isStopped().get()) break;
mCounterThread = new CounterThread(mMainMenu);
mCounterThread.start();
break;
// Stop button clicked?
case R.id.stopButton:
// No thread?
if(null == mCounterThread) break;
// Interrupt thread to stop
mCounterThread.interrupt();
try {
// Wait until current thread stops
mCounterThread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
break;
}
}
class CounterThread extends Thread {
private static final int COUNT_DOWN_START = 10;
private Menu mMenu;
// Indicates if thread is being stopped
// Initially true because the thread is in stopped state
private final AtomicBoolean mIsStopped = new AtomicBoolean(true);
public CounterThread(Menu menu) {
mMenu = menu;
}
@Override
public void run() {
int countDownValue = COUNT_DOWN_START;
// Is not stopped?
while(!mIsStopped.get()) {
// Count down finished?
if(countDownValue == 0) break; // stop thread
// Update menu item with count down value
updateMenuItem(countDownValue);
logThreadMenuUpdate(countDownValue);
// Wait for 1 sec
try {
Thread.sleep(1000); // 1000ms = 1s
} catch(InterruptedException e) {
// Thread has been interrupted to stop?
if(mIsStopped.get()) break; // stop thread
}
// Count down
countDownValue--;
}
}
@Override
public synchronized void start() {
// Change to false allowing thread to run
mIsStopped.set(false);
super.start();
}
@Override
public void interrupt() {
// Thread is being interrupted to stop
// Change to true for thread to stop
mIsStopped.set(true);
super.interrupt();
}
public AtomicBoolean isStopped() {
return mIsStopped;
}
private void updateMenuItem(final int countDownValue) {
runOnUiThread(new Runnable() {
@Override
public void run() {
mMenu.findItem(R.id.menu_counter).setTitle(Integer.toString(countDownValue));
}
});
}
private void logThreadMenuUpdate(int countDownValue) {
StringBuilder str = new StringBuilder();
str.append("Thread name: ").append(Thread.currentThread().getName());
str.append(" - ").append(countDownValue);
Log.d(LOG_TAG, str.toString());
}
}
}
В приведенном выше примере я заменил ваш класс CounterRunnable
на CounterThread
.
. Вы также можете найти реализацию MainActivity
.
Как Я добавил реализацию Activity, добавлю также макет активности и ресурсы XML меню.
res / layout / activity_main. xml
<ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:id="@+id/startButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Start"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toStartOf="@id/stopButton" />
<Button
android:id="@+id/stopButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Stop"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toEndOf="@id/startButton"
app:layout_constraintEnd_toEndOf="parent" />
</ConstraintLayout>
res / menu / main . xml
<menu>
<item
android:id="@+id/menu_counter"
android:title="Counter"
app:showAsAction="always" />
</menu>
Вот скриншот моего примера активности.
Я проверил это с помощью физического устройства, быстро нажимая и переключаясь между кнопками запуска и остановки. Похоже, это работает хорошо.