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

Posted

技术标签:

【中文标题】为了清楚起见,如何将 MainActivity 功能拆分为另一个类?【英文标题】:How can I split MainActivity functionality into an another class for clarity? 【发布时间】:2019-08-19 19:55:35 【问题描述】:

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

为了演示错误,我创建了一个简单的程序,它只有一个 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 或声明一个是 Activity 的字段。 最好的方法是使用一个视图模型,它是一个用于 mvvm 模式的通用后端类。 Viewmodels 允许将 Logic 与 Activity 代码分离。

如果您想继续您的案例,只需声明一个普通的 Java 类并将 Activity 的引用传递给该类的构造函数即可。 Main Activity 的 onCreate 中类似这样的内容:

MainActivityHelper = new MainActivityHelper(this);

之后,您可以在帮助程序中调用您的活动的方法(例如,喜欢 findviewbyid)。

希望这能给你一些提示/帮助。

干杯。

【讨论】:

【参考方案2】:

您不能以这种方式破坏活动。我建议在活动中使用片段,这样你就可以用特定的代码片段隔离每个片段,然后对活动进行简单的回调(此时,活动是一个简单的容器来粘合所有片段,用作调解员)。

请看一下这个Android Fragments。

这个可能已经过时,但它是一个很好的入口点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”类,其中包含一组静态函数,每个函数都有特定的用途。这样,您可以通过将活动代码最小化并将部分代码移动到帮助程序类来使活动代码更具可读性。

此外,您可以将 ViewModel 与 LiveData 结合使用,以分离您的数据“获取”逻辑和 UI 逻辑。你可以在这里了解更多信息:https://developer.android.com/jetpack/docs/guide

【讨论】:

嗨,欢迎来到 Stack Overflow。 SO问题和snsswers易于阅读很重要,因此请再次使用标准句格。这次我已经提交了修改以进行更正。

以上是关于为了清楚起见,如何将 MainActivity 功能拆分为另一个类?的主要内容,如果未能解决你的问题,请参考以下文章

为了清楚起见,值得在调用方法之前创建变量参数

为了清楚起见,我想在 Dart 中使用命名参数。我应该如何处理它们?

在图例圆环图的 onHover 期间更快地加载 Tooltip

Android Activity 生命周期处理

覆盖自定义视图中的空方法并在 MainActivity 中处理它

登录时从另一个活动启动应用程序