java Runnable 已成功发布但未运行

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4083787/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-30 04:42:12  来源:igfitidea点击:

Runnable is posted successfully but not run

javaandroidmultithreadingrunnable

提问by mvds

In an existing Android project I've encountered the following piece of code (where I inserted the debugging litter)

在现有的 Android 项目中,我遇到了以下代码段(我在其中插入了调试垃圾)

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

New to Android development, and having googled around, I understand that this is the way to do stuff without blocking the main (UI) thread, while still setting the image on the UI thread after decoding. (at least according to android-developers)(which I have verified by logging Thread.currentThread().getName()at various places)

刚接触 Android 开发,并在 google 周围搜索,我明白这是在不阻塞主(UI)线程的情况下做事情的方法,同时在解码后仍然在 UI 线程上设置图像。(至少根据 android-developers 的说法)(我已经通过Thread.currentThread().getName()在各个地方登录进行了验证)

Now sometimesthe image just doesn't show up, and stdout only says

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

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

with not a trace of the messages from the Runnable. So appearantly the Runnable doesn't run(), although img.post()returns true. Pulling the ImageView in onCreate()and declaring it finaldoesn't help.

没有来自 Runnable 的消息的踪迹。所以看起来 Runnable 没有run(),虽然img.post()返回true。拉入 ImageViewonCreate()并声明它final没有帮助。

I'm clueless. Simply setting the bitmap directly, while blocking the UI thread, does fix things, but I want to get things right. Does anybody understand what's going on here?

我一窍不通 简单地直接设置位图,同时阻塞 UI 线程,确实可以解决问题,但我想把事情做好。有人明白这里发生了什么吗?

(ps. this was all observed on an Android 1.6 phone and android-3 sdk)

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

回答by kabuko

If you look at the docs for View.postthere's some relevant info:

如果您查看文档以获取View.post一些相关信息:

This method can be invoked from outside of the UI thread only when this View is attached to a window.

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

Since you're doing this in onCreate, it is likely that sometimes your Viewwill not be attached to the window yet. You can verify this by overriding onAttachedToWindowand putting something in the logs and also logging when you post. You'll see that when the post fails, the post call happens before onAttachedToWindow.

由于您在 中执行此操作onCreate,因此有时您View可能还没有附加到窗口。您可以通过覆盖onAttachedToWindow并将某些内容放入日志并在发布时进行记录来验证这一点。你会看到当 post 失败时,post 调用发生在onAttachedToWindow.

As the others have mentioned, you can use Activity.runOnUiThreador provide your own handler. However, if you want to do it directly from the Viewitself, you can simply get the View's handler:

正如其他人提到的,您可以使用Activity.runOnUiThread或提供自己的处理程序。但是,如果您想直接从其View本身执行此操作,则可以简单地获取View的处理程序:

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

This is especially useful if you have a custom view that includes some sort of background loading. There's also the added bonus of not having to create a new separate handler.

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

回答by Nik

I extended ImageViewclass to solve this problem. I collect runnables passed to post while view not attached to window and in onAttachedToWindowpost collected runnable.

我扩展了ImageView类来解决这个问题。我收集传递给帖子的可运行对象,而视图未附加到窗口和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;
    }
}

回答by xandy

I think the problem is you are updating the UI (ImageView) with a separate thread, which is not the UI Thread. The UI can only be updated by the UI Thread.

我认为问题在于您正在使用单独的线程更新 UI(ImageView),该线程不是 UI 线程。UI 只能由 UI 线程更新。

You can solve this by using Handler:

您可以通过使用Handler来解决这个问题:

Handler uiHandler;

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

Then replace your:

然后替换你的:

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

with

uiHandler.post(new Runnable() {

to make sure the imageview is updated in the UI Thread.

确保图像视图在 UI 线程中更新。

Handler is a quite confusing concept, I also took hours of research to really understand about this ;)

Handler 是一个非常令人困惑的概念,我也花了数小时的时间来真正理解这一点;)

回答by Shawn Lauzon

I don't see anything obviously wrong with what you have there; calling View.post() should cause it to run on the UI thread. If your Activity went away (perhaps through a screen rotation), then your ImageView wouldn't be updated, but I would still expect a log entry to say "setting bitmap ...", even if you couldn't see it.

我看不出你那里的东西有什么明显的问题。调用 View.post() 应该使它在 UI 线程上运行。如果您的 Activity 消失(可能是通过屏幕旋转),那么您的 ImageView 将不会更新,但我仍然希望日志条目显示“设置位图...”,即使您看不到它。

I suggest trying the following and see if it makes a difference:

我建议尝试以下操作,看看它是否有所作为:

1) Use Log.d (the standard Android logger) rather that System.out

1) 使用 Log.d(标准的 Android 记录器)而不是 System.out

2) Pass your Runnable to Activity.runOnUiThread() rather than View.post()

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

回答by fantouch

Use the following code, can post your code to MainThread anytime anywhere, but not depends any Contextor Activity. That can prevent view.getHandler()failure or tedious onAttachedToWindow()stuffs etc.

使用以下代码,可以随时随地将代码发布到 MainThread,但不依赖于 anyContextActivity. 这可以防止view.getHandler()失败或乏味的onAttachedToWindow()东西等。

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

回答by Ratatat Richie

I had the same problem, and using view.getHandler() also failed because the handler was not present. runOnUiThread() solved the problem. Presumably this does actually do some queueing until the UI is ready.

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

The cause for me was calling the icon load task in a base class and the result being returned so quickly that the main class hadnt estabished the view (getView() in fragment).

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

I'm a bit suspicious that it might spuriously fail sometime. But I'm now ready for it! Thanks guys.

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