简体   繁体   English

如何从另一个线程返回字符串?

[英]How to return a string from another thread?

I want to return a String "finalurl" from another thread, like this: 我想从另一个线程返回一个字符串“ finalurl”,如下所示:

public String getImageURL(String url) {

    final String finalUrl = url;

    Thread t1 = new Thread(new Runnable() {
        public void run() {
            Document doc = null;
            try {
                doc = Jsoup.connect(finalUrl).get();
            } catch (IOException e) {
                e.printStackTrace();
            }
            Element masthead = doc.select("div.post-image").select("img[src~=(?i)\\.(png|jpe?g)]").first();
            finalUrl = masthead.absUrl("src");
        }
    });

    t1.start();
    return finalUrl;
}

But it does not work. 但这行不通。 How to make it correctly? 如何正确制作?

 return finalUrl;

This code will never return string, that you want. 此代码将永远不会返回您想要的字符串。

You need to fix your logic by one of a lot techiques. 您需要通过多种技术之一来修正逻辑。 The easiest way for you is using handler. 最简单的方法是使用处理程序。 Like this: 像这样:

private static final int URL_MESSAGE = 1;

private final Handler handler = new Handler(Looper.getMainLooper()) {

    @Override
    public void handleMessage(Message message) {
        super.handleMessage(message);
        if (message.arg1 == URL_MESSAGE) {
            final Object obj = message.obj;

            if (obj instanceof String) {
                String url = (String) obj;
            }
        }
    }
};

private final Runnable runnable = new Runnable() {
    public void run() {
        Document doc = null;
        try {
            doc = Jsoup.connect(finalUrl).get();
        } catch (IOException e) {
            e.printStackTrace();
        }
        Element masthead = doc.select("div.post-image").select("img[src~=(?i)\\.(png|jpe?g)]").first();
        String finalUrl = masthead.absUrl("src");

        Message message = new Message();
        message.arg1 = URL_MESSAGE;
        message.obj = finalUrl;
        handler.sendMessage(message);
    }
};

@Override
protected void onDestroy() {
    super.onDestroy();
    handler.removeCallbacks(runnable);
}

private void execute() {
    handler.post(runnable);
}

For such need what you should do is rather: 对于这种需求,您应该做的是:

  1. Create a thread pool 创建一个线程池
  2. Submit your task as a Callable to the thread pool 将您的任务作为Callable提交到线程池
  3. Get the result 得到结果

Create your thread pool using Executors like this for example: 例如,使用这样的Executors创建线程池:

// Create a thread pool composed of only four threads in this case
private final ExecutorService executor = Executors.newFixedThreadPool(4);

Submit your task as a Callable Callable提交您的任务

final Future<String> future = executor.submit(new Callable<String>() {
    @Override
    public String call() throws Exception {
        Document doc = Jsoup.connect(url).get();
        Element masthead = doc.select("div.post-image")
            .select("img[src~=(?i)\\.(png|jpe?g)]").first();
        return masthead.absUrl("src");
    }
});

Get the result 得到结果

try {
    return future.get();
} catch (InterruptedException e) {
    Thread.currentThread().interrupt();
    throw new RuntimeException(e);
} catch (ExecutionException e) {
    throw new RuntimeException(e);
}

NB: The thread pool must not be created at each call, it must be created once for all in your class in order to reuse it at each call. 注意:不能在每次调用时都创建线程池,必须在类中为所有线程一次创建线程池,以便在每次调用时重用线程池。

You haven't made it exactly clear what you are trying to do, but I'm pretty sure you wouldn't want your getImageURL(url) to return until it's got a url. 您尚未完全清楚要执行的操作,但是我很确定您不希望getImageURL(url)返回,直到获得URL。

The right way to do that is to not use a thread . 正确的方法是不使用线程

public String getImageURL(String url) {
    Document doc = null;
    try {
        doc = Jsoup.connect(finalUrl).get();
    } catch (IOException e) {
        throw new RuntimeException(e);
    }
    Element masthead = doc.select("div.post-image").select("img[src~=(?i)\\.(png|jpe?g)]").first();
    return masthead.absUrl("src");
}

If there's some reason why you think you need to use a thread here, then you should ask again in another question, and explain in more detail what you're trying to do and why you want to do it. 如果出于某种原因您认为需要在此处使用线程,则应在另一个问题中再次提出问题,并详细说明您要做什么以及为什么要这样做。


Error says: "06-18 21:22:12.701 7816-7816/pl.dariusz.app I/Choreographer: Skipped 39 frames! The application may be doing too much work on its main thread." 错误说:“ 06-18 21:22:12.701 7816-7816 / pl.dariusz.app I / Choreographer:跳过了39帧!该应用程序可能在其主线程上做太多工作。”

OK, that error doesn't literally mean that the application did too much work in one thread. 好的,该错误并不表示该应用程序在一个线程中做了太多工作。 It means that the GUI called one of your handler functions, and too much time elapsed before the handler returned. 这意味着GUI调用了您的处理程序功能之一,并且在处理程序返回之前已经花费了太多时间

If your event handler functions don't promptly return, it will prevent your application from promptly responding to whatever the user does next. 如果您的事件处理函数未及时返回,则将阻止您的应用程序立即响应用户的下一步操作。 That's what the error message really is trying to tell you. 这就是错误消息实际上试图告诉您的内容。

You can't fix it by doing the "work" in some other thread if your handler still has to wait for the work to be done before it returns. 如果处理程序在返回之前仍然需要等待工作完成,则无法通过在其他线程中执行“工作”来修复该问题。 It's the time that matters. 现在是时候了。

The way to fix that kind of problem is: 解决此类问题的方法是:

  • Your handler puts the GUI in to some kind of state that tells the user, I'm waiting for whatever, 您的处理程序将GUI置于某种状态,告诉用户我正在等待任何东西,

  • Then your handler kicks off a background task that will wait for whatever, (Note: I'm not an Android programmer, but I'm pretty certain that there's a better way to kick off the task than creating a new, naked Thread object.) 然后,您的处理程序启动一个将等待任何内容的后台任务,(注:我不是Android程序员,但是我可以肯定,比创建一个新的裸Thread对象有更好的启动方法。 )

  • Then your handler returns, 然后您的处理程序返回,

  • Your background task runs in some other thread doing something like Jsoup.connect(finalUrl).get(); 您的后台任务在其他线程中运行,执行类似Jsoup.connect(finalUrl).get();

  • Meanwhile, if the user clicks on something, your application can still respond to the user input, even if it's only to pop up a message that says, "not now, I'm still waiting for whatever." 同时,即使用户单击某项,您的应用程序仍可以响应用户输入,即使只是弹出一条消息,即“现在不行,我仍在等待任何内容”。

  • Finally, your background task completes, and it posts and event to the application's event queue (I'm still not an Android programmer, so I don't actually know what method you call to do that) that will update the UI state to show that whatever finally has happened. 最后,您的后台任务完成,并将事件发布到应用程序的事件队列中(我仍然不是Android程序员,所以我实际上不知道您要使用的方法)来更新UI状态以显示不管最终发生了什么。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM