I have a method that reads in an XML file, parses it and loads the individual elements into an array. The code itself works when it is included with an Activity class. It needs to be used from 2 different Activities, so I created a utility class so I can call the one copy from each Activity needed. However, when it runs from the utility class, I get a null point exception. This tells me that I'm breaking a rule of what I can do, and from where. I suspect it's related to the access to the resources, as I also tried to access a string resources (just as a test) and that also throws a NPE.
Here is the utility class. The first Log.i appears in LogCat, but the 2nd does not.
class Utils extends MainActivity
{
String debugTag = DEBUG_TAG + "/Utils";
public void loadRankFile() throws XmlPullParserException, IOException
{
int eventType = -1;
boolean boolFoundRanks = false;
int intCounter = 0;
// this line appears in LogCat
Log.i(debugTag, "Inside loadRankFile utility.");
// this line causes the NPE
XmlResourceParser scoutRanks = getResources().getXml(R.xml.scoutranks);
// this line does not appear in LogCat
Log.i(debugTag, "xml file loaded");
.
.
.
}
This is the code from the Activity that calls the method, above:
public class RankProgressActivity extends MainActivity
{
String debugTag = DEBUG_TAG + "/RankProgressActivity";
Utils utilities = new Utils();
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.rank_progress);
try
{
initSelectScout();
utilities.loadRankFile();
initSelectRank();
}
catch (IOException e)
{
Log.i(debugTag, "Failure initializing Scout Progress activity items", e);
}
catch (XmlPullParserException e)
{
Log.e(debugTag, "Rank file parse error.", e);
}
.
.
.
}
I'm sure I'm making a classic mistake, but I don't see it, and I haven't been able to find guidance as of yet. Any feedback would be appreciated. I'm rather new to Java and Android, so this is very much a learning experience for me.
Thank you in advance.
Your Utils class should not be extending an Activity. Activities are your user facing interfaces, meaning that you implement an Activity when you want to display some sort of UI to the user.
Read up on the documentation for an Activity.
Your Utils class should look something like this:
class Utils
{
private static final String DEBUG_TAG = "Utils";
public ArrayList<String> parseRankFile(Context context) throws XmlPullParserException, IOException
{
ArrayList<String> scoutRanks = new ArrayList<String>();
Log.i(DEBUG_TAG, "Inside loadRankFile utility.");
XmlResourceParser scoutRanksParser = context.getResources().getXml(R.xml.scoutranks);
Log.i(DEBUG_TAG, "xml file loaded");
// do your parsing and populate the scoutRanks ArrayList
return scoutRanks;
}
}
Then in your Activity you would call your Utils method like this :
ArrayList<String> scoutRanks = Utils.parseRankFile(this);
Related
I have a ReaderActivity.java class from where I call signString in signData.java class. If all is well then a new activity named ProductActivity is created. If there is exception in signString method, then ProductActivity is not supposed to be created.
The issue is, I still see ProductActivity is created even though I see the KSIEXCEPTION message in the log. What am I missing here?
public class ReaderActivity extends AppCompatActivity {
.....
public void setGlobal(String actualData) {
signData sign = new signData();
try {
sign.signString(getBaseContext(), finalResults, countToSend, locToSend, typeToSend);
Intent productIntent = new Intent(getBaseContext(), ProductActivity.class);
startActivity(productIntent);
} catch (Exception e) {
e.printStackTrace();
}
}
}
Now in the signData class I have the method
public class signData extends Activity{
public void signString(Context context, String data, String count, String loc, String type){
try {
/*some http connection code here*/
/*some computation related to specific API*/
}
catch (KSIException e) {
Log.i("KSIEXCEPTION","here");
e.printStackTrace();
}
}
}
You cant create object for an activity like this. signData sign = new signData();
2.
The issue is, I still see ProductActivity is created even though I see
the KSIEXCEPTION message in the log. What am I missing here?
Yes you just catching the exception in signString method, so after execution of this method definitely, it will create next activity.
If you dont want to go to next activity, you can move that method to some utility class and you can get some return value(boolean at-least) and based on that you can move to next activity
I have a utility method inside Utility.class which is a wrapper for sending Crashlytics events.
public static void logCrashlyticsEvent(String message) {
...
Crashlytics.getInstance().core.logException(new Exception(message));
...
}
The issue is whenever I use it from another class the Crashlytics dashboard shows the source for the event as Utility.class like this:
Utility.java line 106
com.myApp.util.Utility.logCrashlyticsEvent
Instead of the showing the it as the actual class who called it.
Is there a way wrap the call to Crashlytics so it will still show the calling class as the source for the event?
Thanks.
Edit:
Just to improve on #Andre Classen solution.
public static void logCrashlyticsEvent(HandledException e) {
Crashlytics.getInstance().core.logException(e);
Timber.e("Message: %s", e.getMessage());
// More stuff
}
HandledException:
public class HandledException extends Exception {
public HandledException(#NonNull String message, Object... args) {
super(String.format(message, args));
}
}
Usage:
Utility.logCrashlyticsEvent(new HandledException("Cast exception, input value1: %s, value2: %s", someValue, anotherValue));
You are creating a new Exception instead of logging the source exception , so the solution is easy:
public static void logCrashlyticsEvent(Exception e) {
.
.
Crashlytics.getInstance().core.logException(e);
.
.
}
To use it:
try{
String s=null;
int size=toString().length();
}
catch (NullPointerException e){
com.myApp.util.Utility.logCrashlyticsEvent(e);
}
This way the exception is logged the way you want it.
This question already has answers here:
What is a NullPointerException, and how do I fix it?
(12 answers)
Closed 7 years ago.
New to android programming - apologies for incorrect jargon.
My app can save data entered to EditText fields.
It then can load this data and set the values of this data to String Variables.
Then it preforms a POST HTTP request with these strings.
I'm loading/saving string files using openFileInput and openFileOutput
I've created Methods:
public String LoadMethod()
public String SaveMethod()
These Methods work fine when the Method is in same class as the Activity calling it.
My problem is that 2 Activities need to be able to run the public String LoadMethod()
So what i did was create 2 java class files for Loading and Saving data.
Some commenting is in the files as I've been trying to debug.
LoadUserDetails.java
public class LoadUserDetails extends AppCompatActivity {
public static String sSavedName;
public static String sSavedCompany;
public static String sSavedPhone;
public static String sSavedCarRegistration;
String sNameFile = "name_file";
//private Context context;
public String LoadMethod(){
/* OPEN DETAILS FROM INTERNAL STORAGE*/
//context = getActivity();
/*NAME*/
try {
String sOpenName;
FileInputStream fileInputStream = openFileInput("name_file");
InputStreamReader inputStreamReaderName = new InputStreamReader(fileInputStream);
BufferedReader bufferedReaderName = new BufferedReader(inputStreamReaderName);
StringBuffer stringBufferName = new StringBuffer();
while ((sOpenName = bufferedReaderName.readLine()) != null) {
stringBufferName.append(sOpenName + "\n");
}
sSavedName = (stringBufferName.toString());
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
The code repeats for opening the other 3 string files.
I Launch this method from my UserDetails.java Activity and MainActivity.java Activity using this code:
//Load User Details
LoadUserDetails load = new LoadUserDetails();
load.LoadMethod();
This is the error I get in logcat:
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.visitorrego.oem.smartsigninvisitor/com.visitorrego.oem.smartsigninvisitor.UserDetails}: java.lang.NullPointerException
..........
Caused by: java.lang.NullPointerException
at android.content.ContextWrapper.openFileInput(ContextWrapper.java:191)
at com.visitorrego.oem.smartsigninvisitor.LoadUserDetails.LoadMethod(LoadUserDetails.java:31)
at com.visitorrego.oem.smartsigninvisitor.UserDetails.onCreate(UserDetails.java:37)
I've tried using Context and the ContextWrapper error disappears but i still get the others :(
I know its something to do with calling a method using OpenFileInput from a different class.
I don't have an issue with calling the postrequest method in my webrequest class...
Any ideas?
Can post more code if needed.
As I can understand from your code, the class LoadUserDetails is not an activity,
so probably you might need to change the
public class LoadUserDetails extends AppCompatActivity
to
public class LoadUserDetails
Send The Context as parameter from the page you're calling. Because the context is initialized normally onCreate() (usually for activities).
the function will be
public String LoadMethod(Context context){
....
FileInputStream fileInputStream = context.openFileInput("name_file");
....
}
and you can call it by
LoadUserDetails load = new LoadUserDetails();
load.LoadMethod(getApplicationContext());
I have an app that uses custom Exceptions, such as this:
public class SomeException extends Exception{
private int iCode;
private String iMessage;
public SomeException(){
iCode = 201;
iMessage = **//Get the localized string R.string.error_201??**
}
#Override
public String getMessage() {
return iMessage;
}
#Override
public int getCode() {
return iCode;
}
}
Obviously, I want lo localize the error message. I have possible solutions but non of them satisfy me.
1) Pass "Context" to the constructor, and do ctx.getString(R.string.error_201)
--> Fail, as this Exceptions are sometimes thrown from MODEL classes, so they don't have a Context
2) Pass "Context" when retriveing the message in getMessage() function,
--> Fail, It's necesary to override the super method, to work as all other Exceptions.
Solution I have now: All activities in my app have this onCreate:
public void onCreate(...){
Utils.RESOURCES = getResources();
...
}
Very dirty code... I don't like the solution. My question is then,: is there a way to access the resources without the Context? And most important, How would an application such as mine solve this problem?
What about
public class MyException extends Exception {
private int iCode;
public MyException(int code) {
this.iCode = code;
}
#Override
public String getMessage() {
return "MyException code " + String.valueOf(iCode);
}
public String getLocalizedMessage(Context ctx) {
String message;
if (iCode == 201)
message = ctx.getString(R.string.error_201);
else if (iCode == 202)
message = ctx.getString(R.string.error_202);
// ...
}
}
Even if there was way to access context in different way, you should not do it. If you need to emit exceptions where you cannot pass Context, you should be able to access context before you display such error. I cannot see reason why you should create localized error messages from constructor. You can log to logcat not localized versions if you need. And where you want to display something in UI, you should have context at hand.
You can access only system wide resources without Context.
You need a Context, so I would suggest You to get it as soon as possible, and make it available through a static method or variable. You do the same thing in every Activity, but there is a cleaner method. You should make a custom Application, and override its onCreate() to make the resources public:
public class App extends Application {
private static Resources myResources;
#Override
public void onCreate() {
myResources = getBaseContext().getResources();
super.onCreate();
}
public static Resources getMyResources(){
return myResources;
}
}
The other thing you have to do is to set the Application in your manifest:
<application
android:name="{your_package}.App"
...
Now you can access the resources in all of your Activity without any preparation. Your custom Exception class could also use the externalized resources.
I'm using AsyncTask to download and parse data in a separate thread and I need to pass in the values returned by loadXml into the database.
The problem is that I can't instantiate the database because it requires a context and my DownloadXmlTask is in a separate class to the activity class where it is instantiated.
How do I use pass the values into the database if I can't instantiate the database class?
Code Sample:
public class DownloadXmlTask extends AsyncTask<String,Void,Void>{
public static final String TAG = "VotingApp";
#Override
protected Void doInBackground(String... urls) {
try {
// Get the parsed list of Candidate objects
ArrayList<Candidate> candidatesList = loadXml(urls[0]);
CandidatesDatabaseHelper db = new CandidatesDatabaseHelper(getApplicationContext()); <---- ERROR (I know I can't use getApplicationContext() here)
// Insert the candidates into the database
for(Candidate c : candidatesList){
//NOT FINISHED
}
} catch (IOException e) {
Log.d(TAG, "Error " + e);
} catch (XmlPullParserException e) {
Log.d(TAG, "Error " + e);
}
Log.d(TAG, "NOT WORKING");
return null;
}
You could solve that problem by making AsyncTask an inner class, but if you just do it the way you are currently doing it then technically you could do AsyncTask<Object,Void,Void>:
#Override
protected Void doInBackground(Object... urls) {
Context context = (Context)urls[0]; //should always be true by your own rules
/*then you can also loop the urls for the rest of the Strings to cast
**if there are going to be more. Or not. Your choice*/
//.....
instead of String. When calling .execute(this, someString), send it the Context first and the String second. Then you just cast each of them into their appropriate variables. Try that and let me know if it works. Can't test it out right now unfortunately so you're going to have to test it.