I'm having some strange errors reports on Google Play Developer Console regarding NPEs on Activity context or Application context. I can't recreate this error on my device and I know it's working fine on most devices.
This is my Main Activity, the one that is first opened on app startup:
public class ActSplash extends Activity {
private Sync sync;
private Context ctx;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.act_splash);
do {
ctx = this.getApplicationContext(); //Using just "this" doesn't work either.
} while (ctx==null);
sync = Sync.getInstance(ctx); //Apparently ctx is null at this point in some devices
}
This is my Sync class (Singleton)
public class Sync {
private Context ctx;
private static Sync INSTANCE = null;
public static Sync getInstance(Context ctx) {
if (INSTANCE == null) createInstance(ctx);
return INSTANCE;
}
private synchronized static void createInstance(Context ctx) {
if (INSTANCE == null) {
INSTANCE = new Sync(ctx);
}
}
private Sync(Context _ctx)
{
ctx = _ctx;
//NPE on following line
WifiManager wifiMan = (WifiManager) ctx.getSystemService(Context.WIFI_SERVICE);
...
}
This is the stack trace:
java.lang.RuntimeException: Unable to start activity
ComponentInfo{com.xxx.xxx/com.xxx.xxx.ActSplash}: java.lang.NullPointerException
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2140)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2178)
at android.app.ActivityThread.access$700(ActivityThread.java:141)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1271)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:5118)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:792)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:555)
at dalvik.system.NativeStart.main(Native Method)
Caused by: java.lang.NullPointerException
at com.xxx.xxx.Sync.<init>(SourceFile:82)
at com.xxx.xxx.Sync.void createInstance(android.content.Context)(SourceFile:67)
at com.xxx.xxx.Sync.com.xxx.xxx.Sync getInstance(android.content.Context)(SourceFile:72)
at com.xxx.xxx.ActSplash.void onCreate(android.os.Bundle)(SourceFile:40)
at android.app.Activity.performCreate(Activity.java:5058)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1079)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2104)
... 11 more
What can I do to make sure I have ctx!=null before calling:
sync = Util_Sync.getInstance(ctx);
so as you have code that does not change
do {
ctx = this.getApplicationContext(); //Using just "this" doesn't work either.
} while (ctx==null);
this is going to result in an endless loop, if it fails to get ctx.
Activity is a context! See http://developer.android.com/reference/android/content/Context.html
Known Indirect Subclasses
AbstractInputMethodService, AccessibilityService, AccountAuthenticatorActivity, ActionBarActivity, Activity, ActivityGroup, AliasActivity, Application, BackupAgent, BackupAgentHelper, ContextThemeWrapper, and 23 others.
Try
ctx = this;
Update
Further to your Sync code being posted
private Context ctx;
is never used, so remove it.
Note that this can never be null. Assume to the contrary that it can be, then this means you would have a call such as myObj.myMethod() where myObj is null. But then this method call would throw a NPE before execution enters myMethod().
This means that your error is coming from somewhere else.
Would you mind posting the full constructor ? null pointer exception occurs somewhere inside of Sync() constructor. _ctx is not null though
Related
When using Hilt with Espresso I found that my activity is either not resumed or not destroyed. When I comment out the very first test that launches my activity the second one started to pass. The workaround is to separate each test however this will produce a lot of boiler plate code.
Also I have a custom activity inside the tests that inherits from my main activity.
#RunWith(AndroidJUnit4.class)
#HiltAndroidTest
public class MainActivityTest {
// ... initilisation & mocks
#Before
public void setUp() {
MockitoAnnotations.initMocks(this);
hiltAndroidRule.inject();
context = getInstrumentation().getTargetContext();
// ... other initialisation and setup
}
// Helper classes and functions
#AndroidEntryPoint
public class ModifiedMainActivity extends MainActivity {
// ... custom activity implementations
}
// Factory
private SingleActivityFactory<MainActivity> activityFactory = new SingleActivityFactory<MainActivity>(MainActivity.class) {
#Override
protected MainActivity create(Intent intent) {
ModifiedMainActivity mainActivity = new ModifiedMainActivity();
// other custom activity configuration & setup
return mainActivity;
}
}
#After
public void tearDown() {
// ... other code to tear down some stubs
}
}
Any ideas?
I can provide some code but other is under NDA.
My rules:
#Rule(order = 0)
public HiltAndroidRule hiltAndroidRule = new HiltAndroidRule(this);
#Rule(order = 1)
public ActivityTestRule<MainActivity> mainActivityRule = new ActivityTestRule<>(activityFactory, true, false);
Test example:
#Test
public void test_report_system_back_button_pressed_when_closing_main_activity() {
Intent intent = new Intent(Intent.ACTION_MAIN);
final MainActivity mainActivity = mainActivityRule.launchActivity(intent);
getInstrumentation().runOnMainSync(mainActivity::onBackPressed);
verify(mockedHelper, times(1)).reportEvent(eq(Codes.SYSTEM_BACK_PRESSED), eq("SystemBackPressed"), nullable(Map.class));
}
Exception:
java.lang.RuntimeException: No activities found. Did you forget to launch the activity by calling getActivity() or startActivitySync or similar?
at androidx.test.espresso.base.RootViewPicker.waitForAtLeastOneActivityToBeResumed(RootViewPicker.java:176)
at androidx.test.espresso.base.RootViewPicker.get(RootViewPicker.java:88)
at androidx.test.espresso.ViewInteractionModule.provideRootView(ViewInteractionModule.java:77)
at androidx.test.espresso.ViewInteractionModule_ProvideRootViewFactory.provideRootView(ViewInteractionModule_ProvideRootViewFactory.java:37)
at androidx.test.espresso.ViewInteractionModule_ProvideRootViewFactory.get(ViewInteractionModule_ProvideRootViewFactory.java:27)
at androidx.test.espresso.ViewInteractionModule_ProvideRootViewFactory.get(ViewInteractionModule_ProvideRootViewFactory.java:10)
at androidx.test.espresso.base.ViewFinderImpl.getView(ViewFinderImpl.java:63)
at androidx.test.espresso.ViewInteraction$2.call(ViewInteraction.java:280)
at androidx.test.espresso.ViewInteraction$2.call(ViewInteraction.java:272)
at java.util.concurrent.FutureTask.run(FutureTask.java:237)
at android.os.Handler.handleCallback(Handler.java:751)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6119)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)
I'm trying to use openFileOutput method in a non-activity class. When I try use a context, from the MainActivity (this), the program crash.
Some form to use that method in my class ?
private Context context;
public Events(Context context) {
this.context = context;
}
public void setEvent(int year, int month, int dayNumber, int hour, int minutes, String event, String eventParameters) {
try {
OutputStreamWriter events = new OutputStreamWriter(context.openFileOutput("events.txt", Context.MODE_PRIVATE));
} catch(IOException e) {
e.printStackTrace();
} // End of try
} // End of method - setEvent
I have a personalized dialog, it is used to call the setEvent method.
public CellOptions(final Dialog dialog) {
final Events event = new Events(dialog.getContext());
final TextView newEvent = (TextView) dialog.findViewById(R.id.newEvent), eventView = (TextView) dialog.findViewById(R.id.eventView);
newEvent.setOnClickListener(new View.OnClickListener() {
public void onClick(View option) {
event.setEvent(2018, 0, 1, 0, 0, "New year", "Nothing");
eventView.setBackgroundColor(Color.rgb(0, 0, 8));
}
});
}
public boolean showed() {
return true;
}
Too, I have tried to use setEvent in MainActivity class from the next form.
Events event = new Events(this, the next parameters);
But it doesn't work.
I have searched answers about this problem, but I can't find a solution that helps me.
I found this pages, but the same problem continue.
how to call method in activity form non activity class
Getting activity from context in android
using openFileOutput() in a class. (not an activity)
http://www.sgoliver.net/blog/ficheros-en-android-i-memoria-interna/
When I run my program, it crash when it use the context.
Logcat shows this:
01-03 15:55:25.932: W/Binder(632): Caught a RuntimeException from the binder stub implementation.
01-03 15:55:25.932: W/Binder(632): java.lang.NullPointerException
01-03 15:55:25.932: W/Binder(632): at android.inputmethodservice.IInputMethodWrapper.setSessionEnabled(IInputMethodWrapper.java:280)
01-03 15:55:25.932: W/Binder(632): at com.android.internal.view.IInputMethod$Stub.onTransact(IInputMethod.java:129)
01-03 15:55:25.932: W/Binder(632): at android.os.Binder.execTransact(Binder.java:404)
01-03 15:55:25.932: W/Binder(632): at dalvik.system.NativeStart.run(Native Method)
01-03 15:55:25.932: W/InputMethodManagerService(487): Got RemoteException sending setActive(false) notification to pid 2744 uid 10036
01-03 15:55:26.572: I/ActivityManager(487): Displayed com.android.dropcalendary/.MainActivity: +4s402ms
Using activity method in non-activity class? Short story is, You cannot
But there certainly is a way for that, you can pass in your activity (which usually is not a good idea, if your activity is destroyed it can caused null pointer or memory leak).
One other way is if you need the context, you can use ApplicationContext for that.
Use ApplicationContext instead of context. Since the lifecycle of this Context is preserved until the app is destroyed or finished.
So Context is preserved only until the activity is destroyed.
getApplicationContext();
I've achieved solve the problem.
The method works in a activity, to use the method in a non-activity class, I did use:
getApplicationContext();
I did use it, sending the context since MainActivity, through of CellOptions class, and in CellOptions class I did send the same context.
MainActivity:
new CellOptions(cellOptions, getApplicationContext());
CellOptions class (context = application context):
Events event = new Events(context);
Events class:
context.openFileOutput(events.txt);
Other problem was that I used "/", and instead I used "\\"
When trying to edit a custom arraylist from another Activity the application force closed.
Arraylist in MainActivity:
ArrayList<Contacts> contacts = new ArrayList<Contacts>();
Another Activity:
MainActivity main = new MainActivity();
main.contacts.get(position).contactname=x;
main.contacts.get(position).contactnumber=x;
How can I edit an arraylist from another activity?
Logcat:
09-08 22:53:40.415 1760-1760/com.example.amir_p.contacts E/AndroidRuntime﹕ FATAL EXCEPTION: main
Process: com.example.amir_p.contacts, PID: 1760
java.lang.RuntimeException: Failure delivering result ResultInfo{who=null, request=2, result=-1, data=Intent { (has extras) }} to activity {com.example.amir_p.contacts/com.example.amir_p.contacts.ContactInfo}: java.lang.IndexOutOfBoundsException: Invalid index 0, size is 0
at android.app.ActivityThread.deliverResults(ActivityThread.java:3577)
at android.app.ActivityThread.handleSendResult(ActivityThread.java:3620)
at android.app.ActivityThread.access$1300(ActivityThread.java:151)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1352)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5257)
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:903)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698)
Caused by: java.lang.IndexOutOfBoundsException: Invalid index 0, size is 0
at java.util.ArrayList.throwIndexOutOfBoundsException(ArrayList.java:255)
at java.util.ArrayList.get(ArrayList.java:308)
at com.example.amir_p.contacts.ContactInfo.onActivityResult(ContactInfo.java:53)
at android.app.Activity.dispatchActivityResult(Activity.java:6192)
at android.app.ActivityThread.deliverResults(ActivityThread.java:3573)
Two issues:
1
You can't instantiate an activity:
new MainActivity();
Activities must be launched from an Intent like so:
thisActivity.startActivity( new Intent( NextActivity.class ) );
2
If you want two activities to share a list, then you must instantiate that list in a greater scope, like the Application scope by creating a custom application class or creating a singleton.
Singleton:
public final class MySingleton {
private static final MySingleton SELF = new MySingleton();
private List<Contacts> contacts = new ArrayList<Contacts>();
private boolean didContacts
private MySingleton() {
// Don't want anyone else constructing the singleton.
}
public static MySingleton getInstance() {
return SELF;
}
public List<Contacts> getContacts() {
return contacts;
}
}
Now in any activity you like you may get the list
MySingleton.getInstance().getContacts()
Just be careful of concurrent modification.
Amendment due to a request in comments
It was stated in the comments that you want to change one activity from another. You must realize only one activity is active at a time and so you SHOULD NOT do that, regardless of whether or not you could hack it. I would normally recommend a listener but a listener wont work in this case since only one Activity Another way to do this would be to have some in-memory state that lives outside the activity (maybe the singleton) that the activities can respond to when they regain focus.
Pseudo code
ActivityB {
onClick() {
MySingleton.getInstance().getContacts().add( theContact );
}
}
ActivityA {
onResume() {
// consider contacts may have changed and redraw
listViewAdapter.clear();
listViewAdapter.addAll( MySingleton.getInstance().getContacts() );
}
}
This is the class of which I want to test EditText. But when I try to assign that EditText field in the Test clas it shows an null pointer exception. I have omitted other use less code for the problem
public class LogInActivity extends ActionBarActivity {
private Button signUpButton;
private Button logInButton;
private Intent signUpChoiceIntent;
private Intent homeActivityIntent;
private String username;
private String password;
private EditText usernameTextField;
private EditText passwordTextField;
private HumLogController humLogController;
private String error;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_log_in);
humLogController = (HumLogController) getIntent().getSerializableExtra("controllerObject");
setIntentAndButton();
}
private void setAndCheckFields(){
/** I want to test this, (view with id:- logInUsernameField ) which is working fine in practice, but not passing the test. When I try to call the same id in Test class with instance of this class, it gives a null pointer exception. */
usernameTextField = (EditText) findViewById(R.id.logInUsernameField);
}
This is the test class where I am testing for the EditText field, but giving a null pointer exception
public class LogInActivityInstrumentTest extends InstrumentationTestCase{
LogInActivity logInActivity;
#Override
protected void setUp() throws Exception{
super.setUp();
logInActivity = new LogInActivity();
}
public void testUsernameTextViewNullTest(){
// The line below is line 23. Which is giving null pointer Exception...?
EditText text = (EditText) logInActivity.findViewById(R.id.logInUsernameField);
assertNotNull(text);
}
#Override
protected void tearDown() throws Exception{
super.tearDown();
}
}
The log cat is given below.
java.lang.NullPointerException
at android.app.Activity.findViewById(Activity.java:1853)
at com.example.praduman.humlog.tests.LogInActivityInstrumentTest.testUsernameTextViewNullTest(LogInActivityInstrumentTest.java:23)
at java.lang.reflect.Method.invokeNative(Native Method)
at android.test.InstrumentationTestCase.runMethod(InstrumentationTestCase.java:214)
at android.test.InstrumentationTestCase.runTest(InstrumentationTestCase.java:199)
at android.test.AndroidTestRunner.runTest(AndroidTestRunner.java:191)
at android.test.AndroidTestRunner.runTest(AndroidTestRunner.java:176)
at android.test.InstrumentationTestRunner.onStart(InstrumentationTestRunner.java:554)
at android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:1701)
You cannot create an Activity simply calling its constructor as you did. In a test context, you need some kind of instrumentation to allow everything to work properly. Try to take a look at Espresso (for in device tests) or even Robolectric (for JVM tests).
You can not create an instance of your activity using the constructor like ou have done in the above code.
Try changing the following in your LogInActivityInstrumentTest
public class LogInActivityInstrumentTest extends InstrumentationTestCase<LogInActivity>{
public LogInActivityInstrumentTest() {
super(LogInActivity.class);
}
#Override
protected void setUp() throws Exception{
super.setUp();
logInActivity = new getActivity();
}
}
The documentation for running tests can be found here, on developer.android.com.
In the code you have posted - simple creating the Activty using its constructor does not run it through the lifecycle that an activity expects. The reason for your NullPointerException is the fact that onCreate has not been run, meaning that you are trying to look up a view before you have called setContentView(), therefore, the view really is null.
I have an exception that is thrown after the app has been sitting idle for awhile. It seems to always happen when my app is trying to reference my singleton typeface class.
My singleton class (TypefaceSingleton.java) is used to reference the Roboto fonts from a single source. This is a scaled down version of the actual file. I have labeled the line from the stack trace.
TypefaceSingleton.java class
package com.steve.demo;
import android.content.Context;
import android.graphics.Typeface;
import android.view.View;
public class TypefaceSingleton {
private static Context mContext;
public static void initialize(Context context) {
mContext = context;
}
private static Typeface robotoCondensedBoldItalic;
public static Typeface getRobotoCondensedBoldItalic() {
if (robotoCondensedBoldItalic == null) {
// (TypefaceSingleton.java:111) is below
robotoCondensedBoldItalic = Typeface.createFromAsset(mContext.getAssets(), "fonts/Roboto/RobotoCondensed-BoldItalic.ttf");
}
return robotoCondensedBoldItalic;
}
private static TypefaceSingleton mInstance;
public static TypefaceSingleton getInstance() {
if (mContext == null) {
throw new IllegalArgumentException("This class must be initialized before");
}
if (mInstance == null) {
mInstance = new TypefaceSingleton();
}
return mInstance;
}
private TypefaceSingleton() {
// Todo here
}
}
I initialize the singleton class only once. I have a splashscreen activity that performs the initialization.
SplashScreenActivity.java
// Perform Initialization
TypefaceSingleton.initialize(mContext.getApplicationContext());
TypefaceSingleton.getInstance();
The exception thrown is indicating a null pointer reference to TypefaceSingleton.getRobotoCondensedBoldItalic.
From the Developers Console
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.steve.demo/com.steve.demo.RoutesActivity}: java.lang.NullPointerException
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2334)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2392)
at android.app.ActivityThread.access$900(ActivityThread.java:169)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1280)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:146)
at android.app.ActivityThread.main(ActivityThread.java:5487)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1283)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1099)
at dalvik.system.NativeStart.main(Native Method)
Caused by: java.lang.NullPointerException
at com.steve.demo.TypefaceSingleton.getRobotoCondensedBoldItalic(TypefaceSingleton.java:111)
at com.steve.demo.RoutesActivity.setCustomActionBarTitle(RoutesActivity.java:130)
at com.steve.demo.RoutesActivity.onCreate(RoutesActivity.java:86)
at android.app.Activity.performCreate(Activity.java:5451)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1093)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2298)
... 11 more
I am sure the issue have to with the java is handling memory (ie, garbage collection?) but I not sure how to resolve.
Thanks in advance.
Steve