0

i have successfully get posts and on first 10 posts, i get post content also, but when i scroll down to load more posts, i can see posts with featured image as well, but when i click on those posts i get this error: now its over 2 weeks since i am finding the answer, please help

 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)

this is my PostDetails activity:

 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");

this is Adapter:

 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;
}

and this is my 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);

                    }
                }
            }
        }
    });

and this is my retrofit in 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) {
        }
    });
}

and in end :

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

please help, now its over 2 weeks since i am finding the answer, please

i have tried this method also : How to handle pagination/load more in Retrofit 2.0?

also this one What causes a java.lang.ArrayIndexOutOfBoundsException and how do I prevent it?

a_local_nobody
  • 7,947
  • 5
  • 29
  • 51

3 Answers3

1

Code tells you are passing click item position to next Activity and accessing model object using this position from previous activity, why don't you pass object directly using bundle.putParcelable() to Intent object ?

Why are you overriding getItemViewType(int position) as you are not using multiple view type in Adapter ?. And inside getRetrofit() method you called adapter.notifyDataSetChanged(); though you not completely replacing your list, you just add new items to list , so notifyItemRangeInserted() should be used here. I have made sample project just to address your issue. Let's have a look :-

    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">

Get Parcelable Model Class in NextActivity like below. Inside onCreate() of Target Activity put below code:

    Bundle bundle = getIntent().getBundleExtra("my_bundle");
    Model model = bundle.getParcelable("my_key");
    if (model != null){
        Log.d("tisha==>>","Title = "+model.title);
    }
NRUSINGHA MOHARANA
  • 1,489
  • 8
  • 13
0

I guess the problem lies in your MainActivity where you are trying to get the list item using

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

In this case, your mList is getting refreshed everytime you make a Retrofit call, that means, your RecyclerView list might contain more than 10 elements, but your list would always contain 10 elements. So in your case, you are getting a crash when you click on the 12th (or maybe even 11th) item of the list, this is because your list is always containing 10 items which were fetched using retrofit recently.

To solve this, you should not reassign your list everytime, rather you should be adding the new items to the list, or you can send the complete object in the intent rather than just passing the item position as it is subject to change.

Priyansh Kedia
  • 171
  • 1
  • 6
0

This is happening because MainActivity.mListPost which is only having the latest response which is usually in your case 10 items as you are calling for 10 items at a time. But if you see the list you passing to your adaptor is been increasing with each new call as you are using "add" on the list. hence you adaptor is going to grow with each new API call for the next page, but your MainActivity.mListPost will only have the latest 10 items fetched. Please make sure to update your MainActivity.mListPost similarly you are updating your list for the adapter.

Dinkar Kumar
  • 2,175
  • 2
  • 12
  • 22
  • how can i update MainActivity.mListPost ? please can you provide code ? i am new as developer . – Punjabi Dharti Mar 31 '21 at 07:05
  • rather than using MainActivity.mListPost you can use MainActivity.list because your list field is having up to date data which you have passed to your adapter – Dinkar Kumar Mar 31 '21 at 07:09
  • list is not working in PostDetails Activity, error "'list' has private access in 'com.punjabidharti.myapplication.MainActivity'" – Punjabi Dharti Mar 31 '21 at 07:12
  • you have to provide list same access which you provided to mListPost in your MainActivity. OR you can create a public getter for your list also and then use that getter method in place of MainActivity.mListPost – Dinkar Kumar Mar 31 '21 at 07:15
  • public List list() { //defensive implementation //do not let clients to alter the state of the list //for example, avoiding clear the list through getStringList().clear() return new ArrayList(list); } i have tried something like this, but not works – Punjabi Dharti Mar 31 '21 at 07:29
  • I didn't understand your last comment at all. – Dinkar Kumar Mar 31 '21 at 07:35
  • Can you show me the declaration of mListPost and list in your MainActivity – Dinkar Kumar Mar 31 '21 at 07:37