我在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()中触摸它——它没有给我这个抱怨。
“这是我的代码”
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);
我曾经遇到过这种情况,但我用Handler对象找到了解决方案。
在我的例子中,我想用观察者模式更新一个ProgressDialog。
我的视图实现了观察者并重写了更新方法。
因此,我的主线程创建了视图,另一个线程调用更新方法来更新ProgressDialop和....:
只有创建视图层次结构的原始线程才能接触它
的观点。
可以用Handler对象来解决这个问题。
下面是我代码的不同部分:
public class ViewExecution extends Activity implements Observer{
static final int PROGRESS_DIALOG = 0;
ProgressDialog progressDialog;
int currentNumber;
public void onCreate(Bundle savedInstanceState) {
currentNumber = 0;
final Button launchPolicyButton = ((Button) this.findViewById(R.id.launchButton));
launchPolicyButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
showDialog(PROGRESS_DIALOG);
}
});
}
@Override
protected Dialog onCreateDialog(int id) {
switch(id) {
case PROGRESS_DIALOG:
progressDialog = new ProgressDialog(this);
progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
progressDialog.setMessage("Loading");
progressDialog.setCancelable(true);
return progressDialog;
default:
return null;
}
}
@Override
protected void onPrepareDialog(int id, Dialog dialog) {
switch(id) {
case PROGRESS_DIALOG:
progressDialog.setProgress(0);
}
}
// Define the Handler that receives messages from the thread and update the progress
final Handler handler = new Handler() {
public void handleMessage(Message msg) {
int current = msg.arg1;
progressDialog.setProgress(current);
if (current >= 100){
removeDialog (PROGRESS_DIALOG);
}
}
};
// The method called by the observer (the second thread)
@Override
public void update(Observable obs, Object arg1) {
Message msg = handler.obtainMessage();
msg.arg1 = ++currentPluginNumber;
handler.sendMessage(msg);
}
}
这个解释可以在这个页面上找到,你必须阅读“示例ProgressDialog with a second thread”。