当setProgress更新的Andr​​oid进度不更新进度、setProgress、Andr、oid

2023-09-07 09:43:24 作者:最帅的坏蛋

我已经看到了这个问题问过,但我无法找到问题的解答,我一直在看这个相同的问题数天的闷闷不乐的。

我有,我希望在一个漫长的下载过程更新3进度栏的屏幕。不管我怎么努力,我不能得到进度更新。

完整的源代码是这里:

我的FileDownloadManager类:

 包org.touchandgo.speak;

进口java.io.BufferedReader中;
进口的java.io.File;
进口java.io.FileOutputStream中;
进口java.io.FileReader;
进口java.io.IOException异常;
进口的java.io.InputStream;
进口java.net.HttpURLConnection中;
进口java.net.MalformedURLException;
进口的java.net.URL;
进口的java.util.ArrayList;

进口android.app.Activity;
进口android.app.AlertDialog;
进口android.content.Context;
进口android.content.DialogInterface;
进口android.net.ConnectivityManager;
进口android.os.Bundle;
进口android.os.Environment;
进口android.util.Log;
进口android.view.View;
进口android.widget.Button;
进口android.widget.CheckBox;
进口android.widget.ProgressBar;
进口android.widget.TextView;

公共类FileDownloadManager扩展活动
{
    公共静态最后弦乐FILE_MANIFEST =htt​​p://dl.dropbox.com/u/25690498/TouchAndGoSpeakImages/TouchAndGoSpeak_Download.manifest;
    公共静态最后弦乐LOCAL_FILE_MANIFEST =TouchAndGoSpeak_Download.manifest;
    公共静态最后弦乐LOGID =TouchAndGoSpeak;

    私人字符串msBaseFolder =;
    私人TextView的tvCurrent;

    公共无效的onCreate(包冰柱)
    {
        super.onCreate(冰柱);
        Log.d(LOGID,创建活动);
        的setContentView(R.layout.download);

        mContext =这一点;


        tvCurrent =(TextView中)findViewById(R.id.tvCurrentAction);
        tvCurrent.setText(等待用户输入);
        tvCurrent.invalidate();

        按钮bDownload =(按钮)findViewById(R.id.btnStartDownload);
        bDownload.setOnClickListener(新View.OnClickListener()
        {
            公共无效的onClick(查看arg0中)
            {
                如果(!isNetworkAvailable())
                {
                    AlertDialog adConfirm =新AlertDialog.Builder(mContext).create();
                    adConfirm.setCancelable(假); //这个块的返回按钮
                    adConfirm.setMessage(看样子你是离线的,手机应该是网上的这个工作。);
                    adConfirm.setButton(我在线上,继续前进。新DialogInterface.OnClickListener()
                    {
                        @覆盖
                        公共无效的onClick(DialogInterface对话,诠释其)
                        {
                            dialog.dismiss();
                            downloadfiles();
                        }
                    });
                    adConfirm.setButton2(我会尝试后,新DialogInterface.OnClickListener()
                    {
                        @覆盖
                        公共无效的onClick(DialogInterface对话,诠释其)
                        {
                            dialog.dismiss();
                        }
                    });

                    adConfirm.show();

                }
                其他
                {
                    downloadfiles();
                }
            }
        });

        按钮bDownloadInfo =(按钮)findViewById(R.id.btnDownloadInfo);
        bDownloadInfo.setOnClickListener(新View.OnClickListener()
        {
            公共无效的onClick(查看arg0中)
            {
                AlertDialog adConfirm =新AlertDialog.Builder(mContext).create();
                adConfirm.setCancelable(假); //这个块的返回按钮
                adConfirm.setMessage(此功能会去到互联网并下载触摸和去'说话'免费的图像设置。\ñ\ n强烈建议您使用这样的无线网络连接。\ñ\ n这些图像提供免费的,因为是他们是不是我的工作,但根据从互联网上的各种免费资源,我已经拉到一起。\ n无侵犯版权的目的是请,如果你要声明的版权为所有这些图像与我联系\ n如果你拥有一组图像从另一个源(例如{PECS图像集)中,你可以将这些复制到applocation文件夹的SD卡(+ msBaseFolder +) - 对于要在显示每个文件夹列出你必须有一个相应的图像文件的应用程序来显示(例如,如果你有所谓的2句起动器的文件夹,然后您必须有一个名为2句Starters.jpg'时的图像文件的基本文件夹) ;
                adConfirm.setButton(OK,新DialogInterface.OnClickListener()
                {
                    @覆盖
                    公共无效的onClick(DialogInterface对话,诠释其)
                    {
                        dialog.dismiss();
                    }
                });

                adConfirm.show();
            }
        });


    }


    私人无效processManifest()
    {
        tvCurrent.setText(处理文件下载...);
        tvCurrent.invalidate();

        //获取文本文件
        档案文件=新的文件(msBaseFolder,LOCAL_FILE_MANIFEST);
        Log.d(LOGID,创建新的文件+ msBaseFolder +/+ LOCAL_FILE_MANIFEST);

        //从文件中读取文本
// StringBuilder的文本=新的StringBuilder();
        进度PB =(进度)findViewById(R.id.barFiles);
        INT iLineCnt = getLineCount(LOCAL_FILE_MANIFEST);

        INT iCurrentLine = 0;
        pb.setMax(iLineCnt);
        Log.d(LOGID,设置为进步行数iCurrentLine + iLineCnt的+);

        尝试
        {
            的BufferedReader BR =新的BufferedReader(新的FileReader(文件));
            Log.d(LOGID,创建缓冲读者);
            串线;

            而((行= br.readLine())!= NULL)
            {
                尝试
                {
                    iCurrentLine ++;
                    pb.setProgress(iCurrentLine);
                    pb.invalidate();
                    Log.d(LOGID,设置为进步行数iCurrentLine + iLineCnt的+);
                }
                赶上(例外前)
                {//吞下错误
                }
                的String [] sDownloads = line.split();
                Log.d(LOGID,读行是+行+,其中有+ sDownloads.length +零部件);

                //行应该有3件
                // 1.来源网址
                // 2。指标名称
                // 3.目标文件夹
                如果(sDownloads.length == 3)
                {
                    //是否该文件已经存在
                    文件FIL;
                    文件FLD;
                    如果(sDownloads [2] .equals(。))
                    {
                        FIL =新的文件(msBaseFolder,sDownloads [1]);
                        FLD =新的文件(msBaseFolder);
                    }
                    其他
                    {
                        FIL =新的文件(msBaseFolder +/+ sDownloads [2],sDownloads [1]);
                        FLD =新的文件(msBaseFolder +/+ sDownloads [2]);
                    }

                    //是否文件夹中存在
                    Log.d(LOGID,确保DEST文件夹存在:+ fld.getPath());
                    fld.mkdirs();

                    如果(!fil.exists())
                    {
                        downloadFile(sDownloads [0],sDownloads [1],fld.getPath(),真);
                    }
                    其他
                    {
                        //跳过的文件
                    }
                }
            }
        }
        赶上(例外五)
        {
            //你需要在这里添加正确的错误处理
            Log.e(LOGID,在processmanifest错误:+ e.getMessage());
        }

        //设置文本
        tvCurrent.setText(下载完成后文件...);
        tvCurrent.invalidate();
    }

    私人布尔downloadFile(字符串_source,字符串_dest,字符串_Folder,布尔isManifest)
    {
        尝试
        {
            tvCurrent.setText(下载文件+ _dest +...);
            tvCurrent.invalidate();
            //设置下载网址,网址指向的文件在互联网上
            //这是要下载的文件
            网址URL =新的URL(_source);
            Log.d(LOGID,创建URL);

            //创建新的连接
            HttpURLConnection的的URLConnection =(HttpURLConnection类)url.openConnection();
            Log.d(LOGID,创建HTTP连接);

            //设置一些东西的连接
            urlConnection.setRequestMethod(GET);
            Log.d(LOGID,设置请求方法);
            urlConnection.setDoOutput(真正的);
            Log.d(LOGID,设置则将DoOutput);

            //并连接!
            urlConnection.connect();
            Log.d(LOGID,连接的URL连接);

            //设置的路径,我们要保存文件
            //在这种情况下,将其保存在的根目录
            //SD卡。
            文件SDCardRoot = Environment.getExternalStorageDirectory();
            //创建一个新的文件,指定路径和文件名
            //这是我们要保存的文件。
            档案文件=新的文件(_Folder,_dest);
            Log.d(LOGID,创建DEST文件,路径=+ file.getPath()+...文件=+ file.getName());

            //这将被用于所下载的数据写入到我们创建的文件
            FileOutputStream中fileOutput =新的FileOutputStream(文件);
            Log.d(LOGID,创建文件输出流);

            //这将在从互联网读取数据被用于
            InputStream中的InputStream = urlConnection.getInputStream();
            Log.d(LOGID,创建的输入流);

            //这是文件的总大小
            INT totalSize = urlConnection.getContentLength();
            Log.d(LOGID,拿到总规模+ totalSize);

            //变量来存储下载的总字节
            INT downloadedSize = 0;

            //创建一个缓冲区...
            byte []的缓冲区=新的字节[1024];
            Log.d(LOGID,创建缓冲区);

            INT BufferLength中= 0; //用于存储缓冲器的临时尺寸
            进度PB;
            如果(isManifest)
            {
                PB =(进度)findViewById(R.id.barManifest);
            }
            其他
            {
                PB =(进度)findViewById(R.id.barOneFile);
            }
            pb.setMax(totalSize);
            Log.d(LOGID,设置进度大小);

            pb.setProgress(0);
            pb.invalidate();

            Log.d(LOGID,设置进度为零);

            //现在,读取通过输入缓冲器和将内容写入到该文件
            而(量(bufferLength = inputStream.read(缓冲液))大于0)
            {
                    //在缓冲器的数据添加到该文件中的文件输出流(该文件的SD卡上
                    fileOutput.write(缓冲液,0,BufferLength中);
                    Log.d(LOGID,写道:Infor公司的缓冲区);
                    //加起来的规模,所以我们知道有多少下载
                    downloadedSize + = BufferLength中;
                    //这是在那里你会做一些报告prgress,这样也许
            //的UpdateProgress(downloadedSize,totalSize);

                    pb.setProgress(downloadedSize);
                    pb.invalidate();

                    Log.d(LOGID,设置进度+ downloadedSize);
            }
            pb.setProgress(totalSize);
            pb.invalidate();
            完成后//关闭输出流
            fileOutput.close();
            Log.d(LOGID,关闭输出文件);

            tvCurrent.setText(下载完文件+ _dest +...);
            tvCurrent.invalidate();

            //捕捉一些可能出现的错误?
        }
        赶上(MalformedURLException的E)
        {
            Log.d(LOGID,错误你下载的文件:+ e.getMessage()+...错误的URL);
            返回false;
        }
        赶上(IOException异常E)
        {
            Log.d(LOGID,错误你下载的文件:+ e.getMessage()+... IO异常);
            返回false;
        }
        赶上(例外五)
        {
            Log.d(LOGID,错误你下载的文件:+ e.getMessage()+...一般例外);
            返回false;
        }
        返回true;
    }

    私人布尔getBaseFolder()
    {
        尝试
        {
            msBaseFolder = Environment.getExternalStorageDirectory()+/+ SpeakProperties.msAppFolder(getShared preferences(SpeakProperties.APP_NAME,0));
            文件F =新的文件(msBaseFolder);
            如果(!f.exists())
            {
                msBaseFolder = Environment.getExternalStorageDirectory()+/+ SpeakProperties.APP_DEF_FOLDER;
                F =新的文件(msBaseFolder);
            }

            如果(!f.exists())
            {
                返回createNewBaseFolder();
            }
            其他
            {
                Log.d(LOGID,+ msBaseFolder +这个应用程序的基础文件夹,不存在。);
                返回true;
            }
        }
        赶上(例外前)
        {
            Log.d(LOGID,无法得到基本文件夹:+ msBaseFolder +错误:+ ex.getMessage());
            返回false;
        }
    }

    私人布尔createNewBaseFolder()
    {

        tvCurrent.setText(创建新的基本文件夹...);
        tvCurrent.invalidate();
        最后弦乐sNewBaseFld = Environment.getExternalStorageDirectory()+/+ SpeakProperties.APP_DEF_FOLDER;
        AlertDialog adDelete =新AlertDialog.Builder(本).create();
        adDelete.setCancelable(假); //这个块的返回按钮
        adDelete.setMessage(该应用程序的基础文件夹似乎不存在\ n \ n您希望立即创建一个基于应用程序的默认文件夹设置\ñ\ n此应用程序默认文件夹是:?+ sNewBaseFld);
        adDelete.setButton(OK,新DialogInterface.OnClickListener()
        {
            @覆盖
            公共无效的onClick(DialogInterface对话,诠释其)
            {
                尝试
                {
                    文件FCREATE =新的文件(sNewBaseFld);
                    如果(!fCreate.exists())
                    {
                        fCreate.mkdirs();
                    }
                }
                赶上(例外前)
                {
                    Log.e(LOGID,无法删除文件:+ ex.getMessage());
                    showToast(无法​​创建文件夹:+ sNewBaseFld +的错误是:+ ex.getMessage());
                }
                dialog.dismiss();
            }
        });
        adDelete.setButton2(取消,新DialogInterface.OnClickListener()
        {
            @覆盖
            公共无效的onClick(DialogInterface对话,诠释其)
            {
                dialog.dismiss();
            }
        });

        adDelete.show();

        //现在我们什么创建文件夹?
        文件F =新的文件(sNewBaseFld);
        tvCurrent.setText(完成创建新的基本文件夹...);
        tvCurrent.invalidate();
        返回f.exists();
    }

    无效showToast(弦乐味精){
        AlertDialog广告=新AlertDialog.Builder(本).create();
        ad.setCancelable(假); //这个块的返回按钮
        ad.setMessage(MSG);
        ad.setButton(OK,新DialogInterface.OnClickListener(){
            @覆盖
            公共无效的onClick(DialogInterface对话,诠释它){
                dialog.dismiss();
            }
        });
        ad.show();

    }

    私人无效downloadfiles()
    {
        复选框CB =(复选框)findViewById(R.id.cbDownload);
        如果(!cb.isChecked())
        {
            返回;
        }

        如果(!getBaseFolder())
        {
            返回;
        }

        如果(downloadFile(FILE_MANIFEST,LOCAL_FILE_MANIFEST,msBaseFolder,真))
        {
            processManifest();
        }
        其他
        {
            AlertDialog adConfirm =新AlertDialog.Builder(mContext).create();
            adConfirm.setCancelable(假); //这个块的返回按钮
            adConfirm.setMessage(无法下载图像文件列表中,也许你下线?);
            adConfirm.setButton(OK,新DialogInterface.OnClickListener()
            {
                @覆盖
                公共无效的onClick(DialogInterface对话,诠释其)
                {
                    dialog.dismiss();
                }
            });

            adConfirm.show();

        }
    }

    私人布尔isThereANewDownload()
    {
        tvCurrent.setText(检查,看看是否有新的形象......);
        tvCurrent.invalidate();
        //检查,如果我们有SD卡上的文件TouchAndGoSpeak.manifest
        档案文件=新的文件(msBaseFolder,LOCAL_FILE_MANIFEST);
        如果(!file.exists())
        {
            Log.d(LOGID,无本地清单,以便返回true);
            返回true;
        }

        //如果我们有一个,那么用户已下载之前货单
        //下载新的文件

        Log.d(LOGID,我们有一个本地清单再次得到检查);
        如果(downloadFile(FILE_MANIFEST,LOCAL_FILE_MANIFEST +。新,msBaseFolder,FALSE))
        {
            返程(比较(LOCAL_FILE_MANIFEST,LOCAL_FILE_MANIFEST +。新));
        }
        其他
        {
            AlertDialog adConfirm =新AlertDialog.Builder(mContext).create();
            adConfirm.setCancelable(假); //这个块的返回按钮
            adConfirm.setMessage(无法下载图像文件列表中,也许你正处于离线状态无法核实是否有新的文件会尝试下载的所有文件下?。);
            adConfirm.setButton(OK,新DialogInterface.OnClickListener()
            {
                @覆盖
                公共无效的onClick(DialogInterface对话,诠释其)
                {
                    dialog.dismiss();
                }
            });

            adConfirm.show();
            返回true;
        }
    }

    私人诠释getLineCount(字符串_File)
    {
        INT iLineCount = 0;
        //获取文本文件
        档案文件=新的文件(msBaseFolder,_File);
// StringList的sl_source =新的StringList();

        尝试
        {
            的BufferedReader BR =新的BufferedReader(新的FileReader(文件));
            串线;

            而((行= br.readLine())!= NULL)
            {
                iLineCount ++;
            }
        }
        赶上(IOException异常E)
        {
            //你需要在这里添加正确的错误处理
        }
        返回iLineCount;
    }


    私人布尔比较(字符串_File1,字符串_File2)
    {
        Log.d(LOGID,比较2个文件);

        //获取文本文件
        档案文件=新的文件(msBaseFolder,_File1);
// StringList的sl_source =新的StringList();
        ArrayList的<字符串> _original_data =新的ArrayList<字符串>();
        ArrayList的<字符串> _new_data =新的ArrayList<字符串>();

        尝试 {
            的BufferedReader BR =新的BufferedReader(新的FileReader(文件));
            串线;

            而((行= br.readLine())!= NULL)
            {
                _original_data.add(线);
            }
        }
        赶上(IOException异常E)
        {
            //你需要在这里添加正确的错误处理
        }

        文件=新的文件(msBaseFolder,_File2);
        尝试
        {
            的BufferedReader BR =新的BufferedReader(新的FileReader(文件));
            串线;

            而((行= br.readLine())!= NULL)
            {
                _new_data.add(线);
            }
        }
        赶上(IOException异常E)
        {
            //你需要在这里添加正确的错误处理
        }

        返回_original_data.equals(_new_data);
    }

    / **
     返回:该networkAvailable
     * /
    公共布尔isNetworkAvailable()
    {

        布尔networkAvailable =真;
        尝试
        {
            上下文C = getApplicationContext();
            ConnectivityManager的ConnectionManager =(ConnectivityManager)c.getSystemService(Context.CONNECTIVITY_SERVICE);
            networkAvailable = connectionManager.getActiveNetworkInfo()= NULL和放大器;!&安培; connectionManager.getActiveNetworkInfo()isConnected()。
        }
        赶上(例外前)
        {
            Log.d(LOGID,错误判断网络的连通性:+ ex.getClass()的toString()+的消息:+ ex.getMessage());
        }
        返回networkAvailable;
    }

    私人语境mContext;
}
 

编辑:工作downloadFiles法进度更新

我的最后downloadFile看起来是这个样子的线程和处理程序补充。 该mHandler是UI的OnCreate里面实例化一个私有类变量。

感谢所有帮助大家!

 私人布尔downloadFile(字符串_source,字符串_dest,字符串_Folder,
        布尔isManifest)
{
    m_downloadSuccess = TRUE;
    m_source = _source;
    m_dest = _dest;
    m_Folder = _Folder;
    如果(isManifest)
    {
        m_pb =(进度)findViewById(R.id.barManifest);
    }
    其他
    {
        m_pb =(进度)findViewById(R.id.barOneFile);
    }

    //开始冗长的操作在后台线程
    新主题(新的Runnable()
    {
        公共无效的run()
        {
            尝试
            {
                //更新进度条
                mHandler.post(新的Runnable()
                {
                    公共无效的run()
                    {
                        Log.d(LOGID,设置文件的最大进步+ mFileTotal);
                        Log.d(LOGID,设置文件进度为0);
                        Log.d(LOGID,下载文件+ m_dest +...);
                        tvCurrent.setText(下载文件+ m_dest +...);
                    }
                });

                //设置下载网址,网址指向的文件
                // 因特网
                //这是要下载的文件
                网址URL =新的URL(m_source);
                Log.d(LOGID,创建URL);

                //创建新的连接
                HttpURLConnection的的URLConnection =(HttpURLConnection类)网址
                        .openConnection();
                Log.d(LOGID,创建HTTP连接);

                //设置一些东西的连接
                urlConnection.setRequestMethod(GET);
                Log.d(LOGID,设置请求方法);
                urlConnection.setDoOutput(真正的);
                Log.d(LOGID,设置则将DoOutput);

                //并连接!
                urlConnection.connect();
                Log.d(LOGID,连接的URL连接);

                //设置的路径,我们要保存文件
                //在这种情况下,将其保存在根目录
                //的
                // SD卡。
                文件SDCardRoot = Environment.getExternalStorageDirectory();
                //创建一个新的文件,指定路径和文件名
                //这是我们要保存的文件。
                档案文件=新的文件(m_Folder,m_dest);
                Log.d(LOGID,创建DEST文件,路径=+ file.getPath()
                        +...文件=+ file.getName());

                //这将被用于写入下载数据到
                我们创建//文件
                FileOutputStream中fileOutput =新的FileOutputStream(文件);
                Log.d(LOGID,创建文件输出流);

                //这将在从互联网读取数据被用于
                InputStream中的InputStream = urlConnection.getInputStream();
                Log.d(LOGID,创建的输入流);

                //这是文件的总大小
                mTotalSize = urlConnection.getContentLength();
                Log.d(LOGID,拿到总规模+ mTotalSize);

                //变量来存储下载的总字节
                INT downloadedSize = 0;

                //创建一个缓冲区...
                byte []的缓冲区=新的字节[1024];
                Log.d(LOGID,创建缓冲区);

                INT BufferLength中= 0; //用于存储的临时尺寸
                                        //缓冲区

                mProgressCurrentFileStatus = 0;
                // m_pb.setProgress(0);
                Log.d(LOGID,设置进度为零);

                //更新进度条
                mHandler.post(新的Runnable()
                {
                    公共无效的run()
                    {
                        Log.d(LOGID,设置进度totalsize为+ mTotalSize);
                        m_pb.setMax(mTotalSize);

                        Log.d(LOGID,设置文件的进展+ mFileCount);


                        Log.d(LOGID,设置进步:+ mProgressCurrentFileStatus);
                        m_pb.setProgress(mProgressCurrentFileStatus);
                    }
                });

                //现在,读取通过输入缓冲器和写入的内容
                //到文件
                而(量(bufferLength = inputStream.read(缓冲液))大于0)
                {
                    //在缓冲器的数据添加到该文件的文件中
                    //输出流(在SD卡上的文件
                    fileOutput.write(缓冲液,0,BufferLength中);
                    Log.d(LOGID,写道:Infor公司的缓冲区);
                    //加起来的规模,所以我们知道有多少下载
                    downloadedSize + = BufferLength中;
                    //这是在那里你会做一些报告
                    // prgress,这样也许
                    //的UpdateProgress(downloadedSize,totalSize);

                    mProgressCurrentFileStatus = downloadedSize;
                    //更新进度条
                    mHandler.post(新的Runnable()
                    {
                        公共无效的run()
                        {
                            Log.d(LOGID,设置进度尺寸:+ mTotalSize);
                            m_pb.setMax(mTotalSize);

                            Log.d(LOGID,设置进步:+ mProgressCurrentFileStatus);
                            m_pb.setProgress(mProgressCurrentFileStatus);
                        }
                    });

                    Log.d(LOGID,设置进度+ downloadedSize);
                }
                完成后//关闭输出流
                fileOutput.close();
                Log.d(LOGID,关闭输出文件);

                mHandler.post(新的Runnable()
                {
                    公共无效的run()
                    {
                        tvCurrent.setText(下载完文件+ m_dest +...);
                    }
                });
                m_downloadSuccess = TRUE;
                //捕捉一些可能出现的错误?
            }赶上(MalformedURLException的E)
            {
                Log.d(LOGID,错误你下载的文件:+ e.getMessage()
                        +......错误的URL);
                m_downloadSuccess = FALSE;
            }赶上(IOException异常E)
            {
                Log.d(LOGID,错误你下载的文件:+ e.getMessage()
                        +... IO异常);
                m_downloadSuccess = FALSE;
            }赶上(例外五)
            {
                Log.d(LOGID,错误你下载的文件:+ e.getMessage()
                        +...一般例外);
                m_downloadSuccess = FALSE;
            }
        }
    })。开始();

    返回m_downloadSuccess;
}
 

解决方案

它看起来像你这样做,你衡量进展的内部的工作的你的UI线程(直接从回调称为,不位于内一个新的线程)。这并没有给系统的任何CPU时间来给你临时的最新进展作出回应。

正确的方式来处理,这是做你的工作在后台线程,并定期更新进度。这些更新必须发生在UI线程内,但是你的活动的runOnUiThread(Runnable的)方法可以实现这一目标你。 (另外,您可以发布可运行到你的活动的处理程序的UI线程执行。)

编辑:添加例如用于线程创建的 你的工作在你的downloadFiles()方法完成的,所以这是你想要在一个单独的线程所。更换你downloadFiles()与调用,例如,

 发工人=新主题(新的Runnable(){
    @覆盖
    公共无效的run(){
        downloadFiles();
    }
});
worker.start();
 

现在,你还需要修改downloadFiles() - 因为它不是在UI线程上,它不允许修改UI。与其说 pb.setMax(totalSize)的; ,你需要获得该UI线程中执行。可以编写一个可运行(或数种),以修改UI从正确的螺纹以类似的方式运行一个新的线程:

  runOnUiThread(新的Runnable(){
    @覆盖
    公共无效的run(){
        //做的事情,修改UI
    }
});
 

您唯一需要的东西要小心在这里 - 您可运行的run()方法可能需要访问一些含有runOnUiThread()调用该方法的局部变量。从法律上提供接入,这些变量它使用的必须的是最后。如果您有不能被最终确认变量,你需要自己的值复制到一个最终的变量,可运行使用。例如:

 最终进度final_pb = PB;
最终诠释final_downloadedSize = downloadedSize;
runOnUiThread(新的Runnable(){
    @覆盖
    公共无效的run(){
        final_pb.setProgress(final_downloadedSize);
    }
});
 

I have seen this question asked before, but I can't find an answer that works and I've been looking at this same issue for days glum.

I have a screen with 3 progress bars which I want to update during a lengthy download process. No matter what I try I cannot get the progressbar to update.

The full source is here:

My FileDownloadManager class:

package org.touchandgo.speak;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.net.ConnectivityManager;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.ProgressBar;
import android.widget.TextView;

public class FileDownloadManager  extends Activity 
{
    public static final String FILE_MANIFEST = "https://m.xsw88.com/allimgs/daicuo/20230907/4932.png.jpg'");
                adConfirm.setButton("OK", new DialogInterface.OnClickListener() 
                {
                    @Override
                    public void onClick(DialogInterface dialog, int which) 
                    {
                        dialog.dismiss();
                    }
                });

                adConfirm.show();
            } 
        });


    }


    private void processManifest()
    {
        tvCurrent.setText("Processing files to download...");
        tvCurrent.invalidate();

        //Get the text file
        File file = new File(msBaseFolder,LOCAL_FILE_MANIFEST);
        Log.d(LOGid, "Created new file " + msBaseFolder+ "/" + LOCAL_FILE_MANIFEST);

        //Read text from file
//        StringBuilder text = new StringBuilder();
        ProgressBar pb = (ProgressBar) findViewById(R.id.barFiles);
        int iLineCnt=getLineCount(LOCAL_FILE_MANIFEST);

        int iCurrentLine=0;
        pb.setMax(iLineCnt);
        Log.d(LOGid, "Set progress line count to " + iCurrentLine + " of " + iLineCnt);

        try 
        {
            BufferedReader br = new BufferedReader(new FileReader(file));
            Log.d(LOGid, "Created buffered reader");
            String line;

            while ((line = br.readLine()) != null) 
            {
                try
                {
                    iCurrentLine++;
                    pb.setProgress(iCurrentLine);
                    pb.invalidate();
                    Log.d(LOGid, "Set progress line count to " + iCurrentLine + " of " + iLineCnt);
                }
                catch (Exception ex)
                { // swallow the error
                }
                String[] sDownloads = line.split(";");
                Log.d(LOGid, "Line read was" + line + " of which there are " + sDownloads.length + " parts");

                // line should have 3 parts
                // 1. Source url
                // 2. Target name
                // 3. Target folder
                if (sDownloads.length == 3)
                {
                    // Does the file already exist
                    File fil;
                    File fld;
                    if (sDownloads[2].equals("."))
                    {
                        fil = new File(msBaseFolder, sDownloads[1]);
                        fld = new File(msBaseFolder);
                    }
                    else
                    {
                        fil = new File(msBaseFolder + "/" + sDownloads[2], sDownloads[1]);
                        fld = new File(msBaseFolder + "/" + sDownloads[2]);
                    }

                    // Does the folder exist
                    Log.d(LOGid, "Ensure the dest folder exists: " + fld.getPath());
                    fld.mkdirs();

                    if (!fil.exists() )
                    {
                        downloadFile(sDownloads[0], sDownloads[1], fld.getPath(), true);
                    }
                    else
                    {
                        // Skipping a file
                    }
                }
            }
        }
        catch (Exception e) 
        {
            //You'll need to add proper error handling here
            Log.e(LOGid, "Error in processmanifest:" + e.getMessage());
        }

        //Set the text
        tvCurrent.setText("Finished Downloading Files...");
        tvCurrent.invalidate();
    }

    private boolean downloadFile(String _source, String _dest, String _Folder, boolean isManifest)
    { 
        try
        {
            tvCurrent.setText("Downloading file " + _dest + "...");
            tvCurrent.invalidate();
            //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(_source);
            Log.d(LOGid, "Created URL");

            //create the new connection
            HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
            Log.d(LOGid, "Created HTTP Connection");

            //set up some things on the connection
            urlConnection.setRequestMethod("GET");
            Log.d(LOGid, "Set the request method");
            urlConnection.setDoOutput(true);
            Log.d(LOGid, "Set doOutput");

            //and connect!
            urlConnection.connect();
            Log.d(LOGid, "Connected the url connection");

            //set the path where we want to save the file
            //in this case, going to save it on the root directory of the
            //sd card.
            File SDCardRoot = Environment.getExternalStorageDirectory();
            //create a new file, specifying the path, and the filename
            //which we want to save the file as.
            File file = new File(_Folder, _dest);
            Log.d(LOGid, "Created dest file, path=" + file.getPath() + "...file=" + file.getName());

            //this will be used to write the downloaded data into the file we created
            FileOutputStream fileOutput = new FileOutputStream(file);
            Log.d(LOGid, "Created file output stream");

            //this will be used in reading the data from the internet
            InputStream inputStream = urlConnection.getInputStream();
            Log.d(LOGid, "Created Input stream");

            //this is the total size of the file
            int totalSize = urlConnection.getContentLength();
            Log.d(LOGid, "Got total size " + totalSize);

            //variable to store total downloaded bytes
            int downloadedSize = 0;

            //create a buffer...
            byte[] buffer = new byte[1024];
            Log.d(LOGid, "Created buffer");

            int bufferLength = 0; //used to store a temporary size of the buffer
            ProgressBar pb;
            if (isManifest)
            {
                pb = (ProgressBar) findViewById(R.id.barManifest);    
            }
            else
            {
                pb = (ProgressBar) findViewById(R.id.barOneFile);    
            }
            pb.setMax(totalSize);
            Log.d(LOGid, "Set progressbar size");

            pb.setProgress(0);
            pb.invalidate();

            Log.d(LOGid, "Set progress to zero");

            //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);
                    Log.d(LOGid, "Wrote infor to the buffer");
                    //add up the size so we know how much is downloaded
                    downloadedSize += bufferLength;
                    //this is where you would do something to report the prgress, like this maybe
            //        updateProgress(downloadedSize, totalSize);

                    pb.setProgress(downloadedSize);
                    pb.invalidate();

                    Log.d(LOGid, "Set progress to " + downloadedSize);
            }
            pb.setProgress(totalSize);
            pb.invalidate();
            //close the output stream when done
            fileOutput.close();
            Log.d(LOGid, "closed the output file");

            tvCurrent.setText("Finished Downloading file " + _dest + "...");
            tvCurrent.invalidate();

            //catch some possible errors...
        } 
        catch (MalformedURLException e) 
        {
            Log.d(LOGid,  "Error dowloading file:" + e.getMessage() + "...malformed URL");
            return false;
        } 
        catch (IOException e) 
        {
            Log.d(LOGid,  "Error dowloading file:" + e.getMessage()+ "...IO Exception");
            return false;
        }
        catch (Exception e) 
        {
            Log.d(LOGid,  "Error dowloading file:" + e.getMessage()+ "...generic exception");
            return false;
        }
        return true;
    }

    private boolean getBaseFolder()
    {
        try 
        {
            msBaseFolder = Environment.getExternalStorageDirectory() + "/" + SpeakProperties.msAppFolder(getSharedPreferences(SpeakProperties.APP_NAME, 0));
            File f = new File(msBaseFolder);
            if (!f.exists())
            {
                msBaseFolder = Environment.getExternalStorageDirectory() + "/" + SpeakProperties.APP_DEF_FOLDER;
                f = new File(msBaseFolder);
            } 

            if (!f.exists())
            {
                return createNewBaseFolder();
            }
            else
            {
                Log.d(LOGid, "The base folder for this app" + msBaseFolder + " does exists.");
                return true;                
            }
        }
        catch (Exception ex)
        {
            Log.d(LOGid, "Could not get base folder:" + msBaseFolder + ". Error:" + ex.getMessage());
            return false;
        }
    }

    private boolean createNewBaseFolder()
    {

        tvCurrent.setText("Creating new base folder...");
        tvCurrent.invalidate();
        final String sNewBaseFld = Environment.getExternalStorageDirectory() + "/" + SpeakProperties.APP_DEF_FOLDER;
        AlertDialog adDelete = new AlertDialog.Builder(this).create();
        adDelete.setCancelable(false); // This blocks the 'BACK' button
        adDelete.setMessage("The base folder for the application does not seem to exist. \n\nWould you like to create one now based on the application default folder setting? \n\nThe App Default Folder is:" + sNewBaseFld);
        adDelete.setButton("OK", new DialogInterface.OnClickListener() 
        {
            @Override
            public void onClick(DialogInterface dialog, int which) 
            {
                try
                {
                    File fCreate = new File(sNewBaseFld);
                    if (!fCreate.exists())
                    {
                        fCreate.mkdirs();
                    }
                }                
                catch (Exception ex)
                {
                    Log.e(LOGid, "Could not delete file:" + ex.getMessage());
                    showToast("Could not create folder:" +sNewBaseFld + ". Error was:" + ex.getMessage());
                }
                dialog.dismiss();
            }
        });
        adDelete.setButton2("Cancel", new DialogInterface.OnClickListener() 
        {
            @Override
            public void onClick(DialogInterface dialog, int which) 
            {
                dialog.dismiss();
            }
        });

        adDelete.show();

        // Now did we create the folder?
        File f = new File(sNewBaseFld);
        tvCurrent.setText("Finished Creating new base folder...");
        tvCurrent.invalidate();
        return f.exists();
    }

    void showToast(String msg) {
        AlertDialog ad = new AlertDialog.Builder(this).create();
        ad.setCancelable(false); // This blocks the 'BACK' button
        ad.setMessage(msg);
        ad.setButton("OK", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                dialog.dismiss();
            }
        });
        ad.show();

    }

    private void downloadfiles()
    {
        CheckBox cb = (CheckBox) findViewById(R.id.cbDownload);
        if (!cb.isChecked())
        {
            return;
        }

        if (!getBaseFolder())
        {
            return;
        }

        if (downloadFile(FILE_MANIFEST, LOCAL_FILE_MANIFEST, msBaseFolder, true))
        {
            processManifest();
        }
        else
        {
            AlertDialog adConfirm = new AlertDialog.Builder(mContext).create();
            adConfirm.setCancelable(false); // This blocks the 'BACK' button
            adConfirm.setMessage("Could not download the list of image files, perhaps you are offline?");
            adConfirm.setButton("OK.", new DialogInterface.OnClickListener() 
            {
                @Override
                public void onClick(DialogInterface dialog, int which) 
                {
                    dialog.dismiss();
                }
            });

            adConfirm.show();

        }
    }

    private boolean isThereANewDownload()
    {
        tvCurrent.setText("Checking to see if there are new images...");
        tvCurrent.invalidate();
        // check if we have a TouchAndGoSpeak.manifest file on the sd card
        File file = new File(msBaseFolder,LOCAL_FILE_MANIFEST);
        if (!file.exists())
        {
            Log.d(LOGid, "No Local Manifest so returning true");
            return true;
        }

        // if we have one then the user has downloaded the manifest before
        // download the new file

        Log.d(LOGid, "We have a  Local Manifest getting again to check");
        if (downloadFile(FILE_MANIFEST, LOCAL_FILE_MANIFEST + ".new", msBaseFolder, false))
        {
            return (compare(LOCAL_FILE_MANIFEST, LOCAL_FILE_MANIFEST + ".new"));
        }
        else
        {
            AlertDialog adConfirm = new AlertDialog.Builder(mContext).create();
            adConfirm.setCancelable(false); // This blocks the 'BACK' button
            adConfirm.setMessage("Could not download the list of image files, perhaps you are offline? Unable to check if there are new files. Will try and download all files next.");
            adConfirm.setButton("OK.", new DialogInterface.OnClickListener() 
            {
                @Override
                public void onClick(DialogInterface dialog, int which) 
                {
                    dialog.dismiss();
                }
            });

            adConfirm.show();
            return true;
        }
    }

    private int getLineCount(String _File)
    {
        int iLineCount = 0;
        //Get the text file
        File file = new File(msBaseFolder,_File);
//        StringList sl_source = new StringList();

        try 
        {
            BufferedReader br = new BufferedReader(new FileReader(file));
            String line;

            while ((line = br.readLine()) != null) 
            {
                iLineCount++;
            }
        }
        catch (IOException e) 
        {
            //You'll need to add proper error handling here
        }
        return iLineCount;
    }


    private boolean compare(String _File1, String _File2)
    {
        Log.d(LOGid, "Comparing the 2 files");

        //Get the text file
        File file = new File(msBaseFolder,_File1);
//        StringList sl_source = new StringList();
        ArrayList<String> _original_data = new ArrayList<String>();
        ArrayList<String> _new_data = new ArrayList<String>();

        try {
            BufferedReader br = new BufferedReader(new FileReader(file));
            String line;

            while ((line = br.readLine()) != null) 
            {
                _original_data.add(line);
            }
        }
        catch (IOException e) 
        {
            //You'll need to add proper error handling here
        }

        file = new File(msBaseFolder,_File2);
        try 
        {
            BufferedReader br = new BufferedReader(new FileReader(file));
            String line;

            while ((line = br.readLine()) != null) 
            {
                _new_data.add(line);
            }
        }
        catch (IOException e) 
        {
            //You'll need to add proper error handling here
        }

        return _original_data.equals(_new_data);    
    }

    /**
     * @return the networkAvailable
     */
    public boolean isNetworkAvailable() 
    {

        boolean networkAvailable = true;
        try
        {
            Context c = getApplicationContext();
            ConnectivityManager connectionManager = (ConnectivityManager) c.getSystemService(Context.CONNECTIVITY_SERVICE);
            networkAvailable = connectionManager.getActiveNetworkInfo() != null && connectionManager.getActiveNetworkInfo().isConnected();
        }
        catch (Exception ex)
        {
            Log.d(LOGid, "Error determining the network connectivity:" + ex.getClass().toString() + " message:" + ex.getMessage());
        }
        return networkAvailable;
    }    

    private Context mContext;
}

edit: working downloadFiles method with progressbar updating

My final downloadFile looks like this with the Thread and handler added. The mHandler is a private class variable instantiated inside the onCreate of the UI.

Thanks for all the help everyone!

private boolean downloadFile(String _source, String _dest, String _Folder,
        boolean isManifest) 
{
    m_downloadSuccess = true;
    m_source = _source;
    m_dest = _dest;
    m_Folder = _Folder;
    if (isManifest) 
    {
        m_pb = (ProgressBar) findViewById(R.id.barManifest);
    } 
    else 
    {
        m_pb = (ProgressBar) findViewById(R.id.barOneFile);
    }

    // Start lengthy operation in a background thread
    new Thread(new Runnable() 
    {
        public void run() 
        {
            try 
            {
                // Update the progress bar
                mHandler.post(new Runnable() 
                {
                    public void run() 
                    {
                        Log.d(LOGid, "Set File max progress to " + mFileTotal);
                        Log.d(LOGid, "Set File progress to 0");
                        Log.d(LOGid, "Downloading file " + m_dest + "...");
                        tvCurrent.setText("Downloading file " + m_dest + "...");
                    }
                });

                // 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(m_source);
                Log.d(LOGid, "Created URL");

                // create the new connection
                HttpURLConnection urlConnection = (HttpURLConnection) url
                        .openConnection();
                Log.d(LOGid, "Created HTTP Connection");

                // set up some things on the connection
                urlConnection.setRequestMethod("GET");
                Log.d(LOGid, "Set the request method");
                urlConnection.setDoOutput(true);
                Log.d(LOGid, "Set doOutput");

                // and connect!
                urlConnection.connect();
                Log.d(LOGid, "Connected the url connection");

                // set the path where we want to save the file
                // in this case, going to save it on the root directory of
                // the
                // sd card.
                File SDCardRoot = Environment.getExternalStorageDirectory();
                // create a new file, specifying the path, and the filename
                // which we want to save the file as.
                File file = new File(m_Folder, m_dest);
                Log.d(LOGid, "Created dest file, path=" + file.getPath()
                        + "...file=" + file.getName());

                // this will be used to write the downloaded data into the
                // file we created
                FileOutputStream fileOutput = new FileOutputStream(file);
                Log.d(LOGid, "Created file output stream");

                // this will be used in reading the data from the internet
                InputStream inputStream = urlConnection.getInputStream();
                Log.d(LOGid, "Created Input stream");

                // this is the total size of the file
                mTotalSize = urlConnection.getContentLength();
                Log.d(LOGid, "Got total size " + mTotalSize);

                // variable to store total downloaded bytes
                int downloadedSize = 0;

                // create a buffer...
                byte[] buffer = new byte[1024];
                Log.d(LOGid, "Created buffer");

                int bufferLength = 0; // used to store a temporary size of
                                        // the buffer

                mProgressCurrentFileStatus = 0;
                // m_pb.setProgress(0);
                Log.d(LOGid, "Set progress to zero");

                // Update the progress bar
                mHandler.post(new Runnable() 
                {
                    public void run() 
                    {
                        Log.d(LOGid, "Set progress totalsize to " + mTotalSize);
                        m_pb.setMax(mTotalSize);

                        Log.d(LOGid, "Set File progress to " + mFileCount);


                        Log.d(LOGid, "Set progress to:" + mProgressCurrentFileStatus);
                        m_pb.setProgress(mProgressCurrentFileStatus);
                    }
                });

                // 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);
                    Log.d(LOGid, "Wrote infor to the buffer");
                    // add up the size so we know how much is downloaded
                    downloadedSize += bufferLength;
                    // this is where you would do something to report the
                    // prgress, like this maybe
                    // updateProgress(downloadedSize, totalSize);

                    mProgressCurrentFileStatus = downloadedSize;
                    // Update the progress bar
                    mHandler.post(new Runnable() 
                    {
                        public void run() 
                        {
                            Log.d(LOGid, "Set progress size:" + mTotalSize);
                            m_pb.setMax(mTotalSize);

                            Log.d(LOGid, "Set progress to:" + mProgressCurrentFileStatus);
                            m_pb.setProgress(mProgressCurrentFileStatus);
                        }
                    });

                    Log.d(LOGid, "Set progress to " + downloadedSize);
                }
                // close the output stream when done
                fileOutput.close();
                Log.d(LOGid, "closed the output file");

                mHandler.post(new Runnable() 
                {
                    public void run() 
                    {
                        tvCurrent.setText("Finished Downloading file " + m_dest + "...");
                    }
                });
                m_downloadSuccess = true;
                // catch some possible errors...
            } catch (MalformedURLException e) 
            {
                Log.d(LOGid, "Error dowloading file:" + e.getMessage()
                        + "...malformed URL");
                m_downloadSuccess = false;
            } catch (IOException e) 
            {
                Log.d(LOGid, "Error dowloading file:" + e.getMessage()
                        + "...IO Exception");
                m_downloadSuccess = false;
            } catch (Exception e) 
            {
                Log.d(LOGid, "Error dowloading file:" + e.getMessage()
                        + "...generic exception");
                m_downloadSuccess = false;
            }
        }
    }).start();

    return m_downloadSuccess;
}

解决方案

It looks like you're doing the work that you're measuring progress on within your UI thread (called directly from a callback, not positioned within a new thread). That doesn't give the system any CPU time to respond to your interim progress updates.

The proper way to handle this is to do your work in a background thread, and periodically update the progress. Those updates must happen from within the UI thread, but your Activity's runOnUiThread(Runnable) method can accomplish that for you. (Alternatively you could post the runnable to your Activity's handler for UI-thread execution.)

Edit: added example for thread creation Your work is done in your downloadFiles() method, so this is what you want in a separate thread. Replace your call of downloadFiles() with, for example,

Thread worker = new Thread(new Runnable() {
    @Override
    public void run() {
        downloadFiles();
    }
});
worker.start();

Now you also need to modify downloadFiles() -- since it's not on the UI thread, it's not permitted to modify the UI. Instead of calling pb.setMax(totalSize);, you'll need to get that performed within the UI thread. You can write a runnable (or several of them) to modify the UI from the proper thread in a similar manner to running a new thread:

runOnUiThread(new Runnable() {
    @Override
    public void run() {
        // do things that modify the UI
    }
});

The only thing you need to be careful of here -- your runnable's run() method will probably need access to some of the local variables in the method containing the runOnUiThread() call. To legally provide that access, the variables it uses must be final. If you have variables which cannot be final, you need to copy their value to a final variable that the runnable uses. For example:

final ProgressBar final_pb = pb;
final int final_downloadedSize = downloadedSize;
runOnUiThread(new Runnable() {
    @Override
    public void run() {
        final_pb.setProgress(final_downloadedSize);
    }
});