티스토리 뷰
Stack Overflow에 자주 검색, 등록되는 문제들과 제가 개발 중 찾아 본 문제들 중에서 나중에도 찾아 볼 것 같은 문제들을 정리하고 있습니다.
Stack Overflow에서 가장 먼저 확인하게 되는 가장 높은 점수를 받은 Solution과 현 시점에 도움이 될 수 있는 가장 최근에 업데이트(최소 점수 확보)된 Solution을 각각 정리하였습니다.
아래 word cloud를 통해 이번 포스팅의 주요 키워드를 미리 확인하세요.
Android "Only the original thread that created a view hierarchy can touch its views."
안드로이드 CalledFromWrongThreadException 수정하기
문제 내용
I've built a simple music player in Android. The view for each song contains a SeekBar, implemented like this:
나는 안드로이드에서 간단한 음악 플레이어를 만들었다. 각 곡의 뷰에는 다음과 같이 구현된 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);
}
}
This works fine. Now I want a timer counting the seconds/minutes of the progress of the song. So I put a TextView
in the layout, get it with findViewById()
in onCreate()
, and put this in run()
after progress.setProgress(pos)
:
이것은 잘 작동한다. 이제 나는 노래 진행의 초/분을 세는 타이머를 원한다. 그래서 레이아웃에 TextView를 넣고 onCreate()에서 findViewById() 통해 가져 왔다. 그리고 progress.setProgress(pos) 이후에 run()에 아래 코드를 넣었다:
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);
But that last line gives me the exception:
하지만 그 마지막 줄은 나에게 예외를 준다.
android.view.ViewRoot$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
Yet I'm doing basically the same thing here as I'm doing with the SeekBar
- creating the view in onCreate
, then touching it in run()
- and it doesn't give me this complaint.
하지만 저는 여기서 기본적으로 SeekBar와 동일한 작업을 수행하고 있습니다. onCreate에서 뷰를 만든 다음 run()에서 뷰를 터치합니다. 그리고 그것은 문제가 없습니다.
높은 점수를 받은 Solution
You have to move the portion of the background task that updates the UI onto the main thread. There is a simple piece of code for this:
UI를 업데이트하는 백그라운드 작업 부분을 메인 스레드로 이동해야 합니다. 다음과 같은 간단한 코드가 있습니다.
runOnUiThread(new Runnable() {
@Override
public void run() {
// Stuff that updates the UI
}
});
Documentation for Activity.runOnUiThread
.
Activity.runOnUiThread에 대한 문서입니다.
Just nest this inside the method that is running in the background, and then copy paste the code that implements any updates in the middle of the block. Include only the smallest amount of code possible, otherwise you start to defeat the purpose of the background thread.
백그라운드에서 실행 중인 메서드 내부에 이것을 중첩한 다음 업데이트를 구현하는 코드를 블록 중간에 복사하여 붙여넣습니다. 가능한 최소한의 코드만 포함하십시오. 그렇지 않으면 백그라운드 스레드의 목적이 희석됩니다.
가장 최근 달린 Solution
For anyone using fragment:
Fragment를 사용하는 모든 사용자:
(context as Activity).runOnUiThread {
//TODO
}
출처 : https://stackoverflow.com/questions/5161951/android-only-the-original-thread-that-created-a-view-hierarchy-can-touch-its-vi
'개발 > 안드로이드' 카테고리의 다른 글
어디에서나 어플리케이션 컨텍스트 사용하기 (0) | 2022.12.02 |
---|---|
안드로이드 애플리케이션에서 액티비티 사이에 데이터 전달하기 (0) | 2022.12.02 |
Android에서 화면 크기를 픽셀로 가져오는 방법 (0) | 2022.12.01 |
기본 앱을 사용하지 않고 JavaMail API로 이메일 보내기 (0) | 2022.12.01 |
패키지 이름과 일치하는 클라이언트를 찾을 수 없습니다(Google Analytics) (0) | 2022.12.01 |