java - 由于在Android中解析JSON字符串响应而导致的错误

标签 java android json video youtube

我正在尝试为YouTube channel 创建一个应用,并希望在recyclerview中显示视频列表。我为此使用YoutubeData API v3。我得到一个JSON字符串响应作为对我的查询的返回,并且正在手动解析它。

我创建了一个名为Video的类,用于将有关视频的信息存储在对象中,然后将其添加到ArrayList中以传递给recyclerview适配器。最初它运行良好,但是随着我想传递给Video对象的详细信息数量增加,recyclerview停止工作。它仅显示最新的两个视频,其余的不显示。

一旦我将videoId传递给适配器,回收者 View 就会停止工作。我尝试使用AsyncTask在单独的线程上解析json,但是它不起作用。我在这个错误中停留了很长时间,无法找出原因。请帮忙 !!

这是我的代码:

MainActivity.java:

import android.os.AsyncTask;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;

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

import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;


public class MainActivity extends AppCompatActivity {

    URL url = null;
    String resultString = null;
    RecyclerView rv;
    VideoAdapter adapter;
    ArrayList<Video> titles;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        rv = (RecyclerView) findViewById(R.id.rv_display);
        url = NetworkUtils.buildUrlFromUsername(Config.FOR_USERNAME);
        Log.i("ayusch", "url = " + url);
        new YoutubeQueryTask().execute(url);
        Log.i("ayusch", "After task");

    }

    public void formatJSON(String resultString) {
        new JSONParseTask().execute(resultString);
    }

    public class YoutubeQueryTask extends AsyncTask<URL, Void, String> {


        @Override
        protected String doInBackground(URL... params) {
            URL builtUrl = params[0];
            resultString = "no result";
            try {
                resultString = NetworkUtils.getResponseFromUrl(builtUrl);
            } catch (IOException e) {
                e.printStackTrace();
            }

            return resultString;
        }

        @Override
        protected void onPostExecute(String s) {

            formatJSON(s);

            RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(getApplicationContext());
            rv.setLayoutManager(layoutManager);
            rv.setHasFixedSize(true);
            adapter = new VideoAdapter(titles);
            rv.setAdapter(adapter);
        }
    }


    public class  JSONParseTask extends AsyncTask<String,Void,String>{

        @Override
        protected String doInBackground(String... params) {
            JSONObject itemsObj, thumbnailsObject, defaultObject, obj, snippetObj;
            ArrayList<Video> videoTitles = new ArrayList<>();
            String title, thumbnailUrl, description, videoId;
            try {
                itemsObj = new JSONObject(resultString);
                JSONArray itemsArray = itemsObj.getJSONArray("items");

                for (int i = 0; i < itemsArray.length(); i++) {

                    obj = itemsArray.getJSONObject(i);
                    snippetObj = obj.getJSONObject("snippet");

                    title = snippetObj.getString("title");
                    thumbnailsObject = snippetObj.getJSONObject("thumbnails");
                    defaultObject = thumbnailsObject.getJSONObject("default");
                    thumbnailUrl = defaultObject.getString("url");
                    description = snippetObj.getString("description");
                    videoId = (obj.getJSONObject("id")).getString("videoId");
                    videoTitles.add(new Video(title, thumbnailUrl, description,videoId));
                    Log.i("ayusch", "length of array = " + i);
                }


            } catch (Exception e) {
                e.printStackTrace();
            }

           titles=videoTitles;
            return null;
        }
    }

}

VideoAdapter.java:
public class VideoAdapter extends RecyclerView.Adapter<VideoAdapter.CustomHolder> {

    private int maxNumItems = 25;
    ArrayList<Video> titles;

    public VideoAdapter(ArrayList<Video> titles) {
        this.titles = titles;
    }

    @Override
    public CustomHolder onCreateViewHolder(ViewGroup parent, int viewType) {

        View root = LayoutInflater.from(parent.getContext()).inflate(R.layout.row, parent, false);
        CustomHolder holder = new CustomHolder(root, parent.getContext());
        return holder;
    }

    @Override
    public void onBindViewHolder(CustomHolder holder, int position) {

        holder.tv_title.setText((titles.get(position).title));
        String url = titles.get(position).thumbnailUrl;
        Picasso.with(holder.tv_title.getContext()).load(url).into(holder.iv_thumbnail);
        holder.tv_description.setText((titles.get(position)).description);
    }


    @Override
    public int getItemCount() {
        return titles.size();
    }

    public class CustomHolder extends RecyclerView.ViewHolder {
        TextView tv_title,tv_description;
        ImageView iv_thumbnail;
        Context c;

        public CustomHolder(View itemView, Context context) {
            super(itemView);

            tv_title = (TextView) itemView.findViewById(R.id.tv_video_title);
            iv_thumbnail = (ImageView) itemView.findViewById(R.id.iv_video_thumbnail);
            tv_description = (TextView) itemView.findViewById(R.id.tv_video_description);
            c = context;
        }


    }
}

Video.java:
public class Video {
    String title;
    String thumbnailUrl;
    String description;
    String videoId;

    Video(String vidTitle, String url, String desc, String vidId) {
        title = vidTitle;
        thumbnailUrl = url;
        description = desc;
        videoId = vidId;
    }
}

Error ( just two videos displayed )

Without videoId being passed. It should look like this.

另外,请随时提出任何代码性能方面的改进建议。我仍处于学习阶段,想编写良好的性能代码,并且此应用需要一些时间才能在recyclerview中加载json响应。

最佳答案

1. 执行titles ArrayList initialization并通过adapter方法设置RecyclerView onCreate()

2. 为每个数据提取操作从titles清除JSONParseTask列表。

3. 添加Video对象以列出titles而不是videoTitles

4. 将每个项目添加到adapter.notifyDataSetChanged()列表后,调用RecyclerView以更新titles

如下更新您的MainActivity:

import android.os.AsyncTask;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;

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

import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;


public class MainActivity extends AppCompatActivity {

    URL url = null;
    String resultString = null;
    RecyclerView rv;
    VideoAdapter adapter;
    ArrayList<Video> titles;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        rv = (RecyclerView) findViewById(R.id.rv_display);
        url = NetworkUtils.buildUrlFromUsername(Config.FOR_USERNAME);

        RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(getApplicationContext());
        rv.setLayoutManager(layoutManager);
        rv.setHasFixedSize(true);

        titles = new ArrayList<Video>();
        adapter = new VideoAdapter(titles);
        rv.setAdapter(adapter);

        Log.i("ayusch", "url = " + url);
        new YoutubeQueryTask().execute(url);
        Log.i("ayusch", "After task");
    }

    public void formatJSON(String resultString) {
        new JSONParseTask().execute(resultString);
    }

    public class YoutubeQueryTask extends AsyncTask<URL, Void, String> {

        @Override
        protected String doInBackground(URL... params) {
            URL builtUrl = params[0];
            resultString = "no result";
            try {
                resultString = NetworkUtils.getResponseFromUrl(builtUrl);
            } catch (IOException e) {
                e.printStackTrace();
            }

            return resultString;
        }

        @Override
        protected void onPostExecute(String s) {

            formatJSON(s);
        }
    }

    public class  JSONParseTask extends AsyncTask<String,Void,String>{

        @Override
        protected String doInBackground(String... params) {
            JSONObject itemsObj, thumbnailsObject, defaultObject, obj, snippetObj;

            String title, thumbnailUrl, description, videoId;
            try {
                itemsObj = new JSONObject(resultString);
                JSONArray itemsArray = itemsObj.getJSONArray("items");

                // Required to clear list
                if (itemsArray.length() > 0)
                    titles.clear();

                for (int i = 0; i < itemsArray.length(); i++) {

                    obj = itemsArray.getJSONObject(i);
                    snippetObj = obj.getJSONObject("snippet");

                    title = snippetObj.getString("title");
                    thumbnailsObject = snippetObj.getJSONObject("thumbnails");
                    defaultObject = thumbnailsObject.getJSONObject("default");
                    thumbnailUrl = defaultObject.getString("url");
                    description = snippetObj.getString("description");
                    videoId = (obj.getJSONObject("id")).getString("videoId");

                    // Add to list
                    titles.add(new Video(title, thumbnailUrl, description,videoId));

                    // Update RecyclerView
                    adapter.notifyDataSetChanged();

                    Log.i("ayusch", "length of array = " + i);
                }

            } catch (Exception e) {
                e.printStackTrace();
            }

            return null;
        }
    }

}

希望这会有所帮助〜

关于java - 由于在Android中解析JSON字符串响应而导致的错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43710316/

相关文章:

java - 使用 OAuth2 和 JWT : Encoded password does not look like BCrypt 的 Spring Security

android - 如何在 Cordova for Android 中除周日外的所有日子发送一个通知?

javascript - 根据条件将文本从一个文本框复制到另一个文本框

java - 如何使用 Vavr 正确实现这一点?

java - 如何在 Visual Studio 2017 中使用 Java

Android - 如何从文档中获取选定的文件名

安卓 : Shapefile in Googlemaps

javascript - 在表单提交时格式化 JSON

json - 如何将 json 模式转换为 avro 模式

java - 不知道将该代码放在我的 java 文件中的哪里