You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何提升HttpURLConnection加载Firebase PDF文件的速度?

如何提升从Firebase加载PDF的速度?

我现在能直接从Firebase打开PDF文件,但加载速度太慢——15MB的文件要等30秒左右,而且我的网络状况很好。我想试试增大缓冲区,但不知道具体怎么操作,也不确定这有没有用。请问怎么优化HttpURLConnection的下载速度?

相关代码

public class ViewPDFFiles extends AppCompatActivity {
    PDFView pdfView;
    ProgressBar pb;
    SearchView searchView;
    ArrayAdapter kek;
    ListView myPDFListView;
    DatabaseReference databaseReference;
    StorageReference storageReference;
    List<uploadPDF> uploadPDFS;

    @Override
    protected void onCreate(Bundle savedInstanceState){
        super.onCreate(savedInstanceState);
        setContentView(R.layout.viewallpdf_activity);
        searchView = findViewById(R.id.name_input);
        if(getResources().getBoolean(R.bool.portrait_only)){
            setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
        }
        else
        {
            setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
        }
        int id = getResources().getIdentifier("android:id/search_src_text", null, null);
        EditText searchEditText = (EditText) searchView.findViewById(id);
        if (searchEditText != null) {
            searchEditText.setGravity(Gravity.CENTER);
        }
        searchView.setIconifiedByDefault(false);
        searchView.setOnQueryTextFocusChangeListener(new View.OnFocusChangeListener() {
            private boolean activityStartup = true;
            @Override
            public void onFocusChange(View v, boolean hasFocus) {
                if (hasFocus) {
                    if (activityStartup) {
                        searchView.clearFocus();
                        activityStartup = false;
                    }
                }
            }
        });
        searchView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                searchView.setIconified(false);
            }
        });
        searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
            @Override
            public boolean onQueryTextSubmit(String s) {
                return false;
            }

            @Override
            public boolean onQueryTextChange(String s) {
                kek = (ArrayAdapter) myPDFListView.getAdapter();
                kek.getFilter().filter(s);
                return false;
            }
        });
        AlertDialog.Builder builder = new AlertDialog.Builder(ViewPDFFiles.this);
        builder.setCancelable(true);
        builder.setTitle("Предупреждение!");
        builder.setMessage("Файлы с темами могут открываться некоторое время и отображать пустой белый экран(10-30 секунд), не закрывайте страницу");
        builder.setPositiveButton("Хорошо,я подожду",
                new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        dialog.dismiss();
                    }
                });
        builder.setNegativeButton("", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                dialog.dismiss();
            }
        });

        AlertDialog dialog = builder.create();
        dialog.show();

        storageReference = FirebaseStorage.getInstance().getReference();
        myPDFListView = (ListView) findViewById(R.id.files_list);
        uploadPDFS = new ArrayList<>();

        viewAllFiles();

        myPDFListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> adapterView, View view, int position, long l) {

                setContentView(R.layout.viewfile_activity);
                if(getResources().getBoolean(R.bool.portrait_only)){
                    setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
                }
                else
                {
                    setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
                }
                pdfView=findViewById(R.id.pdfView);
                uploadPDF uploadPDF = uploadPDFS.get(position);
                new RetrievePDFStream().execute(uploadPDF.url);
            }
        });

    }
    class RetrievePDFStream extends AsyncTask<String,Void,InputStream> {
        @Override
        protected InputStream doInBackground(String... strings) {
            InputStream inputStream = null;

            try {
                URL urlx = new URL(strings[0]);
                HttpURLConnection urlConnection = (HttpURLConnection) urlx.openConnection();
                if (urlConnection.getResponseCode() == 200) {
                    inputStream = new BufferedInputStream(urlConnection.getInputStream());

                }
                urlConnection.setConnectTimeout(1000);
            } catch (IOException e) {
                return null;
            }
            return inputStream;
        }

        @Override
        protected void onPostExecute(InputStream inputStream) {
            pdfView.fromStream(inputStream)
                    .enableSwipe(true)
                    .load();
        }

    }
    private void viewAllFiles() {
        databaseReference = FirebaseDatabase.getInstance().getReference("uploads");
        databaseReference.addValueEventListener(new ValueEventListener() {
            @Override
            public void onDataChange(@NonNull DataSnapshot snapshot) {
                for(DataSnapshot postSnapshot : snapshot.getChildren()){
                    uploadPDF uploadPDF = postSnapshot.getValue(com.tokha.diplom.uploadPDF.class);
                    uploadPDFS.add(uploadPDF);
                }
                String[] uploads = new String[uploadPDFS.size()];
                for(int i = 0;i<uploads.length;i++){
                    uploads[i] = uploadPDFS.get(i).getName();
                }
                ArrayAdapter<String> adapter = new ArrayAdapter<String>(getApplicationContext(), android.R.layout.simple_list_item_1, uploads){
                    @NonNull
                    @Override
                    public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
                        View view = super.getView(position, convertView, parent);
                        TextView myText = (TextView) view.findViewById(android.R.id.text1);
                        myText.setTextColor(Color.BLACK);
                        return view;
                    }
                };
                myPDFListView.setAdapter(adapter);
            }

            @Override
            public void onCancelled(@NonNull DatabaseError error) {
            }
        });
    }

    public void goBack(View view) {
        finish();
    }
}

优化方案

  • 增大缓冲区大小
    默认BufferedInputStream的缓冲区是8KB,手动设置更大的缓冲区(比如64KB或128KB)可以减少IO操作次数,提升读取效率。修改RetrievePDFStream中的代码:

    inputStream = new BufferedInputStream(urlConnection.getInputStream(), 1024 * 64); // 64KB缓冲区
    
  • 修复超时设置
    你当前的setConnectTimeout调用在getResponseCode()之后,完全没有生效,而且1秒的连接超时过短,容易导致连接失败。把超时设置移到打开连接后、获取响应码前:

    URL urlx = new URL(strings[0]);
    HttpURLConnection urlConnection = (HttpURLConnection) urlx.openConnection();
    urlConnection.setConnectTimeout(5000); // 5秒连接超时
    urlConnection.setReadTimeout(15000); // 15秒读取超时
    if (urlConnection.getResponseCode() == 200) {
        inputStream = new BufferedInputStream(urlConnection.getInputStream(), 1024 * 64);
    }
    
  • 启用HTTP缓存
    给HttpURLConnection启用缓存,避免重复下载相同文件,节省带宽和时间:

    urlConnection.setUseCaches(true);
    // 可选:设置全局缓存(需要在Application初始化或Activity onCreate中调用一次)
    File cacheDir = getCacheDir();
    HttpResponseCache.install(cacheDir, 10 * 1024 * 1024); // 10MB缓存空间
    
  • 改用Firebase Storage SDK获取流
    不要用HttpURLConnection直接请求Firebase URL,官方SDK内部做了连接池、重试等优化,效率更高。替换RetrievePDFStream的逻辑:

    // 在ListView的Item点击事件中替换原有AsyncTask调用
    uploadPDF uploadPDF = uploadPDFS.get(position);
    StorageReference pdfRef = FirebaseStorage.getInstance().getReferenceFromUrl(uploadPDF.url);
    pdfRef.getStream().addOnSuccessListener(taskSnapshot -> {
        InputStream stream = taskSnapshot.getStream();
        pdfView.fromStream(stream)
                .enableSwipe(true)
                .load();
        // 记得在合适的时机关闭流
        try {
            stream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }).addOnFailureListener(e -> {
        // 处理加载失败的情况
    });
    
  • 分块加载PDF
    如果你使用的是AndroidPdfViewer库,开启分块加载可以让PDF先显示已下载的部分,不需要等整个文件下载完成:

    pdfView.fromStream(inputStream)
            .enableSwipe(true)
            .enableDoubletap(true)
            .swipeHorizontal(false)
            .enableAntialiasing(true)
            .load();
    // 确保使用最新版本的AndroidPdfViewer,新版本对加载逻辑有优化
    

内容的提问来源于stack exchange,提问作者SmyhkS Channe

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 22:16:17