【问题标题】:Android - Stopping/Killing Asynctask after N seconds then calling another AsynctaskAndroid - N 秒后停止/终止 Asynctask,然后调用另一个 Asynctask
【发布时间】:2015-12-10 13:05:03
【问题描述】:

我制作了一个 Android 应用程序,该应用程序通过 Asynctask 向服务器进行身份验证,该任务在用户按钮单击时在后台执行此操作。发生这种情况时,会向用户显示加载弹出窗口或微调器。这一切目前都在工作。

我现在正试图通过设置另一台服务器来创建冗余,以防第一台服务器出现故障。为了适应我的应用程序的这种变化,我想让 2 个异步任务一个接一个地调用。

但是,我遇到了一些问题。

作为测试 url,我一直在使用 10.255.255.1(不可路由的地址)和 www.google.com:81(阻塞的端口,丢弃的数据包)。

  1. 如果服务器 1 没有响应或需要很长时间(使用上面的 url 进行测试),我会尝试在 asynctask 上设置一个计时器 5-10 秒,我尝试过使用

    new MyAsyncTask().execute(serverurl1).get(5000, TimeUnit.MILLISECONDS);
    

    没有用。奇怪的是,它在显示微调器之前等待了 5 秒,然后正常运行(永远等待超过 5 甚至 10 秒标记)。

  2. 我想这第二个问题取决于第一个问题,但是在创建第二个异步任务以查询服务器 2 之前,我如何确保第一个异步任务已完成(或已执行并超过时间限制)?我想我可以使用 STATUS.running (但只有在确保第一个异步任务已经运行之后?

    对于这个,我尝试了 2 个异步任务,如下所示:

    new MyAsyncTask().execute(serverurl1);
    new MyAsyncTask().execute(serverurl2);
    

    希望射出 2 个异步任务能让我得到某种回应。即使 1 失败了,我们仍然可以通过身份验证,但是很遗憾,它不起作用。

我知道你们中的一些人可能会说,通过序列化 asynctask 的行为,它就违背了它的目的。当应用程序与服务器进行自我检查时,我使用它在屏幕上显示微调器。

问题:

  • 如果异步任务被计时器或其他事物停止/杀死,是否仍会调用 onPostExecute?我想知道如果 总是 调用第二个异步任务,这是否是放置第二个异步任务的好地方。

我理想的解决方案是:

  • 用户点击按钮

  • asynctask 1 使用服务器 1 运行和查询

  • 如果出现问题,asynctask 1 在计时器用完后被杀死

  • asynctask 2 然后运行查询服务器 2

  • 如果出现问题,asynctask 2 在计时器用完后被杀死

  • (没有永远运行的进程并显示清除错误消息)

  • 用户点击按钮

  • asynctask 1 使用服务器 1 运行和查询

  • 如果出现问题,asynctask 1 在计时器用完后被杀死

  • 然后通知用户重试(内部设置标志以查询服务器 2)

  • 用户再次点击按钮

  • asynctask 2 然后运行查询服务器 2

  • 如果出现问题,asynctask 2 在计时器用完后被杀死

  • (同样,没有永远运行的进程并显示清除错误消息)

谢谢。

我使用以下方法调用异步块:

private void startTask() throws IOException {
    String url = "http://google.com:81";    
    //String url = "http://10.255.255.1";
    String url2 = "someurlthatworks";   

    // tried this
    new MyAsyncTask().execute(url);
    new MyAsyncTask().execute(url2);

    // and this
    try {
        new MyAsyncTask().execute(url).get(5000, TimeUnit.MILLISECONDS);
    }catch(Exception e){}
}

我在How can I put a timer in an AsyncTask without creating another thread? 看到了这个(用我的变量编辑):

final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
    public void run() {
        new MyAsyncTask.execute(url);
    }
}, 5000);

它对我的问题有用吗?

这是我的异步任务代码块: 类 MyAsyncTask 扩展 AsyncTask {

@Override
protected void onPreExecute() {                                                 
    super.onPreExecute();                                                       
    showDialog(DIALOG_DOWNLOAD_PROGRESS);                                       
}

@Override
protected String doInBackground(String... urls) {                               
    int count;                                                                  
    InputStream input = null;                                                   
    HttpURLConnection httpconnection = null;                                    

    try {
        URL url = new URL(urls[0]);                                             

        httpconnection = (HttpURLConnection) url.openConnection();              
        httpconnection.connect();                                               
        httpconnection.setConnectTimeout(7000);                                 
        httpconnection.setReadTimeout(10000);

        // check here if there is connectivity, server is accessible, http code is 200
        // return error message if any of the above not found

        int lengthOfFile = httpconnection.getContentLength();                   
        input = httpconnection.getInputStream();                                
        byte data[] = new byte[1024];                                           
        long total = 0;                                                         

        while ((count = input.read(data)) != -1) {                              
            total += count;                                                     
            publishProgress(""+(int)((total*100)/lengthOfFile));                
        }

        String msg = new String(data);                                          

        if(msg.contains(someinfo)) {
            allow = true;
        }

        input.close();                                                          
    } catch (Exception e) {}                                                    

    return null;
}

protected void onProgressUpdate(String... progress) {                           
     mProgressDialog.setProgress(Integer.parseInt(progress[0]));                
}

@Override
protected void onPostExecute(String unused) {                                   
    dismissDialog(DIALOG_DOWNLOAD_PROGRESS);                                    

    if(allow){                          
        Toast.makeText(getBaseContext(),"Success",Toast.LENGTH_SHORT).show(); 
    }else{      
        Toast.makeText(getBaseContext(),"Failed",Toast.LENGTH_SHORT).show(); 
    }

}
}

据我所知

httpconnection.setConnectTimeout(7000);                                 
httpconnection.setReadTimeout(10000);

应该可以解决我的问题,但不知何故它不起作用,asynctask 只是一直在等待。

更新:

按照 Marcin Jędrzejewski 的建议,我在连接之前移动连接和读取超时,我得到:

... [socket][1] - [socket][13] here ... 
[socket][14:42141] exception
[CDS]close[42141]
close [socket][/0.0.0.0:42141]
[socket][14] connection www.google.com/4.35.153.212:81;LocalPort=59339(7000)
[CDS]connect[www.google.com/4.35.153.212:81] tm:7
[socket][15:59339] exception
[CDS]close[59339]
close [socket][/0.0.0.0:59339]
[socket][15] connection www.google.com/4.35.153.237:81;LocalPort=56148(7000)
[CDS]connect[www.google.com/4.35.153.237:81] tm:7
[socket][16:56148] exception
[CDS]close[56148]

setconnecttimeout 似乎是每次尝试连接时的超时时间,但有没有办法设置它重试连接的次数而不是总是尝试 16 次?

【问题讨论】:

标签: android timer android-asynctask


【解决方案1】:

您可以在docs 中读到,AsyncTask.get 将抛出 TimeoutException 以防时间过去而没有结果。我对您的建议是在您的 Url 连接上添加超时(如果您使用它),例如:

httpUrlConnection.setConnectTimeout(5000);
httpUrlConnection.setReadTimeout(5000);

这将导致您的 Url 连接在 5 秒后解除阻塞,然后您的 AsyncTask 也将完成。然后在 onPostExecute 中,您可以使用新的 Url 执行另一个 AsyncTask - 以防连接错误。

如果您想中止当前连接 - 正在进行中 - 然后使用:

httpUrlConnection.disconnect();

最后,调用 AsyncTask.get() 并不是一个好主意,正如我上面所描述的 - 它不能保证连接会结束,而且你不能在 UI 线程上调用它。

【讨论】:

  • 我实际上已经设置了连接和读取超时。我读到的问题是,它仅在已经建立连接时才有效,如果问题是 DNS 未得到解决,则它不起作用。所以总而言之,我认为控制整个 asynctask 运行时间而不是试图寻找失败案例会更好。哦,我已经测试过了,在我提到的那 2 个网址上,它们似乎不起作用。
  • @publicknowledge startTask的问题是它必须从UI线程调用(AsyncTask.execute必须在UI线程上调用),所以前两个执行是可以的,但第三个调用继续UI 线程 - 这总是坏主意。您可以尝试使用带有 postDelayed 的处理程序 - 它将在 5 秒后对任何挂起的连接调用断开连接,然后启动新的异步任务。
  • 我明白了。在“get”方法上的所有坏 cmets 之后,我有点想第三个不会那么好,它对我不起作用。我将研究 postDelayed 方法为我的异步任务设置 5 秒的等待时间。
  • 为我的问题添加了更多信息。您能否就如何从该代码断开连接或取消异步任务提供建议?我知道即使用户按下并取消微调器图标后,asynctask 仍然在后台运行。
  • @publicknowledge 实际上在您的 url 连接上设置的超时就足够了,如果您对此有疑问,那么我会在使用以下方法进行连接之前使用处理程序:new Handler(Looper.getMainLooper()).postDelayed 和仅使用处理程序断开连接。然后从 AsyncTask.onPostExecute 内部启动新的异步任务——当然只有在最后一次连接失败的情况下。如果断开连接对您不起作用,那么您可以尝试使用 AsyncTask.cancel,但不会调用 AsyncTask.onPostExecute。
【解决方案2】:

于是我找到了这个话题How to timeout Asynctask and dismiss ProgressDialog?

我在下面的 doInBackground 中实现了我的代码:

long waitTime = 7000;  
long curWaitTime = 0;
while (!timeout && curWaitTime < waitTime){
    // put your network/file code here
    // if the data finishes then you can set timeout to true

    try {
        URL url = new URL(urls[0]);

        httpconnection = (HttpURLConnection) url.openConnection();              
        httpconnection.setConnectTimeout(7000);                                   
        httpconnection.setReadTimeout(9000);
        httpconnection.connect();       

        // check here if there is connectivity, server is accessible, http code is 200
        // return error message if any of the above not found

        input = httpconnection.getInputStream();                                

        byte data[] = new byte[1024];                                           
        input.read(data);
        String msg = new String(data);                                          

        if (msg.contains(someinfo)){                
            allow = true;                                                       
            timeout = true;
        }

        input.close();                                                          
    } catch (Exception e) {}                                                    
    curWaitTime += 7000; 
    try{
        Thread.sleep(100);
    }catch(Exception e){}
}

我将 waitTime 设置为与我的 setConnectTimeout 相同,这使得 while 循环大致在 1 次连接尝试后超时。

我的 startTask() 基本上只是

new MyAsyncTask().execute(url);

带有一些标志让应用程序知道第一个异步任务是否失败,以便它可以尝试:

new MyAsyncTask().execute(url2);

不确定 thread.sleep(100) 的用途。我知道线程在每个 while 循环后休眠 100 毫秒。没有它,代码块仍然可以工作。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-09-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-23
    • 1970-01-01
    相关资源
    最近更新 更多