简体   繁体   English

Android API 26(Oreo)从Internet下载数据文件

[英]Android API 26 (Oreo) downloading data files from the Internet

I have now resolved this problem, which turned out to be something completely different. 我现在已经解决了这个问题,事实证明这完全不同。 Since no-one has responded, the question can be deleted. 由于没有人回答,因此可以删除该问题。

To support API 26 onward, using Android Studio I have already updated my app to explicitly ask for the dangerous permissions I need (WRITE_EXTERNAL_STORAGE, ACCESS_FINE_LOCATION). 为了支持API 26及更高版本,我已经使用Android Studio更新了应用程序,以明确询问我需要的危险权限(WRITE_EXTERNAL_STORAGE,ACCESS_FINE_LOCATION)。 It also uses normal permission INTERNET, which is granted without needing to ask the user. 它还使用普通权限INTERNET,无需询问用户即可授予该权限。

The app when first run attempts to download to local storage some data files (all text) from a specific web site that hosts these files. 该应用程序在首次运行时会尝试从承载这些文件的特定网站上将一些数据文件(所有文本)下载到本地存储中。 Although it works fine in the API 27 emulator, it fails when tested on my phone running Android 8.1.0 (Huawei P20). 尽管它在API 27模拟器中可以正常工作,但是在运行Android 8.1.0(Huawei P20)的手机上进行测试时,它失败了。

Two files are successfully downloaded, but on the third file it throws an IO exception "premature end of file" when getInputStream is called on the connection, there is a 0 byte transfer, and the app exits after displaying a failure message. 成功下载了两个文件,但是在第三个文件上,当在连接上调用getInputStream时,它会引发IO异常“文件的结尾过早”,传输0字节,并且该应用程序在显示失败消息后退出。 However, if I then Clear Data in the app's settings (on the phone), and restart the app on the phone, the full download of all files is successful. 但是,如果我随后在手机的应用程序设置中清除数据,然后在手机上重新启动应用程序,则所有文件的完整下载成功。

This is the function that is called to download each file (the else clause is what's relevant): 这是调用下载每个文件的功能(else子句是相关的):

// Download file from the internet
public static boolean downloadFile(String urlString, String fileName)
{
    mDownloadStatus = false;

    // In local file mode, download.tmp must have been pre-loaded
    if (LOCAL_FILE_MODE && fileName.equals(LOCAL_FILE_NAME))
    {
        File f = new File(dataDir, LOCAL_FILE_NAME);
        if (f.exists())
            mDownloadStatus = true;
        else
            mErrorString = "Pre-loaded " + LOCAL_FILE_NAME + " not found";
    }
    else
    {
        CountDownLatch latch = new CountDownLatch(1);
        Runnable r = new DownloadFile(urlString, fileName, latch);
        new Thread(r).start();

        try
        {
            // Wait for completion
            latch.await();
        }
        catch (InterruptedException e) {}
    }
    return mDownloadStatus;
}

And this is the DownloadFile class: 这是DownloadFile类:

public class DownloadFile implements Runnable
{
    private String          mUrlString;
    private String          mFileName;
    private CountDownLatch  mLatch;

    public DownloadFile(String urlString, String fileName, CountDownLatch latch)
    {
        mUrlString  = urlString;
        mFileName   = fileName;
        mLatch      = latch;
    }

    public void run()
    {
        HttpURLConnection urlConnection = null;

        Spine.mDownloadStatus = false;

        try
        {
            // set the download URL, a url that points to a file on the internet
            // this is the file to be downloaded
            URL url = new URL(mUrlString);

            // create the new connection
            urlConnection = (HttpURLConnection) url.openConnection();

            // set up some things on the connection
            urlConnection.setRequestMethod("GET");
            urlConnection.setDoOutput(true);
            urlConnection.setUseCaches(false);

            // and connect!
            urlConnection.connect();

            // create a new file, specifying the path, and the filename
            // which we want to save the file as.
            File file = new File(Spine.dataDir, mFileName);

            // this will be used to write the downloaded data into the file we
            // created
            FileOutputStream fileOutput = new FileOutputStream(file);

            // this will be used in reading the data from the internet
            InputStream inputStream = urlConnection.getInputStream();

            // create a buffer...
            byte[] buffer = new byte[1024];
            int bufferLength = 0; // used to store a temporary size of the buffer

            // now, read through the input buffer and write the contents to the
            // file
            while ((bufferLength = inputStream.read(buffer)) > 0)
            {
                // add the data in the buffer to the file in the file output
                // stream (the file on the sd card
                fileOutput.write(buffer, 0, bufferLength);
            }

            // close the output stream when done
            fileOutput.close();

            Spine.mDownloadStatus = true;
        }

        // catch some possible errors...
        catch (IOException e)
        {
            Spine.mErrorString = e.getMessage();
        }

        if (urlConnection != null)
            urlConnection.disconnect();

        // Signal completion
        mLatch.countDown();
    }
}

What do I need to do to fix this? 我需要做什么来解决这个问题? I am at my wit's end! 我没办法!

After changing the code to more properly deal with asking for permissions, the original problem described no longer existed. 更改代码以更正确地处理请求权限后,描述的原始问题不再存在。 However I had a totally different problem which I solved. 但是,我有一个完全不同的问题可以解决。 Outline of problem: Worked with API27 emulator in both debug and release builds. 问题概述:在调试和发行版本中都使用API​​27仿真器。 On Huawei P20 (API27), worked on debug, failed on release. 在华为P20(API27)上进行调试,但发布失败。 Once I discovered I could enable debugging for the release build I was able to find the problem and fix it. 一旦发现,就可以为发布版本启用调试功能,便可以找到问题并进行修复。

SharedPreferences for the application seem to persist on the phone somehow even when the app has been uninstalled. 即使卸载了该应用程序,该应用程序的SharedPreferences仍会以某种方式保留在电话上。 The problem was that SharedPreferences said that certain files had already been downloaded when of course they no longer existed on the phone. 问题在于,SharedPreferences表示某些文件当然已经下载了,当然它们在手机上已经不存在了。 My fix was to check in this case if the file existed, and if not I reset the preferences so that the download took place. 我的解决方法是在这种情况下检查文件是否存在,如果不存在,我将重置首选项,以便进行下载。

(I have a suspicion that it was picking up previous SharedPreferences from an earlier version of the app, installed from the Google Play Store and uninstalled so I could test the new version.) (我怀疑它是从较早版本的应用程序中获取先前的SharedPreferences的,并已从Google Play商店安装并卸载了,以便我可以测试新版本。)

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

相关问题 通知无法在Android Oreo(API 26)中显示 - Notifications fail to display in Android Oreo (API 26) 从 API Level &lt; Android 26 (Oreo) 的 RGB 值创建颜色对象 - Create Color object from RGB values for API Level < Android 26 (Oreo) Android Oreo(API26)和android.app.DownloadManager - Android Oreo (API26) and android.app.DownloadManager 如何在Android 8(API 26,Oreo)上使用片段过渡 - How to use Fragment transition on Android 8 (API 26, Oreo) Android Oreo(API 26) - 在外部存储中创建目录 - Android Oreo (API 26) - Create dir in external storage onTaskRemoved()在Android 8.0 Oreo API级别26上不起作用 - onTaskRemoved() doesn't work on Android 8.0 Oreo API level 26 无法在 android oreo(API 级别 26)上以设备管理员身份激活应用 - Unable to activate app as device admin on android oreo(API level 26) 如何更改Android O / Oreo / api 26应用程序语言 - How to change Android O / Oreo / api 26 app language 从API 26:Android 8.0 Oreo开始,不推荐使用Build.SERIAL - Build.SERIAL is deprecated as of API 26: Android 8.0 Oreo 如何在 Android 8.0 中正确更新小部件 - Oreo - API 26 - How To Properly Update A Widget In Android 8.0 - Oreo - API 26
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM