назад нажмите на ссылку нулевого указателя при реализации AsyncTask - PullRequest
0 голосов
/ 04 июня 2018

Я создал файл с именем JoyStickView, который расширяет SurfaceView.В моем файле JoyStickView.java есть следующая функция, которая вызывает AsyncTask для рисования двух джойстиков:

private void drawJoystick(float hatX, float hatY) {
    // Only draw the joystick when SurfaceView has been created
    if (getHolder().getSurface().isValid()) {
        new MultiplyTask().execute();
    }
}

И внутренний класс AsyncTask показан ниже:

 public class MultiplyTask extends AsyncTask<Void, Bitmap, Bitmap[]> {

        @Override
        protected void onPreExecute() {
            //super.onPreExecute();
        }

        @Override
        protected Bitmap[] doInBackground(Void... progress_data) {

            Bitmap[] bitmapArray = new Bitmap[2];
            bitmapArray[0] = BitmapFactory.decodeResource(getResources(), R.drawable.joystick_base);
            bitmapArray[1] = BitmapFactory.decodeResource(getResources(), R.drawable.joystick_hat);
            //publishProgress(bitmapArray);
            return bitmapArray;
        }

        @Override
        protected void onProgressUpdate(Bitmap... bitmapArray) {
            //super.onProgressUpdate(values);\
        }

        @Override
        protected void onPostExecute(Bitmap[] bitmapArray) {
            // super.onPostExecute(s);
            myCanvas = getHolder().lockCanvas();
            myCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
            switch (getId()) {
                case R.id.joystickRight:
                    // draw_joystick_base(myCanvas, R.drawable.joystick_base);

                    float c = bitmapArray[0].getWidth() / 2;
                    float d = bitmapArray[0].getHeight() / 2;
                    myCanvas.drawBitmap(bitmapArray[0], centerX - c, centerY - d, new Paint());
                    break;
                case R.id.joystickLeft:
                    // draw_joystick_base(myCanvas, R.drawable.joystick_base);

                    float c1 = bitmapArray[0].getWidth() / 2;
                    float d1 = bitmapArray[0].getHeight() / 2;
                    myCanvas.drawBitmap(bitmapArray[0], centerX - c1, centerY - d1, new Paint());
                    break;

            }

            float a = bitmapArray[1].getWidth() / 2;
            float b = bitmapArray[1].getHeight() / 2;
            myCanvas.drawBitmap(bitmapArray[1], hatX_tmp - a, hatY_tmp - b, new Paint());
            getHolder().unlockCanvasAndPost(myCanvas);
            // Do things like update the progress bar
        }

        void stopTask() {
            MultiplyTask a = new MultiplyTask();
            a.cancel(true);
        }
    }

Все отлично работает, пока я не нажму кнопку назад, и приложение просто вылетает и выдает мне следующую ошибку нулевого указателя.

  06-03 15:06:15.505 4478-4478/com.example.android.toybot E/AndroidRuntime: FATAL EXCEPTION: main
        Process: com.example.android.toybot, PID: 4478
        java.lang.NullPointerException: Attempt to invoke virtual method 'void android.graphics.Canvas.drawColor(int, android.graphics.PorterDuff$Mode)' on a null object reference
            at com.example.android.toybot.JoyStickView$MultiplyTask.onPostExecute(JoyStickView.java:304)
            at com.example.android.toybot.JoyStickView$MultiplyTask.onPostExecute(JoyStickView.java:274)
            at android.os.AsyncTask.finish(AsyncTask.java:661)
            at android.os.AsyncTask.-wrap1(AsyncTask.java)
            at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:678)
            at android.os.Handler.dispatchMessage(Handler.java:111)
            at android.os.Looper.loop(Looper.java:207)
            at android.app.ActivityThread.main(ActivityThread.java:5688)
            at java.lang.reflect.Method.invoke(Native Method)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:888)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:749)

JoyStickView.java:304 это строка: myCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR); Я думал об отмене моего AsyncTask во время onstop(), но это, похоже, не работает.Кто-нибудь может посоветовать, что я могу сделать?

Обновление: После этого поста я смог последовать примеру LunarLander и реализоватьnew Runnable() чтобы достичь того, что мне было нужно.

1 Ответ

0 голосов
/ 04 июня 2018

Вы получаете доступ к элементу пользовательского интерфейса из отдельного потока, что не рекомендуется.NullPointerException довольно прост.myCanvas = getHolder().lockCanvas(); устанавливает нулевую ссылку на атрибут myCanvas, когда вы заканчиваете занятие нажатием кнопки «назад».

Если код был внутри вашего потока пользовательского интерфейса (то есть внутри любой функции, которая находится в жизненном цикле вашей активности), это могло бы быть обработано функциями жизненного цикла активности, такими как onStop или onDestroy.Однако вы пытаетесь изменить элемент пользовательского интерфейса (myCanvas в вашем случае) из отдельного потока, отличного от потока пользовательского интерфейса, который находится вне области управления ресурсами Activity.Следовательно, getHolder().lockCanvas() получает нулевую ссылку на холст, а вы получаете NullPointerException на чертеже.

Этого можно легко избежать, реализовав интерфейс в качестве прослушивателя для вашего AsyncTask, чтобы функция прослушивателя находилась в вашем Activity и правильно обрабатывала ресурсы.Например, вы можете подумать о создании interface, как это.

public interface MultiplyResponseReceiver {
    void onMultiplyResponseReceived(Bitmap[] bitmapArray);
}

Теперь возьмите атрибут этого интерфейса в вашем AsyncTask вот так.

public class MultiplyTask extends AsyncTask<Void, Bitmap, Bitmap[]> {

    public MultiplyResponseReceiver listener;

    @Override
    protected void onPreExecute() {
        //super.onPreExecute();

    }

    @Override
    protected Bitmap[] doInBackground(Void... progress_data) {

        Bitmap[] bitmapArray = new Bitmap[2];
        bitmapArray[0] = BitmapFactory.decodeResource(getResources(), R.drawable.joystick_base);
        bitmapArray[1] = BitmapFactory.decodeResource(getResources(), R.drawable.joystick_hat);
        //publishProgress(bitmapArray);
        return bitmapArray;
    }

    @Override
    protected void onProgressUpdate(Bitmap... bitmapArray) {
        //super.onProgressUpdate(values);\


    }

    @Override
    protected void onPostExecute(Bitmap[] bitmapArray) {
        // super.onPostExecute(s);
        listener.onMultiplyResponseReceived(bitmapArray);
    }
}

Теперь реализуйте интерфейс в вашем Activity следующим образом.

public class YourActivity extends AppCompatActivity implements MultiplyResponseReceiver {

    @Override
    public void onMultiplyResponseReceived() {

        myCanvas = getHolder().lockCanvas();
        myCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
        switch (getId()) {
            case R.id.joystickRight:
                // draw_joystick_base(myCanvas, R.drawable.joystick_base);

                float c = bitmapArray[0].getWidth() / 2;
                float d = bitmapArray[0].getHeight() / 2;
                myCanvas.drawBitmap(bitmapArray[0], centerX - c, centerY - d, new Paint());
                break;
            case R.id.joystickLeft:
                // draw_joystick_base(myCanvas, R.drawable.joystick_base);

                float c1 = bitmapArray[0].getWidth() / 2;
                float d1 = bitmapArray[0].getHeight() / 2;
                myCanvas.drawBitmap(bitmapArray[0], centerX - c1, centerY - d1, new Paint());
                break;
        }

        float a = bitmapArray[1].getWidth() / 2;
        float b = bitmapArray[1].getHeight() / 2;
        myCanvas.drawBitmap(bitmapArray[1], hatX_tmp - a, hatY_tmp - b, new Paint());
        getHolder().unlockCanvasAndPost(myCanvas);
        // Do things like update the progress bar
    }
}

И, запуская AsyncTask в своей деятельности, не забудьте назначить ему слушателя.

MultiplyTask task = new MultiplyTask();
task.listener = this; 
task.execute();

Код не проверен и может содержать ошибки.Пожалуйста, измените согласно вашей необходимости.Я думаю, у вас уже есть идея.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...