Android - 在N秒后停止/杀死Asynctask然后调用另一个Asynctask

时间:2015-12-09 12:39:27

标签: android timer android-asynctask

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

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

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

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

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

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

    它不起作用。奇怪的是,它在显示旋转轮之前等待了5秒,然后正常执行(等待永远超过5秒甚至10秒标记)。

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

    对于这个,我试过像这样拍摄2个asynctasks:

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

    希望拍摄2个asynctasks会让我得到某种回应。即使1失败了,我们仍然会通过身份验证,但是唉,它没有用。

  3. 我知道有些人可能会说通过序列化asynctask的行为,然后它就会失败它的目的。当应用程序使用服务器检查自己时,我用它来显示屏幕上的微调器。

    问题:

    • 如果一个asynctask被定时器或其他东西停止/杀死,onPostExecute仍然被调用?我想知道如果它是总是,那么这是否是放置第二个asynctask的好地方。

    我理想的解决方案是:

    • 用户点击按钮

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

    它适用于我的问题吗?

    这是我的asynctask代码块:     class 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只是等待。

    更新

    正如MarcinJę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次尝试?

2 个答案:

答案 0 :(得分:2)

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

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

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

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

httpUrlConnection.disconnect();

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

答案 1 :(得分:0)

所以我找到了这个话题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);

使用一些标志让应用知道第一个asynctask是否失败,所以它可以尝试:

new MyAsyncTask().execute(url2);

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