运行不同的线程不允许显示活动

Posted

技术标签:

【中文标题】运行不同的线程不允许显示活动【英文标题】:Running a different thread does not allow the activity to be displayed 【发布时间】:2020-12-14 13:30:56 【问题描述】:

我有这个活动:

public class ResultActivity extends AppCompatActivity implements ResultListener 
    private String code = "";
    private String data = "";

    @Override
    protected void onCreate(Bundle savedInstanceState) 
        try 
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_result);

            code = intent.getStringExtra("code");
            data = intent.getStringExtra("data");

            MyExternal.DecodeAndSend(this, code, data);
        
        catch (Exception e)
        
            e.printStackTrace();
        
    

其中MyExternal 是其他库中的类。

DecodeAndSend 的方法是这样的:

public static boolean DecodeAndSend(ResultListener caller, String codigo, String data)

    try 
        ExecutorService pool = Executors.newFixedThreadPool(1);

        HashMap<String,String> arguments = new HashMap<>();

        Future<String> resultado = pool.submit(new ServerConnection(caller, url, arguments));

        String status = resultado.get();
        if (status.equals("OK"))
            caller.OnSuccess();
        else
            caller.OnError(status);

        pool.shutdown();

        return true;
     catch (IOException e) 
        e.printStackTrace();
     catch (InterruptedException e) 
        e.printStackTrace();
     catch (ExecutionException e) 
        e.printStackTrace();
    

    return false;

最后,ServerConnection 类实现了Callable&lt;String&gt;,所以我向您展示了call 方法:

@Override
public String call() throws Exception 
    Thread.sleep(2000);
    

    return "OK";

Thread.sleep(2000); 的调用实际上是对Web 服务器的调用以发送一些数据。

问题是ResultActivity 直到call 调用返回时才显示其布局。

这段代码缺少什么?

【问题讨论】:

【参考方案1】:

DecodeAndSend 从主线程调用。它调用 Future.get() 等待作业完成,因此它阻塞了主线程。您也应该从后台线程调用此方法。我认为可以将它发送到同一个线程池,因为它是在它等待的第一个作业之后提交的。

你不能从这个方法返回任何关于请求结果的信息,因为它是异步的。

public static void DecodeAndSend(ResultListener caller, String codigo, String data)

    ExecutorService pool = Executors.newFixedThreadPool(1);

    HashMap<String,String> arguments = new HashMap<>();

    Future<String> resultado = pool.submit(new ServerConnection(caller, url, arguments));

    pool.submit(new Runnable() 
        public void run () 
            try 
                String status = resultado.get();
                if (status.equals("OK"))
                    caller.OnSuccess();
                else
                    caller.OnError(status);

                pool.shutdown();
                return;
             catch (IOException e) 
                e.printStackTrace();
             catch (InterruptedException e) 
                e.printStackTrace();
             catch (ExecutionException e) 
                e.printStackTrace();
            
            caller.OnError(null); // No status, only an exception
    );

但是,您的 ServerConnection 类已经采用了 caller 参数,因此它可能应该只处理回调本身。根据您在回调中所做的事情,您可能希望将回调调用发布到主线程。

顺便说一下,Java 中的约定是始终以小写字母(驼峰式)开头的方法名称。

【讨论】:

如果我使用ServerConnection里面的caller来通知任务的状态,我在哪里可以调用pool.shutdown?附言我来自 C# 世界,即使 C# 也使用驼峰式大小写作为标准,方法名称也应该以大写开头。我将更改所有方法名称以遵循 Java 约定。 您可以在pool.submit() 调用之后立即调用它。调用shutDown() 后,已提交的作业仍然运行完成。 (我也使用 C#。使用多种语言的一个令人讨厌的事情是这种约定的差异。我个人更喜欢 Java 方式,因为它使函数在声明站点和调用站点都更好地从构造函数中脱颖而出。)跨度> 【参考方案2】:

Feature.get() 是一个阻塞调用。 UI 线程在等待该调用返回时被阻塞,因此无法处理您的布局。尝试将结果侦听器传递给 ResultListenerServerConnection 并使用这两个回调来相应地更新您的 UI

【讨论】:

【参考方案3】:

Future.get() 是 blocking call - 执行停止,直到结果到达

只有在计算完成后才能使用 get 方法检索结果,必要时阻塞直到它准备好。

所以你的ActivityonCreate 方法调用了那个东西,然后阻塞直到call(它在另一个线程上运行)返回它的结果。所以onCreate没有完成,布局也没有完成。

如果您想使用该阻塞代码,但在视图布局之后,我会使用 Activity lifecycle 的另一部分,例如 onStart(设置一个标志,以便您只运行一次!)。否则,您将需要使用其他一些并发技术来获取结果并使用它。这取决于您对call 函数结果的实际操作

【讨论】:

以上是关于运行不同的线程不允许显示活动的主要内容,如果未能解决你的问题,请参考以下文章

浏览器禁用了javascript致使网页显示不正常怎么办

安卓系统的开发人员选项中的“不保留活动”,和“后台进程限制”中的“不允许后台进程”或“只允许一个后

来自实体框架的 SqlException - 不允许新事务,因为会话中正在运行其他线程

来自实体框架的 SqlException - 不允许新事务,因为会话中正在运行其他线程

如何更改图像并在 5 秒后重新运行线程中的主要活动后不回到 android 中的基本布局

python:如果后台线程处于活动状态,则不会运行weakref.finalize