为了清楚起见,我如何将 MainActivity 功能拆分为另一个 class?

How can I split MainActivity functionality into an another class for clarity?

我有一个 android 程序,我希望能够将 MainActivity 中的功能拆分到多个文件中以保持我的代码井井有条,但我收到空对象引用错误。

为了演示错误,我创建了一个简单的程序,它只有一个 textView 和一个用于更改 textView 的按钮。单击按钮时会发生错误。我该如何解决这个问题,这样我才能得到帮助 class?

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) 

您有一个空指针,因为您还没有为 Main activity 帮助程序设置内容视图。 在另一个内部使用 and Activity 不是到达 objective.

的正确方法

如果您想要一个助手 class,您不必扩展 Activity 或声明一个 Activity 字段。 最好的方法是使用一个视图模型,它是用于 mvvm 模式的通用后端 class。 Viewmodels 允许将逻辑与 Activity 代码分离。

如果你想继续你的案例只需声明一个普通的 Java class 并将 Activity 的引用传递给此 class 的构造函数。 在 Main Activity:

的 onCreate 中有类似这样的内容

MainActivityHelper = new MainActivityHelper(this);

之后,您可以在助手内部调用 activity 的方法(例如喜欢 findviewbyid)。

希望这能给你一些帮助 hints/help。

干杯。

你不能那样破坏 activity。我建议在 activity 中使用片段,这样你就可以将每个片段与特定的代码片段隔离开来,只需简单地回调 activity(此时,activity是一个简单的容器,用于粘合所有片段,充当调解器)。

请看看这个Android Fragments

这个可能已经过时了,但它是一个很好的切入点 vogella

您不能将 activity 拆分为两个扩展 AppCompatActivity class 的 class,但您可以使用助手 class 或 "Utils" class 它包含一组静态函数,每个函数都有特定的用途。通过这种方式,您可以通过最小化代码并将部分代码移动到助手 class.

来使 activity 代码更具可读性

此外,您可以将 ViewModel 与 LiveData 结合使用来分离数据 "Fetching" 逻辑和 UI 逻辑。您可以在此处了解更多相关信息:https://developer.android.com/jetpack/docs/guide

您正在获取 NPE,因为您使用的是 findViewById 而未附加内容视图。

您可以创建一个单独的 class 并将此方法和所有其他方法放入其中:

Class 包含所有常量

public final class Constants {

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

}

Class 包含您所有的方法

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)