私はカウントダウンタイマーを含むアンドロイドアプリを構築しようとしています。各インターバルで3つの画像を表示する必要があります - 200 msのマスキング画像、20 msの刺激画像再び200msの間、別のマスキング画像を生成する。Android:強制的に最新のUIを更新する
このアプリは、メインUIスレッドと時間管理スレッドの2つのスレッドで動作します。
問題は、その間にスリープして画像が表示されないため、UIスレッド自体が更新されないことです。
私は既にUIスレッドを強制的にリフレッシュさせる方法を見つけるために何時間も前から検索しましたが、今までは失敗しています。 例えば、invalidate()やpostinvalidate()のようなメソッドは役に立ちません。
誰かがこの問題のヒントまたは解決策を持っているなら、それは素晴らしいことでしょう。
ありがとうございました。
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
Button button;
ImageView imageView;
TextView textViewCounter;
boolean buttonWasPressed = false;
double startTime;
double currentTime;
double timer;
final int INTERVALS = 2;
final double SECONDS_TO_NANOSECONDS_COEFFICIENT = 1000000000.0;
// length of the interval in seconds
final double INTERVAL_LENGTH = 10 * SECONDS_TO_NANOSECONDS_COEFFICIENT;
int intervalCounter = 0;
// masking time in milliseconds (200)
final double MASKING_TIME = 0.2 * SECONDS_TO_NANOSECONDS_COEFFICIENT;
// stimulus time in milliseconds (20)
final double STIMULUS_TIME = 0.02 * SECONDS_TO_NANOSECONDS_COEFFICIENT;
boolean stimuliShouldBeDisplayed = false;
boolean stimuliIsDisplayed = false;
boolean imageViewShouldBeCleared = false;
Handler handler;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.setContentView(R.layout.activity_main);
button = (Button) this.findViewById(R.id.button);
if (button != null) {
button.setOnClickListener(this);
}
imageView = (ImageView) this.findViewById(R.id.imageView);
textViewCounter = (TextView) this.findViewById(R.id.textViewCounter);
// messages are sent to the thread where the Handler was created
handler = new Handler() {
@Override
public void handleMessage(Message msg) {
// not sure if you must always clear the message queue
this.removeMessages(0);
double tempStartTime = System.nanoTime();
// milliseconds are okay
textViewCounter.setText(String.valueOf(timer/1000000) + " ms");
if (stimuliShouldBeDisplayed && !stimuliIsDisplayed) {
stimuliIsDisplayed = true;
// show mask
imageView.setImageResource(R.mipmap.mask);
try {
Thread.sleep((long) (MASKING_TIME/1000000));
} catch (InterruptedException e) {
e.printStackTrace(
// update our timer (milliseconds are okay)
timer += System.nanoTime() - tempStartTime;
textViewCounter.setText(String.valueOf(timer/1000000) + " ms");
// show stimulus
imageView.setImageResource(R.mipmap.stimulus);
try {
Thread.sleep((long) (STIMULUS_TIME/1000000));
} catch (InterruptedException e) {
e.printStackTrace();
}
// update our timer (milliseconds are okay)
timer += System.nanoTime() - tempStartTime;
textViewCounter.setText(String.valueOf(timer/1000000) + " ms");
// show mask
imageView.setImageResource(R.mipmap.mask);
try {
Thread.sleep((long) (MASKING_TIME/1000000));
} catch (InterruptedException e) {
e.printStackTrace();
}
// update our timer (milliseconds are okay)
timer += System.nanoTime() - tempStartTime;
textViewCounter.setText(String.valueOf(timer/1000000) + " ms");
}
// clear the imageView
if (imageViewShouldBeCleared) {
imageView.setImageResource(0);
imageViewShouldBeCleared = false;
stimuliIsDisplayed = false;
stimuliShouldBeDisplayed = false;
}
}
};
}
@Override
public void onClick(View v) {
if (v == button && !buttonWasPressed) {
buttonWasPressed = true;
// let's start our timer
startTime = System.nanoTime();
Runnable runnableTimeManagement = new Runnable() {
@Override
public void run() {
while (currentTime - startTime <= INTERVAL_LENGTH && intervalCounter < INTERVALS) {
currentTime = System.nanoTime();
timer = currentTime - startTime;
// next interval
if (timer > INTERVAL_LENGTH) {
intervalCounter++;
startTime = currentTime;
imageViewShouldBeCleared = true;
}
// 1 seconds extra for the communication time between TimeManagement Thread and GUI Thread
if (timer + SECONDS_TO_NANOSECONDS_COEFFICIENT >= INTERVAL_LENGTH - 2 * MASKING_TIME - STIMULUS_TIME) {
stimuliShouldBeDisplayed = true;
}
// we must always create a new empty message
Message message = Message.obtain();
// we send message to the main UI thread
handler.sendMessage(message);
try {
Thread.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// time is over
buttonWasPressed = false;
intervalCounter = 0;
}
};
new Thread(runnableTimeManagement).start();
}
}
}
画像の表示時間を別の方法で正確に制御する方法を知っている人はいますか?最良の解決策は、1つのフレームだけの刺激画像を表示することです。しかし、私はフレームレートにアクセスする方法を知らない。
私はすぐにUIスレッドを強制的にリフレッシュする可能性がありますか?
ほとんどの携帯電話には、リフレッシュレートが固定されています。参照してください:http://stackoverflow.com/questions/3966468/controlling-display-refresh-rate-on-android-device –
私の知る限り、ほとんどの携帯電話は60 Hzのリフレッシュレートを持って、それは1のレート/ 60秒= 16.7ms。 – MBot
はい固定リフレッシュレートの倍数(16.7 msまたは33.4 ms)で画像が表示されます。許容範囲内であれば、CanvasまたはOpenGL ESで達成可能であることを確認してください。 –