Users of the app I am working on have a crashing issue. This is the stack trace I get from the console.
java.lang.NullPointerException: Attempt to write to field 'int android.support.v4.app.Fragment.mNextAnim' on a null object reference
at android.support.v4.app.BackStackRecord.popFromBackStack(BackStackRecord.java:924)
at android.support.v4.app.FragmentManagerImpl.popBackStackState(FragmentManager.java:1605)
at android.support.v4.app.FragmentManagerImpl$4.run(FragmentManager.java:532)
at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1501)
at android.support.v4.app.FragmentManagerImpl$1.run(FragmentManager.java:458)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:145)
at android.app.ActivityThread.main(ActivityThread.java:5942)
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:1399)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1194)
The crash only happens with users that have Galaxy Note3 or Galaxy S4 phones with 5.x or at least those our the only one that have got reported but it has happen a lot. It seems to happen on transition between fragments or sometimes when coming back from the camera. Here are my transition methods.
public void popBackStackToOr(String popBackFragmentName, String secondPopBackFragment)
{
int backStackId = 0;
int backStackCount = getSupportFragmentManager().getBackStackEntryCount();
List<Fragment> fragments = getSupportFragmentManager().getFragments();
for (int k = (backStackCount - 1); k > 0; k--)
{
String aFragmentClass = fragments.get(k).getClass().toString();
String[] splitList = aFragmentClass.split("\\.");
aFragmentClass = splitList[splitList.length - 1];
boolean firstOptionTrue = aFragmentClass.equalsIgnoreCase(popBackFragmentName);
boolean secondOptionTrue = aFragmentClass.equalsIgnoreCase(secondPopBackFragment);
if ( (firstOptionTrue) || (secondOptionTrue) )
{
backStackId = getSupportFragmentManager().getBackStackEntryAt(k).getId();
break;
}
}
getSupportFragmentManager().popBackStack(backStackId, android.support.v4.app.FragmentManager.POP_BACK_STACK_INCLUSIVE); //Immediate
}
public void popBackStackForReview(String popBackFragmentName)
{
int backStackId = 0;
int backStackCount = getSupportFragmentManager().getBackStackEntryCount();
List<Fragment> fragments = getSupportFragmentManager().getFragments();
for (int k = (backStackCount - 1); k > 0; k--)
{
String aFragmentClass = fragments.get(k).getClass().toString();
String[] splitList = aFragmentClass.split("\\.");
aFragmentClass = splitList[splitList.length - 1];
if (aFragmentClass.equalsIgnoreCase(popBackFragmentName))
{
backStackId = getSupportFragmentManager().getBackStackEntryAt(k).getId();
break;
}
}
getSupportFragmentManager().popBackStack(backStackId, android.support.v4.app.FragmentManager.POP_BACK_STACK_INCLUSIVE);
}
public void transitionToLoginPage()
{
Fragment newFragment = new LoginPage();
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.frame_container, newFragment);
//transaction.addToBackStack(null);
transaction.commitAllowingStateLoss();
}
public void transitionToNewScreen(Fragment newFragment, Bundle bundle)
{
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
if (currentFragment != null)
{
transaction.remove(currentFragment);
}
currentFragment = newFragment;
if (bundle != null)
{
newFragment.setArguments(bundle);
}
transaction.replace(R.id.frame_container, newFragment);
transaction.addToBackStack("dummy");
transaction.commitAllowingStateLoss();
}
public void transitionToNewScreenAndEmptyStack(Fragment newFragment)
{
getSupportFragmentManager().popBackStack(0, android.support.v4.app.FragmentManager.POP_BACK_STACK_INCLUSIVE);
currentFragment = newFragment;
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.frame_container, newFragment);
transaction.addToBackStack(null);
transaction.commitAllowingStateLoss();
}
These are the only methods that do transition in the app. So I am assuming it is coming from one of these. But the stack trace does not go back to any code I wrote so I am not sure. I have found similar problems saying that this is a Android 5.x issue and there was no fix. So any help to remove this issue would be great
It's because you are calling remove() add() etc. methods with null value.
and please keep in mind that replace() = remove()->add() one by one.
Try to use Fragments extending android.support.v4.app.Fragment instead of android.app.Fragment and use the android.app.FragmentTransaction instead of android.support.v4.app.FragmentTransaction
This bug already solved in this question:
Trying to remove fragment from view gives me NullPointerException on mNextAnim
Try it out.
Related
I found this code to pass the data from a fragment to another:
Fragment 1:
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
Fragment2 fragment2 = new Fragment2();
Bundle bundle = new Bundle();
bundle.putString("data", data);
fragmentTransaction.replace(R.id.fragment_container, fragment2);
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
Fragment 2:
Bundle bundle = getArguments();
assert bundle != null;
String data = bundle.getString("data");
But I dont want to change the fragment. So I removed parts of it. But it doesnt work. Here my code:
Fragment 1:
public void openActifity2(){
Fragment_score fragment_score = new Fragment_score();
Bundle bundle = new Bundle();
bundle.putInt("FINISHED_LEVELS", finishedLevels);
bundle.putInt("FAILED_LEVELS", failedLevels);
bundle.putInt("SKIPPED_LEVELS", skippedLevels);
bundle.putInt("USED_HINTS", usedHints);
fragment_score.setArguments(bundle);
}
Fragment 2:
Bundle bundle = getArguments();
int finishedLevels = bundle.getInt("FINISHED_LEVELS");
int failedLevels = bundle.getInt("FINISHED_LEVELS");
int skippedLevels = bundle.getInt("FINISHED_LEVELS");
int usedHints = bundle.getInt("FINISHED_LEVELS");
Do I have to use the code I found on the internet or does my version work too?
I get this error when I open the second fragment:
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.rexan_snerficonquiz, PID: 20931
java.lang.NullPointerException: Attempt to invoke virtual method 'int android.os.Bundle.getInt(java.lang.String)' on a null object reference
at com.example.rexan_snerficonquiz.Fragment_score.onCreateView(Fragment_score.java:26)
at androidx.fragment.app.Fragment.performCreateView(Fragment.java:2600)
at androidx.fragment.app.FragmentManagerImpl.moveToState(FragmentManagerImpl.java:881)
at androidx.fragment.app.FragmentManagerImpl.moveFragmentToExpectedState(FragmentManagerImpl.java:1238)
at androidx.fragment.app.FragmentManagerImpl.moveToState(FragmentManagerImpl.java:1303)
at androidx.fragment.app.BackStackRecord.executeOps(BackStackRecord.java:439)
at androidx.fragment.app.FragmentManagerImpl.executeOps(FragmentManagerImpl.java:2079)
at androidx.fragment.app.FragmentManagerImpl.executeOpsTogether(FragmentManagerImpl.java:1869)
at androidx.fragment.app.FragmentManagerImpl.removeRedundantOperationsAndExecute(FragmentManagerImpl.java:1824)
at androidx.fragment.app.FragmentManagerImpl.execPendingActions(FragmentManagerImpl.java:1727)
at androidx.fragment.app.FragmentManagerImpl$2.run(FragmentManagerImpl.java:150)
at android.os.Handler.handleCallback(Handler.java:938)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:223)
at android.app.ActivityThread.main(ActivityThread.java:7523)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:941)
in order to avoid getting the error, try this
Bundle bundle = getArguments();
if(bundle != null){
int finishedLevels = bundle.getInt("FINISHED_LEVELS", "DEFAULT_VALUE");
int failedLevels = bundle.getInt("FINISHED_LEVELS", "DEFAULT_VALUE");
int skippedLevels = bundle.getInt("FINISHED_LEVELS", "DEFAULT_VALUE");
int usedHints = bundle.getInt("FINISHED_LEVELS", "DEFAULT_VALUE");
}
Based on your comments, you can change fragment in onOptionsItemSelected method
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.action_1) {
// add your action here that you want
return true;
}else if (id==R.id.action_2) {
// add your action here that you want
return true;
}
return super.onOptionsItemSelected(item);
}
If you change the fragments than your code will be working fine. But if you don't want to change fragments than 1) int finishedLevels = bundle.getInt("FINISHED_LEVELS", 0); OR 2) Instead of bundle use static global variables public static int finishedLevels = 0; in Fragment 1 and then simply get their value in Fragment 2 using class name reference.
Note: If you don't want to change the fragment and want values in Fragment 2 then i would recommend the static variables
I am having troubles with my Fragments. I have four fragments which were in portrait mode.
Setting the fragments
public void setCorrectNavigationItem(int id) {
if (id == R.id.nav_auftragsbilder) {
fragment = new AuftragsbilderFragment();
id = R.id.nav_auftragsbilder;
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
} else if (id == R.id.nav_auftragskorrektur) {
fragment = new AuftragskorrekturFragment();
id = R.id.nav_auftragskorrektur;
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
} else if (id == R.id.nav_lagerplatz) {
fragment = new LagerplatzFragment();
id = R.id.nav_lagerplatz;
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
} else if (id == R.id.nav_biegenstatus) {
fragment = new BiegestatusFragment();
id = R.id.nav_biegenstatus;
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
}
_navigationView.setCheckedItem(id);
_selectedMenuItem = id;
SharedPreferences.Editor editor = menuCheck.edit();
editor.putInt("id", id);
editor.commit();
//Fragment öffnen
if (fragment != null) {
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction ft = fragmentManager.beginTransaction();
ft.replace(R.id.fragment_container, fragment);
ft.commit();
}
}
So in my fragment setting method I now have to set the orientation for each different fragment. I had to change my 'BiegestatusFragment' to landscape, there I am calling a method which is scanning barcodes, on intent result I set parameters in my Fragment.
Here is my Barcode-Scanning Activity
//Biegestatus Begleitschein-Barcodes
public void makeBiegestatusBegleitscheinBarcode() {
_lastAction = ACTION_BIEGESTATUS_BEGLEITSCHEIN_BARCODE;
if (!checkCameraPermission(this, PERMISSIONS)) {
ActivityCompat.requestPermissions(this, PERMISSIONS, PERMISSION_ALL);
} else {
Intent intent = new Intent(this, ContinuousCaptureActivity.class);
startActivityForResult(intent, 1);
}
}
Intent Result
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (data != null) {
ArrayList<String> begleitscheine = data.getStringArrayListExtra("begleitscheine");
if (resultCode == 1 && begleitscheine != null) {
//HERE IT IS NULL
((BiegestatusFragment) fragment).setBegleitscheine(begleitscheine);
} else {
Toast.makeText(this, "Scannen abgebrochen", Toast.LENGTH_LONG).show();
}
} else {
Toast.makeText(this, "Unbekannter Fehler aufgetreten, Entwickler kontaktieren.", Toast.LENGTH_LONG).show();
}
}
Fragments onCreateView
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_biegestatus, container, false);
_cardEdit = (EditText) v.findViewById(R.id.workerEdit);
_scrollViewArticles = (ScrollView) v.findViewById(R.id.scrollViewArticles);
_searchImageLayout = (LinearLayout) v.findViewById(R.id.searchImageLayout);
_personalNummer = (EditText) v.findViewById(R.id.workerEdit);
_progressBar = (LinearLayout) v.findViewById(R.id.progressBar);
_maschinenPicker = (NumberPicker) v.findViewById(R.id.maschinenPicker);
_pickerHolder = (LinearLayout) v.findViewById(R.id.pickerHolder);
_scanBegleitscheinBtn = (Button) v.findViewById(R.id.scanBegleitscheinBtn);
return v;
}
Method should be called
public void setBegleitscheine(ArrayList<String> begleitscheine) {
_begleitscheine = begleitscheine;
}
Now my Fragment is null because of the orientation change.
Removing the orientation setting methods solves my problem. But I need to have this fragment in landscape.
Error
E/AndroidRuntime: FATAL EXCEPTION: main
Process: at.co.era.bilder.erabilderapp, PID: 21835
java.lang.RuntimeException: Failure delivering result ResultInfo{who=null, request=1, result=1, data=Intent { launchParam=MultiScreenLaunchParams { mDisplayId=0 mBaseDisplayId=0 mFlags=0 }(has extras) }} to activity {at.co.era.bilder.erabilderapp/at.co.era.bilder.erabilderapp.HomeActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'void at.co.era.bilder.erabilderapp.BiegestatusFragment.setBegleitscheine(java.util.ArrayList)' on a null object reference
at android.app.ActivityThread.deliverResults(ActivityThread.java:4520)
at android.app.ActivityThread.handleSendResult(ActivityThread.java:4563)
at android.app.ActivityThread.-wrap22(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1698)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6776)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1496)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1386)
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'void at.co.era.bilder.erabilderapp.BiegestatusFragment.setBegleitscheine(java.util.ArrayList)' on a null object reference
at at.co.era.bilder.erabilderapp.HomeActivity.onActivityResult(HomeActivity.java:1130)
at android.app.Activity.dispatchActivityResult(Activity.java:7280)
at android.app.ActivityThread.deliverResults(ActivityThread.java:4516)
at android.app.ActivityThread.handleSendResult(ActivityThread.java:4563)
at android.app.ActivityThread.-wrap22(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1698)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6776)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1496)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1386)
//Fragment öffnen
if (fragment != null) {
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction ft = fragmentManager.beginTransaction();
ft.replace(R.id.fragment_container, fragment);
ft.addToBackStack(null); // or you can give it any name instead of null to get the frament when poping the fragment from backstack
ft.commit();
}
You can force your activity not to reload after orientation changed by adding the following line in manifest to your activity tag
android:configChanges="orientation"
Inside fragment ,in onCreateView() try using :
setRetainInstance(true);
Check the doc here :
https://developer.android.com/reference/android/app/Fragment#setRetainInstance(boolean)
So I'm working on an app and I had this part working for days, and out of no where it just stopped working for no reason...
I also had the same error when I was trying to use another headless fragment in my MainActivity, but ended up replacing the fragment with inner methods inside of the MainActivity and everything went back to working properly.
However, I can't rewrite every bit of code I have just to avoid using fragments. The fragment code is below.
public class IMEIFragment extends Fragment implements ActivityCompat.OnRequestPermissionsResultCallback{
public static final String TAG_IMEI = "IMEILoader";
protected Activity mActivity;
private String RecordedIMEI;
//public static final String CHECK_INTERNET = "network_connection";
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return null; //Do we need this at all?
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
Activity activity = context instanceof Activity ? (Activity) context : null;
mActivity = activity;
}
//Is this needed?
#SuppressWarnings("deprecation")
#Override
public void onAttach(Activity activity) {
activity = getActivity();
if (isAdded() && activity != null) {
super.onAttach(activity);
}
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
mActivity = activity;
}
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
}
#Override
public void onDetach() {
super.onDetach();
mActivity = null;
}
public String loadIMEI(Context context) {
if (Build.VERSION.SDK_INT >= 23) {
if (ActivityCompat.checkSelfPermission(context, Manifest.permission.READ_PHONE_STATE)
!= PackageManager.PERMISSION_GRANTED) {
// READ_PHONE_STATE permission has not been granted.
requestPermissions(context);
} else {
// READ_PHONE_STATE permission is already been granted.
RecordedIMEI = permissionGrantedActions(context);
}
if (RecordedIMEI != null) {
Log.i("loadIMEIService", "IMEI number returned!");
}
} else {
// READ_PHONE_STATE permission is already been granted.
RecordedIMEI = permissionGrantedActions(context);
}
if (RecordedIMEI != null) {
Log.i("loadIMEIService", "IMEI number returned!");
}
return RecordedIMEI;
}
private void requestPermissions(Context context) {
if (ContextCompat.checkSelfPermission(context, Manifest.permission.READ_PHONE_STATE) != PackageManager.PERMISSION_GRANTED) {
Log.i("loadIMEIService", "READ_PHONE_STATE permission not granted, asking for it...");
// TODO create proper notification content
PermissionHelper.requestPermissions(((PriceActivity) getActivity()),
new String[]{Manifest.permission.READ_PHONE_STATE},
Constants.PERM_REQUEST_PHONE_STATE,
getString(R.string.notify_perm_title),
getString(R.string.notify_perm_body),
R.drawable.ic_security);
}
}
// Callback received when a permissions request has been completed.
#Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
boolean isGranted = false;
for (int i = 0; i < grantResults.length; i++)
if (permissions[i].equals(Manifest.permission.READ_PHONE_STATE) && (grantResults[i] == PackageManager.PERMISSION_GRANTED))
isGranted = true;
if (isGranted) {
Context context = getActivity().getApplicationContext();
permissionGrantedActions(context);
}
else
Log.w("loadIMEIService", "READ_PHONE_STATE permission not granted. loadIMEI will not be available.");
}
public String permissionGrantedActions(Context context) {
//Have an object of TelephonyManager
TelephonyManager tm =(TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);
//Get IMEI Number of Phone
String IMEINumber = tm.getDeviceId();
if(IMEINumber != null) {
Log.i("loadIMEIService", "IMEI number recorded!");
}
return IMEINumber;
}
}
Error is below:
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.android.project1, PID: 5498
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.android.project1/com.android.project1.main.MainActivity}: java.lang.IllegalStateException: Fragment IMEIFragment{3e80da7 IMEILoader} not attached to Activity
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2416)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2476)
at android.app.ActivityThread.-wrap11(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1344)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5417)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
Caused by: java.lang.IllegalStateException: Fragment IMEIFragment{3e80da7 IMEILoader} not attached to Activity
at android.app.Fragment.getResources(Fragment.java:805)
at android.app.Fragment.getString(Fragment.java:827)
at com.android.project1.fragments.IMEIFragment.requestPermissions(IMEIFragment.java:107)
at com.android.project1.fragments.IMEIFragment.loadIMEI(IMEIFragment.java:80)
at com.android.project1.main.MainActivity.onCreate(MainActivity.java:108)
at android.app.Activity.performCreate(Activity.java:6237)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1107)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2369)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2476)
at android.app.ActivityThread.-wrap11(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1344)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5417)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
And here's the relevant part of my MainActivity:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mDeviceCode = (TextView) findViewById(R.id.device_code);
// Initializing headless fragment
mFragment =
(IMEIFragment) getFragmentManager()
.findFragmentByTag("IMEILoader");
if (mFragment == null) {
mFragment = new IMEIFragment();
getFragmentManager().beginTransaction()
.add(mFragment, "IMEILoader").commit();
}
if (mFragment != null) {
mNumber = mFragment.loadIMEI(MainActivity.this);
mDeviceCode.setText(Html.fromHtml("<b>IMEI</b>: " + mNumber));
}
I literally had the exact same code working for over a week. Anyone knows what could be the problem?
Edit 1: The error is pointing to requestPermissions inside my fragment
Fragments should be self contained as much as possible. You are calling directly into your IMEIFragment from the activity,
Caused by: java.lang.IllegalStateException: Fragment IMEIFragment{3e80da7 IMEILoader} not attached to Activity
at android.app.Fragment.getResources(Fragment.java:805)
at android.app.Fragment.getString(Fragment.java:827)
at com.android.project1.fragments.IMEIFragment.requestPermissions(IMEIFragment.java:107)
at com.android.project1.fragments.IMEIFragment.loadIMEI(IMEIFragment.java:80)
at com.android.project1.main.MainActivity.onCreate(MainActivity.java:108)
You can't do that. Adding the fragment via a transaction from the activity is an asynchronous operation. E.g., when the commit() method completes, the fragment is not initialized. Moreover, you have no way of knowing when it's initialized. That's why it should be self contained. The fragment decides when to call loadIMEI(), not the activity.
If you really need it to be initiated by the activity, you can add a callback from the fragment to the activity like,
void onFragmentReady(Fragment f);
Or something.
And yes, onCreateView() should return something. If your fragment really doesn't have any UI at all, you don't need it to be a fragment.
I'm trying to implement a preference fragment in my app, so I set preferences.xml file, fragment that is supposed to show preferences, and fragment transaction. When I try to show SettingsFragment, the app crashes with this error log:
java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.Class java.lang.Object.getClass()' on a null object reference
at android.support.v4.app.BackStackRecord.doAddOp(BackStackRecord.java:431)
at android.support.v4.app.BackStackRecord.replace(BackStackRecord.java:481)
at android.support.v4.app.BackStackRecord.replace(BackStackRecord.java:472)
at com.ikurek.pwr.MainActivity.onNavigationItemSelected(MainActivity.java:145)
at android.support.design.widget.NavigationView$1.onMenuItemSelected(NavigationView.java:153)
at android.support.v7.view.menu.MenuBuilder.dispatchMenuItemSelected(MenuBuilder.java:810)
at android.support.v7.view.menu.MenuItemImpl.invoke(MenuItemImpl.java:152)
at android.support.v7.view.menu.MenuBuilder.performItemAction(MenuBuilder.java:957)
at android.support.design.internal.NavigationMenuPresenter$1.onClick(NavigationMenuPresenter.java:328)
at android.view.View.performClick(View.java:4780)
at android.view.View$PerformClick.run(View.java:19866)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5254)
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)
Why is this object null? How else am I supposed to set up a setting fragment? I know that solution for this is proably very simple, but somehow I cannot figure this out by myself. Here's my code:
Part that calls fragment transaction from MainActivity:
public boolean onNavigationItemSelected(MenuItem item) {
Fragment fragment = null;
Class fragmentClass = null;
int id = item.getItemId();
if (id == R.id.nav_news) {
fragmentClass = NewsFragment.class;
} else if (id == R.id.nav_map) {
fragmentClass = CatFragment.class;
} else if (id == R.id.nav_buildings) {
fragmentClass = BuildingsFragment.class;
} else if (id == R.id.nav_settings) {
fragmentClass = SettingsFragment.class;
} else if (id == R.id.nav_info) {
fragmentClass = AppInfoFragment.class;
} else if (id == R.id.nav_bugreport) {
fragmentClass = ContactFragment.class;
}
try {
fragment = (Fragment) fragmentClass.newInstance();
} catch (Exception e) {
e.printStackTrace();
}
FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.beginTransaction().replace(R.id.frameLayoutForFragments, fragment).commit();
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
drawer.closeDrawer(GravityCompat.START);
return true;
}
My preferences.xml:
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<CheckBoxPreference
android:defaultValue="false"
android:key="saveLastPosition"
android:summary="1st check box"
android:title="Check"/>
<CheckBoxPreference
android:defaultValue="true"
android:key="keepScreenOn"
android:summary="2nd check box"
android:title="Box"/>
</PreferenceScreen>
And my SettingsFragment:
public class SettingsFragment extends PreferenceFragment {
public SettingsFragment() {
// Required empty public constructor
}
public static SettingsFragment newInstance() {
SettingsFragment fragment = new SettingsFragment();
return fragment;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.preferences);
}
}
Well from what I can tell you are passing a null fragment to your fragment manager. As you will notice:
Fragment fragment = null;
Class fragmentClass = SettingsFragment.class;
FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.beginTransaction().replace(R.id.frameLayoutForFragments, fragment).commit();
You have:
Fragment fragment = null;
You never actually declare this as a SettingsFragment. You should either have:
Fragment fragment = new SettingsFragment();
Or declare it in your replace statement.
Class fragmentClass = SettingsFragment.class;
FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.beginTransaction().replace(R.id.frameLayoutForFragments, new SettingsFragment()).commit();
I want to make it clear that this question will look very similar to one I asked earlier, but that I'm not asking exactly the same thing.
In my previous question, I got a RuntimeException/IllegalStateException, which told me my Activity got destroyed upon adding a new fragment.
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.tim.timapp
/com.example.tim.timapp.MainActivity}: java.lang.IllegalStateException:
Activity has been destroyed
In that case, it turned out it had to do with me creating new instances of MainActivityin an invalid way:
MainActivity ma = new MainActivity();
(PSA: Don't do the above, use MainActivity ma = (MainActivity) getActivity(); instead.)
I have now corrected this in my entire project, and am getting almost exactly the same error. Let me be clear: I (think I) know the original error was fixed, because I got a different error in between these two RE's, which I was able to fix myself.
To reiterate on my gibberish: Got the first RE, fixed it with the answer on my question, got a different error, fixed that myself, got almost exactly the same RE.
I have searched through my entire project to see if I had anything similar to the error I made before, but I can't find anything, so here I am. So basically, the answer I got on my previous question fixed my issue, temporarily. That answer however, does not help me with this new error I'm getting, that's why I'm asking this question.
TL;DR: Answer on Q1 fixed my issue at first(which makes it a working answer), but it does not fix the issue I'm having right now, which is almost the same.
The actual question
So, now we've got that bit out of the way, let's get on with my issue. So, I'm getting a RuntimeException/IllegalStateExcetion:
java.lang.RuntimeException: Unable to start activity
ComponentInfo{com.example.tim.timapp/com.example.tim.timapp.MainActivity}:
java.lang.IllegalStateException: Activity has been destroyed
(PS. It's only a RE because I have my app navigate to the GeneralSettings fragment on startup, for debugging ease.)
I've read up on this kind of error, but nothing I could find that applies on my project.
So, what is causing this RuntimeException/IllegalStateException?
Full log
04-05 14:17:53.140 23411-23411/? I/art: Not late-enabling -Xcheck:jni (already on)
04-05 14:17:53.190 23411-23411/com.example.tim.timapp W/System: ClassLoader referenced unknown path: /data/app/com.example.tim.timapp-1/lib/x86_64
04-05 14:17:53.210 23411-23411/com.example.tim.timapp D/TEST DBHandler: sInstance == null
04-05 14:17:53.370 23411-23411/com.example.tim.timapp D/AndroidRuntime: Shutting down VM
04-05 14:17:53.370 23411-23411/com.example.tim.timapp E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.tim.timapp, PID: 23411
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.tim.timapp/com.example.tim.timapp.MainActivity}: java.lang.IllegalStateException: Activity has been destroyed
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2416)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2476)
at android.app.ActivityThread.-wrap11(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1344)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5417)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
Caused by: java.lang.IllegalStateException: Activity has been destroyed
at android.app.FragmentManagerImpl.enqueueAction(FragmentManager.java:1433)
at android.app.BackStackRecord.commitInternal(BackStackRecord.java:687)
at android.app.BackStackRecord.commit(BackStackRecord.java:663)
at com.example.tim.timapp.MainActivity.DrawVariableFragments(MainActivity.java:276)
at com.example.fragments.Settings.GeneralSettingsFragment.onCreateView(GeneralSettingsFragment.java:58)
at android.app.Fragment.performCreateView(Fragment.java:2220)
at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:973)
at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:1148)
at android.app.BackStackRecord.run(BackStackRecord.java:793)
at android.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1535)
at android.app.FragmentController.execPendingActions(FragmentController.java:325)
at android.app.Activity.performStart(Activity.java:6252)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2379)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2476)
at android.app.ActivityThread.-wrap11(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1344)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5417)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
MainActivity (Snippet)
package com.example.tim.timapp;
public class MainActivity extends AppCompatActivity
implements NavigationView.OnNavigationItemSelectedListener {
private static boolean isMainShown = false;
private static boolean isSettingsShown = false;
private static boolean doSavePopup = false;
private static String backTitle = "";
private String tag = "TEST MA";
DBHandler dbHandler;
Menu menu;
public void DrawVariableFragments(String base,String token){
// FragmentManager fm = getFragmentManager();
ArrayList<String> Data;
dbHandler = DBHandler.getInstance(this);
int AmountOfEntries;
int SettingsContainer;
String SettingsTag;
Fragment SettingsVariableFragment;
Fragment SettingsEmptyFragment;
if (base.equalsIgnoreCase("StuffManager")) {
Data = new ArrayList<String>() {{add("StuffManager"); add("name"); add("tag"); }};
SettingsContainer = R.id.FragmentContainer2;
SettingsTag = getString(R.string.navdrawer_stuffmanager);
SettingsVariableFragment = new StuffManagerVariableFragment();
SettingsEmptyFragment = new StuffManagerEmptyFragment();
} else if (base.equalsIgnoreCase("GeneralSettings")) {
Data = new ArrayList<String>() {{add("GeneralSettings"); add("name"); add("ip"); add("port"); add("username"); add("pass"); }};
SettingsContainer = R.id.FragmentContainerGeneralSettings;
SettingsTag = getString(R.string.navdrawer_generalsettings);
SettingsVariableFragment = new GeneralSettingsVariableFragment();
SettingsEmptyFragment = new GeneralSettingsEmptyFragment();
} else {
Log.e(tag, "String Base not recognised");
return;
}
AmountOfEntries = dbHandler.returnArray(base, Data.get(1)).size();
FragmentManager fm = getFragmentManager().findFragmentByTag(SettingsTag).getChildFragmentManager();
if ((dbHandler.returnArray(base, Data.get(1))).size() == 0 ) {
// Log.d(tag, "SettingsContainer1: " + String.valueOf(SettingsContainer) + "; SettingsEmtpyFragment1: " + SettingsEmptyFragment + "; Base1: " + base);
fm.beginTransaction().add(SettingsContainer, SettingsEmptyFragment, (base + "EmptyFragment")).commit();
fm.executePendingTransactions();
return;
}
if (AmountOfEntries > 0) {
String EmptyFragName = (base + "EmptyFragment");
if ((fm.findFragmentByTag(EmptyFragName)) != null) {
fm.beginTransaction().remove(fm.findFragmentByTag(EmptyFragName)).commit();
fm.executePendingTransactions();
}
for (int i = 0; i < AmountOfEntries; i++) {
ArrayList<String> fragmentData = new ArrayList<>();
for (int k=1; k < Data.size(); k++) {
int j=k-1;
fragmentData.set(j, (dbHandler.returnArray(base, Data.get(k)).get(j)));
}
if (token.equalsIgnoreCase("edit")) {
LinearLayout linearLayout = (LinearLayout) findViewById(SettingsContainer);
linearLayout.removeAllViews();
DrawVariableFragments(base ,"draw");
} else if (token.equalsIgnoreCase("add")) {
if (fm.findFragmentByTag(fragmentData.get(i)) == null) {
fm.beginTransaction().add(SettingsContainer, SettingsVariableFragment, fragmentData.get(0)).commit();
fm.executePendingTransactions();
if (base.equalsIgnoreCase("StuffManager")) {
((StuffManagerVariableFragment) fm
.findFragmentByTag(fragmentData.get(i)))
.setText(fragmentData.get(0), fragmentData.get(1));
} else if (base.equalsIgnoreCase("GeneralSettings")) {
((GeneralSettingsVariableFragment) fm
.findFragmentByTag(fragmentData.get(i)))
.setText(fragmentData.get(0), fragmentData.get(1), fragmentData.get(2), fragmentData.get(3));
}
}
} else if (token.equalsIgnoreCase("draw")) {
fm.beginTransaction().add(SettingsContainer, SettingsVariableFragment, fragmentData.get(0)).commit();
fm.executePendingTransactions();
if (base.equalsIgnoreCase("StuffManager")) {
((StuffManagerVariableFragment) fm
.findFragmentByTag(fragmentData.get(i)))
.setText(fragmentData.get(0), fragmentData.get(1));
} else if (base.equalsIgnoreCase("GeneralSettings")) {
((GeneralSettingsVariableFragment) fm
.findFragmentByTag(fragmentData.get(i)))
.setText(fragmentData.get(0), fragmentData.get(1), fragmentData.get(2), fragmentData.get(3));
}
}
}
} else {
Log.d("TEST", "WTF, nameArray.size != 0 && !> 0");
}
}
}
GeneralSettingsFragment (Snippet)
package com.example.fragments.Settings;
public class GeneralSettingsFragment extends Fragment {
MainActivity ma;
DBHandler dbHandler;
private static Menu optionsMenu;
public static boolean hideDeleteAllButton = false;
LinearLayout linearLayout;
View rootView;
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
rootView = inflater.inflate(R.layout.fragment_generalsettings, container, false);
ma = (MainActivity) getActivity();
linearLayout = (LinearLayout) rootView.findViewById(R.id.FragmentContainerGeneralSettings);
if (linearLayout == null) {
Log.e("GMF", "Layout is null");
} else if (linearLayout.getChildCount() == 0) {
GeneralSettingsInitialInputDialog GSIID = new GeneralSettingsInitialInputDialog();
GSIID.show(getFragmentManager(), "dialog");
hideDeleteAllButton = true;
} else {
hideDeleteAllButton = false;
}
ma.DrawVariableFragments("GeneralSettings", "draw");
return rootView;
}
}
You are still doing things in an unsupported way. In MainActivity.DrawVariableFragments() you are creating a new GeneralSettingsVariableFragment() and then call getChildFragmentManager() on it and attempt to commit a fragment.
The GeneralSettingsFragment has not yet been attached to an Activity so it does not have a host. This throws the IllegalStateException("Activity has been destroyed") exception you are seeing when you try to commit the FragmentTransaction.
It is unclear why you are creating a new GeneralSettingsVariableFragmentwhen you are already inside a new instance of one.
To properly lookup an existing fragment use getFragmentManager().findFragmentByTag(...) or getFragmentManager().findFragmentById(...).