在安卓系统中,为什么我的进度条会冻结?

6
我正在从服务器检索数据时显示进度条,然后在图表上显示该数据,但是在绘制图表数据时,我的进度条会冻结,有人知道为什么吗?感谢您的帮助。
private ProgressDialog pd;
private Handler handler = new Handler() {
    @Override
    public void handleMessage(Message msg) {        
        Toast.makeText(context, "Please Wait...", Toast.LENGTH_LONG).show();
        Thread t = new Thread(new Runnable() {              
            @Override
            public void run() {
                functionDrawMyData();/*in this function i am accessing activity view and drawing data on that view at time of drawing my Progress bar Freezes */
            }
        });
        runOnUiThread(t);
        pd.dismiss();           
    }
};  

我正在使用一个叫做“retrieving data finished”的handler,在获取数据后调用。当点击按钮时,我会获取数据并显示进度条。
ImageButton myButton = (ImageButton) findViewById(R.id.myBtn);
pair1ChartButton.setOnClickListener(new OnClickListener() {
        @Override
        public void onClick(View v) {               
                pd = ProgressDialog.show(v.getContext(),"Please wait...","Retrieving data ...",true,
                        true,
                        new DialogInterface.OnCancelListener(){
                            @Override
                            public void onCancel(DialogInterface dialog) {

                            }
                        });
                Thread t = new Thread(new Runnable() {                      
                    @Override
                    public void run() {
                            getDataFromServer();//calling function to get data from server
                        handler.sendEmptyMessage(0);                    
                    }
                });
                t.start();
        }
    });
4个回答

3
请记住,安卓会将对话框的引用保存在内存中,以便不需要重复创建。所以进度对话框第一次可以正常工作,但下一次可能会卡住或停止响应。
注意:即使关闭了对话框,安卓也不会清除其内存引用。
Activity类中有一个名为removeDialog(int id)的方法,可以清除内存引用。
以下是如何显示和删除对话框。
protected Dialog onCreateDialog(int id) {
        // TODO Auto-generated method stub
        switch(id){
          case 0:{
             dialog = ProgressDialog.show(this, "", 
                    "Loading. Please wait...", true);
             return dialog;
          }
             }

        return super.onCreateDialog(id);
    }

现在只需调用showDialog(0)来显示对话框,removeDialog(0)来隐藏它。

1
这应该是被接受的答案。但需要注意的是,ProgressDialog已经被弃用,应该避免使用。 - herrmartell

2
您应该利用 AsyncTask(一个智能的后台线程)和 ProgressDialog 来完成这个任务。
AsyncTask 可以正确、简单地使用 UI 线程。这个类允许在后台执行操作并在 UI 线程上发布结果,而不必操纵线程或处理程序。
异步任务由在后台线程上运行的计算和在 UI 线程上发布结果的过程定义。异步任务由 3 种泛型类型 Params、Progress 和 Result 定义,有 4 个步骤:begin、doInBackground、processProgress 和 end。 四个步骤 当异步任务被执行时,任务经过 4 个步骤: onPreExecute(),在任务执行后立即在 UI 线程上调用。这一步通常用于设置任务,例如在用户界面中显示进度条。

doInBackground(Params...)在onPreExecute()执行完成后立即在后台线程上调用。此步骤用于执行可能需要很长时间的后台计算。异步任务的参数传递到此步骤中。计算的结果必须由此步骤返回,并将传递回最后一步。此步骤还可以使用publishProgress(Progress...)发布一个或多个进度单位。这些值在UI线程上发布,在onProgressUpdate(Progress...)步骤中。

onProgressUpdate(Progress...)在调用publishProgress(Progress...)后在UI线程上调用。执行的时间未定义。此方法用于在后台计算仍在执行时在用户界面中显示任何形式的进度。例如,它可以用于动画化进度条或在文本字段中显示日志。

onPostExecute(Result)在后台计算完成后在UI线程上调用。后台计算的结果作为参数传递到此步骤中。 线程规则

必须遵循一些线程规则,以使此类正常工作:

任务实例必须在UI线程上创建。 execute(Params...) 必须在UI线程上调用。 不要手动调用 onPreExecute()、onPostExecute(Result)、doInBackground(Params...) 和 onProgressUpdate(Progress...)。 该任务只能执行一次(如果尝试进行第二次执行,则会抛出异常)。 示例代码 在此示例中适配器所做的事情并不重要,更重要的是要了解您需要使用AsyncTask来显示进度对话框。
private class PrepareAdapter1 extends AsyncTask<Void,Void,ContactsListCursorAdapter > {
    ProgressDialog dialog;
    @Override
    protected void onPreExecute() {
        dialog = new ProgressDialog(viewContacts.this);
        dialog.setMessage(getString(R.string.please_wait_while_loading));
        dialog.setIndeterminate(true);
        dialog.setCancelable(false);
        dialog.show();
    }
    /* (non-Javadoc)
     * @see android.os.AsyncTask#doInBackground(Params[])
     */
    @Override
    protected ContactsListCursorAdapter doInBackground(Void... params) {
        cur1 = objItem.getContacts();
        startManagingCursor(cur1);

        adapter1 = new ContactsListCursorAdapter (viewContacts.this,
                R.layout.contact_for_listitem, cur1, new String[] {}, new int[] {});

        return adapter1;
    }

    protected void onPostExecute(ContactsListCursorAdapter result) {
        list.setAdapter(result);
        dialog.dismiss();
    }
}

在这个AsyncTask子类中,我如何访问我的活动视图? - savy
我不明白preExecute()中的viewContacts是什么。 - savy
这是包含私有类的父类名称。 - Pentium10
但我遇到了以下问题:无法在未调用Looper.prepare()的线程中创建处理程序。 - savy
我正在从doInBackground调用一个函数,该函数位于该类之外,并且在该函数中,我正在将一些视图添加到LinearLayout中,之后我得到了上述错误。 - savy

0

这是因为您在关闭或解除对话框之前就开始更新UI。这就是导致进度对话框冻结的原因。

所以请将您的代码更改为以下内容:

     pd.dismiss();  
    runOnUiThread(t);

然后,在调用runOnUiThread(t)之前,您必须关闭旧对话框并启动新的进度对话框。 - Andro Selva

0

我也遇到了同样的问题,但我自己解决了。

只需查看我的示例代码,你就会明白。

public class NearByLoc extends AsyncTask<Void, Void, Void> {
    @SuppressLint("InlinedApi")
    protected void onPreExecute() {

        // pdailog.show();
        loading_spinnerMain.setVisibility(View.VISIBLE);
    }


@Override
    protected Void doInBackground(Void... params) {
     //write your entire code [logic]here

  }
@Override
    protected void onPostExecute(Void unused) {

        //finally list of data setting to the adapter
        //before setting to the adapter you should dismiss Progress spinnerr 

        loading_spinnerMain.setVisibility(View.GONE);
        NearByMeAdapter adapter = new NearByMeAdapter(NearByMe.this, list);

        listViewNearLoc.setAdapter(adapter);
}

这对我有用..希望它能帮到你


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接