【问题标题】:Getting Error On Click When Scrolled To Next Page滚动到下一页时点击错误
【发布时间】:2021-06-27 02:31:38
【问题描述】:

我已经成功获得帖子,在前 10 个帖子中,我也获得了帖子内容,但是当我向下滚动以加载更多帖子时,我也可以看到带有特色图片的帖子,但是当我点击这些帖子时,我得到了这个错误:现在已经超过 2 周了,因为我找到了答案,请帮助

 Caused by: java.lang.IndexOutOfBoundsException: Index: 11, Size: 10
        at java.util.ArrayList.get(ArrayList.java:437)
        at com.punjabidharti.myapplication.PostDetails.onCreate(PostDetails.java:30)

这是我的 PostDetails 活动:

 Intent i = getIntent();
    int position = i.getExtras().getInt("itemPosition");

    Log.e("PostDetails ", "title is " + MainActivity.mListPost.get(position).getTitle().getRendered());

    this.title = (TextView) findViewById(R.id.title);

    title.setText(Html.fromHtml(MainActivity.mListPost.get(position).getTitle().getRendered()));



    String data = String.valueOf((Html.fromHtml(MainActivity.mListPost.get(position).getContent().getRendered())));

    WebView webview = (WebView)this.findViewById(R.id.postwebview);
    webview.getSettings().setJavaScriptEnabled(true);
    webview.loadData(data, "text/html; charset=utf-8", "UTF-8");

这是适配器:

 private ArrayList<Model> dataset;
private Context mContext;
int total_types;





public RecyclerViewAdapter(ArrayList<Model> mlist, Context context) {
    this.dataset = mlist;
    this.mContext = context;
    total_types = dataset.size();
}

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



public static class ImageTypeViewHolder extends RecyclerView.ViewHolder{


    TextView title, subtitle;
    ImageView imageView;


    public ImageTypeViewHolder(View itemView) {
        super(itemView);

        this.title = (TextView)  itemView.findViewById(R.id.title);
        this.subtitle = (TextView) itemView.findViewById(R.id.subtitle);
        //at the moment, it is displaying an icon for all posts
        this.imageView = (ImageView) itemView.findViewById(R.id.Icon);
    }
}

@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    View view = LayoutInflater.from( parent.getContext()).inflate(R.layout.postdetails, parent, false);
    return new ImageTypeViewHolder(view) ;
}



@Override
public int getItemViewType(int position) {

    return position;
}

@Override
public void onBindViewHolder(final RecyclerView.ViewHolder holder, final int position) {
    final Model object = dataset.get(position);

    ( (ImageTypeViewHolder) holder).title.setText( object.title );
    ( (ImageTypeViewHolder) holder).subtitle.setText( object.subtitle );
    Glide.with(mContext)
            .load(object.Image)
            .dontAnimate()
            .placeholder(R.drawable.icon)
            .into(((ImageTypeViewHolder) holder).imageView);
    ( (ImageTypeViewHolder) holder).title.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            Intent intent = new Intent(mContext, PostDetails.class);
            intent.putExtra("itemPosition", position);
            mContext.startActivity(intent);
        }
    });
    ( (ImageTypeViewHolder) holder).subtitle.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            Intent intent = new Intent(mContext, PostDetails.class);
            intent.putExtra("itemPosition", position);
            mContext.startActivity(intent);
        }
    });
    ( (ImageTypeViewHolder) holder).imageView.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            Intent intent = new Intent(mContext, PostDetails.class);
            intent.putExtra("itemPosition", position);
            mContext.startActivity(intent);
        }
    });



    /// dataset.get(position)
}



@Override
public long getItemId(int position) {
    return position;
}

这是我的 MainActivity:

recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
    progressBar = (ProgressBar) findViewById(R.id.progressbar);
    mLayoutManager = new LinearLayoutManager(MainActivity.this, LinearLayoutManager.VERTICAL, false);
    recyclerView.setLayoutManager(mLayoutManager);
    list = new ArrayList<Model>();

    getRetrofit();
    adapter = new RecyclerViewAdapter( list, MainActivity.this);
    recyclerView.setAdapter(adapter);




    recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
        @Override
        public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
            if (dy > 0) { //check for scroll down
                visibleItemCount = mLayoutManager.getChildCount();
                totalItemCount = mLayoutManager.getItemCount();
                pastVisiblesItems = mLayoutManager.findFirstVisibleItemPosition();

                if (loading) {
                    if ((visibleItemCount + pastVisiblesItems) >= totalItemCount) {
                        loading = false;
                        Log.v("...", "Last Item Wow !");
                        // Do pagination.. i.e. fetch new data
                        getRetrofit();
                        adapter = new RecyclerViewAdapter( list, MainActivity.this);
                        recyclerView.setAdapter(adapter);

                    }
                }
            }
        }
    });

这是我在 mainactivity 中的改造:

 public void getRetrofit(){
    Retrofit retrofit = new Retrofit.Builder()
            .baseUrl(baseURL)
            .addConverterFactory(GsonConverterFactory.create())
            .build();
    RetrofitArrayApi service = retrofit.create(RetrofitArrayApi.class);
    String yourURl = yourURL.replace(baseURL,"");
    Call<List<WPPost>>  call = service.getPostInfo( yourURl);
    call.enqueue(new Callback<List<WPPost>>() {
        @Override
        public void onResponse(Call<List<WPPost>> call, Response<List<WPPost>> response) {
            Log.e("mainactivyt", " response "+ response.body());
            mListPost = response.body();
            progressBar.setVisibility(View.GONE);
            if (response.body() != null) {


                for (int i = 0; i < response.body().size(); i++ ) {




                    Log.e("size", list.size() + "");


                    System.out.println("The shortest word i is:" + i );




                    Log.e("main ", " title " + response.body().get(i).getTitle().getRendered() + " " +
                            response.body().get(i).getId());
                    String tempdetails = response.body().get(i).getExcerpt().getRendered().toString();
                    tempdetails = tempdetails.replace("<p>", "");
                    tempdetails = tempdetails.replace("</p>", "");
                    tempdetails = tempdetails.replace("[&hellip;]", "");
                    list.add(new Model(Model.IMAGE_TYPE, response.body().get(i).getTitle().getRendered(),
                            tempdetails,
                            response.body().get(i).getImages().getMedium()));


                    adapter.notifyDataSetChanged();




                }




                progressBar.setVisibility(View.GONE);
            } else {
                progressBar.setVisibility(View.GONE);
            }




        }
        @Override
        public void onFailure(Call<List<WPPost>> call, Throwable t) {
        }
    });
}

最后:

 public static List<WPPost> getList(){
    return  mListPost;
}

请帮忙,距离我找到答案已经超过 2 周了,请

我也试过这个方法:How to handle pagination/load more in Retrofit 2.0?

还有这个What causes a java.lang.ArrayIndexOutOfBoundsException and how do I prevent it?

【问题讨论】:

    标签: android arraylist android-recyclerview retrofit2 onscrolllistener


    【解决方案1】:

    代码告诉你正在将点击项位置传递给下一个活动,并使用上一个活动的这个位置访问模型对象,你为什么不直接使用 bundle.putParcelable() 将对象传递给 Intent 对象?

    为什么要覆盖 getItemViewType(int position),因为您没有在 Adapter 中使用多视图类型?在 getRetrofit() 方法中,您调用了 adapter.notifyDataSetChanged(); 虽然您没有完全替换您的列表,但您只是将新项目添加到 list ,所以这里应该使用 notifyItemRangeInserted() 。我制作了示例项目只是为了解决您的问题。让我们看看:-

        public class RecyclerViewTestActivity extends AppCompatActivity {
    
        private MyAdapter adapter;
        private boolean loading = false;
        int pastVisiblesItems, visibleItemCount, totalItemCount;
        LinearLayoutManager mLayoutManager;
        String baseURL = "https://my.backend.url";
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(baseURL)
                .addConverterFactory(GsonConverterFactory.create())
                .build();
        RetrofitArrayApi service = retrofit.create(RetrofitArrayApi.class);
        String yourURl = yourURL.replace(baseURL,"");
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_recycler_view_test);
    
            RecyclerView recyclerView = findViewById(R.id.recycler_view);
            mLayoutManager = new LinearLayoutManager(this);
            recyclerView.setLayoutManager(mLayoutManager);
            adapter = new MyAdapter(new ArrayList<>());
            recyclerView.setAdapter(adapter);
    
    
            recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
                @Override
                public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                    if (dy > 0) { //check for scroll down
                        visibleItemCount = mLayoutManager.getChildCount();
                        totalItemCount = mLayoutManager.getItemCount();
                        pastVisiblesItems = mLayoutManager.findFirstVisibleItemPosition();
    
                        if ((visibleItemCount + pastVisiblesItems) >= totalItemCount) {
    
                            Log.d("tisha==>>","Is loading = "+loading);
                            // Do pagination.. i.e. fetch new data
    
                            if (!loading){
                                adapter.showHideProgress(true);
                                loading = true;
                                getRetrofit();
                            }
                        }
                    }
                }
            });
            getRetrofit();
        }
              void getRetrofit(){
    
            // fetching data from remote server.....
            try {
                List<Model> list = new ArrayList<>();
                
                Call<List<WPPost>>  call = service.getPostInfo( yourURl);
                call.enqueue(new Callback<List<WPPost>>() {
                    @Override
                    public void onResponse(Call<List<WPPost>> call, Response<List<WPPost>> response) {
                        Log.d("==>>", " response "+ response.body());
                        mListPost = response.body();
                        progressBar.setVisibility(View.GONE);
                        if (response.body() != null) {
    
                            for (int i = 0; i < response.body().size(); i++ ) {
    
                                Log.d("==>>", list.size() + "");
    
                                Log.d("==>>", " title " + response.body().get(i).getTitle().getRendered() + " " +
                                        response.body().get(i).getId());
                                String tempdetails = response.body().get(i).getExcerpt().getRendered().toString();
                                tempdetails = tempdetails.replace("<p>", "");
                                tempdetails = tempdetails.replace("</p>", "");
                                tempdetails = tempdetails.replace("[&hellip;]", "");
                                list.add(new Model(Model.IMAGE_TYPE, response.body().get(i).getTitle().getRendered(),
                                        tempdetails,
                                        response.body().get(i).getImages().getMedium()));
    
                            }
                            if (loading){
                                loading = false;
                                adapter.showHideProgress(false);
                            }
                            adapter.addItemsToList(list);
                            progressBar.setVisibility(View.GONE);
                        } else {
                            progressBar.setVisibility(View.GONE);
                        }
                    }
                    @Override
                    public void onFailure(Call<List<WPPost>> call, Throwable t) {
                    }
                });
    
            }catch (Exception exception){
                Log.d("tisha==>>"," "+exception.getLocalizedMessage());
            }
        }
    
    // Customize Model Class as per your requirement-----------------
    class Model implements Parcelable {
        String title;
        String subTitle;
        String imageUrl;
        Model(String title, String subTitle, String imageUrl){
            this.title = title;
            this.subTitle = subTitle;
            this.imageUrl = imageUrl;
        }
    
        protected Model(Parcel in) {
            title = in.readString();
            subTitle = in.readString();
            imageUrl = in.readString();
        }
    
        public static final Creator<Model> CREATOR = new Creator<Model>() {
            @Override
            public Model createFromParcel(Parcel in) {
                return new Model(in);
            }
    
            @Override
            public Model[] newArray(int size) {
                return new Model[size];
            }
        };
    
        @Override
        public int describeContents() {
            return 0;
        }
    
        @Override
        public void writeToParcel(Parcel dest, int flags) {
            dest.writeString(title);
            dest.writeString(subTitle);
            dest.writeString(imageUrl);
        }
    }
    class MyAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>{
        List<Model> modelList;
        int viewTypeData = 0,viewTypeProgress = 1;
        MyAdapter(List<Model> list){
            modelList = list;
        }
        @NonNull
        @Override
        public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
    mContext = parent.getContext();
            if (viewType == viewTypeData){
                View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.recycler_item_view,parent,false);
                return new MyDataHolder(view);
            }else {
                View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.recycler_item_loading,parent,false);
                return new MyProgressHolder(view);
            }
        }
    
        @Override
        public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
            Model model = modelList.get(position);
            if (holder instanceof MyDataHolder){
                ((MyDataHolder)holder).showModel(model);
            }else
                ((MyProgressHolder)holder).show();
        }
    
        @Override
        public int getItemCount() {
            return modelList.size();
        }
    
        @Override
        public int getItemViewType(int position){
            if (modelList.get(position).title.equals("progress"))
                return viewTypeProgress;
            else
                return viewTypeData;
        }
        void showHideProgress(boolean shouldShowProgress){
            if (shouldShowProgress){
                modelList.add(new Model("progress","",""));
                notifyItemInserted(modelList.size()-1);
            }else {
                Log.d("tisha==>>","Size before removal = "+modelList.size());
                modelList.remove(modelList.size()-1);
                notifyItemRemoved(modelList.size()-1);
                Log.d("tisha==>>","Size after removal = "+modelList.size());
            }
        }
        void addItemsToList(List<Model> newItems){
            if (modelList.isEmpty()){
                modelList.addAll(newItems);
                notifyDataSetChanged();
                Log.d("tisha==>>","First time List size = "+modelList.size());
            }else {
                int lastItemPosition = modelList.size() -1;
                Log.d("tisha==>>","Old list size = "+modelList.size()+ "Last Item position= "+lastItemPosition);
                modelList.addAll(newItems);
                Log.d("tisha==>>","Update List size = "+modelList.size());
                notifyItemRangeInserted(lastItemPosition,newItems.size());
            }
        }
        static class MyDataHolder extends RecyclerView.ViewHolder{
            TextView titleView,subTitleView;
            ImageView imageView;LinearLayout rootView;
            // Use Glide to load image to image view 
            public MyDataHolder(@NonNull View itemView) {
                super(itemView);
                titleView = itemView.findViewById(R.id.recycler_item_title_tv);
                subTitleView = 
    itemView.findViewById(R.id.recycler_item_subtitle_tv);
                imageView = itemView.findViewById(R.id.recycler_img_view);
    rootView = itemView.findViewById(R.id.recycler_item_root_view);
                rootView.setOnClickListener(v -> {
                    Bundle bundle = new Bundle();
                    
    bundle.putParcelable("my_key",modelList.get(getAdapterPosition()));
                    Intent intent = new Intent(mContext, DetialsActivity.class);
                    intent.putExtra("my_bundle",bundle);
                    mContext.startActivity(intent);
                });
            }
            void showModel(Model model){
                titleView.setText(model.title);
                subTitleView.setText(model.subTitle);
            }
        }
        static class MyProgressHolder extends RecyclerView.ViewHolder{
            ProgressBar progressBar;
            public MyProgressHolder(@NonNull View itemView) {
                super(itemView);
                progressBar = itemView.findViewById(R.id.recycler_item_progress);
            }
            void show(){
                progressBar.setVisibility(View.VISIBLE);
            }
        }
    }
    

    recycler_item_view.xml

    <LinearLayout  xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal"
    android:id="@+id/recycler_item_root_view">
    <ImageView
        android:id="@+id/recycler_img_view"
        android:layout_width="50dp"
        android:layout_height="50dp"/>
    <LinearLayout
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:layout_weight="1"
        android:layout_gravity="center_vertical">
        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:id="@+id/recycler_item_title_tv"
            android:gravity="center">
        </TextView>
        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:id="@+id/recycler_item_subtitle_tv"
            android:gravity="start">
        </TextView>
    </LinearLayout>
    

    recycler_item_loading.xml

    <ProgressBar
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="50dp"
    android:id="@+id/recycler_item_progress"
    android:indeterminate="true">
    

    在 NextActivity 中获取 Parcelable 模型类,如下所示。在目标 Activity 的 onCreate() 中放入以下代码:

        Bundle bundle = getIntent().getBundleExtra("my_bundle");
        Model model = bundle.getParcelable("my_key");
        if (model != null){
            Log.d("tisha==>>","Title = "+model.title);
        }
    

    【讨论】:

    • 我没有测试你的改造部分,希望你得到正确的数据并将其正确添加到列表中。请随时询问与此相关的任何问题。快乐编码!!!
    • 我在这里遇到错误 dataset.add(new Model("progress","")); “预期 4 个参数,但发现 2 个”当我删除此代码时,帖子显示在 android studio 运行窗口中,但在设备屏幕上为空白
    • 哦,只需在构造函数中添加另一个空字符串。我将更新我的答案。
    • 答案已更新。请检查一下。如果您将对象直接从一个活动传递到另一个活动,那么它比再次发送位置和搜索列表中的项目要好。而且你永远不会在这个方法中得到 IndexOutOfBoundException。
    • 还是一样,我可以在 Android Studio 的运行窗口中看到帖子列表标题,但是在设备屏幕上是空白的,我看不到任何错误
    【解决方案2】:

    我猜问题出在您的 MainActivity 中,您试图在其中获取列表项

    Log.e("PostDetails ", "title is " + MainActivity.mListPost.get(position).getTitle().getRendered());
    

    在这种情况下,您的 mList 会在您每次进行 Retrofit 调用时刷新,这意味着您的 RecyclerView 列表可能包含超过 10 个元素,但您的列表将始终包含 10 个元素。因此,在您的情况下,当您单击列表的第 12 个(甚至可能是第 11 个)项目时,您会遇到崩溃,这是因为您的列表始终包含最近使用改造获取的 10 个项目。

    为了解决这个问题,您不应该每次都重新分配列表,而应该将新项目添加到列表中,或者您可以在意图中发送完整的对象,而不是仅仅传递项目位置,因为它可能会发生变化.

    【讨论】:

    • 请告诉我该怎么做?
    • 你能详细说明吗?
    【解决方案3】:

    发生这种情况是因为 MainActivity.mListPost 只有最新的响应,在您的情况下通常是 10 个项目,因为您一次调用 10 个项目。 但是,如果您看到传递给适配器的列表随着每次新调用而增加,因为您在列表上使用“添加”。 因此,您的适配器将随着下一页的每个新 API 调用而增长,但您的 MainActivity.mListPost 只会获取最新的 10 个项目。 请确保更新您的 MainActivity.mListPost,就像您正在更新适配器的列表一样。

    【讨论】:

    • 如何更新 MainActivity.mListPost ?请问你能提供代码吗?我是新开发者。
    • 您可以使用 MainActivity.list 而不是使用 MainActivity.mListPost,因为您的列表字段包含您已传递给适配器的最新数据
    • list 在 PostDetails Activity 中不起作用,错误“'list' 在 'com.punjabidharti.myapplication.MainActivity' 中有私有访问权限”
    • 您必须提供与您在 MainActivity 中提供给 mListPost 的列表相同的访问权限。或者您也可以为您的列表创建一个公共 getter,然后使用该 getter 方法代替 MainActivity.mListPost
    • public List list() { //防御性实现 //不要让客户端改变列表的状态 //例如避免通过getStringList().clear( ) 返回新的 ArrayList(list);我已经尝试过这样的事情,但不起作用
    猜你喜欢
    • 1970-01-01
    • 2016-01-29
    • 2014-02-17
    • 1970-01-01
    • 1970-01-01
    • 2022-01-22
    • 2015-09-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多