使用 asynctask 的文件下载在中间停止

file download using asynctask stops in middle

我正在为我的客户创建一个应用程序,他的一个要求是在设备上下载并安装一个外部 apk(大小约为 62mb)。这些设备将被植根,所以这不是问题。但是,在使用 AsyncTask 下载 apk 时,progress bar 在达到 34% 后重置为 0%(每次都精确到 34%,即使在不同的设备上也是如此)并抛出 java.io.IOException: unexpected end of stream.

这是我正在使用的代码:

public class InstallAPK extends AsyncTask<Void,Integer,Void> {

ProgressDialog progressDialog;
int status = 0;

private Context context;
public InstallAPK(Context context, ProgressDialog progress){
    this.context = context;
    this.progressDialog = progress;
}

public void onPreExecute() {
    if(progressDialog!=null)
        progressDialog.show();
}

@Override
protected Void doInBackground(Void... arg0) {
    try {
        URL url = new URL(context.getString(R.string.kodi_apk_link));
        HttpURLConnection c = (HttpURLConnection) url.openConnection();
        c.setRequestMethod("GET");
        c.setDoOutput(true);
        c.connect();

        // getting file length
        int lenghtOfFile = c.getContentLength();
        Log.e("File length", ""+lenghtOfFile);

        File outputFile = new File(context.getFilesDir(), context.getString(R.string.kodi_apk_name));
        if(outputFile.exists()){
            if(outputFile.length() != lenghtOfFile)
                outputFile.delete();
            else {
                publishProgress(-1);
                final String libs = "LD_LIBRARY_PATH=/vendor/lib:/system/lib ";
                final String commands = libs + "pm install -r " + context.getFilesDir().getAbsolutePath() + "/"
                        + context.getString(R.string.kodi_apk_name);
                installApk(commands);
                return null;                    
            }
        }
        FileOutputStream fos = new FileOutputStream(outputFile);

        InputStream is = c.getInputStream();
        //i tried both, with and without buffered reader
        BufferedInputStream bufferedInputStream = new BufferedInputStream(is);

        byte[] buffer = new byte[1024];
        int len1 = 0, total=0;

        if (lenghtOfFile != -1)
        {
            buffer = new byte[lenghtOfFile];
            do {
                len1 += bufferedInputStream.read(buffer, len1, lenghtOfFile-len1);
                publishProgress((int)((len1*100)/lenghtOfFile));
            } while (len1 < lenghtOfFile);
        }

        //I was using this code before, but it's not working too
        /*while ((len1 = is.read(buffer)) != -1) {
            total += len1;
            publishProgress((int)((total*100)/lenghtOfFile));
            fos.write(buffer, 0, len1);
        }*/
        fos.flush();
        fos.close();
        bufferedInputStream.close();
        is.close();

        //Log.e("Directory path", myDir.getAbsolutePath());

        publishProgress(-1);

        final String libs = "LD_LIBRARY_PATH=/vendor/lib:/system/lib ";

        final String commands = libs + "pm install -r " + context.getFilesDir().getAbsolutePath() + "/"
                + context.getString(R.string.kodi_apk_name);

        installApk(commands);


    } catch (FileNotFoundException fnfe) {
        status = 1;
        Log.e("File", "FileNotFoundException! " + fnfe);
    }

    catch(Exception e)
    {
        Log.e("UpdateAPP", "Exception " + e);
    }
    return null;
}

protected void onProgressUpdate(Integer... progress) {
    if(progress[0]!=-1) {
        // setting progress percentage
        progressDialog.setProgress(progress[0]);
    } else {
        progressDialog.setIndeterminate(true);
        progressDialog.setMessage("Installing Kodi...");
    }
}

public void onPostExecute(Void unused) {
    if(progressDialog!=null) {
        progressDialog.dismiss();
    }
    if(status == 1)
        Toast.makeText(context,"App Not Available",Toast.LENGTH_LONG).show();
    else
        Toast.makeText(context,"Successfully installed the app",Toast.LENGTH_LONG).show();

    Intent LaunchIntent = context.getPackageManager().getLaunchIntentForPackage(context.getString(R.string.kodi_apk_package));
    if(LaunchIntent!=null)
        context.startActivity(LaunchIntent);
    else
        Toast.makeText(context, "Error in installig Kodi, Try again.", Toast.LENGTH_LONG).show();
}

private void installApk(String commands) {
    try {
        Process p = Runtime.getRuntime().exec("su");
        InputStream es = p.getErrorStream();
        DataOutputStream os = new DataOutputStream(p.getOutputStream());

        os.writeBytes(commands + "\n");

        os.writeBytes("exit\n");
        os.flush();

        int read;
        byte[] buffer = new byte[4096];
        String output = new String();
        while ((read = es.read(buffer)) > 0) {
            output += new String(buffer, 0, read);
        }

        Log.v("AutoUpdaterActivity", output.toString());

        p.waitFor();

    } catch (IOException e) {
        Log.v("AutoUpdaterActivity", e.toString());
    } catch (InterruptedException e) {
        Log.v("AutoUpdaterActivity", e.toString());
    }
}

}

您应该为 HttpURLConnection 添加连接超时。

      HttpURLConnection c = (HttpURLConnection) url.openConnection();
      c.setRequestMethod("GET");
      c.setDoOutput(true);
      //set timeout to 5 seconds , set your time here
      c.setConnectTimeout(5000);
      c.connect();
   
它对 me.I 有用,希望对你有用。

我已尽一切努力使此代码正常工作。但是,它没有。然后我找到了一个替代方案。我尝试 IntentService 下载 apk,令人惊讶的是它成功了。我认为 AsyncTask 可能对下载有某种限制。要使用 IntentService 下载,我使用 this code。答案非常有用。它还有一些其他可供下载的选择。