0

I have a utility class for diagnostics (run time info, warning and error events) that defines the codes, severity levels, and human-readable messages for all possible diagnostics. There is also a DiagHolder that holds the information for the diag that was selected from the array and accessors for that data.

I am refactoring away from hardcoded strings in the Java in order to use R.string for localization of the text that describes the diagnostic.

    public class Diagnostic {

    // Debugging
    private static final boolean D = true;  // debugging?
    private static final String TAG = "Diagnostic";
    static Context mContext;
    DiagHolder mDiagHolder;
    String mTimestamp;


    public enum DIAG_TYPE{
        INFO,
        WARNING,
        ERROR
    }

    public enum DIAG_CODE {
        SYSTEM_ONLINE,
        SELF_TEST_COMPLETE,
        GPS_SYNCH,
        BATTERY_50,
        BATTERY_25,
        UNEXPECTED_RESET,
        UNKNOWN_ERROR
    }

    static final DiagHolder[] Diags = {

            //new DiagHolder("System powered up.", DIAG_CODE.SYSTEM_ONLINE, DIAG_TYPE.INFO),
            new DiagHolder(mContext.getResources().getString(R.string.SYSTEM_ONLINE), DIAG_CODE.SYSTEM_ONLINE, DIAG_TYPE.INFO),
            new DiagHolder("Self test complete. No issues.", DIAG_CODE.SELF_TEST_COMPLETE, DIAG_TYPE.INFO),
            new DiagHolder("GPS synchronized.", DIAG_CODE.GPS_SYNCH, DIAG_TYPE.INFO),
            new DiagHolder("Battery less than 50 percent.", DIAG_CODE.BATTERY_50, DIAG_TYPE.WARNING),
            new DiagHolder("Battery less than 25 percent.", DIAG_CODE.BATTERY_25, DIAG_TYPE.WARNING),
            new DiagHolder("Unexpected reset occured.", DIAG_CODE.UNEXPECTED_RESET, DIAG_TYPE.ERROR),
            new DiagHolder("Unknown error.", DIAG_CODE.UNKNOWN_ERROR, DIAG_TYPE.ERROR),
    };

    public static class DiagHolder {
        private String mmDescription;
        private DIAG_CODE mmCode;
        private DIAG_TYPE mmType;

        DiagHolder(String description, DIAG_CODE code, DIAG_TYPE type)
        {
            this.mmDescription = description;
            this.mmCode = code;
            this.mmType = type;
        }
    }


    Diagnostic(DIAG_CODE code, String timestamp, Context context) {
        if (code.ordinal() >= 0 && code.ordinal() < Diags.length) {
            this.mDiagHolder = Diags[code.ordinal()];
            this.mTimestamp = timestamp;
            this.mContext = context;
        }
        else {
            this.mDiagHolder = new DiagHolder("Invalid diagnostic.", DIAG_CODE.UNKNOWN_ERROR, DIAG_TYPE.ERROR);
        }

    }

    public String getDescription()
    {
        return this.mDiagHolder.mmDescription;
    }

    public DIAG_CODE getCode()
    {
        return this.mDiagHolder.mmCode;
    }

    public DIAG_TYPE getType()
    {
        return this.mDiagHolder.mmType;
    }

    public String getmTimestamp()
    {
        return mTimestamp;
    }
}

As you can see above, I have commented out the first diag with the table and replaced it with a line that accesses R.string. I accessed R by passing context to the Diagnostic from the Activity.This will not work, however, since it generates an NPE on the getResources() call.

Below id the call from the activity. I have added a dummy diagnostic for display:

public class ViewDiagnosticsActivity extends AppCompatActivity {
...
private void buildDiagnosticList()
{
    Diagnostic p = new Diagnostic(Diagnostic.DIAG_CODE.SYSTEM_ONLINE, "26OCT16 1439:10.76", this.getApplicationContext());
    diagnostics.add(p);
}

}

Is there a better pattern for doing this?

sje
  • 117
  • 1
  • 9
  • how `context` is declarated and initialized in `Diagnostic` class? – nandsito Oct 26 '16 at 14:37
  • [This](http://stackoverflow.com/questions/4391720/how-can-i-get-a-resource-content-from-a-static-context) should work. Filling up my 30 chars... – carrybit Oct 26 '16 at 14:47
  • Added more of the code for review. – sje Oct 26 '16 at 14:59
  • you are initializing `mContext`, which is a static field, in the constructor. Be careful not to mix static and non-static fields (and inner classes, for that matter) – nandsito Oct 26 '16 at 15:06

3 Answers3

2

Since Diags is a static field, it will be initialized just after the DiagHolder class is loaded. At that time, context is probably not initialized yet, presuming that classes are loaded much before contexts are set up. So, using a context in static initializations is dangerous.

In this case, in DiagHolder class you can make a method like

public static void init(Context context);

and initialize your Diags field in it.

nandsito
  • 3,782
  • 2
  • 19
  • 26
0

The NullPointerException is quite clear: ''context'' is never defined.

Pay attention that your ''DiagHolder'' is a static inner class, and therefore it can be instatiated without an instance of the enclosing class, but in that case it does not have access to instance members of the enclosing class (because they don't exist!)

Edo user1419293
  • 171
  • 2
  • 9
  • Yes, I assumed this was the the issue but I am unsure how to work around it. Maybe using an Init(), as suggested by @nandsito ? – sje Oct 26 '16 at 14:59
  • The problem still is that your Diags is a static variables but in Diags you try to access to mContext that will not exist unless the class is instantiated. Remove the static modifier from Diags and it will work. – Edo user1419293 Nov 05 '16 at 06:38
0

here, i have declared a static Context, before accessing that DiagHolder[],must initialize that static context.

package com.example.prince.practice;

import android.content.Context;

public class Diagnostic {
public static Context context;

public enum DIAG_TYPE {
    INFO, ERROR
}

public enum DIAG_CODE {
    SYSTEM_ONLINE, SYSTEM_OFFLINE
}

public static class DiagHolder {
    private String mmDescription;
    private DIAG_CODE mmCode;
    private DIAG_TYPE mmType;

    DiagHolder(String description, DIAG_CODE code, DIAG_TYPE type) {
        this.mmDescription = description;
        this.mmCode = code;
        this.mmType = type;
    }

    static final DiagHolder[] Diags = {
            //new DiagHolder("System powered up.", DIAG_CODE.SYSTEM_ONLINE, DIAG_TYPE.INFO),
            new DiagHolder(context.getResources().getString(R.string.SYSTEM_ONLIN), DIAG_CODE.SYSTEM_ONLINE, DIAG_TYPE.INFO)
    };
}

}

use from activity, like this:

    Diagnostic.context = this;
    Diagnostic.DiagHolder[] holders = Diagnostic.DiagHolder.Diags;