在 AsyncTask 操作期间未显示不确定的 ProgressBar

Posted

技术标签:

【中文标题】在 AsyncTask 操作期间未显示不确定的 ProgressBar【英文标题】:Indeterminate ProgressBar not showing during AsyncTask operation 【发布时间】:2016-11-12 07:55:59 【问题描述】:

我有一个 GoogleTranslate.java 文件,它有一个类 GoogleTranslate,它扩展了 AsyncTask。此任务的目的是执行 Google 翻译。

我还有另一个类 MyVocab,它允许用户在警报对话框中输入要翻译的单词。因此,在单击警报对话框按钮时,将通过调用 GoogleTranslate 类将单词翻译成所需的语言。但是,当我将进度条从 MyVocab 传递到 GoogleTranslate 时,它​​不起作用。当操作运行时(在可观察的时间内),进度条不显示。我在 onPreExecute 中将进度条设置为 VISIBLE,并在 onPostExecute 中将其设置为 GONE。

我想知道是不是因为我在两个不同的 java 文件中有 GoogleTranslate 和 MyVocab,因为我看到的大多数示例都有异步类和在同一个 java 文件中调用它的类。如果我做错了什么导致了这个问题,请告诉我。

相关代码如下:

谷歌翻译.java

public class GoogleTranslate extends AsyncTask<String, Void, String>

private ProgressBar mProgressBar;

public GoogleTranslate(ProgressBar progressBar) 
    super();
    mProgressBar = progressBar;


@Override
protected void onPreExecute() 
    mProgressBar.setVisibility(View.VISIBLE);


@Override
protected void onPostExecute(String s) 
    mProgressBar.setVisibility(View.GONE);


@Override
protected String doInBackground(String... params) 
    String vocab = params[0];
    String source = params[1];
    String target = params[2];

    String sourceQuery = "";
    String targetQuery = "&target=" + target;

    // "" means its
    if (!source.equals("Detect Language")) 
        sourceQuery = "&source=" + source;
    

    try 
        String APIKey = "MY_API_KEY";
        String encodedQuery = URLEncoder.encode(vocab, "UTF-8");
        URL url = new URL("https://www.googleapis.com/language/translate/v2?key=" +
                APIKey +
                "&q=" +
                encodedQuery +
                sourceQuery +
                targetQuery);
        HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
        try 
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(urlConnection.getInputStream()));
            StringBuilder stringBuilder = new StringBuilder();
            String line;
            while ((line = bufferedReader.readLine()) != null) 
                stringBuilder.append(line).append("\n");
            
            bufferedReader.close();
            return stringBuilder.toString();
        
        finally 
            urlConnection.disconnect();
        
    
    catch (Exception e) 
        return null;
    



来自 MyVocab 的部分方法:

protected void addVocabAlertDialog(final VocabDbHelper dbHelper, final String category,
                                 final VocabCursorAdapter cursorAdapter) 
    AlertDialog.Builder builder = new AlertDialog.Builder(this);
    builder.setTitle("Add Vocab");

    LayoutInflater li = LayoutInflater.from(CategoryItem.this);
    View promptsView = li.inflate(R.layout.alert_dialog_add_vocab, null);
    final EditText vocabInput = (EditText) promptsView.findViewById(R.id.vocabInput);
    final EditText definitionInput = (EditText) promptsView.findViewById(R.id.definitionInput);
    final ProgressBar progressBar = (ProgressBar) promptsView.findViewById(R.id.progressBar);
    builder.setView(promptsView);

    final GoogleTranslate googleTranslate = new GoogleTranslate(progressBar);
    // Set up the buttons
    builder.setPositiveButton("OK", new DialogInterface.OnClickListener() 
        @Override
        public void onClick(DialogInterface dialog, int which) 
            String vocab = vocabInput.getText().toString();
            String definition = definitionInput.getText().toString();
            dbHelper.insertVocab(category, vocab, definition, 0);
            if (!category.equals(VocabDbContract.CATEGORY_NAME_MY_WORD_BANK)) 
                dbHelper.insertVocab(VocabDbContract.CATEGORY_NAME_MY_WORD_BANK, vocab, definition, 0);
            
            // Update Cursor
            Cursor cursor = dbHelper.getVocabCursor(category);
            cursorAdapter.changeCursor(cursor);
        
    );
    final AlertDialog dialog = builder.create();

    dialog.show();

    dialog.getButton(AlertDialog.BUTTON_NEUTRAL).setOnClickListener(new View.OnClickListener() 
        @Override
        public void onClick(View v) 
            String vocab = vocabInput.getText().toString();

            SharedPreferences sharedPreferences = getSharedPreferences("Translation", MODE_PRIVATE);
            int sourcePos = sharedPreferences.getInt("Source", 0); // 0 is for Detect Language
            int targetPos = sharedPreferences.getInt("Target", 19); // 19 is for English

            String source = LanguageOptions.FROM_LANGUAGE_CODE[sourcePos];
            String target = LanguageOptions.TO_LANGUAGE_CODE[targetPos];

            final AlertDialog.Builder builder = new AlertDialog.Builder(CategoryItem.this);
            builder.setMessage("Network is unavailable. Please try again later.");
            builder.setNegativeButton("OK", new DialogInterface.OnClickListener() 
                @Override
                public void onClick(DialogInterface dialog, int which) 
                    dialog.cancel();
                
            );
            AlertDialog dialog = builder.create();

            if (isNetworkAvailable()) 
                AsyncTask<String, Void, String> asyncTask = googleTranslate.execute(vocab, source, target);
                try 
                    String translatedJSON = asyncTask.get();
                    JSONParser jsonParser = new JSONParser();
                    String translatedText = jsonParser.parseJSONForTranslation(translatedJSON);
                    definitionInput.setText(translatedText);
                 catch (Exception e) 
                    dialog.show();
                
            
            else 
                dialog.show();
            
        
    );


包含进度条的 XML 文件:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_
android:layout_
android:orientation="vertical">

<EditText
    android:layout_
    android:layout_
    android:hint="Vocab"
    android:id="@+id/vocabInput"
    android:inputType="textAutoComplete"/>

<EditText
    android:layout_
    android:layout_
    android:hint="Definition"
    android:id="@+id/definitionInput"
    android:inputType="textAutoComplete"
    android:layout_below="@+id/vocabInput"
    android:layout_alignParentLeft="true"
    android:layout_alignParentStart="true" />

<ProgressBar
    android:layout_
    android:layout_
    android:layout_centerInParent="true"
    android:visibility="gone"
    android:indeterminate="true"
    android:id="@+id/progressBar"/>

【问题讨论】:

在异步任务完成工作时,您的第一个对话框是否仍然可见? 是的,它仍然可见。当我单击“翻译”(中性)按钮时,它似乎一直处于按下状态(按钮有阴影表示被按下),直到翻译操作完成。该对话框旨在在翻译操作期间和之后保持打开状态。 快速(愚蠢)检查:您的主题 colorAccent 是否与进度条背景不同?因为progressBar默认给colorAccent着色... 是的!如果我只是设置进度条 VISIBLE 而不将其设置为 GONE 或 INVISIBLE,我能够让它显示出来,所以这不是问题。感谢您的意见! 我刚刚测试了您的 GoogleTranslate 课程,进度条非常适合我。起初我没有看到进度,因为我有一个异常所以任务立即结束。无论如何,为了看到进度条,我只是在帖子执行中添加了一个延迟:@Override protected void onPostExecute(String s) new Handler().postDelayed(new Runnable() @Override public void run() mProgressBar.setVisibility(View.GONE); ,3000); 您可以试试这个以排除任务太快吗? 【参考方案1】:

我建议改用ProgressDialog

我从ProgressBar 切换,因为我遇到了类似的问题,即使在我的AsyncTask 的默认构造函数中以编程方式创建了一个。

public class GoogleTranslate extends AsyncTask<String, Void, String> 
    private ProgressDialog mProgressDialog;
    private Context mContext;

    public GoogleTranslate(Context context) 
        mContext = context;
    

     @Override
     protected void onPreExecute() 

         mProgressDialog = ProgressDialog.show(
                mContext,
                "Please wait", // Title
                "Translating", // Message
                true           // Indeteriminate flag
         );
     

     @Override
     protected String doInBackground(String... params) 
         ...
     

     @Override
     protected void onPostExecute(String s) 
         if (mProgressDialog != null) 
              mProgressDialog.dismiss();
         
         ...
     
 

这样称呼AsyncTask

new GoogleTranslate(getActivity() /* or getContext() */).execute(vocab, source, target);

【讨论】:

感谢您的建议!我实际上也在考虑这个选项。但是,Android 官方文档说“避免 ProgressDialog | Android 包含另一个名为 ProgressDialog 的对话框类,它显示带有进度条的对话框。但是,如果您需要指示加载或不确定进度,则应遵循 Progress & Activity 的设计指南并在您的布局中使用 ProgressBar。”所以我看看我是否仍然可以继续使用 ProgressBar,除非没有办法修复它。再次感谢! @Charles Li 好吧,Android 文档只是要遵循的指南。我被困了 3 天,试图解决 ProgressBar 问题,直到我最终决定使用 ProgressDialog(我阅读了文档并且和你现在有同样的想法)。我建议您等待几天,如果您仍然找不到有效的解决方案,请使用ProgressDialog :) 是的!这也是我的想法!这是我寻找解决方案的最后努力。大声笑非常感谢您的意见!【参考方案2】:

尽量避免使用 AsyncTask get() 方法并改用监听器。 您应该以这种方式更新您的代码:

1) 在您的 googleTranslate 类中,添加一个监听器:

private Listener listener;

    public interface Listener
        void onTaskResult(String string);
    

    public void setListener(Listener listener)
        this.listener = listener;
    

并在你的 onPostExecute 中调用它:

 @Override
    protected void onPostExecute(String s) 
        if (listener!=null) listener.onTaskResult(s); 
                mProgressBar.setVisibility(View.GONE);

    

2) 更新您的主类,将 get 替换为侦听器管理,替换为:

AsyncTask<String, Void, String> asyncTask = googleTranslate.execute(vocab, source, target);
                try 
                    String translatedJSON = asyncTask.get();
                    JSONParser jsonParser = new JSONParser();
                    String translatedText = jsonParser.parseJSONForTranslation(translatedJSON);
                    definitionInput.setText(translatedText);
                 catch (Exception e) 
                    dialog.show();
                

用这个:

googleTranslate.setListener(new GoogleTranslate.Listener() 
            @Override
            public void onTaskResult(String string) 
                    String translatedJSON = string;
                    JSONParser jsonParser = new JSONParser();
                    String translatedText = jsonParser.parseJSONForTranslation(translatedJSON);
                    definitionInput.setText(translatedText);
            
        );
        googleTranslate.execute(vocab, source, target);

希望对你有所帮助。

【讨论】:

非常感谢您在这段时间内提供的帮助 Federico!我花了一些时间来理解你的代码,但现在对我来说很有意义并且它有效!现在我需要更深入地了解 asynctask.get!再次感谢!【参考方案3】:

在执行googleTranslate之前添加这个:

 progressBar.setVisibility(View.VISIBLE);
 progressBar.setProgress(0);
 AsyncTask<String, Void, String> asyncTask = googleTranslate.execute(vocab,source, target);

并在googleTranslate 中实现onProgressUpdate

此链接可能会有所帮助:

http://www.concretepage.com/android/android-asynctask-example-with-progress-bar

【讨论】:

感谢您的意见。但是,当我按照您的建议添加两行代码时,没有任何变化。我刚刚发布了包含进度条的警报对话框的 xml 文件。这是一个循环进度条(不确定),这就是我没有实现 onProgressUpdate 的原因。在这种情况下,我还需要执行 onProgressupdate 吗?因为我相信提供的示例是针对确定的进度条。谢谢! 您是否将 `android:indeterminate="true" ` 添加到您的 xml 中以获得进度条? 我之前没有,但即使现在添加,也没有任何变化。顺便说一句,使用我当前的 xml(有或没有 indeterminte="true"),通过在 xml 中将其默认可见性设置为“可见”,将显示不确定的进度条,所以问题很简单控制它出现的时间。感谢您的帮助! 我在想这可能是因为 Java 是按值传递的,所以我在 GoogleTranslate 类中设置进度条的方式是不正确的。仍在尝试不同的方法【参考方案4】:

尝试将 ProgressBar 作为 GoogleTranslate 类的构造函数参数传递。

【讨论】:

我试过这样做,但还是不行。谢谢你!【参考方案5】:

在 onPreExecute 方法中添加进度条并将其隐藏在 onPostExecute 中。

private class MyAsyncThread extends AsyncTask<Void, Void, String>

            @SuppressWarnings("finally")

            @Override
            protected String doInBackground(Void... params) 
                // TODO Auto-generated method stub
                try 

                // your code

                
                catch (Exception e) 
                    // TODO: handle exception
                
                finally
                

                    return "OK";

                

            
            @Override
            protected void onPostExecute(String result) 
                // TODO Auto-generated method stub
                super.onPostExecute(result);

               if (progressDialog != null) 
                   progressDialog.dismiss();
                   progressDialog = null;
               

                        catch (Exception e) 
                            // TODO: handle exception
                            e.printStackTrace();
                        
            


            @Override
            protected void onPreExecute() 
                super.onPreExecute();
                progressDialog = ProgressDialog.show(this, null, "Please wait....");
            

【讨论】:

【参考方案6】:

那是因为您通过asyncTask.get() 调用阻塞了主线程,因此在 asyncTask 完成之前无法运行任何 UI 操作。

删除此调用并改为在其 onPostExecute(String s) and onCancelled() 回调中处理 asyncTask 的结果。

【讨论】:

以上是关于在 AsyncTask 操作期间未显示不确定的 ProgressBar的主要内容,如果未能解决你的问题,请参考以下文章

AsyncTask onPreExecute() 中未显示进度条

从 DialogFragment 调用的 AsyncTask 中的 ProgressDialog 未显示

AsyncTask 内的数据库操作中未出现进度对话框

ProgressBar 未显示在 AsyncTask 中

正确使用AsyncTask get()

Android - 仅在 AsyncTask 未完成时单击按钮时显示进度对话框