下载过程中的错误处理逻辑是:

1. 在DownThread的run方法发现异常,调用sendMessage(int type, int data)创建消息添加到队列中。

@Override
public void run() {
    InputStream is = null;
    HttpURLConnection conn = null;
    try {
        file.seek(start);
        URL connUrl = new URL(url);
        conn = (HttpURLConnection) connUrl.openConnection();
        conn.setRequestMethod("GET");
        conn.setConnectTimeout(DownTask.connectTimeout);
        conn.setRequestProperty("Range", "bytes=" + start + "-" + end);
        int responseCode = conn.getResponseCode();
        Logger.d(TAG, "下载资源的字节范围:" + start + "-" + end);
        if (start > end) {
            sendMessage(DownMessage.MSG_SUCCESS, 0);
            return;
        }
        if (responseCode == HttpURLConnection.HTTP_PARTIAL || responseCode == HttpURLConnection.HTTP_OK) {
            is = new BufferedInputStream(conn.getInputStream(), 8192);
            byte[] buffer = new byte[204800];// 20K缓存
            int len = 0;
            while ((len = is.read(buffer)) != -1 && running) {
                file.write(buffer, 0, len);
                sendMessage(DownMessage.MSG_UPDATE, len);
            }
            sendMessage(DownMessage.MSG_SUCCESS, 0);
        } else {
            sendMessage(DownMessage.MSG_ERROR, 10);
        }
    } catch (IOException ex) {
        try {
            sendMessage(DownMessage.MSG_ERROR, 0);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        ex.printStackTrace();
    } catch (InterruptedException ex) {
        ex.printStackTrace();
    } finally {
        try {
            sendMessage(DownMessage.MSG_STOP, 0);
        } catch (InterruptedException e1) {
        }
        if (file != null) {
            try {
                file.close();
            } catch (IOException e) {
            }
        }
        file = null;
        if (is != null) {
            try {
                is.close();
            } catch (IOException e) {
            }
        }
        is = null;
        if (conn != null)
            conn.disconnect();
        conn = null;
        release();
    }
}

2. 在DownTask的run方法之while循环中取出队列中的消息并且进行处理。不同类别的消息分别进行不同处理,消息类别有:MSG_SUCCESS, MSG_ERROR, MSG_UPDATE, MSG_STOP等。

DownMessage msg;
running = true;
while (running) {
    msg = queue.take();
    switch (msg.type) {
    case DownMessage.MSG_SUCCESS:
        running = false;
        if (downListener != null)
            downListener.onDownFinish();
        break;
    case DownMessage.MSG_UPDATE:
        if (downListener != null) {
            downListener.onDownUpdate(msg.data);
        }
        break;
    case DownMessage.MSG_ERROR:
        running = false;
        if (downThread != null) {
            downThread.canleDown();
        }
        notifyDownError(ERROR_UNKNOWN);
        break;
    case DownMessage.MSG_STOP:
        running = false;
        if (downListener != null) {
            downListener.onDownPause();
        }
        break;
    }
    recyle(msg);

downListener.onDownError因大量使用,所以在提取出来,放在notifyDownError方法中。

/**
 * 下载出错
 *
 * @param type
 */
private void notifyDownError(int type) {
    if (downListener != null)
        downListener.onDownError(type);
}


3. 在DownService中实现OnDownListener接口,在接口方法中调用句柄Handler对象来处理不同类别的消息,处理操作包括更新数据库表,展现Toast提示等。

在启动一个下载任务时,实现OnDownListener接口。

/**
 * 启动一个下载任务。
 *
 * @param down
 * @param downTask
 */
public void launchDownloadTask(final Down down, DownTask downTask) {
    downListener = new OnDownListener() {
        @Override
        public void onDownUpdate(int len) {
            downHandler.obtainMessage(UPDATE_DOWN, len, 0, down).sendToTarget();
        }
        @Override
        public void onDownStart(int total) {
            if (down.getLength() < 1) {
                down.setLength(total);
                down.setLengthStr(Formatter.formatFileSize(DownService.this, total));
            }
        }
        @Override
        public void onDownFinish() {
            downHandler.obtainMessage(DOWN_FINISH, down).sendToTarget();
        }
        @Override
        public void onDownError(int type) {
            handler.obtainMessage(DOWN_FAIL, type, 0, down).sendToTarget();
        }
        @Override
        public void onDownPause() {
            downHandler.obtainMessage(PAUSE_DOWN, down).sendToTarget();
        }
    };
    downTask.setOnDownListener(downListener);
    executorService.execute(downTask);
}

例如,处理WIFI断开产生的IO异常逻辑:

wifi断开导致IO异常,创建MSG_ERROR消息,添加到队列中。从队列中取出MSG_ERROR消息并处理:取消DownThread线程,设置running为false以结束while循环,在OnDownListener接口实现类中,调用Handler对象更新数据库表等。