Reputation: 303
I'm working on application that have two Views
one is UI and other is VideoView
.
UI thread is used until some events happen and then I want to setContentView
to VideoView
, but I got error on setting content view from UI to VideoView
. For VideoView I use code below:
setContentView(R.layout.videoview);
VideoView = (VideoView) findViewById(R.id.videoview);
String path= "android.resource://"+getPackageName()+"/"+R.raw.vid;
VideoView.setVideoURI(Uri.parse(path));
VideoView.start();
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<VideoView
android:id="@+id/videoview"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
Here is error that I'm getting:
android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
What am I doing wrong?
EDIT 0: Code from UI thread:
public class View extends SurfaceView implements Runnable{
Thread Thread = null;
SurfaceHolder SurfaceHolder;
boolean Play;
public View(Context context){
super(context);
SurfaceHolder=getHolder();
}
@Override
public void run() {
while(Play){
if(!SurfaceHolder.getSurface().isValid())
continue;
//drawing
if(something)
Video();
}
public void Pause(){
//called from onPause()
Play=false;
while(true){
try {
if(Thread!=null)
Thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
break;
}
Thread=null;
}
public void Resume(){
//called from onResume()
Play=true;
Thread = new Thread(this);
Thread.start();
}
public void Video(){
setContentView(R.layout.videoview);
VideoView = (VideoView) findViewById(R.id.videoview);
String path= "android.resource://"+getPackageName()+"/"+R.raw.vid;
VideoView.setVideoURI(Uri.parse(path));
VideoView.start();
}
}
Upvotes: 1
Views: 927
Reputation: 11093
You call setContentView()
from the non-UI-thread.
public class View extends SurfaceView implements Runnable{
@Override
public void run() {
while(Play){
if(!SurfaceHolder.getSurface().isValid())
continue;
//drawing
if(something)
Video();
}
}
public void Resume() {
//called from onResume()
Play=true;
Thread = new Thread(this);
Thread.start();
}
public void Video(){
setContentView(R.layout.videoview);
/* more code */
}
}
onResume
is called, which creates a new Thread
(Thread = new Thread(this);
) which you start, so void run()
is called (remember, from the non-ui-thread which you just created). run()
calls video()
, which, in its turn, calls setContentView()
. Voila, you called setContentView()
from the non-UI-thread.
You shouldnt let a view implement runnable
, let alone let a View manage a Thread. It is managed by the UI-thread, no other. A possibility might be to get the context from the view and use the runOnUiThread(Runnable r)
method, but better yet: let the UI-thread do UI-work like showing video's.
// I think even this might work. Not 100% sure, I do this out of the top of my head.
public void onResume() {
if (condition)
getContext().runOnUiThread(new Runnable() {
public void run() {
video();
}
});
}
Upvotes: 1