我在处理 Contex 时做错了什么(Java - Android)

What am I doing wrong with my handling of Contex ( Java - Android)

我制作了一个 class(第一个代码块),它接收一堆数据,创建 3 个 TextView,然后 returns 一个 RelativeLayout,其中三个都是子视图。要做到这一点,我需要让 class 的构造函数接受 'Context' 的参数,因为我需要 'Context' 来创建 TextView。但是,当我尝试创建 class 并传入上下文(通过 getApplicationContex)时,出现错误(请参阅下面第二个代码块中的日志)

Class:

package com.pp.camry.schoolprojectorganizer;
//These imports are used to setup the android widgets that the class generates
import android.content.Context;
import android.view.View;
import android.widget.TextView;
import android.widget.RelativeLayout;

//Imports for the date handling in the createPartTwo method
import java.util.Date;
import org.joda.time.DateTime;
import java.util.GregorianCalendar;
import org.joda.time.Interval;
import org.joda.time.Period;



public class ToDoItem {
    //Context Variable
    private Context con;
    // Variable Storage for the three different TextView instances
    private TextView firstElement = new TextView(con);
    private TextView secondElement = new TextView(con);
    private TextView thirdElement = new TextView(con);
    //Class Version (to prevent errors in serialization
    public final double version = 1.0;
    //Calaender input variable
    private DateTime finalInputDate;
    //Main Return Variable
    private RelativeLayout finalLayout = new RelativeLayout(con);

    /**
     * This is the main public constructor method of the class
     * @param c The current context of the program
     */
    public ToDoItem(Context c){
        con = c;
    }

    /**
     * This method calls the create method on all three other views and cobines them into a view container
     * @param eventName Name of the event for the first text box
     * @param className Name of the class for the third text box
     * @param year Year of the end of the timer
     * @param month Month of the end of the timer
     * @param day Day of the end of the timer
     * @param hour Hour of the end of the timer
     * @param minute Minute of the end of the timer
     */
    public RelativeLayout createViews(String eventName, String className, int year, int month, int day, int hour, int minute){
        firstElement = createPartOne(eventName);
        secondElement= createPartTwo(year, month, day, hour, minute);
        thirdElement = createPartThree(className);
        finalLayout.addView(firstElement);
        finalLayout.addView(secondElement);
        finalLayout.addView(thirdElement);
        //TODO Finish this method, so that the layout looks nice when its returned
        return finalLayout;
    }

    /**
     * The next three methods are the main constructors of the elements of the class. These methods
     * create the various TextView that get put together in the later methods
     */

    /**
     *Creates a TextView with from the given string
     * @param title Title used for the Text View
     * @return  Returns a TextView Instance
     */
    public TextView createPartOne(String title){
        //Create and apply the various properties to the new TextView before returning it
        //TODO add some more configuration code in here once we see what the feild looks like
        TextView tempText = new TextView(con);
        tempText.setText(title);
        tempText.setHeight(150);
        tempText.setWidth(950);
        tempText.setTextSize(40);
        tempText.setTextAlignment(View.TEXT_ALIGNMENT_CENTER);
        return tempText;
    }

    /**
     * Sets up the second TextView for the block. This one contains the countdown timer to the
     * date passed into it
     * @param year Int number representing the year
     * @param month Int number representing the month
     * @param day Int number representing the day
     * @param hour Int number representing the hour
     * @param minute Int number representing the minute
     * @return Returns a TextView with the specified countdown timer
     */
    public TextView createPartTwo(int year, int month, int day, int hour, int minute){
        //Construct the current time
        Date currentDate = new Date();
        DateTime currentTime = new DateTime(currentDate);
        //Construct the inputed time
        GregorianCalendar input = new GregorianCalendar();
        input.set(year, month, day, hour, minute);
        DateTime inputTime = new DateTime(input.getTime());
        finalInputDate = inputTime.toDateTime();
        //Do the Comparison
        Interval timeBet = new Interval(inputTime, currentTime);
        //Create the Ui Element
        TextView tempText = new TextView(con);
        Period outputTime = timeBet.toPeriod();
        //Formating stuff down here (really borring, and propaly has the bug your looking for)
        int outcome;
        if(outputTime.getYears()<1 && outputTime.getMonths()<1 && outputTime.getDays()<1 && outputTime.getHours()<1){
            tempText.setText(outputTime.getMinutes() + " Minutes");
            outcome = 0;
        }
        if(outputTime.getYears()<1 && outputTime.getMonths()<1 && outputTime.getDays()<1){
            tempText.setText(outputTime.getHours() + " Hours " + outputTime.getMinutes() + " Minutes ");
            outcome = 1;
        }
        if(outputTime.getYears()<1 && outputTime.getMonths()<1){
            tempText.setText(outputTime.getDays() + " Days " + outputTime.getHours() + " Hours " +
                outputTime.getMinutes() + " Minutes ");
            outcome = 2;
        }
        if(outputTime.getYears() < 1){
            tempText.setText(outputTime.getMonths() + " Months " + outputTime.getDays()
                    + " Days " + outputTime.getHours() + " Hours " + outputTime.getMinutes() + " Minutes ");
            outcome = 3;
        }
        else{
            tempText.setText( outputTime.getYears() + " Years " + outputTime.getMonths() +
                    " Months " + outputTime.getDays() + " Days " + outputTime.getHours()
                    + " Hours " + outputTime.getMinutes() + " Minutes ");
            outcome = 4;
        }
        //Setup the basics of the textView
        tempText.setWidth(950);
        tempText.setHeight(250);
        //Modify the Text box further according to the outcome variable. Bigger amounts of numbers need smaller font
        if(outcome == 0){
            tempText.setTextSize(25);
        }
        if(outcome == 1){
            tempText.setTextSize(20);
        }
        if(outcome == 2 ){
            tempText.setTextSize(15);
        }
        if(outcome == 3){
            tempText.setTextSize(10);
        }
        if(outcome == 4){
            tempText.setTextSize(5);
        }
        //Return tempText
        return tempText;
    }

    /**
     * This method creates the class name box, the last of the three
     * @param className Name of the school class provided by the user
     * @return Returns a TextView with the passed in text in it
     */
    public TextView createPartThree(String className){
        TextView tempText = new TextView(con);
        tempText.setText(className);
        tempText.setHeight(125);
        tempText.setWidth(950);
        tempText.setTextSize(30);
        tempText.setTextAlignment(View.TEXT_ALIGNMENT_CENTER);
        return tempText;
    }

    /**
     * The following methods are for the utility of the class
     */
    public void updatePartTwo(){
        createPartTwo(finalInputDate.getYear(), finalInputDate.getMonthOfYear(), finalInputDate.getDayOfMonth(),
                finalInputDate.getHourOfDay(), finalInputDate.getMinuteOfHour());
    }

}

这是错误日志:

01-30 23:22:02.077  13627-13627/com.pp.camry.schoolprojectorganizer E/AndroidRuntime﹕ FATAL EXCEPTION: main
        Process: com.pp.camry.schoolprojectorganizer, PID: 13627
        java.lang.RuntimeException: Unable to start activity ComponentInfo{com.pp.camry.schoolprojectorganizer/com.pp.camry.schoolprojectorganizer.MainScreen}: java.lang.NullPointerException: Attempt to invoke virtual method 'android.content.res.Resources android.content.Context.getResources()' on a null object reference
                at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2298)
                at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2360)
                at android.app.ActivityThread.access0(ActivityThread.java:144)
                at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1278)
                at android.os.Handler.dispatchMessage(Handler.java:102)
                at android.os.Looper.loop(Looper.java:135)
                at android.app.ActivityThread.main(ActivityThread.java:5221)
                at java.lang.reflect.Method.invoke(Native Method)
                at java.lang.reflect.Method.invoke(Method.java:372)
                at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:899)
                at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:694)
         Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'android.content.res.Resources android.content.Context.getResources()' on a null object reference
                at android.view.ViewConfiguration.get(ViewConfiguration.java:359)
                at android.view.View.<init>(View.java:3580)
                at android.view.View.<init>(View.java:3675)
                at android.widget.TextView.<init>(TextView.java:634)
                at android.widget.TextView.<init>(TextView.java:629)
                at android.widget.TextView.<init>(TextView.java:625)
                at android.widget.TextView.<init>(TextView.java:621)
                at com.pp.camry.schoolprojectorganizer.ToDoItem.<init>(ToDoItem.java:26)
                at com.pp.camry.schoolprojectorganizer.MainScreen.onCreate(MainScreen.java:19)
                at android.app.Activity.performCreate(Activity.java:5933)
                at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1105)
                at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2251)
                at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2360)
                at android.app.ActivityThread.access0(ActivityThread.java:144)
                at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1278)
                at android.os.Handler.dispatchMessage(Handler.java:102)
                at android.os.Looper.loop(Looper.java:135)
                at android.app.ActivityThread.main(ActivityThread.java:5221)
                at java.lang.reflect.Method.invoke(Native Method)
                at java.lang.reflect.Method.invoke(Method.java:372)
                at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:899)
                at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:694)

这是导致错误的调用:

ToDoItem test = new ToDoItem(getApplicationContext());

如果我理解我的代码给我的错误,那么我对上下文的调用似乎返回了一个空对象。但是我不明白为什么会这样。非常感谢任何帮助,请注意这是我的第一个 android 应用程序,所以如果我遗漏了一些非常明显或简单的东西

NullPointerException: Attempt to invoke virtual method 'android.content.res.Resources android.content.Context.getResources()' on a null object reference

因为 firstElement,secondElement and thirdElement TextView 是在调用 class 构造函数之前使用 con 创建的,您正在其中初始化 con 。这样做:

private TextView firstElement,secondElement,thirdElement;
public ToDoItem(Context c){
        con = c;
        firstElement= new TextView(con);
        secondElement = new TextView(con);
        thirdElement = new TextView(con);
    }

建议: 使用当前应用程序组件上下文而不是 getApplicationContext() 来创建视图。

ToDoItem test = new ToDoItem(ActivityName.this);

切勿使用非常量或已设置的数据初始化 class 成员。

在调用 class 的实际构造函数并设置上下文之前,您正在使用对上下文的引用创建对象。

public ToDoItem(Context c){
    con = c;
    firstElement = new TextView(con);
    secondElement = new TextView(con);
    thirdElement = new TextView(con);
}