处理程序/可运行延迟有时会产生不同步的事件

2024-04-18

当尝试学习如何创建延迟时,我研究并发现主要答案是使用 Handler/Runnable/postDelayed。

                        Handler handler=new Handler();
                        final Runnable r = new Runnable()
                        {
                            public void run() 
                            {
                                delayedMethod();
                            }
                        };
                        handler.postDelayed(r, 1000);

一段时间以来,这工作得很好,但我又添加了一些正在进行的事情,现在它们有时会以错误的顺序发生。

本组活动:

画屏1()
...
延迟绘制屏幕2()
...
画屏3()

搞砸了(有时)并这样做:

画屏1()
...
画屏3()
...
延迟PaintScreen2()(最后运行并被paintScreen3的操作弄乱)

似乎没有另一种创建延迟的好方法 - 一种不创建线程的方法。

为了确保代码事件以正确的顺序运行,我尝试过的解决方案:

0 将主进程放在一个大的同步块中。

1 在主流程涉及的每个方法的方法名中放入synchronized关键字。

2 仅将synchronized关键字放在Runnable中的方法上。

3 去掉 Handler/Runnable/postdelayed 并替换为 handler.sendEmptyMessageDelayed(0,1000)

4 创建一个 Handler 实例变量,供每个 Handler/Runnable 块使用(而不是 Handler handler1、handler2、handler3 等)

5

                        Handler handler=new Handler();
                        final Runnable r = new Runnable()
                        {
                            public void run() 
                            {
                                waitOver = true;
                            }
                        };
                        handler.postDelayed(r, 1000);

                        while (waitOver == false) {

                        }
                        delayedMethod();
                        waitOver = false;

我的下一次尝试可能是尝试以某种方式使用 Thread 类,以便我可以调用 thread.join()。 我担心,如果失败了,接下来的事情将变得非常漫长和复杂。

有什么建议么?

有解决方案的简单示例吗?

Thanks

编辑:我可能对 Handler/Runnable 是否会导致文字线程感到困惑。

编辑:这是一个游戏。用户进行移动,屏幕更新以显示移动,计算告诉他们得分,重新为屏幕上的框着色,添加延迟以允许用户看到他们的点,然后调用方法来删除彩色方块,当该方法完成时,我们返回到调用它的方法(包含处理程序/可运行),代码继续向下调用另一个方法,导致棋盘的随机方块变成紫色。因此,应该发生用户移动、重新绘制以显示得分、延迟以便用户可以看到得分、重新绘制以擦除方块,然后发生随机紫色方块。有时会发生的情况(据我所知)是随机的紫色方块会在它应该执行之前执行,选择得分的方块之一,进行干扰,并使其清理方法变得混乱并且无法清理。

主要方法(){
...
如果(得分){
方块辉光();
...
//延迟,以便用户可以在清理发生之前看到发光
处理程序可运行
清理(​​);
后延迟
}
...
紫色方块();
}

我希望这不会更加令人困惑。 PurpleSquare 在清理之前运行,事情就搞砸了。

编辑: 尝试过这个: 6

                        CountDownLatch doneSignal = new CountDownLatch(1);
                        Handler handler=new Handler();
                        final LatchedRunnable lr = new LatchedRunnable(doneSignal);
                        handler.postDelayed(lr, COMPUTER_MOVE_DELAY);
                        try {
                            doneSignal.await();
                        } catch (InterruptedException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        }

                        class LatchedRunnable implements Runnable {
                            private final CountDownLatch doneSignal;

                            LatchedRunnable(CountDownLatch doneSignal) {
                                this.doneSignal = doneSignal;
                            }

                            public void run() {
                                 delayedProcess();
                                 doneSignal.countDown();                                                                                                                                                               
                            }
                        }    

7

                        ExecutorService executorService = Executors.newFixedThreadPool(5);
                        final CountDownLatch latch = new CountDownLatch(1);
                        executorService.execute(new Runnable() {
                            public void run() {
                                try {
                                    Looper.prepare();
                                    Handler handler=new Handler();
                                    final Runnable r = new Runnable()
                                    {
                                        public void run() 
                                        {
                                            delayedMethodCleanupCalc();
                                        }
                                    };
                                    handler.postDelayed(r, 4000);
                                } finally {
                                    latch.countDown();
                                }  
                            }
                        });
                        try {
                            latch.await();
                            delayedMethodPaintScreen();
                        } catch (InterruptedException e) {
                            // todo >> handle exception
                        }

PurpleSquare 在清理之前运行,事情搞砸了

mainmethod() {
...
if (pointscored) {
    squaresglow();
    ...
    //delay so user can see the glow before the cleanup happens
    Handler-runnable
        cleanup();
    postdelayed
}
...
purpleSquare();
} 

你这里有一个设计缺陷。将处理程序视为一个消息队列,每当处理器决定处理消息时,“稍后”就会执行代码,而 postDelayed 是将该消息填充到队列底部的不精确方式。如果您调用 postDelayed 并且当前方法中仍有代码行需要执行,那么这些代码行很可能会在收到 postDelayed 消息之前执行。

您要做的是确保在 pointscored 例程完成其工作后调用 PurpleSquare(),这可能需要等待它完成。在这种情况下,PostDelaying 到消息队列不是您应该做的。您应该使用的是信号量和 pointScored 线程。

考虑以下代码设计:

final Runnable pointScoredTask = new Runnable() {
    public synchronized void run() {
        try {
            squaresglow();
            //...
            Thread.sleep(2500); //2.5 sec before cleanup occurs
            cleanup();
        } catch (InterruptedException e) {
        }
        notify(); //make sure we call notify even if interrupted
    }
};
void mainmethod() {
    //...
    if (bPointWasScored) {
        synchronized (pointScoredTask) {
            try {
                Thread psThread = new Thread(pointScoredTask,"pointscored");
                psThread.start(); //thread will start to call run(), but we get control back to avoid race condition
                pointScoredTask.wait(6000); //wait no more than 6 sec for the notify() call
            } catch (InterruptedException e) {
            } 
        }
        //if a point was scored, nothing past this line will execute until scoreglow has been cleaned up 
    }
    //...
    purpleSquare();
    //...
}

我知道您宁愿避免使用线程,但有些东西在您使用它们时效果会更好。尝试上述设计,看看是否可以解决您遇到的同步问题。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

处理程序/可运行延迟有时会产生不同步的事件 的相关文章

  • Android自定义控件命名空间问题

    我一直在为 Android 开发自定义控件 尽管我尝试按照建议进行操作here https stackoverflow com questions 4495511 how to pass custom component parameter
  • BluetoothAdapter.getDefaultAdapter() 不返回 null

    这是我的第一篇文章 所以如果我做了一些愚蠢的事情 请告诉我 这个问题可能看起来与其他帖子类似 但或多或 少与我所看到的所有内容相反 关于该项目的事情 我正在开发 android 4 0 4 4 应用程序 我正在使用蓝牙 我正在运行 andr
  • 从 BroadcastReceiver 获取方法来更新 UI

    我正在尝试根据变量的变化更新用户界面BroadcastReceiver 因此 我需要调用一个扩展类的方法 以获取我提到的变量 BroadcastReceiver in MainActivity取决于但我无法以任何方式获得真正的返回值 扩展的
  • ListView:防止视图回收

    我有一个使用回收视图的 ListView 我试图阻止视图被回收 所以我使用 setHasTransientState android support v4 view ViewCompatJB setHasTransientState Vie
  • 游标索引越界异常

    打开后出现光标索引越界错误 数据库 请任何人告诉我如何打开现有数据库 sqllite Android 我想在数据库上触发一个选择查询 检索一些信息 public void getPatient SQLiteDatabase db Strin
  • 多语言 Android 应用程序:在电子邮件和密码字段中显示英文键盘

    我们正在开发一款多语言 Android 应用程序 针对英语和阿拉伯语 面临的问题是在登录和注册屏幕中 我们希望仅以英文文本输入用户名和密码字段 从而显示英文键盘 无论设备区域设置语言如何 已尝试在 edittext 中设置 inputtyp
  • 在后台服务中持续获取位置更新

    我正在开发需要在后台服务中持续获取位置更新的应用程序 我已经使用了它正在使用的后台粘性服务 但是 即使我添加了启动广播并在那里启动了服务 启动完成后服务也没有启动 服务启动并立即被杀死 另外 这不适用于奥利奥 服务在应用程序关闭几分钟后停止
  • 无法在云控制台中启用 Maps SDK for Android

    我在云控制台中启用适用于 Android 的 Maps SDK 时遇到此问题 https console cloud google com https console cloud google com 它会抛出以下错误 附截图 我收到错误消
  • 如何在android中画一条曲线?

    我是 Android 新手 正在开发一个关于绘制线条的示例项目 我想画一条连接两点的曲线或高架线 x1 y1 and x2 y2 我试过canvas drawArc 方法 但是RectF内的值drawArc方法只是圆的 x y 中心点 它在
  • 并行化斐波那契序列生成器

    我正在学习并行化 在一项练习中 我得到了一些我应该提高性能的算法 其中之一是斐波那契数列生成器 array 0 0 array 1 1 for q 2 q lt MAX q array q array q 1 array q 2 我怀疑 这
  • Android 消费品:“已经拥有该商品”,但 inventory.hasPurchase() 为 false

    我被 Google In App v3 困住了 我测试了一次没有消费的购买 例如 当应用程序在购买和消费之间崩溃时 现在我找不到出路 如果我尝试再次购买 它会显示 您已经拥有该商品 但是当我测试所有权时 它说我不拥有它 Inventory
  • 一段时间后终止线程的最 Pythonic 方法

    我想在线程中运行一个进程 它正在迭代一个大型数据库表 当线程运行时 我只想让程序等待 如果该线程花费的时间超过 30 秒 我想终止该线程并执行其他操作 通过终止线程 我的意思是我希望它停止活动并优雅地释放资源 我认为最好的方法是通过Thre
  • Android httpclient文件上传数据损坏和超时问题

    我在 Android 中上传图像时遇到问题 我正在使用 apache httpmime 4 1 lib 代码是这样的 MultipartEntity reqEntity new MultipartEntity HttpMultipartMo
  • 如何在Android网格视图中设置单元格大小?

    我正在尝试为应用程序制作一个带有大图标的网格视图 但我找不到任何有关修改 Android 上网格布局上的单元格大小的教程 有人可以给我一个例子或相关链接吗 Thanks 就像另一个一样适配器视图 http developer android
  • Android Drawable 绘图性能?

    在我看来 我有一个简单的 ARGB 可绘制对象 大约需要 2 毫秒才能绘制 但我可以在 0 5 毫秒内绘制与位图相同的文件 只是一些快速代码 我真的不能认为它是一个选项 优化可绘制对象的绘制速度的最佳方法是什么 这取决于可绘制的数量以及每个
  • 将 Crashlytics 集成到图书馆项目

    我有一个图书馆项目 自定义视图库项目 它没有任何活动 服务 我想将 Crashlytics SDK 集成到我的库中 当我尝试通过 Android Studio 的 Crashlytics 插件 工具栏中的图标 添加它时 它只是停留在 Che
  • 如何通过 AppCompatActivity 使用 YouTube Android 播放器 API

    为了在我的应用程序中播放视频 我决定扩展 YouTube Android Player API 但问题是我的菜单消失了 因为我没有从 AppCompatActivity 扩展 问题是 如何使用 YouTube Android Player
  • 改造方法调用可能会产生“java.lang.NullPointerException”

    使用 Retrofit 2 3 0 我在 Android Studio 中收到以下消息 有关如何删除此 IDE 错误消息的任何建议 谢谢 来自Response文档 http square github io retrofit 2 x ret
  • 在android中使用BaseActivity的不同活动中的通用标头

    我想编写一次代码并在不同的活动中使用 我创建了一个Base Activity class为了那个原因 此外 不同活动中所有布局的标题都是相同的 我在以下人员的帮助下做到了这一点
  • 如何检查设备上是否安装了文本转语音 (TTS) 的特定语言数据?

    我正在创建一个使用文本转语音的应用程序 我希望用户能够离线使用它 因此我检查设备上是否安装了 TTS 数据 以下是执行此操作的代码 Check tts data is installed Intent checkTTSIntent new

随机推荐