【问题标题】:View.GONE vs View.INVISIBLE in updating UI from another threadView.GONE vs View.INVISIBLE 从另一个线程更新 UI
【发布时间】:2019-06-30 05:37:29
【问题描述】:

我在另一个线程中使用了setVisibility(View.INVISIBLE),但视图消失了,但是当我使用View.GONE 时,应用程序崩溃并出现错误:

只有创建视图层次结构的原始线程才能触及它的 意见。

setVisibility(View.INVISIBLE)setVisibility(View.GONE) 都在更新UI 线程时有什么区别?

        final Thread thread = new Thread(new Runnable() {
        @Override
        public void run() {
            progressBar.setVisibility(View.INVISIBLE);
            textView.setVisibility(View.GONE);
        }
    });

更新

我知道INVISIBLEGONE 之间的区别。我的意思是为什么INVISIBLE 没有例外,同时它还触及另一个线程中的 UI 元素?

【问题讨论】:

  • 两者都不应该在另一个线程中使用。那个成功是纯粹的运气。
  • UI 元素的更新应始终在主线程上完成。
  • setVisibility(View.INVISIBLE) 只会使视图不可见。该视图仍然存在,只是不可见,如果您在其上放置一个 clicklistener,如果您单击该位置,它仍然可以工作,但 setVisibility(View.GONE); 只是使它好像没有视图没有 onclick 会起作用,如果您在此视图下方设置另一个视图,那么该视图将简单地上升,因为该视图不再存在
  • Android UI 更新需要在 MainThread 中完成。发布崩溃日志。

标签: android user-interface view invisible


【解决方案1】:

您只能从 UI 线程更改布局,因为 View.INVISIBLE 不会对视图的结构进行任何更改,因为 View 仍然存在,例如占用空间,而View.GONE 释放已用空间,这是层次结构的变化。

您可以使用runOnUiThread 修复它。

【讨论】:

    【解决方案2】:

    来自docs

    INVISIBLE : 这个视图是不可见的,但它仍然占用空间 布局目的。与 setVisibility(int) 和 android:visibility 一起使用。

    GONE : 这个视图是不可见的,它不占用任何空间 布局目的。与 setVisibility(int) 和 android:visibility 一起使用。

    所以如果你使用不可见的标志视图将被隐藏,但它占用的空间会在那里,如果你使用消失的标志视图将被隐藏并且它所占据的空间将会消失。

    另外,您正在从主线程以外的线程更改视图,因为主线程是唯一可以与 ui 元素交互的线程。

    【讨论】:

    • 为什么INVISIBLE没有异常,同时还触及其他线程的UI元素?
    【解决方案3】:

    好吧,在一种情况下,这个问题对我来说似乎是合理的。如果您运行以下代码:-

     @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_home);
        button=findViewById(R.id.btn1);
        new Thread(new Runnable() {
            @Override
            public void run() {
                button.setVisibility(View.INVISIBLE);
                Log.e("thread",Thread.currentThread().getName());
            }
        }).start();
    }
    

    它运行没有错误并将Button 的可见性设置为INVISIBLE。对于VISIBLE 和任何其他调用视图的操作,它将运行类似的操作。

    new Thread(new Runnable() {
            @Override
            public void run() {
                Log.e("thread",Thread.currentThread().getName());
                button.setText("Hi from "+Thread.currentThread().getName());
    
            }
        }).start();
    

    这也会运行。是的,它确实将当前线程打印为新线程:- E/thread: Thread-16.
    我认为原因是 View#post() 。 View 上的任何操作都应该在它在屏幕上绘制之后执行。在这种情况下,View 现在被绘制,但这就是为什么当前操作将推送主线程处理程序的消息队列。它会在绘制完成后运行(由于View#post()而在主线程上)没有任何错误。

    另一方面,如果您在某些事件单击按钮单击时调用它,则会抛出 Exception,因为视图已被绘制,它将直接在同一线程上调用操作,而不通过 Handler 发布它。

    希望我已经说得够清楚了。如果这个理论无论如何是错误的,请纠正我。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-12-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-10-15
      相关资源
      最近更新 更多