Как я могу разделить функциональность MainActivity на другой класс для наглядности?

#java #android #nullpointerexception #illegalstateexception #main-activity

#java #Android #исключение nullpointerexception #исключение illegalstateexception #main-activity

Вопрос:

У меня есть программа для Android, и я хочу иметь возможность разделить функциональность в MainActivity на несколько файлов, чтобы сохранить упорядоченный код, но я получаю ошибку null object reference.

Чтобы продемонстрировать ошибку, я создал простую программу, в которой есть только TextView и кнопка для изменения TextView. Ошибка возникает при нажатии кнопки. Как я могу исправить эту проблему, чтобы у меня был вспомогательный класс?

MainActivity.java

 package com.example.testapp;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;

public class MainActivity extends AppCompatActivity {
    private MainActivityHelper mainActivityHelper;

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

        mainActivityHelper = new MainActivityHelper();
    }

    public void buttonPressed(View view) {
        mainActivityHelper.changeText();
    }
}
  

MainActivityHelper.java

 package com.example.testapp;

import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

public class MainActivityHelper extends AppCompatActivity {
    public MainActivityHelper() {

    }

    public void changeText() {
        TextView textView = findViewById(R.id.helloString);

        if(textView.getText().toString() == "Hello World!") {
            textView.setText("Goodbye world!");
        }
        else {
            textView.setText("Hello World!");
        }
    }
}
  

AndroidManifest.xml

 <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.testapp">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>
  

Сообщение об ошибке:

 E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.example.testapp, PID: 17322
    java.lang.IllegalStateException: Could not execute method for android:onClick
        at android.support.v7.app.AppCompatViewInflater$DeclaredOnClickListener.onClick(AppCompatViewInflater.java:389)
        at android.view.View.performClick(View.java:6294)
        at android.view.View$PerformClick.run(View.java:24770)
        at android.os.Handler.handleCallback(Handler.java:790)
        at android.os.Handler.dispatchMessage(Handler.java:99)
        at android.os.Looper.loop(Looper.java:164)
        at android.app.ActivityThread.main(ActivityThread.java:6494)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)
     Caused by: java.lang.reflect.InvocationTargetException
        at java.lang.reflect.Method.invoke(Native Method)
        at android.support.v7.app.AppCompatViewInflater$DeclaredOnClickListener.onClick(AppCompatViewInflater.java:384)
        at android.view.View.performClick(View.java:6294) 
        at android.view.View$PerformClick.run(View.java:24770) 
        at android.os.Handler.handleCallback(Handler.java:790) 
        at android.os.Handler.dispatchMessage(Handler.java:99) 
        at android.os.Looper.loop(Looper.java:164) 
        at android.app.ActivityThread.main(ActivityThread.java:6494) 
        at java.lang.reflect.Method.invoke(Native Method) 
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438) 
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807) 
     Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'android.view.Window$Callback android.view.Window.getCallback()' on a null object reference
        at android.support.v7.app.AppCompatDelegateImplBase.<init>(AppCompatDelegateImplBase.java:117)
        at android.support.v7.app.AppCompatDelegateImplV9.<init>(AppCompatDelegateImplV9.java:149)
        at android.support.v7.app.AppCompatDelegateImplV14.<init>(AppCompatDelegateImplV14.java:56)
        at android.support.v7.app.AppCompatDelegateImplV23.<init>(AppCompatDelegateImplV23.java:31)
        at android.support.v7.app.AppCompatDelegateImplN.<init>(AppCompatDelegateImplN.java:31)
        at android.support.v7.app.AppCompatDelegate.create(AppCompatDelegate.java:198)
        at android.support.v7.app.AppCompatDelegate.create(AppCompatDelegate.java:183)
        at android.support.v7.app.AppCompatActivity.getDelegate(AppCompatActivity.java:519)
        at android.support.v7.app.AppCompatActivity.findViewById(AppCompatActivity.java:190)
        at com.example.testapp.MainActivityHelper.changeText(MainActivityHelper.java:14)
        at com.example.testapp.MainActivity.buttonPressed(MainActivity.java:19)
        at java.lang.reflect.Method.invoke(Native Method) 
        at android.support.v7.app.AppCompatViewInflater$DeclaredOnClickListener.onClick(AppCompatViewInflater.java:384) 
        at android.view.View.performClick(View.java:6294) 
        at android.view.View$PerformClick.run(View.java:24770) 
        at android.os.Handler.handleCallback(Handler.java:790) 
        at android.os.Handler.dispatchMessage(Handler.java:99) 
        at android.os.Looper.loop(Looper.java:164) 
        at android.app.ActivityThread.main(ActivityThread.java:6494) 
        at java.lang.reflect.Method.invoke(Native Method) 
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438) 
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807 

Ответ №1:

У вас есть нулевой указатель, потому что вы не установили представление содержимого для Main activity helper. Использование и активность внутри другого — неправильный способ достижения вашей цели.

Если вы хотите иметь вспомогательный класс, вам не нужно расширять Activity или объявлять поле, которое является Activity. Лучший способ — использовать viewmodel, который является общим серверным классом, используемым в шаблоне mvvm. Viewmodels позволяет отделять Логику от кода действия.

Если вы хотите продолжить свой случай, просто объявите обычный класс Java и передайте ссылку Activity конструктору этого класса. Что-то подобное этому в onCreate of Main Activity:

MainActivityHelper = новый MainActivityHelper(этот);

После этого вы можете вызывать методы вашей активности внутри помощника (например, likes findviewbyid).

Надеюсь, это даст вам несколько советов / помощи.

Ваше здоровье.

Ответ №2:

Вы не можете просто прервать действие таким образом. Я бы рекомендовал использовать фрагменты внутри activity, таким образом, вы могли бы изолировать каждый фрагмент с помощью определенных фрагментов кода и просто выполнить простой обратный вызов activity (на данном этапе activity представляет собой простой контейнер для склеивания всех фрагментов, служит посредником).

Пожалуйста, взгляните на эти фрагменты Android.

Этот может быть устаревшим, но это хорошая точка входа vogella.

Ответ №3:

вы получаете NPE , потому что используете findViewById без прикрепления представления содержимого.

вы можете создать отдельный класс и поместить в него этот метод и все ваши другие методы:

Класс, содержащий все ваши константы

 public final class Constants {

    public static final String HELLO_WORLD = "Hello World!";
    public static final String GOODBYE_WORLD = "Goodbye world!";

}
  

Класс, который содержит все ваши методы

 public class Methods {

    public static void changeText(TextView textView) {
        if(textView.getText().toString() == Constants.HELLO_WORLD) {
            textView.setText(Constants.GOODBYE_WORLD);
        }
        else {
            textView.setText(Constants.HELLO_WORLD);
        }
    }


    public static void otherMethods() {
        // other methods
    }


}
  

И использовать его внутри вашего MainActivity вот так

 setContentView(R.layout.activity_main);

TextView textView = findViewById(R.id.helloString);
Methods.changeText(textView)
  

Ответ №4:

Вы не можете разделить activity на два класса, которые расширяют класс AppCompatActivity, но у вас может быть вспомогательный класс или класс «Utils», который содержит набор статических функций, каждая из которых служит определенной цели. Таким образом, вы можете сделать код activity более читаемым, сведя его к минимуму и переместив части вашего кода во вспомогательный класс.

Кроме того, вы можете использовать ViewModel с LiveData для разделения вашей логики «выборки» данных и логики пользовательского интерфейса. Вы можете узнать больше об этом здесь:https://developer.android.com/jetpack/docs/guide

Комментарии:

1. Привет, добро пожаловать в Stack Overflow. Важно, чтобы вопросы SO и snswers были удобочитаемыми, поэтому, пожалуйста, используйте стандартный регистр предложений в другой раз. Я отправил правку, чтобы исправить это на этот раз.