Android onCreate called twice after phone reboot, makes fragment stop working - java

I have written an application for Android that has an issue (crash) when it is launched immediately (with in 5 seconds or so) after the phone is rebooted. Due to one reason or another, the OnCreate method is called for a second time. I thought this may have been the problem, but after researching this, I found out the android system may recall onCreate after start up as it is still starting system services - such as getting the "MCM".
In my application in the MainActivity I have a statically bound fragment that is bound through XML. The fragment has code in it that checks that location permissions were granted:
if (ActivityCompat.checkSelfPermission(this.getContext(), Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this.getContext(), Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED)
The problem is, this.getContext() returns null! It definitely has something to do with the fact onCreate is being called more than once, because when the phone is not booting and onCreate is only called once the application works perfectly!
Here is the only reference I make to the fragment in my onCreate method in the mainActivity:
android.support.v4.app.Fragment fragMap = getSupportFragmentManager().findFragmentById(R.id.mv_1);
if (fragMap instanceof FragmentMap)
{
theMap = (FragmentMap) fragMap;
}
Here is the fragment bound through XML:
<fragment
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:id="#+id/mv_1"
android:name="com.sunhillo.personneltrackerv002.FragmentMap"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:layout_marginBottom="64dp"/>
Thank you very much for any help you can provide! I am still new to Android programming, and am attempting to learn the ins and outs!

If your ultimate aim is to access the location permissions, simply add these permissions in manifest file. And if you wish to perform this check via java, don't add this to individual fragments. Add this syntax only to the MainActivity java file that refers to the fragments. I hope this helps. :)

You should use launch mode Single Task or Single top which will avoid calling multiple onCreate and you should use getApplicationContext().

Related

Can I Close a FragmentContainerView from Inside a Fragment?

This is my first time using Fragments and I'm rather new to Android. I'm using Fragments to manage a settings menu for my app.
I have a MainActivity with a FragmentContainerView, the XML is like so:
<androidx.fragment.app.FragmentContainerView
android:visibility="gone"
android:id="#+id/main_activity_fragment_container"
android:background="#color/white"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"/>
In the MainActivity.java File I have a method assigned to a button to make the FragmentContainerView visible, like so:
private void showFragments(FragmentContainerView fragmentContainerView) {
fragmentContainerView.setVisibility(View.VISIBLE);
// There is more to this method, but I don't think it is necessary for this example
}
I'm able to navigate all around the settings menu: inflate fragments, replace fragments, update Shared Preferences, use Browser Intent, etc. - everything I need to do for a settings menu.
What I haven't been able to figure out is how to closeout the Settings Menu (close the FragmentContainerView in the MainActivity) after a selection has been made (and thus return to the game). I can create a "close" button in every fragment - but I can't figure out a method to close (setVisibility to GONE) the MainActivity's FragmentContainerView.
Once I'm in a Fragment - is it even possible to access the FragmentContainerView the fragment resides inside of? I've tried a number of ways to access it and set the visibility to GONE, but I just get a crash.
Inside a fragment:
FragmentContainerView mainActivityFragmentContainer = (FragmentContainerView) view.findViewById(R.id.main_activity_fragment_container);
public void closeFragment(FragmentContainerView mainActivityFragmentContainer) {
mainActivityFragmentContainer.setVisibility(View.GONE);
// This causes a crash, the error log states:
// NullPointerException: Attempt to invoke virtual method 'void androidx.fragment.app.FragmentContainerView.setVisibility(int)' on a null object reference
}
I know a workaround where I don't have the fragmentContainerView fill up the entire screen and leave space for an external close button - but this solution seems inefficient.Any advice would be helpful!
Yes you can do it,
1- Create a public function in your MainActivity that closes the fragment container:
public void closeFragment() {
fragmentContainerView.setVisibility(View.GONE);
}
2- Call that function from your fragment when you need it:
// getActivity() will return the activity linked to that fragment so this fragment should be linked MainActivity
MainActivity activity = (MainActivity) getActivity();
acitvity.closeFragment();

Getting NullPointerException first time when Activity loads but working fine second time

I am starting EditCardActivity from MainActivity.
The app crashes first time and Android system shows an alert to "Open App Again".
When I reopen the app, it works as expected.
I have seen many answers on this site and I have done following according to those answers but it didn't work.
I have called the setContentView() inside onCreate() method before calling findViewByID().
I have verified that the ID I am passing in findViewByID() is spelled correctly.
I also tried to make the EditText a class member too and initialize it in onCreate() method.
I also tried using onStart(), onPostCreate() methods too.
I feel that the View has not been loaded when I am trying to call it and thus findViewByID() returns null. Hence I tried using Thread.sleep(1000) to give it 1 second to load but still same issue.
Here's the part of code that is having problem.
// MainActivity.java
public void editCard(View v) {
Intent i = new Intent(this, EditCardActivity.class);
startActivity(i);
}
<!--activity_edit_card.xml-->
...
<EditText
android:id="#+id/add_card_category_et"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="#dimen/margin"
android:ems="10"
android:hint="#string/add_card_category_et_hint"
android:inputType="text"
android:textSize="#dimen/font_size" />
...
// EditCardActivity.java
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_edit_card);
showContents();
}
private void showContents() {
EditText editCardCategoryET = findViewById(R.id.add_card_category_et);
editCardCategoryET.setText(currentCard.getCategory()); // This line is throwing NullPointerException
}
Error
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.TextView.setText(java.lang.CharSequence)' on a null object reference
Edit:
I got what was causing the error.
I was referring to the add_card_category_et instead of edit_card_category_et.
The former view belonged to the different layout file of another Activity of my application.
I am sorry I couldn't catch this small error.
Although small, it made me stuck for 3 days.
Anyway thanks for your answers and comments.
Because editCardCategoryET cant find any value. So it throws Exception. It can be solve by add extra character by adding " " . Then app will not crush. editCardCategoryET.setText(" "+currentCard.getCategory()); .
Also you can handle it in a try(), catch() method.

What causes the LoginActivity to run for the first time in the Socket.io android application example by nkzawa?

I have been trying to fully understand nkzawa's android example on github for socket.io
Relative link:
https://github.com/nkzawa/socket.io-android-chat/tree/master/app/src/main/java/com/github/nkzawa/socketio/androidchat
(AndoridManifest.xml is in the "main" folder)
I have been told that android decides which activity to run first from a tag inside AndroidManifest.xml that would have < action ... .MAIN and < category ... .LAUNCHER inside the activity. When I look at AndroidManifest.xml I see the aforementioned tags inside of the MainActivity declaration. Great! So MainActivity must be the first to run. Now, when I look at MainActivity.java I see an onCreate() method that just sets the content view with not much else to be seen.... So how does the LoginActivity start?
I have setup the server side of things without an issue and I can compile and run the example, connect to my server and all that... I just don't understand how the onCreate() method is first called for the LoginActivity.
There is definitely something I am missing. The LoginActivity must be started somewhere else besides AndroidMainifest.xml or MainActivity.java..
If anyone could point me in the right direction even it would be great! Thanks so much.
Alright I think I got it.
1. App starts at MainActivity.onCreate()
2. Sets content view with: setContentView(R.layout.activity_main)
3. Activity_main.xml opens a fragment that uses class MainFragment
4. MainFragment.onCreate() does some work then calls startSignIn()
5. startSignIn() calls startActivityForResult(intent, REQUEST_LOGIN) with the intent as the LoginActivity!
Now the LoginActivity has begun :)

How can I prevent "java.lang.IllegalStateException: Fragment already added" when replacing fragments?

Despite my efforts to prevent fragments from being added more than once, I continue to encounter java.lang.IllegalStateException: Fragment already added: VideoFragment.
I have an activity where VideoFragment is instantiated in onCreate only. In the only place I attempt to display the VideoFragment, I first check whether this fragment has been added already.
private VideoFragment videoFragment;
public void onCreate(Bundle savedInstanceState) {
...
videoFragment = new VideoFragment();
...
}
private void showVideoFragment() {
if (!videoFragment.isAdded()) {
FragmentTransaction transaction = getFragmentManager().beginTransaction();
transaction.replace(R.id.fragment_container, videoFragment, "video").commit();
}
}
I have not been able to consistently reproduce this problem to examine in the debugger, but my runtime error reporting continues to report the exception java.lang.IllegalStateException: Fragment already added: VideoFragment for users, with stack traces composed of Android classes.
/FragmentManager.java:1133→ android.app.FragmentManagerImpl.addFragment
/BackStackRecord.java:648→ android.app.BackStackRecord.run
/FragmentManager.java:1453→ android.app.FragmentManagerImpl.execPendingActions
/FragmentManager.java:443→ android.app.FragmentManagerImpl$1.run
/Handler.java:733→ android.os.Handler.handleCallback
/Handler.java:95→ android.os.Handler.dispatchMessage
/Looper.java:146→ android.os.Looper.loop
/ActivityThread.java:5487→ android.app.ActivityThread.main
/Method.java:-2→ java.lang.reflect.Method.invokeNative
/Method.java:515→ java.lang.reflect.Method.invoke
/ZygoteInit.java:1283→ com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run
/ZygoteInit.java:1099→ com.android.internal.os.ZygoteInit.main
/NativeStart.java:-2→ dalvik.system.NativeStart.main
Does the definition of added in isAdded() not match the one used to check fragment transactions?
Or is there some way the videoFragment reference in the activity is not the same? Is this something I need to explicitly handle when saving state http://developer.android.com/guide/components/activities.html#SavingActivityState?
Or is there a reliable alternative way of checking whether the fragment has already been added?
UPDATE
I have figured out how to semi-reliably produce the problem.
Start application
Navigate away from application, and run other programs for awhile. On my Galaxy Nexus (which is pretty slow these days), using Chrome to read a few news articles seems sufficient. When returning to the home screen, if it takes a few seconds to render then the application will likely throw the fragment exception.
Restart application and trigger fragment change
If I kill and simply run the application, everything appears to be fine. Or if I navigate away from the application and come back immediately, it works okay. It's only if the application is left in the background for a bit (enough to remove from memory?), that the fragment issue appears.
I also tried, to no effect, in onCreate
View v = findViewById(R.id.fragment_container);
if(v != null){
Log.d(TAG, "disabling save for fragment_container");
v.setSaveEnabled(false);
v.setSaveFromParentEnabled(false);
}
I also tried checking Fragment prior = getFragmentManager().findFragmentByTag("video"); and Fragment prior2 = getFragmentManager().findFragmentById(R.id.fragment_container); before running the replace fragment transaction, but these come up null.
My problem in fact looks very similar to
https://code.google.com/p/android/issues/detail?id=61247
though the time appears less an issue than memory/cache effects. It is completely unclear to me why that issue was closed.
I will try to produce a simple application that replicates this issue. My current one uses webrtc, and the logcat output is completely cluttered with webrtc messages.
I see a few things here:
Your problem occours propably when Activity is recreated by the system. You can simply simulate it by changing device orientation.
isAdded() returns false, because Activity was recreated so this method is called for new instatnce of VideoFragment which hasn't knowledge about previous add.
showVideoFragment() actually add fragment to Activity instead of just show it. I suggest you rename that method to somethink like "addVideoFragment" and move it to onCreate() method. If you do that you resolve the issue.
If you really want to show or hide fragment use methods from FragmentTransaction eg:
FragmentManager fm = getFragmentManager();
fm.beginTransaction()
.setCustomAnimations(android.R.animator.fade_in, android.R.animator.fade_out)
.show(somefrag) // or hide
.commit();
Hint:
When you a priori know that you fragment is always the VideoFragment you can simply use:
<fragment
android:name="com.example.VideoFragment"
android:id="#+id/video_fragment"
android:layout_width="match_parent"
android:layout_height="match_parent" />
find it:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.fragment_layout);
VideoFragment fragment = (VideoFragment) getFragmentManager().findFragmentById(R.id.video_fragmen);
}
and make whatever you want with the instance.
I think I have successfully fixed this error, by trying to reproduce this in a simpler example:
https://stackoverflow.com/a/30672516/4107809
I was making a mistake where multiple instances of a fragment (not the VideoFragment) were added in successive calls to onCreate caused by recreation of the Activity. This fragment addition did not trigger the java.lang.IllegalStateException: Fragment already added because apparently this happens only if you try to add the same fragment instance more than once, not multiple instances of the same fragment.
Upon calling the fragment replace method, the java.lang.IllegalStateException: Fragment already added is generated for the new VideoFragment, even though the VideoFragment is only added once using replace.
By ensuring the different fragment was added only once, the replace by the VideoFragment no longer generates java.lang.IllegalStateException: Fragment already added: VideoFragment, at least for the steps for reproducing I outlined above. The IllegalStateException appears to have nothing to do with adding/replacing the VideoFragment, but with the state of the fragments being replaced.
I am displeased by this resolution for two reasons:
The error message is misleading. It says the VideoFragment has already been added, and I have resolved this by making sure that a different fragment is not added more than once, which did not generate an exception.
The replace documentation is very misleading. Based on my reading, it should not matter what the state of the fragment container is prior to calling to replace; the end state should be determined solely by the fragment that is added from the replace argument. I think this discrepancy is most clear in the linked question, though the answerer in that question disagrees.
Replace an existing fragment that was added to a container. This is essentially the same as calling remove(Fragment) for all currently added fragments that were added with the same containerViewId and then add(int, Fragment, String) with the same arguments given here.

Android - SPAN_EXCLUSIVE_EXCLUSIVE spans cannot have a zero length

I have the following layout (virtually empty):
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/set_layout"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:contentDescription="content desc"
android:orientation="vertical" >
<TextView android:id="#+id/text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello, I am a TextView" />
</LinearLayout>
The Activity class contains the following:
public class TestActivity extends Activity {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test);
}
}
When I run this on my mobile device I get the following error:
SpannableStringBuilder
SPAN_EXCLUSIVE_EXCLUSIVE spans cannot have a zero length
I have tried this with and without the TextView and the error still remains, I must be doing something fundamentally wrong for such a basic layout to cause this.
Does anyone have any ideas on how I can get this to load without the error?
I have run into the same error entries in LogCat. In my case it's caused by the 3rd party keyboard I am using. When I change it back to Android keyboard, the error entry does not show up any more.
Because the error you're getting is not related to an EditText, then it's not related to your keyboard.
The errors you are getting are not a result of your code; you probably are testing on a Samsung device that has Samsung's TouchWiz.
I had the same errors, then I tested on a Nexus S (also by Samsung, but pure Android OS without TouchWiz) and I didn't get this error.
So, in your case, just ignore these errors while testing on a device! :)
Looking at your code, I'm not sure why you're getting that error, but I had this same error but with EditText fields.
Changing android:inputType="text" (or any of the other inputType text variations) to android:inputType="textNoSuggestions" (or android:inputType="textEmailAddress|textNoSuggestions", for example) fixed it for me.
You can also set this in Code with something like
mInputField.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
Looks like Android assumes by default that EditText fields will have suggestions. When they don't, it errors. Not 100% confident in that explanation, but the above mentioned changes fixed it for me.
http://developer.android.com/reference/android/text/Spanned.html#SPAN_EXCLUSIVE_EXCLUSIVE
Hope this helps!
On your android phone go to:
settings -> application manager -> all -> samsung keyboard and then click on "clear cache"
(delete all data collected by this application).
Try using the default Android keyboard it will disappear
Make clear you have pass a value in your MainAcitivity for the following methods onCreateOptionsMenu and onCreate
In some cases, the developer deletes the "return super.onCreateOptionsMenu(menu)" statement and changed to "return true".
This worked for me...on every device
<EditText
android:maxLines="1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:textSize="15sp"
android:layout_centerVertical="true"
android:textColor="#000"
android:id="#+id/input_search"
android:background="#null"
android:inputType="text"
android:hint="Enter Address, City or Zip Code"
android:imeOptions="actionSearch"
/>
In Java code:
mSearchText.setOnEditorActionListener(new TextView.OnEditorActionListener() {
#Override
public boolean onEditorAction(TextView textView, int actionId, KeyEvent keyEvent) {
if(actionId == EditorInfo.IME_ACTION_SEARCH
|| actionId == EditorInfo.IME_ACTION_DONE
|| keyEvent.getAction() == KeyEvent.ACTION_DOWN
|| keyEvent.getAction() == KeyEvent.KEYCODE_ENTER){
//execute our method for searching
}
return false;
}
});
I had the same warning and found that removing an unused #id got rid of the warning. For me it was obvious as the #id was associated with a growing list of textViews linked to a database, so there was a warning for each entry.
Masood Moshref is right, this error occur because the option menu of Menu is not well prepared by lacking "return super.onCreateOptionsMenu(menu)" in onCreate() method.
To try to debug this error, first go to your android terminal / console and execute this command:
ps | grep THE_ERROR_PID_YOU_GET_(IT_IS_A_NUMBER)
then if the output comes out as your app... it is your app causing the error. Try to look for empty Strings that you pass into the layout.
I had this exact same problem and it was my fault as I was passing an empty String into my layout. After changing the "" to " " this error went away.
If you don't get your app from the console output, then it is something else causing it (probably, as others said, the android keyboard)
I have faced the same issue. I almost wasted almost couple of weeks to resolved this issue.
Finally I had on doubt on myself and tried to create another project by copy and paste some startup files like SplashScreen & LoginScreen.
But with the same code still i was getting SPAN_EXCLUSIVE_EXCLUSIVE.
Then i have removed the handler code from splash screen and tried again and Wow its working.
I am not getting SPAN_EXCLUSIVE_EXCLUSIVE issue in logcat.
I wondering, why it is? till the time did not get any other solution but by removing handler from splash screen it is working.
Try and update here if it is resolved or not.
Check if you have any element such as button or text view duplicated (copied twice) in the screen where this encounters. I did this unnoticed and had to face the same issue.
I ran into this problem too when I copied some text from the Internet. My solution is to trim the text/remove formatting before doing any further processing.
I had the same problem but with a listView.... i solved it because i was using a wrong R.id.listView that list View needed to have a value, in my case it was strings that i saved on listView2... so the right code was R.id.listView2
I had the same problem then i fixed it by following code!
text = (EditText)findViewById(R.id.TextVoiceeditText);
text.setInputType(InputType.TYPE_CLASS_TEXT|InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
this error also occurs due to changed API URL. try hitting the URL you are using in postman and c if it's working properly.
rechecking the APIs solved my problem
try avoiding use of view in xml design.I too had the same probem but when I removed the view. its worked perfectly.
like example:
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Username"
android:inputType="number"
android:textColor="#fff" />
<view
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="#f9d7db" />
also check and try changing by trial and error android:inputType="number" to android:inputType="text" or better not using it if not required .Sometimes keyboard stuck and gets error in some of the devices.
In my case, the EditText fields with inputType as text / textCapCharacters were casing this error. I noticed this in my logcat whenever I used backspace to completely remove the text typed in any of these fields.
The solution which worked for me was to change the inputType of those fields to textNoSuggestions as this was the most suited type and didn't give me any unwanted errors anymore.
in my case i click on recent apps shortcut on my cell phone and close all apps. This solution always work for me, because this error not related to code.
**DONT PUT SET TEXT IN TEXT WATCHER**etSearch.addTextChangedListener(object : TextWatcher {
override fun afterTextChanged(s: Editable) {
visibleResultList = false
if (s.toString().length != 0) {
getSearchSuggetion(no_of_rec, 0, s.toString())
} else {
// etSearch.setText("")
}
Log.e("text_change","============"+s.toString())
}
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {}
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
}
})
To solve this problem just add android:usesCleartextTraffic="true" in your AndroidManifest.xml file which is at ..\app\src\main\AndroidManifest.xml just like bellow...

Categories

Resources