简体   繁体   中英

How to parse JSON with Retrofit and display it?

I am facing a problem with parsing JSON using Retrofit.

This is my JSON:

{
    "page": 1,
    "limit": 10,
    "explicit": false,
    "has_more": true,
    "list": [
        {
            "id": "x4wqlq6",
            "title": "Xavier Mignot : « Il nous manque toujours des points »",
            "created_time": 1476019523,
            "thumbnail_medium_url": "http://s2.dmcdn.net/c2Vct/160x120-gDr.jpg"
        },
        {
            "id": "x4wq5k7",
            "title": "David Mélé : « Cette victoire fait du bien dans les têtes de tout le monde »",
            "created_time": 1476001049,
            "thumbnail_medium_url": "http://s1.dmcdn.net/c2CqJ/160x120-Aj4.jpg"
        },
        …
    ]
}

I would like to display the title, the id, and the link.

My Video model:

public class Video {

    @SerializedName("list")
    @Expose
    private List list;

    public List getList() {
        return list;
    }

    public void setList(List list) {
        this.list = list;
    }

    public class List {

        @SerializedName("id")
        @Expose
        private String id;
        @SerializedName("title")
        @Expose
        private String title;
        @SerializedName("created_time")
        @Expose
        private String created_time;
        @SerializedName("thumbnail_medium_url")
        @Expose
        private String thumbnail_medium_url;

        public String getId() {
            return id;
        }

        public void setId(String id) {
            this.id = id;
        }
        public String getTitle() {
            return title;
        }
        public void setTitle(String title) {
            this.title = title;        }
        public String getCreated_time() {
            return created_time;
        }

        public void setCreated_time(String created_time) {
            this.created_time = created_time;
        }

        public String getThumbnail_medium_url() {
            return thumbnail_medium_url;
        }

        public void setThumbnail_medium_url(String thumbnail_medium_url) {
            this.thumbnail_medium_url = thumbnail_medium_url;
        }
    }
}

Here is the main class:

public class Videos extends MainActivity{

    private ListView listView;
    private View parentView;
    private ArrayList<Video> videoList;
    private CustomListViewAdapterV adapter;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_videos);
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);
        videoList = new ArrayList<>();
        parentView = findViewById(R.id.parentLayout);
        DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
        ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
                this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
        drawer.setDrawerListener(toggle);
        toggle.syncState();
        NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);
        navigationView.setNavigationItemSelectedListener(this);
        listView = (ListView) findViewById(R.id.list1);
        listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                Snackbar.make(parentView, videoList.get(position) + " => " + videoList.get(position), Snackbar.LENGTH_LONG).show();
                // a revoirr
                /*String url = alist.get(position).getThumbnail_medium_url();
                Intent i = new Intent(Videos.this,  daylimotion.class);
                i.putExtra("url", url);
                startActivity(i);*/
            }
        });
        Toast toast = Toast.makeText(getApplicationContext(), R.string.string_click_to_load, Toast.LENGTH_LONG);
        toast.setGravity(Gravity.CENTER, 0, 0);
        toast.show();

        FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
        assert fab != null;
        fab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(@NonNull final View view) {
                /**
                 * Checking Internet Connection
                 */
                if (InternetConnection.isNetworkAvailable(getApplicationContext())) {
                    final ProgressDialog dialog;
                    /**
                     * Progress Dialog for User Interaction
                     */
                    dialog = new ProgressDialog(Videos.this);
                    dialog.setTitle(getString(R.string.string_getting_json_title));
                    dialog.setMessage(getString(R.string.string_getting_json_message));
                    dialog.show();

                    //Creating an object of our api interface
                    ApiInterface api = ApiClientV.getApiInterface();
                    /**
                     * Calling JSON
                     */
                    Call<VideoList> call = api.getJsn();
                    /**
                     * Enqueue Callback will be call when get response...
                     */
                    call.enqueue(new Callback<VideoList>() {
                        @Override
                        public void onResponse(Call<VideoList> call, Response<VideoList> response) {
                            //Dismiss Dialog
                            dialog.dismiss();
                            if(response.isSuccessful()) {
                                /**
                                 * Got Successfully
                                 */

                               videoList = response.body().getList();


                                /**
                                 * Binding that List to Adapter
                                 */
                                adapter = new CustomListViewAdapterV(Videos.this, videoList);
                                listView.setAdapter(adapter);

                            } else {
                                Snackbar.make(parentView, R.string.string_some_thing_wrong, Snackbar.LENGTH_LONG).show();
                            }
                        }

                        @Override
                        public void onFailure(Call<VideoList> call, Throwable t) {
                            dialog.dismiss();
                        }
                    });
                } else {
                    Snackbar.make(parentView, R.string.string_internet_connection_not_available, Snackbar.LENGTH_LONG).show();
                }
            }
        });

This is the VideoList class. It's for calling JSON. It's using in the videos ( the main):

public class VideoList {

    @SerializedName("list")
    @Expose
    private ArrayList<Video> list = new ArrayList<>();
    public ArrayList<Video> getList() {
        return list;
    }

}

After we found the adapter, the application hung in this part of codes. Exactly in vh.textViewTitle.setText(item.getList().getTitle()) this variable still null :(

public class CustomListViewAdapterV extends ArrayAdapter<Video> {

    List<Video> videoList;
    Context context;
    private LayoutInflater mInflater;

    // Constructors
    public CustomListViewAdapterV(Context context, ArrayList<Video> objects) {
        super(context, 0, objects);
        this.context = context;
        this.mInflater = LayoutInflater.from(context);
        videoList = objects;
    }


    @Override
   public Video getItem(int position) {
       return videoList.get(position);
   }


    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        final ViewHolder vh;
        if (convertView == null) {
            View view = mInflater.inflate(R.layout.list_item_videos, parent, false);
            vh = ViewHolder.create((RelativeLayout) view);
            view.setTag(vh);
        } else {
            vh = (ViewHolder) convertView.getTag();
        }

        Video item = getItem(position);
        vh.textViewTitle.setText(item.getList().getTitle());
        vh.textViewCreated_time.setText(item.getList().getCreated_time());
        vh.textViewId.setText(item.getList().getId());
        Picasso.with(context).load(item.getList().getThumbnail_medium_url()).placeholder(R.mipmap.ic_launcher).error(R.mipmap.ic_launcher).into(vh.imageView);

        return vh.rootView;
    }

    private static class ViewHolder {
        public final RelativeLayout rootView;
        public final ImageView imageView;
        public final TextView textViewTitle;
        public final TextView textViewCreated_time;
        public final TextView textViewId;
        private ViewHolder(RelativeLayout rootView,  ImageView imageView, TextView textViewTitle, TextView textViewCreated_time, TextView textViewId) {
           this.rootView = rootView;
            this.imageView = imageView;
            this.textViewTitle = textViewTitle;
            this.textViewCreated_time = textViewCreated_time;
            this.textViewId = textViewId;
        }

        public static ViewHolder create(RelativeLayout rootView) {
           ImageView imageView = (ImageView) rootView.findViewById(R.id.imageView);
            TextView textViewTitle = (TextView) rootView.findViewById(R.id.textViewTitle);
            TextView textViewCreated_time = (TextView) rootView.findViewById(R.id.textViewCreated_time);
            TextView textViewId = (TextView) rootView.findViewById(R.id.textViewId);
            return new ViewHolder(rootView, imageView, textViewCreated_time,  textViewTitle, textViewId);
        }
    }
}

Could someone please help explain why the application is hanging?

Your JSON object is not correct. The Video class should not have a list, that should represent the items within the list only.

Video.class

public class Video {

    @SerializedName("id")
    @Expose
    private String id;
    @SerializedName("title")
    @Expose
    private String title;
    @SerializedName("created_time")
    @Expose
    private String created_time;
    @SerializedName("thumbnail_medium_url")
    @Expose
    private String thumbnail_medium_url;

}

VideoList.class

public class VideoList {

    // TODO: Add "page", "limit", "explicit", "hasMore"

    @SerializedName("list")
    @Expose
    private ArrayList<Video> list = new ArrayList<>();
    public ArrayList<Video> getList() {
        return list;
    }
}

I don't see anything obvious that would cause it to hang, You'll need to set some breakpoints and step through the code.

One suggestion, that has nothing to do with your problem. I'd move the adapter creation and assignment to the ListView outside of the callback.
Put it directly under the listView assignment and inside the callback, just set the data in the already defined arrayList and call notifyDataSetChanged on the adapter. This is much more efficient than recreating the adapter each time you get a new dataset.

listView = (ListView) findViewById(R.id.list1);
// Move the two lines below under this line.
adapter = new CustomListViewAdapterV(Videos.this, videoList);
listView.setAdapter(adapter);

And inside the callback, add this:

// Puts the data in the array, this is already there..
videoList = response.body().getList();
// Notify that the list has changed and redraw the screen.
adapter.notifiyDataSetChanged();

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM