post方法究竟做了什么?

Gal*_*Gal 95 android

我遇到了一个非常奇怪的功能.

当我试图在主线程上运行动画时,它不会启动.当我使用运行所述动画

getView().post(new Runnable() {
            @Override
            public void run() {
                getView().startAnimation(a);
            }
        });
Run Code Online (Sandbox Code Playgroud)

它确实开始了.

CurrentThread在开始动画之前打印过并打印出来main.

显然,我在这里遗漏了一些东西,因为两者都应该在主线程上启动动画......我的猜测是,当post将任务添加到队列中时,它会在更"正确的时间"开始,但我很想知道这里发生的事情更深入.

编辑:让我清楚一点 - 我的问题是,为什么在帖子上启动动画会导致它启动,当在主线程上启动动画时没有.

Tal*_*lha 150

post:post导致Runnable被添加到消息队列中

Runnable:表示可以执行的命令.通常用于在不同的Thread中运行代码.

run() :开始执行类'代码的活动部分.当启动一个使用实现Runnable的类创建的线程时,将调用此方法.

getView().post(new Runnable() {

         @Override
         public void run() {
             getView().startAnimation(a);
         }
     });
Run Code Online (Sandbox Code Playgroud)

代码:getView().startAnimation(a);

在你的代码中,

post导致Runnable(代码将在不同的线程中运行)添加消息队列.

因此,当从messageQueue获取startAnimation时,将在新线程中触发startAnimation

[编辑1]

为什么我们使用新线程而不是UI线程(主线程)?

UI线程:

  • 启动应用程序时,将自动创建Ui线程

  • 它负责将事件分派给适当的小部件,这包括绘图事件.

  • 它也是您与Android小部件交互的线程

例如,如果触摸屏幕上的a按钮,UI线程会将触摸事件调度到窗口小部件,窗口小部件又设置其按下状态并将无效请求发布到事件队列.UI线程将请求出列并通知窗口小部件重绘自身.

如果用户按下将执行longOperation的按钮会发生什么?

((Button)findViewById(R.id.Button1)).setOnClickListener(           
             new OnClickListener() {        
        @Override
    public void onClick(View v) {
            final Bitmap b = loadImageFromNetwork();
            mImageView.setImageBitmap(b);
}
});
Run Code Online (Sandbox Code Playgroud)

用户界面冻结了.该计划甚至可能会崩溃.

public void onClick(View v) {
  new Thread(new Runnable() {
    public void run() {
        final Bitmap b = loadImageFromNetwork();
        mImageView.setImageBitmap(b);
    }
  }).start();
}
Run Code Online (Sandbox Code Playgroud)

它打破了永远不会直接从工作线程更新UI的android规则

Android提供了几种从其他线程访问UI线程的方法.

  • Activity.runOnUiThread(可运行)
  • View.post(可运行)
  • View.postDelayed(Runnable,long)
  • 处理器

如下,

View.post(可运行)

public void onClick(View v) {
  new Thread(new Runnable() {
    public void run() {
      final Bitmap b = loadImageFromNetwork();
      mImageView.post(new Runnable() {
        public void run() {
          mImageView.setImageBitmap(b);
        }
      });
    }
  }).start();
}
Run Code Online (Sandbox Code Playgroud)

处理器

final Handler myHandler = new Handler(Looper.getMainLooper());

(new Thread(new Runnable() {

    @Override
    public void run() {
       final Bitmap b = loadImageFromNetwork();
      myHandler.post(new Runnable() {                           

        @Override
        public void run() {
           mImageView.setImageBitmap(b);
          }
        });
      }
    })).start();                
}
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

有关更多信息

http://android-developers.blogspot.com/2009/05/painless-threading.html

http://www.aviyehuda.com/blog/2010/12/20/android-multithreading-in-a-ui-environment/

  • 那么为什么在post上启动动画与在主线程上运行动画不同,当它们最终都在同一个线程上运行时? (14认同)
  • 我不认为这回答了这个问题,对于那些对ui-thread和多线程一无所知的初学者来说,这更像是一个通用的答案.这并没有解释为什么在队列中向前抛出动画会使动画工作; 动画应该是直接在ui线程中执行的东西,而不使用任何post()或runOnUiThread()技巧. (13认同)
  • 性能不佳与不显示动画有什么关系? (3认同)
  • 所有UI工作都应在主线程(UI线程)上。通过使用post()而不是立即在主线程中调用来使动画起作用的技巧是时间:如果立即在主线程中调用,则意味着您告诉“立即开始动画”,但是此时可能是视图尚未准备好用于动画(测量,绘制...)。但是,如果将其放在post()中,它将在某个时候将队列中的startAnimation挂起,以准备为动画准备的视图。 (2认同)

Joe*_*nte 24

这是在onCreate还是onCreateView上完成的?如果是这样,应用程序可能不处于视图附加到窗口的状态.许多基于View指标的算法可能无效,因为可能尚未计算View的测量值和位置等.Android动画通常要求它们通过UI数学运行

View.post实际上是在View的消息循环中对动画进行排队,因此一旦视图附加到窗口,它就会执行动画而不是手动执行.

您实际上是在UI线程上运行,但是在不同的时间运行

  • 接受的答案具有误导性,其中海报指出“发布导致可运行(代码将在不同的线程中运行)”。这是正确的答案“你实际上是在 UI 线程上运行东西,但在不同的时间” - 加 1 (3认同)

Tas*_*orf 17

看看这里有一个很好的答案.view.post()与handler.post()非常相似.它进入主线程队列并在其他待处理任务完成后执行.如果调用activity.runOnUiThread(),它将立即在UI线程上调用.

  • 我发现的一个巨大(并且非常有用)的差异是view.post()中的runnable将在首次显示View时被调用.IE,您可以将其设置为在View膨胀后开始动画,然后在将来的某个时刻,最后将其添加到视图层次结构中.此时,动画将执行,您不必担心它. (31认同)

car*_*izo 6

我认为问题可能是您调用 post() 方法的生命周期方法。你是在onCreate()中做的吗?如果是这样,请查看我在活动的 onResume() 文档中找到的内容:

onResume()

在 API 级别 1 中添加 void onResume () 在 onRestoreInstanceState(Bundle)、onRestart() 或 onPause() 之后调用,以便您的 Activity 开始与用户交互。这是开始动画、打开独占访问设备(例如相机)等的好地方。

https://developer.android.com/reference/android/app/Activity.html#onResume()

因此,正如 Joe Plante 所说,也许在调用 post() 时视图还没有准备好启动动画,因此请尝试将其移至 onResume()。

PD:实际上,如果您确实将代码移至 onResume() 那么我认为您可以删除 post() 调用,因为您已经在 ui 线程中并且视图应该准备好启动动画。

  • 在最初“视图准备就绪”之后,`onResume` 可能会被多次调用(屏幕进入睡眠状态、活动推送到后台堆栈等)。如果从“onResume”调用,则可能需要一个标志来跟踪动画已经开始的天气,以避免多次(重新)启动。 (3认同)