125

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

当我试图在主线程上运行动画时,它没有启动。当我使用运行所述动画时

getView().post(new Runnable() {
            @Override
            public void run() {
                getView().startAnimation(a);
            }
        });

它确实开始了。

我已经CurrentThread在开始动画之前打印了并且都打印了main

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

编辑:让我把事情弄清楚 - 我的问题是,为什么在 post 上启动动画会导致它启动,而在主线程上启动动画时却不会。

4

4 回答 4

169

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

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

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

getView().post(new Runnable() {

         @Override
         public void run() {
             getView().startAnimation(a);
         }
     });

代码getView().startAnimation(a);

在你的代码中,

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

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

[编辑 1]

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

用户界面线程:

  • 应用程序启动时,会自动创建 Ui Thread

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

  • 它也是您与 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);
}
});

用户界面冻结。该程序甚至可能崩溃。

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

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

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

  • Activity.runOnUiThread(可运行)
  • View.post(可运行)
  • View.postDelayed(可运行,长)
  • 处理程序

如下图,

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();
}

处理程序

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();                
}

在此处输入图像描述

欲了解更多信息

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

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

于 2012-12-12T12:56:46.843 回答
41

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

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

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

于 2014-10-22T15:54:46.973 回答
20

看看这里以获得一个好的答案。view.post() 与 handler.post() 几乎相同。它进入主线程队列并在其他待处理任务完成后执行。如果您调用 activity.runOnUiThread() ,它将立即在 UI 线程上调用。

于 2012-12-12T12:47:45.543 回答
5

我认为问题可能是您调用 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 线程中并且视图应该准备好开始动画了。

于 2016-11-15T06:09:00.903 回答