2

I'm creating an app that display movie poster in a gridview. I'm using an API from themoviedb.org. The problem is I'm getting the follow error when I run my app and I'm struggling to fix it:

07-18 20:27:39.244    2751-2751/? E/AndroidRuntime﹕ FATAL EXCEPTION: main
    Process: com.projmobileapp.pmdbadd.pmdb, PID: 2751
    java.lang.RuntimeException: Unable to start activity ComponentInfo{com.projmobileapp.pmdbadd.pmdb/com.projmobileapp.pmdbadd.pmdb.MainActivity}: android.view.InflateException: Binary XML file line #1: Error inflating class fragment
            at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2693)
            at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2758)
            at android.app.ActivityThread.access$900(ActivityThread.java:177)
            at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1448)
            at android.os.Handler.dispatchMessage(Handler.java:102)
            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:1400)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1195)
     Caused by: android.view.InflateException: Binary XML file line #1: Error inflating class fragment
            at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:770)
            at android.view.LayoutInflater.inflate(LayoutInflater.java:483)
            at android.view.LayoutInflater.inflate(LayoutInflater.java:415)
            at android.view.LayoutInflater.inflate(LayoutInflater.java:366)
            at android.support.v7.app.AppCompatDelegateImplV7.setContentView(AppCompatDelegateImplV7.java:249)
            at android.support.v7.app.AppCompatActivity.setContentView(AppCompatActivity.java:106)
            at com.projmobileapp.pmdbadd.pmdb.MainActivity.onCreate(MainActivity.java:15)
            at android.app.Activity.performCreate(Activity.java:6289)
            at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1119)
            at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2646)
            at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2758)
            at android.app.ActivityThread.access$900(ActivityThread.java:177)
            at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1448)
            at android.os.Handler.dispatchMessage(Handler.java:102)
            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:1400)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1195)
     Caused by: java.lang.NullPointerException: Attempt to invoke interface method 'int java.util.List.size()' on a null object reference
            at android.widget.ArrayAdapter.getCount(ArrayAdapter.java:330)
            at android.widget.GridView.setAdapter(GridView.java:201)
            at com.projmobileapp.pmdbadd.pmdb.MainActivityFragment.onCreateView(MainActivityFragment.java:53)
            at android.support.v4.app.Fragment.performCreateView(Fragment.java:1789)
            at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:924)
            at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1116)
            at android.support.v4.app.FragmentManagerImpl.addFragment(FragmentManager.java:1218)
            at android.support.v4.app.FragmentManagerImpl.onCreateView(FragmentManager.java:2170)
            at android.support.v4.app.FragmentActivity.onCreateView(FragmentActivity.java:300)
            at android.support.v7.app.AppCompatDelegateImplV7.callActivityOnCreateView(AppCompatDelegateImplV7.java:838)
            at android.support.v7.app.AppCompatDelegateImplV11.callActivityOnCreateView(AppCompatDelegateImplV11.java:34)
            at android.support.v7.app.AppCompatDelegateImplV7.onCreateView(AppCompatDelegateImplV7.java:826)
            at android.support.v4.view.LayoutInflaterCompatHC$FactoryWrapperHC.onCreateView(LayoutInflaterCompatHC.java:44)
            at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:732)
            at android.view.LayoutInflater.inflate(LayoutInflater.java:483)
            at android.view.LayoutInflater.inflate(LayoutInflater.java:415)
            at android.view.LayoutInflater.inflate(LayoutInflater.java:366)
            at android.support.v7.app.AppCompatDelegateImplV7.setContentView(AppCompatDelegateImplV7.java:249)
            at android.support.v7.app.AppCompatActivity.setContentView(AppCompatActivity.java:106)
            at com.projmobileapp.pmdbadd.pmdb.MainActivity.onCreate(MainActivity.java:15)
            at android.app.Activity.performCreate(Activity.java:6289)
            at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1119)
            at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2646)
            at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2758)
            at android.app.ActivityThread.access$900(ActivityThread.java:177)
            at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1448)
            at android.os.Handler.dispatchMessage(Handler.java:102)
            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:1400)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1195)
07-18 20:27:39.244    2702-2702/? W/ResourcesManager﹕ Asset path '/system/framework/twframework.jar' does not exist or contains no resources.

Here's my code

package com.projmobileapp.pmdbadd.pmdb;

import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.GridView;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;

public class MainActivityFragment extends Fragment {

    private ArrayList<Movie> flavorList;


    public MainActivityFragment() {
    }

    MovieAdapter mMovieAdapter;


    public void onSaveInstanceState(Bundle outState) {
        outState.putParcelableArrayList("flavors", flavorList);
        super.onSaveInstanceState(outState);
    }


    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {

        View rootView = inflater.inflate(R.layout.fragment_main, container, false);

        mMovieAdapter = new MovieAdapter(getActivity(), flavorList);
        GridView listView = (GridView) rootView.findViewById(R.id.gridview_movie);
        listView.setAdapter(mMovieAdapter);
        updateMovie();

    return rootView;

    }


    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setHasOptionsMenu(true);
    }

    @Override
    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
        // Inflate the menu; this adds items to the action bar if it is present.
        inflater.inflate(R.menu.mainactivityfragment, menu);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        int id = item.getItemId();
        if (id == R.id.action_refresh) {
            updateMovie();
            return true;
        }
        return super.onOptionsItemSelected(item);
    }

    private void updateMovie() {
        FetchMovieTask movieTask = new FetchMovieTask();
        movieTask.execute();
    }

    class FetchMovieTask extends AsyncTask<Void, Void, List<Movie>> {
        private final String LOG_TAG = FetchMovieTask.class.getSimpleName();

        @Override
        protected List<Movie> doInBackground(Void... params) {
            HttpURLConnection urlConnection = null;
            BufferedReader reader = null;

            // Will contain the raw JSON response as a string.
            String movieJsonStr = null;

            try {
                URL url = new URL("http://api.themoviedb.org/3/discover/movie?sort_by=popularity.desc&api_key=InsertAPIKey");

                urlConnection = (HttpURLConnection) url.openConnection();
                urlConnection.setRequestMethod("GET");
                urlConnection.connect();

                // Read the input stream into a String
                InputStream inputStream = urlConnection.getInputStream();
                StringBuffer buffer = new StringBuffer();
                if (inputStream == null) {
                    // Nothing to do.
                    return null;
                }
                reader = new BufferedReader(new InputStreamReader(inputStream));

                String line;
                while ((line = reader.readLine()) != null) {

                    buffer.append(line + "\n");
                }

                if (buffer.length() == 0) {
                    // Stream was empty.  No point in parsing.
                    return null;
                }
                movieJsonStr = buffer.toString();

            } catch (IOException e) {
                Log.e(LOG_TAG, "Error ", e);
                return null;
            } finally {
                if (urlConnection != null) {
                    urlConnection.disconnect();
                }
                if (reader != null) {
                    try {
                        reader.close();
                    } catch (final IOException e) {
                        Log.e(LOG_TAG, "Error closing stream", e);
                    }
                }
            }
            try {
                return getMovieDataFromJson(movieJsonStr);
            } catch (JSONException j) {
                Log.e(LOG_TAG, "JSON Error", j);
            }
            return null;
        }

        private List<Movie> getMovieDataFromJson(String forecastJsonStr)
                throws JSONException {
            List<Movie> movies = new ArrayList<>();
            JSONObject movieJson = new JSONObject(forecastJsonStr);
            JSONArray movieArray = movieJson.getJSONArray("results");
            for (int i = 0; i < movieArray.length(); i++) {
                JSONObject movie = movieArray.getJSONObject(i);
                Movie movie1 = new Movie(movieJson.getString("original_title"), movieJson.getDouble("vote_average"), movieJson.getString("release_date"), movieJson.getString("overview"), movieJson.getString("poster_path"));
                movies.add(movie1);

            }
            return movies;
        }





        @Override
        protected void onPostExecute(List<Movie> movies) {
            if (movies != null) {
                mMovieAdapter.clear();
                for(Movie dayForecastStr : movies) {
                    mMovieAdapter.add(dayForecastStr);
                }
                // New data is back from the server.  Hooray!
            }
        }
    }


}

Could someone please advise

7
  • in onCreateView(), flavorList is null, but it shouldn't be. Fix that Commented Jul 18, 2015 at 19:43
  • First of all remove the MainActivityFragment() {} constructor. You dont mess with Fragment and activity constructors in android. Just delete or comment it out. Commented Jul 18, 2015 at 19:44
  • I believe that you are supposedly saving the list out into the bundle on saveInstanceState for rotation, you're not actually reading it back in onCreate or onCreateView in case the bundle is not null. Also, I'm not even sure if Movie is actually a parcelable (use parcelabler.com ), but even if it were, this wouldn't work as you need to use writeTypedList and readTypedList and NOT ParcelableArrayList. Commented Jul 18, 2015 at 19:46
  • 1
    @SamratDutta All subclasses of Fragment NEED an empty constructor. See the docs Commented Jul 18, 2015 at 19:56
  • 1
    @AdnanElezovic: "All subclasses of Fragment NEED an empty constructor" -- yes, and therefore they usually do not implement one, getting instead the automatically-generated public zero-argument constructor. Having any constructor implemented on a Fragment subclass is a code smell. Having a constructor that fails to chain to a superclass constructor is an outright mistake, as now any code in the Fragment constructor will not get executed. At the moment, there is no code there, but that could easily change in future versions of Android (or support-v4 for the backport). Commented Jul 18, 2015 at 20:14

3 Answers 3

4

I believe that you are supposedly saving the list out into the bundle on saveInstanceState for rotation, you're not actually reading it back in onCreate or onCreateView in case the bundle is not null. Also, I'm not even sure if Movie is actually a parcelable (use http://parcelabler.com ), but even if it were, this wouldn't work as you need to use writeTypedList and readTypedList and NOT writeParcelableArrayList (that returns List<Parcelable> on read, and that is NOT what you want).

But the current problem is that you should not give a null to the adapter in this line:

mMovieAdapter = new MovieAdapter(getActivity(), flavorList);

Initialize the adapter and set it only when you actually have data, or initialize it with an empty list.

Really though, use writeTypedList and readTypedList, otherwise you'll run into a lot of issues later on with state saving.

Sign up to request clarification or add additional context in comments.

1 Comment

hi thanks for the reply, would you be able to give an example of how I can use writeTypedList and readTypedList in this case?
4
mMovieAdapter = new MovieAdapter(getActivity(), flavorList);

At this point in the code, flavorList is null. Do not create the MovieAdapter and call setAdapter() on the ListView until you have your movies. Or, initialize flavorList to be an empty ArrayList<Movie> before creating the adapter.

Also, please remove your broken MainActivityFragment constructor, or chain to the superclass constructor from inside of it.

6 Comments

Apparently, all classes that extend Fragment require an empty constructor. So, that is not broken afterall.
@SamratDutta: Oh, yes it is. Never implement a constructor without chaining to the superclass unless you wrote the entire class tree all the way to Object. Moreover, by simply deleting this broken constructor, the OP would get the automatically-generated public zero-argument constructor, which does chain to the superclass constructor.
@CommonsWare If you check out the given template for a fragment (when you create a new fragment in android studio), you will see it comes with a empty constructor with no super() call, and a comment block above /* Required emply constructor */.
@AdnanElezovic: And I believe that I already filed a bug for that broken bit of the template. If not, I'll do so shortly.
@CommonsWare That was exactly my initial reaction. And that is what i commented in the original post. That not writting anything means having a default constructor with a call to the super class constructor. But then someone brought it to my attention that the empty constructor is required. I did a google search, and a stackoverflow answer suggested the same. That is when I made this comment. Anyway, i am clearly not well informed in this issue. So probably you are right. I need to do some research.
|
1

For anyone that is using GsonFormatter plugin to retrieve information from a RESTful API, make sure that you do a clean Format of the Gson Formatter (Remove generated code in the class and redo it)..

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.