I am working on adding Shared Preferences to my Note taking Android App and I am running into a peculiar null pointer exception. I am currently testing settings for font size and typeface in my app and have been able to successfully save the shared preferences for both but am having trouble with the retrieval part. When the settings are changed, they successfully change the font and font size on a Fragment for the remainder of time the app is opened but I cannot restore them if the app is restarted.
First weird Null Pointer is in the onCreate.
OnCreate:
//create a new note fragment if one has not been created yet
mNoteFragment = (NoteFragment) getFragmentManager().findFragmentById(R.id.container);
if (mNoteFragment == null) {
mNoteFragment = new NoteFragment();
getFragmentManager().beginTransaction()
.replace(R.id.container, mNoteFragment).commit();
}
//restore SharedPreferences
SharedPreferences sharedPrefs = getPreferences(0);
int stylePref = sharedPrefs.getInt(SharedPreferanceConstants.PREF_FONT_SIZE, 2);
String fontPref = sharedPrefs.getString(SharedPreferanceConstants.PREF_TYPEFACE, "");
Log.e("STYLEID", String.valueOf(stylePref));
Log.e("FONTTYPE", fontPref);
onStyleChange(null , stylePref); //NULL POINTER EXCEPTION HERE
onFontChange(null, fontPref);
The logs output "3" and "Impact" which are the correct values for size and font which indicates that stylePref and fontPref are not null.
The next Null Pointer is below.:
#Override
public void onStyleChange(CustomStyleDialogFragment dialog, int styleId) {
Log.d("NOTEFRAGMENT", String.valueOf(mNoteFragment));
mNoteFragment.setCustomStyle(styleId); //NULL POINTER EXCEPTION HERE
}
#Override
public void onFontChange(CustomStyleDialogFragment dialog, String fontName) {
mNoteFragment.setCustomFont(fontName);
}
I have tested logging the value of styleId and got "3" so that doesn't seem to be the issue. mNoteFragment isnt null either based on the log.
Here is the third NP Exception in the NoteFragment.java. This is where I ultimately set the EditText view to the desired settings. I had no trouble changing font and size without shared preferences so I am not sure the issue here.
public void setCustomFont(String fontName) {
if(fontName.equals("Helvetica")) {
mEditText.setTypeface(mHelvetica);
}
else if(fontName.equals("Helvetica-Neue")) {
mEditText.setTypeface(mHelveticaNeue);
}
else if(fontName.equals("Impact")) {
mEditText.setTypeface(mImpact);
}
else {
mEditText.setTypeface(Typeface.DEFAULT);
}
}
public void setCustomStyle(int styleId) {
if(styleId == 1) {
mEditText.setTextAppearance(getActivity(), android.R.style.TextAppearance_Small);
}
else if(styleId == 2) {
mEditText.setTextAppearance(getActivity(), android.R.style.TextAppearance_Medium);
}
else if(styleId == 3) {
//NULL POINTER EXCEPTION HERE
mEditText.setTextAppearance(getActivity(), android.R.style.TextAppearance_Large);
}
}
And of course, here is the logcat. Thanks in advance!
11-18 10:31:53.030 18966-18966/com.richluick.blocnotes I/Process﹕ Sending signal. PID: 18966 SIG: 9
11-18 10:35:32.838 19248-19248/com.richluick.blocnotes D/STYLEID﹕ 3
11-18 10:35:32.838 19248-19248/com.richluick.blocnotes D/FONTTYPE﹕ Impact
11-18 10:35:32.839 19248-19248/com.richluick.blocnotes D/ERROR﹕ NoteFragment{422972f8 id=0x7f090001}
11-18 10:35:32.840 19248-19248/com.richluick.blocnotes D/AndroidRuntime﹕ Shutting down VM
11-18 10:35:32.840 19248-19248/com.richluick.blocnotes W/dalvikvm﹕ threadid=1: thread exiting with uncaught exception (group=0x4197dd40)
11-18 10:35:32.842 19248-19248/com.richluick.blocnotes E/AndroidRuntime﹕ FATAL EXCEPTION: main
Process: com.richluick.blocnotes, PID: 19248
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.richluick.blocnotes/com.richluick.blocnotes.BlocNotes}: java.lang.NullPointerException
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2198)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2257)
at android.app.ActivityThread.access$800(ActivityThread.java:139)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1210)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:136)
at android.app.ActivityThread.main(ActivityThread.java:5097)
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:785)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:601)
at dalvik.system.NativeStart.main(Native Method)
Caused by: java.lang.NullPointerException
at com.richluick.blocnotes.NoteFragment.setCustomStyle(NoteFragment.java:86)
at com.richluick.blocnotes.BlocNotes.onStyleChange(BlocNotes.java:139)
at com.richluick.blocnotes.BlocNotes.onCreate(BlocNotes.java:61)
at android.app.Activity.performCreate(Activity.java:5248)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1110)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2162)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2257)
at android.app.ActivityThread.access$800(ActivityThread.java:139)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1210)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:136)
at android.app.ActivityThread.main(ActivityThread.java:5097)
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:785)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:601)
at dalvik.system.NativeStart.main(Native Method)
NoteFragment.java
public class NoteFragment extends Fragment {
public EditText mEditText;
private Typeface mHelvetica;
private Typeface mHelveticaNeue;
private Typeface mImpact;
private static final String TEXT = "text";
#Override
public void onSaveInstanceState(Bundle savedInstanceState) {
super.onSaveInstanceState(savedInstanceState);
savedInstanceState.putString(TEXT, mEditText.getText().toString());
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_note, container, false);
setHasOptionsMenu(true);
//restore state of app when activity is destroyed and restarted
mEditText = (EditText) rootView.findViewById(R.id.editText);
if (savedInstanceState != null) {
mEditText.setText(savedInstanceState.getString(TEXT));
}
//Store the font assets as variables
mHelvetica = Typeface.createFromAsset(getActivity().getAssets(), "fonts/Helvetica_Reg.ttf");
mHelveticaNeue = Typeface.createFromAsset(getActivity().getAssets(), "fonts/HelveticaNeue_Lt.ttf");
mImpact = Typeface.createFromAsset(getActivity().getAssets(), "fonts/impact.ttf");
return rootView;
}
/**
* This is a setter method for setting the font the user has selected from the spinner
*
* param fontName the name of the font the user selected
* #return void
* */
public void setCustomFont(String fontName) {
if(fontName.equals("Helvetica")) {
mEditText.setTypeface(mHelvetica);
}
else if(fontName.equals("Helvetica-Neue")) {
mEditText.setTypeface(mHelveticaNeue);
}
else if(fontName.equals("Impact")) {
mEditText.setTypeface(mImpact);
}
else {
mEditText.setTypeface(Typeface.DEFAULT);
}
}
/**
* This is a setter method for setting the font style the user has selected from custom menu
*
* param styleId the integer id of the font stlye selected (SMALL, MEDIUM, LARGE)
* #return void
* */
public void setCustomStyle(int styleId) {
if(styleId == 1) {
mEditText.setTextAppearance(getActivity(), android.R.style.TextAppearance_Small);
}
else if(styleId == 2) {
mEditText.setTextAppearance(getActivity(), android.R.style.TextAppearance_Medium);
}
else if(styleId == 3) {
Log.d("EDITTEXT", String.valueOf(mEditText));
mEditText.setTextAppearance(getActivity(), android.R.style.TextAppearance_Large);
}
}
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
// Inflate the menu; this adds items to the action bar if it is present.
super.onCreateOptionsMenu(menu, inflater);
inflater = getActivity().getMenuInflater();
inflater.inflate(R.menu.bloc_notes, menu);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.action_erase) {
mEditText.setText("");
}
return super.onOptionsItemSelected(item);
}
}
In your SomeActivity.onCreate() you are creating an instance of NoteFragment, but even if you commit it via a transaction, it won't be inflated and created right away. Which basically means, the NoteFragment.onCreateView() was not executed and the fragments UI is not yet created. However, your Activity.onCreate() assumes, that mFragment.mEditText is already set, which is not the case, so you run into a NullPointerException.
Take a look at the FragmentTransation.commit method: http://developer.android.com/reference/android/support/v4/app/FragmentTransaction.html#commit()
Schedules a commit of this transaction. The commit does not happen immediately; it will
be scheduled as work on the main thread to be done the next time that thread is ready.
Your mEditText in your NoteFragment is null at this time, hence the NPE.
Just init your member mEditText in onCreate() or onActivityCreated() of the fragment, not onCreateView(). That should ensure that mEditText is not null when you call your setters.
Whatever happens, you should be protecting against a null mEditText in your setter functions.
EDIT this is what I meant:
public void setCustomFont(String fontName) {
if(mEditText != null){
if(fontName.equals("Helvetica")) {
mEditText.setTypeface(mHelvetica);
}
else if(fontName.equals("Helvetica-Neue")) {
mEditText.setTypeface(mHelveticaNeue);
}
else if(fontName.equals("Impact")) {
mEditText.setTypeface(mImpact);
}
else {
mEditText.setTypeface(Typeface.DEFAULT);
}
}
}
EDIT 2: Oncreate will not be a good place. Basically you want to call your setter after the fragmentmanager has committed your change, so that mEditText has been initialized.
EDIT 3 - Try this with your initial code:
getFragmentManager().beginTransaction().replace(R.id.container, mNoteFragment).commit();
getFragmentManager().executePendingTransactions();
Okay so I am not sure why this works but I was able to figure out the anwer based on this question:
onCreateView() in Fragment is not called immediately, even after FragmentManager.executePendingTransactions()
I added the following line
getFragmentManager().executePendingTransactions();
and then moved everthing to the onStart method
#Override
protected void onStart() {
super.onStart();
//create a new note fragment if one has not been created yet
mNoteFragment = (NoteFragment) getFragmentManager().findFragmentById(R.id.container);
if (mNoteFragment == null) {
mNoteFragment = new NoteFragment();
getFragmentManager().beginTransaction().replace(R.id.container, mNoteFragment).commit();
getFragmentManager().executePendingTransactions();
}
//restore SharedPreferences
SharedPreferences sharedPrefs = getPreferences(0);
int stylePref = sharedPrefs.getInt(SharedPreferanceConstants.PREF_FONT_SIZE, 2);
String fontPref = sharedPrefs.getString(SharedPreferanceConstants.PREF_TYPEFACE, "");
Log.d("STYLEID", String.valueOf(stylePref));
Log.d("FONTTYPE", fontPref);
onStyleChange(null , stylePref);
onFontChange(null, fontPref);
}
and for some reason it works fine now. If anyone could explain why that would be great
Try use 'apply' instead of 'commit' , the justification is here -> What's the difference between commit() and apply() in Shared Preference by Lukas Knuth.
But basically, apply() will commits its changes to the in-memory SharedPreferences immediately.
It's strong recommended use a class to manager your preferences, like 'MyPreferencesManager'.
Related
This question already has answers here:
What is a NullPointerException, and how do I fix it?
(12 answers)
Closed 5 years ago.
My application has a Progress Dialog for login process and when the orientation is changed while dialog box is open, app crashes.This all works fine, except when screen orientation changes while the dialog is up. At this point the app crashes. I am figuring out this issue from the last 3 nights but not able to get it, please help.
My fragment:
public class Example extends Fragment {
private static final String TAG = "LoginActivity";
private static final int REQUEST_SIGNUP = 0;
Unbinder unbinder;
#BindView(R.id.input_email) EditText _emailText;
#BindView(R.id.input_password) EditText _passwordText;
#BindView(R.id.btn_login) Button _loginButton;
#BindView(R.id.link_signup) TextView _signupLink;
#Override
public void onDestroyView() {
super.onDestroyView();
// unbind the view to free some memory
unbinder.unbind();
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.Example, container, false);
unbinder=ButterKnife.bind(this,rootView);
_loginButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
login();
}
});
_signupLink.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view)
{
Intent create= new Intent(getActivity(),NewAccount.class);
startActivity(create);
}
});
return rootView;
}
public void login() {
Log.d(TAG, "Login");
if (!validate()) {
onLoginFailed();
return;
}
_loginButton.setEnabled(false);
final ProgressDialog progressDialog = new ProgressDialog(getActivity(),
R.style.AppTheme_Dark_Dialog);
progressDialog.setIndeterminate(true);
progressDialog.setMessage("Authenticating...");
progressDialog.show();
//new YourAsynTask(getActivity()).execute();
String email = _emailText.getText().toString();
String password = _passwordText.getText().toString();
// TODO: Implement your own authentication logic here.
new android.os.Handler().postDelayed(
new Runnable() {
public void run() {
// On complete call either onLoginSuccess or onLoginFailed
onLoginSuccess();
// onLoginFailed();
progressDialog.dismiss();
}
}, 3000);
}
#Override
public void onPause() {
Log.e("DEBUG", "OnPause of loginFragment1");
super.onPause();
}
public void onLoginSuccess() {
_loginButton.setEnabled(true);
Intent i=new Intent(getActivity(),SuccessLogin.class);
startActivity(i);
}
public void onLoginFailed() {
Toast.makeText(getActivity(), "Login failed", Toast.LENGTH_LONG).show();
_loginButton.setEnabled(true);
}
public boolean validate() {
boolean valid = true;
String email = _emailText.getText().toString();
String password = _passwordText.getText().toString();
if (email.isEmpty() || !android.util.Patterns.EMAIL_ADDRESS.matcher(email).matches()) {
_emailText.setError("enter a valid email address");
valid = false;
} else {
_emailText.setError(null);
}
if (password.isEmpty() || password.length() < 4 || password.length() > 10) {
_passwordText.setError("between 4 and 10 alphanumeric characters");
valid = false;
} else {
_passwordText.setError(null);
}
return valid;
}
Logcat output:
11-16 19:20:10.955 4022-4022/com.example.a1332931.login_application E/WindowManager: android.view.WindowLeaked: Activity com.example.a1332931.login_application.TabActivity has leaked window com.android.internal.policy.PhoneWindow$DecorView{42b6135 V.E...... R......D 0,0-683,232} that was originally added here
at android.view.ViewRootImpl.<init>(ViewRootImpl.java:375)
at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:299)
at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:85)
at android.app.Dialog.show(Dialog.java:319)
at com.example.a1332931.login_application.Example.login(Example.java:156)
at com.example.a1332931.login_application.Example$1.onClick(Example.java:67)
at android.view.View.performClick(View.java:5201)
at android.view.View$PerformClick.run(View.java:21163)
at android.os.Handler.handleCallback(Handler.java:746)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5443)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:728)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:618)
11-16 19:20:10.957 4022-4095/com.example.a1332931.login_application E/Surface: getSlotFromBufferLocked: unknown buffer: 0xb8aa6c60
11-16 19:20:12.512 4022-4022/com.example.a1332931.login_application E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.a1332931.login_application, PID: 4022
java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.Button.setEnabled(boolean)' on a null object reference
at com.example.a1332931.login_application.Example.onLoginSuccess(Example.java:200)
at com.example.a1332931.login_application.Example$3.run(Example.java:168)
at android.os.Handler.handleCallback(Handler.java:746)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5443)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:728)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:618)
Add this configuration change in your Android manifest activity:
<activity
android:name="YourActivity"
android:configChanges="orientation|keyboardHidden|screenSize"/>
i have a SwitchCompat widget in the ActionBar.
When back button is pressed, and "reopen" the app, SwitchCompat loses the state, goes from on to off.
I am implementing a foreground, but this does not prevent the SwitchCompat changes state.
I tried with SharedPreferences but app crash.
MainActivity.java
SwitchCompat switchService;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
switchService = (SwitchCompat) findViewById(R.id.toggleButton);
LoadPreferences();
}
private void SavePreferences(){
SharedPreferences sharedPreferences = getPreferences(MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putBoolean("state", switchService.isEnabled());
editor.apply(); // I missed to save the data to preference here,.
}
private void LoadPreferences(){
SharedPreferences sharedPreferences = getPreferences(MODE_PRIVATE);
Boolean state = sharedPreferences.getBoolean("state", false);
switchService.setEnabled(state);
}
#Override
public void onBackPressed() {
SavePreferences();
super.onBackPressed();
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
MenuItem item = menu.findItem(R.id.toggle_ButtonL);
MenuItemCompat.getActionView(item).findViewById(R.id.toggleButton);
switchService = (SwitchCompat) MenuItemCompat.getActionView(item);
switchService.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (isChecked) {
// Creates SMSMonitorService intent
Intent SMSMonitorIntent = new Intent(MainActivity.this, SMSMonitorService.class);
// Start SMSMonitorService
startService(SMSMonitorIntent);
Log.i(DEBUG_TAG, "SMSMonitor Started");
} else {
// Creates SMSMonitorService intent
Intent SMSMonitorIntent = new Intent(MainActivity.this, SMSMonitorService.class);
// Stop SMSMonitorService
stopService(SMSMonitorIntent);
Log.i(DEBUG_TAG,"SMSMonitor Stopped");
Toast.makeText(getApplicationContext(), getResources().getString(R.string.toggle_off), Toast.LENGTH_SHORT).show();
}
}
});
return true;
}
Logcat:
01-25 23:41:07.995 1341-1341/com.test.wikitext E/AndroidRuntime﹕ FATAL EXCEPTION: main
Process: com.test.wikitext, PID: 1341
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.test.wikitext/com.test.wikitext.MainActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.support.v7.widget.SwitchCompat.setEnabled(boolean)' 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.access$800(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 'void android.support.v7.widget.SwitchCompat.setEnabled(boolean)' on a null object reference
at com.test.wikitext.MainActivity.LoadPreferences(MainActivity.java:249)
at com.test.wikitext.MainActivity.onCreate(MainActivity.java:73)
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.access$800(ActivityThread.java:144)
(continue)
How i can save the state of SwitchCompat that when back button is pressed this no loses their present state?
I know i was late to the party , but this might help others
Hi as like you i've been searching answer for this the answer is in your question just replace the code like the following
In OnCreateOptionsMenu change the code from
MenuItem item = menu.findItem(R.id.toggle_ButtonL);
MenuItemCompat.getActionView(item).findViewById(R.id.toggleButton);
switchService = (SwitchCompat) MenuItemCompat.getActionView(item);
to
MenuItem item = menu.findItem(R.id.toggle_ButtonL);
switchService = (SwitchCompat)MenuItemCompat.getActionView(item).findViewById(R.id.toggleButton);
this will do the trick. now we can get rid of that NullPointerException
You must remove
switchService = (SwitchCompat) findViewById(R.id.toggleButton);
LoadPreferences();
from onCreate method because the SwitchCompat is not in your layout and it is on the actionBar. then call LoadPreferences(); after
switchService = (SwitchCompat) MenuItemCompat.getActionView(item);
I seem to be fighting with a race condition, the cause of which I can't seem to pin down. When executing the below code, I intermittently get the stack trace below.
Is there some obvious rule of the Fragment lifecycle I am disobeying? I am not clear on what would explicitly forbid me from performing a transaction here to handle the event.
I am using a WebViewClient to detect external URLs clicked within a local .html document - as in, URLs which point to a non-local host. I am using Otto's EventBus to post those actions to an Activity. When the Activity receives those events, I want to show those external URLs in a different Fragment, by calling FragmentTransaction.replace()
DefaultWebViewClient.java
#Override
public boolean shouldOverrideUrlLoading(final WebView view, final String url) {
boolean shouldOverride;
if (urlIsLocal(url)) {
shouldOverride = super.shouldOverrideUrlLoading(view, url);
} else {
// trigger an event for the fragment to swap out
// return true to tell the webview not to load it...
EventBus.getInstance().post(new LoadExternalUrlEvent(url));
shouldOverride = true;
}
return shouldOverride;
}
FragmentActivity.java
#Subscribe
public void onLoadExternalUrlEvent(LoadExternalUrlEvent externalLoadEvent) {
final BrowserFragment browserFragment = new BrowserFragment();
Bundle args = new Bundle();
args.putSerializable(BrowserFragment.ARG_LOAD_EXTERNAL_URL_EVENT, externalLoadEvent);
browserFragment.setArguments(args);
getSupportFragmentManager().beginTransaction()
.replace(R.id.fragment_container, browserFragment, BrowserFragment.FRAGMENT_TAG)
.addToBackStack(null).commit();
}
LoadExternalUrlEvent.java
public class LoadExternalUrlEvent implements Serializable {
private static final long serialVersionUID = 1L;
public final String url;
public LoadExternalUrlEvent(String url) {
this.url = url;
}
#Override
public String toString() {
return "LoadExternalUrlEvent [url=" + url + "]";
}
}
EventBus.java
import com.squareup.otto.Bus;
public class EventBus {
private static Bus _INSTANCE;
public static synchronized Bus getInstance() {
if (null == _INSTANCE) {
_INSTANCE = new Bus();
}
return _INSTANCE;
}
}
Stack trace
java.lang.RuntimeException: Could not dispatch event: class <omitted>.LoadExternalUrlEvent to handler [EventHandler public void <omitted>Activity.onLoadExternalUrlEvent(<omitted>LoadExternalUrlEvent)]: Can not perform this action after onSaveInstanceState
at com.squareup.otto.Bus.throwRuntimeException(Bus.java:456)
at com.squareup.otto.Bus.dispatch(Bus.java:386)
at com.squareup.otto.Bus.dispatchQueuedEvents(Bus.java:367)
at com.squareup.otto.Bus.post(Bus.java:336)
at <omitted>DefaultWebViewClient.shouldOverrideUrlLoading(DefaultWebViewClient.java:51)
at com.android.webview.chromium.WebViewContentsClientAdapter.shouldOverrideUrlLoading(WebViewContentsClientAdapter.java:293)
at com.android.org.chromium.android_webview.AwContentsClientBridge.shouldOverrideUrlLoading(AwContentsClientBridge.java:96)
at com.android.org.chromium.base.SystemMessageHandler.nativeDoRunLoopOnce(Native Method)
at com.android.org.chromium.base.SystemMessageHandler.handleMessage(SystemMessageHandler.java:27)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:157)
at android.app.ActivityThread.main(ActivityThread.java:5356)
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:1265)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1081)
at dalvik.system.NativeStart.main(Native Method)
Caused by: java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
at android.support.v4.app.FragmentManagerImpl.checkStateLoss(FragmentManager.java:1360)
at android.support.v4.app.FragmentManagerImpl.enqueueAction(FragmentManager.java:1378)
at android.support.v4.app.BackStackRecord.commitInternal(BackStackRecord.java:595)
at android.support.v4.app.BackStackRecord.commit(BackStackRecord.java:574)
at <omitted>Activity.run(<omitted>Activity.java:162)
at <omitted>Activity.onLoadExternalUrlEvent(<omitted>Activity.java:156)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.squareup.otto.EventHandler.handleEvent(EventHandler.java:89)
at com.squareup.otto.Bus.dispatch(Bus.java:384)
... 15 more
A/libc(2689): Fatal signal 6 (SIGABRT) at 0x00000a81 (code=-6), thread 2689
I discovered the problem.
Because I was calling EventBus.register() in Activity.onCreate() I was getting multiple instances of the Activity on my backstack which would act as responders to these events.
The solution is to either register your Activity as late as possible with
#Override
protected void onResume() {
super.onResume();
EventBus.getInstance().register(this);
}
#Override
protected void onPause() {
EventBus.getInstance().unregister(this);
super.onPause();
}
or to declare your Activity as a single instance with
android:launchMode="singleTask"
I've programmed a game for android, everything works fine, but now I want my app to have Google play Games services (leaderboards and achievements). I used the Google example code to log in to the Google services (no errors in the script), but every time I want to connect with my App in debug mode, I get this error:
6-29 11:48:29.391 23779-23779/com.JFKGames.theepicbutton E/AndroidRuntime﹕ FATAL EXCEPTION: main
Process: com.JFKGames.theepicbutton, PID: 23779
java.lang.RuntimeException: Failure delivering result ResultInfo{who=null, request=9001, result=10004, data=null} to activity {com.JFKGames.theepicbutton/com.JFKGames.theepicbutton.MainActivity}: java.lang.IllegalStateException: GoogleApiClient must be connected.
at android.app.ActivityThread.deliverResults(ActivityThread.java:3446)
at android.app.ActivityThread.handleSendResult(ActivityThread.java:3489)
at android.app.ActivityThread.access$1300(ActivityThread.java:139)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1258)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:136)
at android.app.ActivityThread.main(ActivityThread.java:5102)
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:785)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:601)
at dalvik.system.NativeStart.main(Native Method)
Caused by: java.lang.IllegalStateException: GoogleApiClient must be connected.
at com.google.android.gms.internal.fq.a(Unknown Source)
at com.google.android.gms.games.Games.c(Unknown Source)
at com.google.android.gms.games.internal.api.LeaderboardsImpl.submitScore(Unknown Source)
at com.google.android.gms.games.internal.api.LeaderboardsImpl.submitScore(Unknown Source)
at com.JFKGames.theepicbutton.MainActivity.onActivityResult(MainActivity.java:79)
at android.app.Activity.dispatchActivityResult(Activity.java:5446)
at android.app.ActivityThread.deliverResults(ActivityThread.java:3442)
at android.app.ActivityThread.handleSendResult(ActivityThread.java:3489)
at android.app.ActivityThread.access$1300(ActivityThread.java:139)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1258)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:136)
at android.app.ActivityThread.main(ActivityThread.java:5102)
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:785)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:601)
at dalvik.system.NativeStart.main(Native Method)
And the App crashes. Here's my code for the MainActivity where I want it to connect:
public class MainActivity extends BaseGameActivity implements
GameHelper.GameHelperListener, View.OnClickListener {
public static int REQUEST_LEADERBOARD = 1002;
boolean mExplicitSignOut = false;
boolean mInSignInFlow = false;
GoogleApiClient mClient() {
return null;
}
#Override
protected void onCreate(Bundle savedInstanceState) {
setRequestedClients(BaseGameActivity.CLIENT_GAMES | BaseGameActivity.CLIENT_APPSTATE);
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button button = (Button)findViewById(R.id.startbutton);
button.setOnClickListener (this);
Button highscorebutton = (Button)findViewById(R.id.highscorebutton);
highscorebutton.setOnClickListener(this);
findViewById(R.id.sign_in_button).setOnClickListener(this);
findViewById(R.id.sign_out_button).setOnClickListener(this);
}
public void onClick(View view) {
if(view.getId()==R.id.startbutton) {
startActivityForResult(new Intent(this, buttonActivity.class), 1);
} else if(view.getId()==R.id.highscorebutton) {
startActivityForResult(Games.Leaderboards.getLeaderboardIntent(getApiClient(), getString(R.string.the_best_players)),REQUEST_LEADERBOARD);
} else if (view.getId() == R.id.sign_in_button) {
// start the asynchronous sign in flow
beginUserInitiatedSignIn();
}
else if (view.getId() == R.id.sign_out_button) {
// sign out.
signOut();
// show sign-in button, hide the sign-out button
findViewById(R.id.sign_in_button).setVisibility(View.VISIBLE);
findViewById(R.id.sign_out_button).setVisibility(View.GONE);
}
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
Games.Leaderboards.submitScore(getApiClient(), getString(R.string.the_best_players), resultCode);
if(requestCode==1) {
if(resultCode > leseHighscore()) {
schreibeHighscore(resultCode);
}
}
}
#Override
public void onSignInFailed() {
findViewById(R.id.sign_in_button).setVisibility(View.VISIBLE);
findViewById(R.id.sign_out_button).setVisibility(View.GONE);
}
#Override
public void onSignInSucceeded() {
View a = findViewById(R.id.highscorebutton);
a.setVisibility(View.VISIBLE);
View b = findViewById(R.id.button3);
b.setVisibility(View.VISIBLE);
findViewById(R.id.sign_in_button).setVisibility(View.GONE);
findViewById(R.id.sign_out_button).setVisibility(View.VISIBLE);
}
}
Thanks, GoogleWelt
According to the official documentation, "Before any operation is executed, the GoogleApiClient must be connected"
When the user in not connected(signed in) and clicks to show leaderboards or achievements, it results in the exception thrown. Modify your code for launching the leaderboard like this:
} else if(view.getId()==R.id.highscorebutton) {
if (isSignedIn())
startActivityForResult(Games.Leaderboards.getLeaderboardIntent(getApiClient(), getString(R.string.the_best_players)), REQUEST_LEADERBOARD);
else showAlert("Please sign in to view leaderboards");
}
Use the same logic for showing achievements:
if (isSignedIn())
startActivityForResult(Games.Achievements.getAchievementsIntent(getApiClient()), REQUEST_ACHIEVEMENT);
else showAlert("Please sign in to view achievements");
Check the part where you are getting ApiClient i.e. getApiClient().
Write the code below to see if GoogleApiClient is Connected or not.
GoogleApiClient mGoogleApiClient;
if(mGoogleApiClient.isConnected()){
// good
}else{
//connect it
mGoogleApiClient.connect(GoogleApiClient.SIGN_IN_MODE_OPTIONAL);
}
I have a working code now with my thesis but I decided to clean it up using functions/methods/objects (not really sure what to call them) but after organizing them, my app crashes everytime i start it. I dont really know what the problem is.
Main Screen shows Start and Exit Button. When I press START, the app says "Unfortunately thesis has stopped".
My code goes like this:
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.items, menu);
View v = (View) menu.findItem(R.id.search).getActionView();
final EditText txtSearch = ( EditText ) v.findViewById(R.id.txt_search);
txtSearch.setOnEditorActionListener(new OnEditorActionListener() {
#Override
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
String curtextArray = txtSearch.getText().toString();
char[] curletters = curtextArray.toCharArray();
char[] curenhancedLetters = curtextArray.toCharArray();
//probably, problem here on Stemming stem
Stemming stem = new Stemming(curtextArray, curletters, curenhancedLetters);
AsyncTaskRunner newTask = new AsyncTaskRunner(enhancedStem);
// and probably, problem is here on the stem.<x process>;
stem.removeApostrophe();
stem.vowelMarking();
stem.shortSyllable();
if (continueStem == 1){
stem.region1();
stem.region2();
stem.shortWord();
stem.step0();
stem.step1a();
stem.step1b();
newTask.execute();
}
return false;
};
});
return super.onCreateOptionsMenu(menu);
}
Here's my Stemming Class
public class Stemming {
String textArray;
char[] letters;
char[] enhancedLetters;
public Stemming (String curtextArray, char[] curletters, char[] curenhancedLetters){
this.textArray = curtextArray;
this.letters = curletters;
this.enhancedLetters = curenhancedLetters;
}
public Stemming(){
}
public void removeApostrophe(){
...processes here
}
public void vowelMarking(){
...processes here
}
public void shortSyllable(){
...processes here
}
public void region1(){
...processes here
}
public void region2(){
...processes here
}
public void shortWord(){
...processes here
}
public void step0(){
...processes here
}
public void step1a(){
...processes here
}
public void step1b(){
...processes here
}
}
}
I have a theory on why it crashes. Is this method possible? (pseudocode):
public class Stemming {
String result;
String sample = "A A A A A";
public void changeAtoB{
//do process to convert all As to Bs making String sample = "B B B B B"
result = sample;
}
public void changeBtoC{
//do process to convert all Bs to Cs making String result = "C C C C C"
result = result;
}
... so on {
}
}
What I did was process the string in a straight manner without doing any variable declarations (my variables are declared globally) or initializations. and I also did not put any return statements.
My code used to work when It was still without those functions/methods/objects.
Sorry about my long post. Don't know how to explain it better. I hope you help me. Thank you in Advance!
LOGCAT:
>E/AndroidRuntime(11007): FATAL EXCEPTION: main
E/AndroidRuntime(11007): java.lang.RuntimeException: Unable to instantiate activity ComponentInfo{com.atienzaerni.thesis/com.atienzaerni.thesis.secondactivity}: java.lang.NullPointerException
E/AndroidRuntime(11007): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1891)
E/AndroidRuntime(11007): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1992)
E/AndroidRuntime(11007): at android.app.ActivityThread.access$600(ActivityThread.java:127)
E/AndroidRuntime(11007): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1158)
E/AndroidRuntime(11007): at android.os.Handler.dispatchMessage(Handler.java:99)
E/AndroidRuntime(11007): at android.os.Looper.loop(Looper.java:137)
E/AndroidRuntime(11007): at android.app.ActivityThread.main(ActivityThread.java:4441)
E/AndroidRuntime(11007): at java.lang.reflect.Method.invokeNative(Native Method)
E/AndroidRuntime(11007): at java.lang.reflect.Method.invoke(Method.java:511)
E/AndroidRuntime(11007): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784)
E/AndroidRuntime(11007): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)
E/AndroidRuntime(11007): at dalvik.system.NativeStart.main(Native Method)
E/AndroidRuntime(11007): Caused by: java.lang.NullPointerException
E/AndroidRuntime(11007): at android.app.Activity.findViewById(Activity.java:1794)
E/AndroidRuntime(11007): at com.atienzaerni.thesis.secondactivity.<init>(secondactivity.java:54)
E/AndroidRuntime(11007): at java.lang.Class.newInstanceImpl(Native Method)
E/AndroidRuntime(11007): at java.lang.Class.newInstance(Class.java:1319)
E/AndroidRuntime(11007): at android.app.Instrumentation.newActivity(Instrumentation.java:1023)
E/AndroidRuntime(11007): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1882)
E/AndroidRuntime(11007): ... 11 more
I/Process(11007): Sending signal. PID: 11007 SIG: 9
(I'm using my phone by the way. Not an emulator. If this makes a difference)
It looks like you are getting a NullPointerException because v is null at this line:
final EditText txtSearch = ( EditText ) v.findViewById(R.id.txt_search);
This is probably caused by null being returned from the menu items action view here:
View v = (View) menu.findItem(R.id.search).getActionView();
You should either set the action view in code and not call getActionView or make sure you have a proper action view set in the menu XML. Without seeing your menu XML it's hard to tell if the problem lies in the XML.