4

I'm trying to develop an app that has a Navigation Drawer and a Fragment to display data. This is my app activity stack:

->Login(checks if it's logged in, it skips loading the view and proceeds to Timeline)

->Timeline

This is the way I get the error:

->I start the app

->It bypasses the Login screen because I'm already logged in

->Everything looks fine, then I click Log Out from the Menu Drawer or press Back Button

->I get back to the Login Screen

->Now if I press Login again and start the Timeline activity again, my app crashes...

Here are the codes. This is the logcat:

11-15 21:11:52.050  18695-18695/lazarko.pocketformulas E/AndroidRuntime﹕ FATAL EXCEPTION: main
    java.lang.RuntimeException: Unable to start activity ComponentInfo{lazarko.pocketformulas/lazarko.pocketformulas.Timeline}: android.view.InflateException: Binary XML file line #28: Error inflating class fragment
            at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2355)
            at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2391)
            at android.app.ActivityThread.access$600(ActivityThread.java:151)
            at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1335)
            at android.os.Handler.dispatchMessage(Handler.java:99)
            at android.os.Looper.loop(Looper.java:155)
            at android.app.ActivityThread.main(ActivityThread.java:5520)
            at java.lang.reflect.Method.invokeNative(Native Method)
            at java.lang.reflect.Method.invoke(Method.java:511)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1029)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:796)
            at dalvik.system.NativeStart.main(Native Method)
     Caused by: android.view.InflateException: Binary XML file line #28: Error inflating class fragment
            at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:704)
            at android.view.LayoutInflater.rInflate(LayoutInflater.java:746)
            at android.view.LayoutInflater.inflate(LayoutInflater.java:489)
            at android.view.LayoutInflater.inflate(LayoutInflater.java:396)
            at android.view.LayoutInflater.inflate(LayoutInflater.java:352)
            at com.android.internal.policy.impl.PhoneWindow.setContentView(PhoneWindow.java:324)
            at android.app.Activity.setContentView(Activity.java:1912)
            at lazarko.pocketformulas.Timeline.onCreate(Timeline.java:35)
            at android.app.Activity.performCreate(Activity.java:5066)
            at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1101)
            at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2311)
            at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2391)
            at android.app.ActivityThread.access$600(ActivityThread.java:151)
            at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1335)
            at android.os.Handler.dispatchMessage(Handler.java:99)
            at android.os.Looper.loop(Looper.java:155)
            at android.app.ActivityThread.main(ActivityThread.java:5520)
            at java.lang.reflect.Method.invokeNative(Native Method)
            at java.lang.reflect.Method.invoke(Method.java:511)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1029)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:796)
            at dalvik.system.NativeStart.main(Native Method)
     Caused by: java.lang.NullPointerException
            at android.support.v4.widget.DrawerLayout.isDrawerView(DrawerLayout.java:1097)
            at android.support.v4.widget.DrawerLayout.closeDrawer(DrawerLayout.java:1306)
            at lazarko.pocketformulas.NavigationDrawerFragment.selectItem(NavigationDrawerFragment.java:209)
            at lazarko.pocketformulas.NavigationDrawerFragment.onCreate(NavigationDrawerFragment.java:82)
            at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:798)
            at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:1015)
            at android.app.FragmentManagerImpl.addFragment(FragmentManager.java:1114)
            at android.app.Activity.onCreateView(Activity.java:4722)
            at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:680)
            at android.view.LayoutInflater.rInflate(LayoutInflater.java:746)
            at android.view.LayoutInflater.inflate(LayoutInflater.java:489)
            at android.view.LayoutInflater.inflate(LayoutInflater.java:396)
            at android.view.LayoutInflater.inflate(LayoutInflater.java:352)
            at com.android.internal.policy.impl.PhoneWindow.setContentView(PhoneWindow.java:324)
            at android.app.Activity.setContentView(Activity.java:1912)
            at lazarko.pocketformulas.Timeline.onCreate(Timeline.java:35)
            at android.app.Activity.performCreate(Activity.java:5066)
            at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1101)
            at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2311)
            at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2391)
            at android.app.ActivityThread.access$600(ActivityThread.java:151)
            at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1335)
            at android.os.Handler.dispatchMessage(Handler.java:99)
            at android.os.Looper.loop(Looper.java:155)
            at android.app.ActivityThread.main(ActivityThread.java:5520)
            at java.lang.reflect.Method.invokeNative(Native Method)
            at java.lang.reflect.Method.invoke(Method.java:511)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1029)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:796)
            at dalvik.system.NativeStart.main(Native Method)

This is my Activity code:

public class Timeline extends FragmentActivity
        implements NavigationDrawerFragment.NavigationDrawerCallbacks, SearchView.OnQueryTextListener {
    private static NavigationDrawerFragment mNavigationDrawerFragment;
    private CharSequence mTitle;
    public static Context context;
    SearchView searchView;



    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_timeline);
        context = getApplicationContext();
        mNavigationDrawerFragment = (NavigationDrawerFragment)
                getFragmentManager().findFragmentById(R.id.navigation_drawer);
        mTitle = getTitle();

        // Set up the drawer.
        mNavigationDrawerFragment.setUp(
                R.id.navigation_drawer,
                (DrawerLayout) findViewById(R.id.drawer_layout));
    }
    public static Context getContext() {
        return context;
    }

    @Override
    protected void onStart() {
        super.onStart();
    }

    @Override
    protected void onResume() {
        super.onStart();
        FragmentManager fragmentManager = getSupportFragmentManager();
        SharedPreferences preferencesFragmentData = getSharedPreferences("fragmentData", 0);
        String fragmentID = preferencesFragmentData.getString("currentFragment", "");

        if(fragmentID == "FAVORITES_FRAGMENT")
            fragmentManager.beginTransaction().replace(R.id.container, new Favorites()).commit();
        else if (fragmentID == "TIMELINE_FRAGMENT")
            fragmentManager.beginTransaction().replace(R.id.container, new PlaceholderFragment()).commit();
        else if (fragmentID == "SETTINGS_FRAGMENT")
            fragmentManager.beginTransaction().replace(R.id.container, new Settings()).commit();
    }

    @Override
    protected void onPause() {
        super.onPause();
    }

    @Override
    public void onNavigationDrawerItemSelected(int position) {
        FragmentManager fragmentManager = getSupportFragmentManager();
        SharedPreferences preferencesFragmentData = getSharedPreferences("fragmentData", 0);
        SharedPreferences.Editor editorFragmentData = preferencesFragmentData.edit();
        switch(position) {
            case 1:
                //Timeline clicked
                editorFragmentData.putString("currentFragment", "TIMELINE_FRAGMENT");
                editorFragmentData.commit();
                fragmentManager.beginTransaction()
                        .replace(R.id.container, new PlaceholderFragment(), "TIMELINE_FRAGMENT")
                        .commit();
                break;
            case 2:
                //Favorites clicked
                editorFragmentData.putString("currentFragment", "FAVORITES_FRAGMENT");
                editorFragmentData.commit();
                fragmentManager.beginTransaction()
                        .replace(R.id.container, new Favorites(), "FAVORITES_FRAGMENT")
                        .commit();
                break;
            case 3:
                //Settings clicked
                editorFragmentData.putString("currentFragment", "SETTINGS_FRAGMENT");
                editorFragmentData.commit();
                fragmentManager.beginTransaction()
                        .replace(R.id.container, new Settings())
                        .commit();
                break;
            case 4:
                //Log Out clicked
                SharedPreferences loginDataPreferences = getSharedPreferences("loginData", 0);
                SharedPreferences.Editor editorLogin = loginDataPreferences.edit();
                editorLogin.putBoolean("loggedIn", false);
                editorLogin.commit();
                Intent intent = new Intent(getApplicationContext(), Login.class);
                startActivity(intent);
                break;
            default:
                editorFragmentData.putString("currentFragment", "TIMELINE_FRAGMENT");
                editorFragmentData.commit();
                fragmentManager.beginTransaction()
                        .replace(R.id.container, new PlaceholderFragment())
                        .commit();
                break;
        }

    }

    public void restoreActionBar() {
        ActionBar actionBar = getActionBar();
        actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
        actionBar.setDisplayShowTitleEnabled(true);
    }


    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        if(!mNavigationDrawerFragment.isDrawerOpen()) {
            menu.clear();
            getMenuInflater().inflate(R.menu.timeline, menu);
            //restoreActionBar();

            searchView = new SearchView(getActionBar().getThemedContext());
            searchView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
            searchView.setQueryHint(Html.fromHtml("<font color=#FFFFFF>Search ... </font>"));
            searchView.setOnQueryTextListener(this);
            searchView.clearFocus();

            menu.add("Search").setIcon(R.drawable.ic_action_action_search).setActionView(searchView).setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM | MenuItem.SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW);
        }
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        return false;
    }

    //User searched for a formula and pressed Enter
    @Override
    public boolean onQueryTextSubmit(String s) {
        SharedPreferences preferencesFragmentData = getSharedPreferences("fragmentData", 0);
        String currentFragment = preferencesFragmentData.getString("currentFragment", "");

        if(currentFragment == "TIMELINE_FRAGMENT"){
            //Log.e("TIMELINE", currentFragment + "IN THE IF FRAGMENT");
            //Toast.makeText(getContext(), "You searched for: " + s + " in Timeline Fragment!", Toast.LENGTH_SHORT).show();
        } else if (currentFragment == "FAVORITES_FRAGMENT"){
            //Log.e("TIMELINE", currentFragment + "IN THE IF FRAGMENT");
            //Toast.makeText(getContext(), "You searched for: " + s + " in FAVORITES Fragment!", Toast.LENGTH_SHORT).show();
        }

        //Hide the keyboard
        InputMethodManager inputManager = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
        inputManager.hideSoftInputFromWindow(this.getCurrentFocus().getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);

        invalidateOptionsMenu();

        return true;
    }

    //user started typing, this code block is for Autocomplete or Suggestions based on his current input
    @Override
    public boolean onQueryTextChange(String s) {
        return false;
    }
}

This is the first Fragment that's being shown:

/**
 * Created by lazarnikolov on 11/8/14.
 */
public class PlaceholderFragment extends Fragment {
    /**
     * The fragment argument representing the section number for this
     * fragment.
     */
    private static final String ARG_SECTION_NUMBER = "section_number";
    private static View rootView;
    FavoritesDatabaseAdapter favoritesDB;
    SwipeRefreshLayout swipeRefreshLayout = null;

    /**
     * Returns a new instance of this fragment for the given section
     * number.
     */

    public PlaceholderFragment() {
    }

    @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, final ViewGroup container,
                             Bundle savedInstanceState) {
        if (rootView != null) {
            ViewGroup parent = (ViewGroup) rootView.getParent();
            if (parent != null)
                parent.removeView(rootView);
        }
        try {
            rootView = inflater.inflate(R.layout.fragment_timeline, container, false);
        } catch (InflateException e) {

        }

        favoritesDB = new FavoritesDatabaseAdapter(getActivity().getApplicationContext());
        final ContentValues contentValues = new ContentValues();

        final LinearLayout llScrollViewContainerItems = (LinearLayout) container.findViewById(R.id.llScrollViewContainerItems);
        llScrollViewContainerItems.removeAllViews();
        ActionBar actionBar = getActivity().getActionBar();
        final Typeface font = Typeface.createFromAsset(getActivity().getAssets(), "ubuntu.ttf");
        actionBar.setBackgroundDrawable(new ColorDrawable(getResources().getColor(R.color.PeterRiver)));
        actionBar.setDisplayShowTitleEnabled(true);
        actionBar.setTitle("Timeline");

        swipeRefreshLayout = (SwipeRefreshLayout) container.findViewById(R.id.container);

        swipeRefreshLayout.setColorSchemeResources(R.color.Alizarin, R.color.Emerald, R.color.PeterRiver, R.color.Amethyst, R.color.WetAsphalt);
        swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {...}
        return rootView;
    }

    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);

    }

    @Override
    public void onStop() {
        super.onStop();
    }

    @Override
    public void onDestroyView() {
        super.onDestroyView();
        Fragment f = (Fragment) getFragmentManager()
                .findFragmentByTag("TIMELINE_FRAGMENT");
        if (f != null)
            getFragmentManager().beginTransaction().remove(f).commit();
    }
}

Here's my activity_timeline.xml file, where the error occurs:

<!-- A DrawerLayout is intended to be used as the top-level content view using match_parent for both width and height to consume the full space available. -->
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools" android:id="@+id/drawer_layout"
    android:layout_width="match_parent" android:layout_height="match_parent"
    tools:context=".Timeline">

    <!-- As the main content view, the view below consumes the entire
         space available using match_parent in both dimensions. -->
    <android.support.v4.widget.SwipeRefreshLayout android:id="@+id/container" android:layout_width="match_parent"
        android:layout_height="match_parent" android:orientation="vertical">
        <ScrollView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:id="@+id/svContainerViews">
            <LinearLayout android:id="@+id/llScrollViewContainerItems" android:layout_width="match_parent"
                android:layout_height="match_parent" android:orientation="vertical">
            </LinearLayout>
        </ScrollView>
    </android.support.v4.widget.SwipeRefreshLayout>

    <!-- android:layout_gravity="start" tells DrawerLayout to treat
         this as a sliding drawer on the left side for left-to-right
         languages and on the right side for right-to-left languages.
         If you're not building against API 17 or higher, use
         android:layout_gravity="left" instead. -->
    <!-- The drawer is given a fixed width in dp and extends the full height of
         the container. -->
    <fragment android:id="@+id/navigation_drawer"
        android:layout_width="@dimen/navigation_drawer_width" android:layout_height="match_parent"
        android:layout_gravity="start"
        android:name="lazarko.pocketformulas.NavigationDrawerFragment"
        tools:layout="@layout/fragment_navigation_drawer" />

</android.support.v4.widget.DrawerLayout>

And my Login Activity class:

/**
 * Created by lazarnikolov on 11/8/14.
 */
public class Login extends Activity{
    EditText etEmail, etPassword;
    Button bLogin, bRegister;
    Typeface font;
    TextView tvLogIn;

    @Override
    protected void onCreate(final Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        SharedPreferences preferences = getSharedPreferences("loginData", 0);
        boolean loggedIn = preferences.getBoolean("loggedIn", false);

        if(loggedIn) {
            Intent intent = new Intent("android.intent.action.TIMELINE");
            startActivity(intent);
        }
        SharedPreferences initialFragmentData = getSharedPreferences("fragmentData", 0);
        SharedPreferences.Editor initialEditorFragmentData = initialFragmentData.edit();
        initialEditorFragmentData.putString("currentFragment", "TIMELINE_FRAGMENT");
        initialEditorFragmentData.commit();

        setContentView(R.layout.login);
        font = Typeface.createFromAsset(getAssets(), "ubuntu.ttf");

        etEmail = (EditText) findViewById(R.id.etEmail);
        etEmail.setTypeface(font);
        etPassword = (EditText) findViewById(R.id.etPassword);
        etPassword.setTypeface(font);
        tvLogIn = (TextView) findViewById(R.id.tvRegister);
        tvLogIn.setTypeface(font);
        bLogin = (Button) findViewById(R.id.bLogin);
        bLogin.setTypeface(font);

        bLogin.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                SharedPreferences preferences = getSharedPreferences("loginData", 0);
                SharedPreferences.Editor editor = preferences.edit();
                editor.putBoolean("loggedIn", true);
                editor.commit();
                communicate();
                Intent intent = new Intent("android.intent.action.TIMELINE");
                //intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
                startActivity(intent);
            }
        });

        bRegister = (Button) findViewById(R.id.bRegister);
        bRegister.setTypeface(font);
        bRegister.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent intent = new Intent("android.intent.action.REGISTER");
                startActivity(intent);
            }
        });
    }

    //    SERVER COMMUNICATION CLASS INITIALIZATION
    private void communicate() {
        new GetData().execute();
    }

    //    SERVER COMMUNICATION CLASS
    private class GetData extends AsyncTask<Void, Void, String> {
        @Override
        protected String doInBackground(Void... voids) {
            Looper.prepare();
            String data = "";
            InputStream inputStream = null;
            try {
                HttpClient httpClient = new DefaultHttpClient();
                HttpPost httpPost = new HttpPost("*******");

                String json = "";
                JSONObject object = new JSONObject();
                object.accumulate("email", etEmail.getText().toString());
                object.accumulate("password", etPassword.getText().toString());
                json = object.toString();
                StringEntity se = new StringEntity(json);
                httpPost.setEntity(se);
                httpPost.setHeader("Accept", "application/json");
                httpPost.setHeader("Content-type", "application/json");
                HttpResponse response = httpClient.execute(httpPost);
                inputStream = response.getEntity().getContent();
                if(inputStream != null){
                    Toast.makeText(getApplicationContext(), "Logged in!", Toast.LENGTH_SHORT).show();
                } else {
                    Toast.makeText(getApplicationContext(), "Invalid username/password", Toast.LENGTH_SHORT).show();
                }

            } catch(Exception e) {
                Log.e("log_tag", "Error in http connection: " + e.toString());
            }
            return data;
        }

        @Override
        protected void onPostExecute(String result) {
            //Toast.makeText(getApplicationContext(), result, Toast.LENGTH_LONG).show();
        }
    }

    @Override onStart(), onRestart(), onResume()...
}

I've been searching for way too long and I still couldn't find a solution. Please take a look and post me what you think it's the problem!

Thanks a lot!

Lazar Nikolov
  • 928
  • 14
  • 21

2 Answers2

3

Look closer/debug lazarko.pocketformulas.NavigationDrawerFragment.java line 209 (it belongs to selectItem() method)
According to your stack trace you may have a null or not properly initialized object there

Update To get to the reason of why it sometime happens and sometime not (if I correctly understand) there are more questions to ask.
1) Does it happen when you start your activity after a while? If so it may be linked to the fact that system has freed resources and your activity is recreated

2) If not - you have to move step by step to find reason.
Track down where the object get nulled. It may be:
-- on re-creation of parent object (when you don't initialize it properly)
-- inside its class (just ctrl+f all occurrences)
-- outside its class. To track this make object private and declare setter method

sberezin
  • 3,266
  • 23
  • 28
  • 1
    Yes I know that it's a Null, and I know where it is, it's on setContentView(R.layout.activity_timeline); in my Timeline Class, onCreate method. But I don't know why is that happening. As I wrote above, I enter that activity, everything looks good, looks normal, but when I exit it and later try to enter again it throws a NullPointerException on setContentView... – Lazar Nikolov Nov 15 '14 at 23:30
  • 1
    No look, I start the app, The Login activity is first, but it's being bypassed because I set a rule if you're logged in, the login screen shouldn't show up. After the bypassing comes up the Timeline screen. Everything looks good, no errors no crashes. Then I click Log Out and it brings me the Login Screen. Again, no errors no crashes. After that I click on Log In button to take me to the Timeline screen. And that its when the crash occurs. When I visit the Timeline activity twice. Timeline > Login > Timeline. – Lazar Nikolov Nov 16 '14 at 14:37
  • Sorry, don' have exact answer. But if it's null (and wasn't null before) there MUST BE the place where it gets nulled! Please see update 2). Usually the reason is simple, you just have to find it – sberezin Nov 17 '14 at 06:46
1

Okay I've fixed the bug. I've been using the wrong Flag for the intent. This is the fix:

intent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);

I inserted this where I'm starting the Timeline activity, and on the Log Out button too. Now I don't get that NullPointerException error on setContentView.

Lazar Nikolov
  • 928
  • 14
  • 21