Вопрос по android-asynctask, android – Обновление TextView из Async Task, использующего пользовательский диалог программы

5

В одном из моих приложений у меня есть сценарий, в котором мне нужно выполнить некоторую фоновую задачу. Для этого я использую Async Task. Также я использую пользовательский диалог прогресса. Ниже приведен макет пользовательского диалога прогресса

<code><?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/layout_root"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_gravity="center_vertical|center_horizontal"
    android:orientation="vertical" >

    <ProgressBar
        android:layout_width="60dp"
        android:layout_height="60dp"
        android:indeterminateDrawable="@drawable/progressloader" 
        android:layout_gravity="center"/>

    <TextView
        android:id="@+id/progressMessage"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textColor="@color/black"
        android:textSize="18sp"
        android:text="Please wait...." />

</LinearLayout>
</code>

Все работает нормально, но когда я пытаюсь установить текст в TextView, я получаю Java NullPointerException.

Код AsyncTask

<code>private class InitialSetup extends AsyncTask<String, Integer, Long> {

        ProgressDialog dialog = new ProgressDialog(getParent(),R.style.progressdialog);


        @Override
        protected void onPreExecute() {
            dialog.show();
            dialog.setContentView(R.layout.progressbar);

        }

        @Override
        protected Long doInBackground(String... urls) {
                    //    txtView.setText("Testing");    here I am getting the error
            fetchDetails();

            return 0;
        }

        @Override
        protected void onPostExecute(Long result) {

            if (this.dialog.isShowing()) {
                this.dialog.dismiss();
            }

            populateUI(getApplicationContext());
        }
    }
</code>

Основная деятельность

<code>public class SummaryActivity extends Activity {


final TextView txtView = (TextView)findbyid(R.id.progressMessage);
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.accountsummary);

              new InitialSetup().execute("");

    }
}
</code>
Не могли бы вы отредактировать свой пост и добавить код своей Asynctask? Также было бы полезно добавить строку, где происходит исключение NullPointerException. dennisg
@ dennisg Пожалуйста, смотрите редактирование Allwyn

Ваш Ответ

4   ответа
13

TextView из которых вы хотите установить текст можно найти в XML-файле progressbar.xml (т.R.layout.progressbar). ЭтоTextView может быть получено после настройки просмотра контента (используяsetContentView()). В вашем коде вы устанавливаете его до того, как этот вызов был, и код mussharapp, он вызывает его рано. А именно, он называет это посsetContentView(R.layout.accountsummary) вызов, который не содержитTextView. Следовательно, переменнаяtxtView будет НЕДЕЙСТВИТЕЛЕН, и вы получитеNullPointerException.

Что вы должны сделать, это следующее:

Установите переменную txtView вonPreExecute, послеsetContentView называется На основе Пареш Майяны Объяснение: Используйте метод runOnUiThread.

Для кода смотрите ниже:

private class InitialSetup extends AsyncTask<String, Integer, Long> {

        ProgressDialog dialog = new ProgressDialog(getParent(),R.style.progressdialog);
        // The variable is moved here, we only need it here while displaying the
        // progress dialog.
        TextView txtView;

        @Override
        protected void onPreExecute() {
            dialog.show();
            dialog.setContentView(R.layout.progressbar);
            // Set the variable txtView here, after setContentView on the dialog
            // has been called! use dialog.findViewById().
            txtView = dialog.findViewById(R.id.progressMessage); 
        }

        @Override
        protected Long doInBackground(String... urls) {
            // Already suggested by Paresh Mayani:
            // Use the runOnUiThread method.
            // See his explanation.
            runOnUiThread(new Runnable() {
               @Override
               public void run() {
                  txtView.setText("Testing");       
               }
            });

            fetchDetails();
            return 0;
        }

        @Override
        protected void onPostExecute(Long result) {

            if (this.dialog.isShowing()) {
                this.dialog.dismiss();
            }

            populateUI(getApplicationContext());
        }
    }
Благодарность. Это сработало Allwyn
12

потому что вы пытаетесь установить TextView внутри метода doInBackground (), а это недопустимо,

Почему не разрешено? Потому что работает только один поток, который является основным потоком пользовательского интерфейса, и он не позволяет обновлять пользовательский интерфейс из процесса потока. читать больше информации здесь: Painless Threading

Так что есть решение, если вы хотите установить TextView внутри метода doInBackground (), выполните операции обновления пользовательского интерфейса внутри RunOnUiThread метод.

Иначе предложение заключается в том, чтобы выполнять все связанные с отображением / обновлением пользовательского интерфейса операции внутри метода onPostExecute () вместо метода doInBackground () вашего класса AsyncTask.

Спасибо за помощ Allwyn
1
(TextView)findViewByid(R.id.progressMessage);

должен выполняться только после команды setContentView ().

TextView txtView;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.accountsummary);
    **txtView = (TextView)findbyid(R.id.progressMessage);**


    new InitialSetup().execute("");

}

Также вы можете изменять только элементы пользовательского интерфейса в основном потоке пользовательского интерфейса. doInBackground () не находится в основном потоке пользовательского интерфейса. Внесите изменения в пользовательский интерфейс в onPostExecute

public class InitialSetup extends AsyncTask<String, Integer, Long> {

        private Activity activity;
        ProgressDialog progressDialog;

        public InitialSetup(Activity activity) {
            this.activity = activity;
        }




        @Override
        protected void onPreExecute() {
            progressDialog = new ProgressDialog(activity);
            progressDialog.setMessage("Starting task....");
            progressDialog.show();    
        }

        @Override
        protected Long doInBackground(String... urls) {
            // do something

            //        

            return 0;
        }

        @Override
        protected void onPostExecute(Long result) {
            progressDialog.dismiss();
             //Perform all UI changes here
            **textView.setText("Text#2");**
        }
    }
Я пытался, но все еще получаю ошибку. Также TextView, который я пытаюсь обновить, является частью пользовательского макета диалога прогресс Allwyn
1

вы не должны вносить изменения в пользовательский интерфейс ни в какой поток, кроме потока, который создает пользовательский интерфейс. Но у AsyncTask есть метод, который называется

onProgressUpdate()

который всегда будет работать в потоке пользовательского интерфейса. Таким образом, в зависимости от изменений, внесенных dennisg, ваш код должен выглядеть следующим образом:

private class InitialSetup extends AsyncTask<String, String, Long> {

    ProgressDialog dialog = new ProgressDialog(getParent(),R.style.progressdialog);
    // The variable is moved here, we only need it here while displaying the
    // progress dialog.
    TextView txtView;

    @Override
    protected void onPreExecute() {
        dialog.show();
        dialog.setContentView(R.layout.progressbar);
        // Set the variable txtView here, after setContentView on the dialog
        // has been called! use dialog.findViewById().
        txtView = dialog.findViewById(R.id.progressMessage); 
    }

    @Override
    protected Long doInBackground(String... urls) {
        publishProgress("Testing");

        fetchDetails();

        return 0;
    }

    @Override
    protected void onPostExecute(Long result) {

        if (this.dialog.isShowing()) {
            this.dialog.dismiss();
        }

        populateUI(getApplicationContext());
    }

    @Override
    protected void onProgressUpdate(String... update) {
        if (update.length > 0)
            txtView.setText(update[0]); 
    }
}

Обратите внимание, что тип параметра onProgressUpdate - это второй тип, заданный в AsyncTask!

Extra: Чтобы сделать ваш код более надежным, вы должны проверить, существует ли диалоговое окно прогресса, прежде чем задавать текст.

Похожие вопросы