我在Android上构建了一个简单的音乐播放器。每首歌的视图都包含一个SeekBar,实现如下:
public class Song extends Activity implements OnClickListener,Runnable {
private SeekBar progress;
private MediaPlayer mp;
// ...
private ServiceConnection onService = new ServiceConnection() {
public void onServiceConnected(ComponentName className,
IBinder rawBinder) {
appService = ((MPService.LocalBinder)rawBinder).getService(); // service that handles the MediaPlayer
progress.setVisibility(SeekBar.VISIBLE);
progress.setProgress(0);
mp = appService.getMP();
appService.playSong(title);
progress.setMax(mp.getDuration());
new Thread(Song.this).start();
}
public void onServiceDisconnected(ComponentName classname) {
appService = null;
}
};
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.song);
// ...
progress = (SeekBar) findViewById(R.id.progress);
// ...
}
public void run() {
int pos = 0;
int total = mp.getDuration();
while (mp != null && pos<total) {
try {
Thread.sleep(1000);
pos = appService.getSongPosition();
} catch (InterruptedException e) {
return;
} catch (Exception e) {
return;
}
progress.setProgress(pos);
}
}
这很好。现在我想要一个计时器计算秒/分钟的歌曲的进展。所以我把一个TextView在布局,得到它与findViewById()在onCreate(),并把这个在run()后的progress.setProgress(pos):
String time = String.format("%d:%d",
TimeUnit.MILLISECONDS.toMinutes(pos),
TimeUnit.MILLISECONDS.toSeconds(pos),
TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(
pos))
);
currentTime.setText(time); // currentTime = (TextView) findViewById(R.id.current_time);
但最后一句给了我一个例外:
android.view。只有创建视图层次结构的原始线程才能触及它的视图。
然而,我在这里所做的事情基本上与我在SeekBar中所做的事情相同——在onCreate中创建视图,然后在run()中触摸它——它没有给我这个抱怨。
对于runOnUiThread()方法的一行程序版本,您可以使用lambda函数,即:
runOnUiThread(() -> doStuff(Object, myValue));
其中doStuff()可以表示一些用于修改某些UI对象值的方法(设置文本,改变颜色等)。
我发现当尝试更新多个UI对象而不需要每个对象都有6行Runnable定义时,这要整洁得多,就像投票最多的答案中提到的那样,这绝不是不正确的,它只是占用了更多的空间,而且我发现可读性较差。
所以这个:
runOnUiThread(new Runnable() {
@Override
public void run() {
doStuff(myTextView, "myNewText");
}
});
可以变成这样:
runOnUiThread(() -> doStuff(myTextView, "myNewText"));
doStuff的定义在别处。
或者如果你不需要这么一般化,只需要设置TextView对象的文本:
runOnUiThread(() -> myTextView.setText("myNewText"));
RunOnUIThread似乎对我不起作用,但下面的程序最终解决了我的问题。
_ = MainThread.InvokeOnMainThreadAsync(async () =>
{
this.LoadApplication(Startup.Init(this.ConfigureServices));
var authenticationService = App.ServiceProvider.GetService<AuthenticationService>();
if (authenticationService.AuthenticationResult == null)
{
await authenticationService.AuthenticateAsync(AuthenticationUserFlow.SignUpSignIn, CrossCurrentActivity.Current.Activity).ConfigureAwait(false);
}
});
在启动过程中。Init方法有ReactiveUI路由,这需要在主线程上调用。这个Invoke方法也比RunOnUIThread更好地接受async/await。
所以我需要在主线程上调用方法的任何地方都使用这个。
请评论这一点,如果有人知道一些我不知道的,可以帮助我提高我的申请。
“这是我的代码”
Timer timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
KeyValuePair<String, String> keyValuePair = getCalculateDifferenceBetweenTwoTimes();
CharSequence charSequence = getPresenterUtil().contact(
getPresenterUtil().messageStyle("Check-in", Color.GRAY, Typeface.NORMAL, 0.9f),
UtilPresenter.LINE,
getPresenterUtil().messageStyle(keyValuePair.getKey(), Color.BLACK, Typeface.NORMAL, 1.3f),
UtilPresenter.LINE,
UtilPresenter.LINE,
getPresenterUtil().messageStyle("Tempo de execução", Color.GRAY, Typeface.NORMAL, 0.9f),
UtilPresenter.LINE,
getPresenterUtil().messageStyle(keyValuePair.getValue(), Color.BLACK, Typeface.NORMAL, 1.3f)
);
if (materialDialog.getContentView() != null) {
materialDialog.getContentView().setText(charSequence);
}
}
});
}
}, 0, 1000);
我看到你已经接受了@providence的答案。以防万一,您也可以使用处理程序!首先,处理int字段。
private static final int SHOW_LOG = 1;
private static final int HIDE_LOG = 0;
接下来,将处理程序实例作为字段。
//TODO __________[ Handler ]__________
@SuppressLint("HandlerLeak")
protected Handler handler = new Handler()
{
@Override
public void handleMessage(Message msg)
{
// Put code here...
// Set a switch statement to toggle it on or off.
switch(msg.what)
{
case SHOW_LOG:
{
ads.setVisibility(View.VISIBLE);
break;
}
case HIDE_LOG:
{
ads.setVisibility(View.GONE);
break;
}
}
}
};
创建一个方法。
//TODO __________[ Callbacks ]__________
@Override
public void showHandler(boolean show)
{
handler.sendEmptyMessage(show ? SHOW_LOG : HIDE_LOG);
}
最后,把这个放在onCreate()方法。
showHandler(true);