Java.lang.NullPointerException: попытка вызвать виртуальный метод 'android.view.View.MainActivity.findViewById(int)' для ссылки на нулевой объект

У меня есть класс под названием MainActivity.java, который вызывает класс AsyncTask. У последнего класса есть findViewById(), который в выполнении возвращает эту ошибку:

java.lang.NullPointerException: Attempt to invoke virtual method 'android.view.View <mypackage>.MainActivity.findViewById(int)' on a null object reference

Я не понимаю, как я могу отредактировать ImageView, расположенный в R.layout.activity_main, после чего закончится AsyncTask.

MainActivity.java

public class MainActivity extends Activity {

    public MainActivity() {}

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        new Connection().execute();
    }

}

Connection.java

public class Connection extends AsyncTask<String, Void, String> {
    public String result;

    //I know, this isn't correct, how can i do?
    public MainActivity MainActivity;

    @Override
    protected String doInBackground(String... arg0) {
        // TODO Auto-generated method stub
                //...

        return "a string";
    }

    protected void onPostExecute(String result) {
        super.onPostExecute(result);
                    //...

            // Where the error is generated
            ImageView image = (ImageView) MainActivity.findViewById(R.id.image);

            //...

    }
}

Ответ 1

Ошибка заключается в том, что

public MainActivity MainActivity;

никогда не инициализируется, указывая на нуль. Чтобы ваш код работал, минимальный шаг в MainActivity

new Connection(this).execute();

В соединении

public class Connection extends AsyncTask<String, Void, String> {

    public MainActivity MainActivity;

    public Connection(MainActivity activity) {
        MainActivity = activity;
    }

Но создание задачи в onCreate и передаче Activity - это не лучшая идея. Кроме того, имена полей всегда должны начинаться с строчной буквы.

Лучший способ - передать ImageView в AsyncTask. Не запускайте задачу до запуска Activity, а также не забывайте отменять задачу при остановке Activity.

public final class MainActivity extends Activity {

    public MainActivity() {}

    private Connection connection;
    private ImageView imageView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        imageView = (ImageView) findViewById(R.id.image);
    }

    @Override
    protected void onStart() {
        super.onStart();
        if (connection == null || connection.getStatus() != AsyncTask.Status.RUNNING) {
            connection = new Connection(imageView);
            connection.execute();
        }
    }

    @Override
    protected void onStop() {
        super.onStop();
        if (connection != null && connection.getStatus() == AsyncTask.Status.RUNNING) {
            connection.cancel(true);
        }
    }

}

В Connection.java сохраните ImageView как WeakReference, чтобы избежать утечек.

public final class Connection extends AsyncTask<String, Void, String> {

    private final WeakReference<ImageView> imageViewRef;

    public Connection(ImageView view) {
        imageViewRef = new WeakReference<ImageView>(view);
    }

    @Override
    protected String doInBackground(String... arg0) {
        // TODO Auto-generated method stub
                //...

        return "a string";
    }

    @Override
    protected void onPostExecute(String result) {
        super.onPostExecute(result);
                //...

        final ImageView imageView = imageViewRef.get();
        // if the Activity is still alive, the ImageView will not be null
        if (imageView != null) {
            // set an image or whatever you need
            image.setImageResource(666);
        }

    }

Ответ 2

Поместите изображение в качестве переменной вашего класса

private ImageView image;

в вашей инициализации onCreate

image = (ImageView) findViewById(R.id.image);


public class Connection extends AsyncTask<String, Void, String> {
        public String result;

        //I know, this isn't correct, how can i do?
        public MainActivity MainActivity;

        @Override
        protected String doInBackground(String... arg0) {
        // TODO Auto-generated method stub
            //...

        return "a string";
    }

    protected void onPostExecute(String result) {
        super.onPostExecute(result);
                //...

        // Where the error is generated
        //do other stuff with your imageview

        //...

    }
}

Ответ 3

Вы не указали, какой параметр вы передадите на Connection.java AsyncTask.

У одного из моих учеников тоже есть такая же проблема. Хотя он использует Volley Library для HttpConnection (размещение данных), и основной проблемой было: он пишет URL напрямую без префикса протокола http i.e.

String post_url ="api/do_post";

Просто добавьте http/https в начало вашего почтового URL:

String post_url ="http://api/do_post";

Ответ 4

На самом деле я работал с приложением для работы и обслуживания. я тоже получил, в том, что в bindservice я использовал флаг BIND_IMPORTANT вместо использования BIND_AUTO_CREATE.

Как только я изменил флаг, он успешно сработал у меня.