Runnable已成功发布但未运行

在一个现有的Android项目中,我遇到了下面这段代码(我插入了debugging垃圾)

ImageView img = null; public void onCreate(...) { img = (ImageView)findViewById(R.id.image); new Thread() { public void run() { final Bitmap bmp = BitmapFactory.decodeFile("/sdcard/someImage.jpg"); System.out.println("bitmap: "+bmp.toString()+" img: "+img.toString()); if ( !img.post(new Runnable() { public void run() { System.out.println("setting bitmap..."); img.setImageBitmap(bmp); System.out.println("bitmap set."); } }) ) System.out.println("Runnable won't run!"); System.out.println("runnable posted"); } }.start(); 

刚刚开始Android开发,我已经了解到这是在不阻塞主(UI)线程的情况下执行内容的方式,同时在解码之后仍然在UI线程上设置图像。 (至less根据android开发人员) (我已通过在各个地方loggingThread.currentThread().getName()validation)

现在有时图像不显示,标准输出只是说

 I/System.out( 8066): bitmap: android.graphics.Bitmap@432f3ee8 img: android.widget.ImageView@4339d698 I/System.out( 8066): runnable posted 

没有来自Runnable的消息的痕迹。 所以显然Runnable不run() ,虽然img.post()返回true 。 在onCreate()拉取ImageView并声明它是没有帮助的。

我无能为力 直接设置位图,而阻止UI线程,确实解决了一些问题,但我想把事情做好。 有人明白这里发生了什么事吗?

(PS。这是在Android 1.6手机和android-3 sdk上观察到的)

Solutions Collecting From Web of "Runnable已成功发布但未运行"

如果你看看View.post的文档,有一些相关的信息:

仅当此视图附加到窗口时,才能从UI线程之外调用此方法。

由于你在onCreate这样做,有时候你的View可能不会被粘贴到窗口上。 您可以通过覆盖onAttachedToWindow并在日志中添加内容并logging您的日志来validation。 你会看到,当post失败时,post调用发生在onAttachedToWindow之前。

正如其他人提到的,你可以使用Activity.runOnUiThread或提供你自己的处理程序。 然而,如果你想直接从View本身,你可以简单地得到View的处理程序:

 view.getHandler().post(...); 

如果您有一个包含某种背景加载的自定义视图,这是特别有用的。 还有不必创build一个新的单独的处理程序的额外的好处。

我扩展了ImageView类来解决这个问题。 我收集传递给过onAttachedToWindow视图不附加到窗口,并在onAttachedToWindow后收集可运行。

 public class ImageView extends android.widget.ImageView { List<Runnable> postQueue = new ArrayList<Runnable>(); boolean attached; public ImageView(Context context) { super(context); } public ImageView(Context context, AttributeSet attrs) { super(context, attrs); } public ImageView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } @Override protected void onAttachedToWindow() { super.onAttachedToWindow(); attached = true; for (Iterator<Runnable> posts = postQueue.iterator(); posts.hasNext();) { super.post(posts.next()); posts.remove(); } } @Override protected void onDetachedFromWindow() { attached = false; super.onDetachedFromWindow(); } @Override public boolean post(Runnable action) { if (attached) return super.post(action); else postQueue.add(action); return true; } } 

我认为问题是你正在更新UI(ImageView)与一个单独的线程,这不是UI线程。 UI只能由UI线程更新。

你可以使用Handler来解决这个问题:

 Handler uiHandler; public void onCreate(){ ... uiHandler = new Handler(); // This makes the handler attached to UI Thread ... } 

然后replace你的:

 if ( !img.post(new Runnable() { 

 uiHandler.post(new Runnable() { 

以确保在UI线程中更新imageview。

处理程序是一个相当混乱的概念,我也花了几个小时的研究来真正理解这个;)

我没有看到你有什么明显的错误, 调用View.post()应该使它在UI线程上运行。 如果您的活动消失了(也许通过屏幕旋转),那么您的ImageView将不会被更新,但我仍然期望一个日志条目说“设置位图…”,即使你看不到它。

我build议尝试下面,看看它是否有所作为:

1)使用Log.d(标准Androidlogging器)而不是System.out

2)将你的Runnable传递给Activity.runOnUiThread()而不是View.post()

使用下面的代码,可以随时随地将代码发布到MainThread,但不取决于任何ContextActivity 。 这可以防止view.getHandler()失败或繁琐onAttachedToWindow()东西等

  new Handler(Looper.getMainLooper()).post(new Runnable() { @Override public void run() { //TODO } }); 

我有同样的问题,并使用view.getHandler()也失败,因为处理程序不存在。 runOnUiThread()解决了这个问题。 据推测,这实际上是做一些排队,直到UI准备就绪。

我的原因是在基类中调用图标加载任务,并且返回的结果太快,以至于主类没有build立视图(片段中的getView())。

我有点怀疑它可能虚假地失败。 但我现在准备好了! 多谢你们。