Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/229.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
我如何从Android中的另一个线程操作主线程UI元素?_Android_Multithreading - Fatal编程技术网

我如何从Android中的另一个线程操作主线程UI元素?

我如何从Android中的另一个线程操作主线程UI元素?,android,multithreading,Android,Multithreading,我的应用程序将运行在自己线程上的SurfaceView与运行在主应用程序线程上的一组常规视图相结合。在大多数情况下,这很好。然而,当我试图在SurfaceView的线程上触发对主应用程序线程中的一个UI元素的更改时,我得到了android.View.ViewRoot$calledFromErrorThreadException 有没有正确的方法?我应该使用异步任务吗?Runonuithread()?或者,将自己线程上的SurfaceView与主线程上的其他UI元素混合只是一件天生的坏事 如果我的

我的应用程序将运行在自己线程上的SurfaceView与运行在主应用程序线程上的一组常规视图相结合。在大多数情况下,这很好。然而,当我试图在SurfaceView的线程上触发对主应用程序线程中的一个UI元素的更改时,我得到了android.View.ViewRoot$calledFromErrorThreadException

有没有正确的方法?我应该使用异步任务吗?Runonuithread()?或者,将自己线程上的SurfaceView与主线程上的其他UI元素混合只是一件天生的坏事

如果我的问题没有意义,这里的伪代码可能更清晰

// Activity runs on main application thread
public class MainActivity extends Activity {
    RelativeLayout layout;
    TextView popup;
    MySurfaceView mysurfaceview;

    protected void onCreate(Bundle savedInstanceState) {
        ...
        setContentView(layout);
        layout.addView(mysurfaceview);  // Surface View is displayed
        popup.setText("You won");       // created but not displayed yet
    }
    public void showPopup() {
        layout.addView(popup);
    }
}

// Surface View runs on its own separate thread
public class MySurfaceView extends SurfaceView implements SurfaceHolder.Callback, OnTouchListener {
    private ViewThread mThread;

    public boolean onTouch(View v, MotionEvent event) { 
        ...
        if (someCondition == true) {
            mainactivity.showPopup();
            // This works because onTouch() is called by main app thread
        }
    }
    public void Draw(Canvas canvas) { 
        ...
        if (someCondition == true) {
            mainactivity.showPopup();
            // This crashes with ViewRoot$CalledFromWrongThreadException
            // because Draw is called by mThread
            // Is this fixable?
        }
    }
}

简单的答案是您不能从非UI线程更新UI元素


您需要有一个回调方法或一些回调主线程的东西来更新UI

简单的答案是您不能从非UI线程更新UI元素


您需要有一个回调方法或调用主线程的东西来更新UI

您需要使用这个-

runOnUiThread(new Runnable() {

        @Override
        public void run() {
            // TODO Populate UI

        }
    });

你需要使用这个-

runOnUiThread(new Runnable() {

        @Override
        public void run() {
            // TODO Populate UI

        }
    });
我应该使用异步任务吗?Runonuithread()

这两个都可以。我通常使用
AsyncTask
来处理大多数需要在后台处理后更新
UI
的事情。但两者都应该有效

我应该使用异步任务吗?Runonuithread()

这两个都可以。我通常使用
AsyncTask
来处理大多数需要在后台处理后更新
UI
的事情。但两者都应该有效


并且

您不能从UI线程以外的其他线程更改UI元素。但是,您仍然可以从另一个线程向UI线程发布命令以更新元素。

您可以执行以下操作:

在UI线程中实例化处理程序,如:

final Handler handler = new Handler();
然后在另一个线程中,您可以向UI线程发布消息,通过处理程序更新视图,如下所示:

handler.post(new Runnable(){

    public void run(){
        //Update your view here
    }
});
你应该是个好孩子。请记住,您必须在UI线程中实例化处理程序。



如果您正在
活动
实例中运行其他线程,则可以使用:

this.runOnUiThread(new Runnable(){

     public void run(){
         //your UI update code here
     }
});

不能从UI线程以外的其他线程更改UI元素。但是,您仍然可以从另一个线程向UI线程发布命令以更新元素。

您可以执行以下操作:

在UI线程中实例化处理程序,如:

final Handler handler = new Handler();
然后在另一个线程中,您可以向UI线程发布消息,通过处理程序更新视图,如下所示:

handler.post(new Runnable(){

    public void run(){
        //Update your view here
    }
});
你应该是个好孩子。请记住,您必须在UI线程中实例化处理程序。



如果您正在
活动
实例中运行其他线程,则可以使用:

this.runOnUiThread(new Runnable(){

     public void run(){
         //your UI update code here
     }
});

你为什么不使用回调呢?在MySurfaceView中,您可以添加一个接口

public interface onClickSurfaceView{
     public void change();
}
然后在您的活动中实现
MySurfaceView.onClickSurfaceView
,您可以参考
surfaceView
。然后调用
surfaceView.setListener(this)
将活动注册为订户,
您可以在change()方法中调用update-your-UI。

为什么不使用callback?在MySurfaceView中,您可以添加一个接口

public interface onClickSurfaceView{
     public void change();
}
然后在您的活动中实现
MySurfaceView.onClickSurfaceView
,您可以参考
surfaceView
。然后调用
surfaceView.setListener(this)
将活动注册为订户,
您可以在change()方法中调用update-your-UI。

您能澄清一下它的位置吗?是否应该在MainActivity中创建它,然后mysurfaceview.draw()将调用什么?我想在这种情况下,
runOnUiThread()
可能更容易实现,也不太混乱。请参阅我的示例链接(刚刚更新了错误的链接),不客气。通常,当我需要更新
UI
时,我会使用
AsyncTask
进行后台操作,但在再次查看您所拥有的内容后,
runOnUiThread()
可能会更容易。但是,如果您还不确定自己是否了解异步任务在未来的工作方式,请将其通读几遍……非常有帮助。您能澄清一下它将在哪里使用吗?是否应该在MainActivity中创建它,然后mysurfaceview.draw()将调用什么?我想在这种情况下,
runOnUiThread()
可能更容易实现,也不太混乱。请参阅我的示例链接(刚刚更新了错误的链接),不客气。通常,当我需要更新
UI
时,我会使用
AsyncTask
进行后台操作,但在再次查看您所拥有的内容后,
runOnUiThread()
可能会更容易。但是,如果你还不确定自己是否了解这对未来的工作方式,请将
AsyncTask
文档通读几遍……非常有用。+1对于另一种方法-我是否正确地认为这将与rununuithread做的差不多,并且两者都可以工作?它们都做相同的事情,但是您可以在任何地方使用第一个选项,而第二个选项只能在
活动
中使用,因为
runOnUiThread()
方法仅在
活动
类中声明,这两种方法都可以工作?它们都可以做相同的事情,但是您可以在任何地方使用第一个选项,而第二个选项只能在
活动
中使用,因为
runOnUiThread()
方法仅在
活动
类中声明。