Related
I am facing issue in highlighting the text as the google reads it. Every device is having its own speed of reading the text due to which highlighting text along with sound cause problem and seems inconsistent in some devices.
I have tried Progressive Textview class to highlight the sentence as google start it reading. In this class, I need to define run task value in floats so as to start the highlighting speed. Bellow is the custom class code:
public class ProgressTextView extends AppCompatTextView {
private SpannableTask spannableTask;
private ProgressListener progressListener;
private boolean changeColor = false;
public ProgressTextView(Context context) {
super(context);
init(null);
}
public ProgressTextView(Context context, #Nullable AttributeSet attrs) {
super(context, attrs);
init(getContext().obtainStyledAttributes(attrs, R.styleable.ProgressTextView));
}
public ProgressTextView(Context context, #Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(getContext().obtainStyledAttributes(attrs, R.styleable.ProgressTextView, defStyleAttr, 0));
}
private void init(#Nullable TypedArray typedArray) {
this.spannableTask = new SpannableTask(this, getText().toString());
this.spannableTask.setDefaultTextColor(this.getTextColors().getDefaultColor());
int textColor = typedArray.getColor(R.styleable.ProgressTextView_highlightTextColor, 0);
if (textColor != 0) {
this.spannableTask.setHighlightTextColor(textColor);
}
}
public void addProgressListener(ProgressListener progressListener) {
this.progressListener = progressListener;
}
public SpannableTask getSpannableTask() {
return this.spannableTask;
}
public SpannableTask getSpannableTask(String text) {
this.spannableTask = new SpannableTask(this, text);
this.spannableTask.setHighlightTextColor(getResources().getColor(R.color.yellow));
this.spannableTask.setHighlightBackgroundTextColor(getResources().getColor(R.color.black));
this.spannableTask.setDefaultTextColor(getResources().getColor(R.color.text_color));
return this.spannableTask;
}
public class SpannableTask implements Runnable {
private Handler handler = new Handler();
private SpannableString spannableString;
private String text;
private ProgressTextView spannableTextView;
private int second;
private int defaultTextColor = R.color.text_color;
private int highlightTextColor = Color.YELLOW;
private int backgroundTextColor = Color.BLACK;
public SpannableTask(ProgressTextView spannableTextView, String text) {
this.text = text;
this.spannableString = new SpannableString(text);
this.spannableTextView = spannableTextView;
initTextView(defaultTextColor,backgroundTextColor, text.length());
}
public void runTask(float second) {
this.second = ((int) (second * 1000) / text.length());
new Thread(this).run();
}
public void runTask(int second) {
this.second = second / text.length();
new Thread(this).run();
}
#Override
public void run() {
for (int i = 0; i <= text.length(); i++) {
final int value = i;
handler.postDelayed(new Runnable() {
#Override
public void run() {
changeColor = true;
initTextView(highlightTextColor,backgroundTextColor, value);
if (value == text.length() && progressListener != null) {
cancel();
progressListener.complete();
}
}
}, second * i);
}
}
private void initTextView(int color,int backgroundcolor, int length) {
if(!changeColor){
this.spannableString.setSpan(new BackgroundColorSpan(Color.WHITE), 0, length, 0);
this.spannableString.setSpan( new ForegroundColorSpan(getResources().getColor(R.color.text_color)), 0,length, 0);
SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder();
spannableStringBuilder.append(spannableString);
this.spannableTextView.setText(spannableString);
}else{
this.spannableString.setSpan(new BackgroundColorSpan(color), 0, length, 0);
this.spannableString.setSpan( new ForegroundColorSpan(backgroundcolor), 0,length, 0);
SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder();
spannableStringBuilder.append(spannableString);
this.spannableTextView.setText(spannableString);
}
}
public void cancel() {
changeColor =false;
initTextView(defaultTextColor,backgroundTextColor, text.length());
handler.removeCallbacksAndMessages(null);
}
public void setDefaultTextColor(int defaultTextColor) {
this.defaultTextColor = defaultTextColor;
initTextView(defaultTextColor,backgroundTextColor, text.length());
}
public void setHighlightTextColor(int highlightTextColor) {
this.highlightTextColor = highlightTextColor;
}
public void setHighlightBackgroundTextColor(int backgroundTextColor) {
this.backgroundTextColor = backgroundTextColor;
}
}
}
And in my main voice Activity, I am using GTS to read the dynamic text
private ProgressTextView.SpannableTask target = null;
private boolean isSpeech=false;
TextToSpeech textToSpeech;
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_voice);
new RetrieveFeedTask().execute("");
}
public static class RetrieveFeedTask extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... params) {
try {
String apiUrl= "https://maps.googleapis.com/maps/api/geocode/json?latlng="+mCurrentLocation.getLatitude()+","+mCurrentLocation.getLongitude()+"&key=YOUR KEY";
URL url = new URL(apiUrl);
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
try {
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(urlConnection.getInputStream()));
StringBuilder stringBuilder = new StringBuilder();
String line;
while ((line = bufferedReader.readLine()) != null) {
stringBuilder.append(line).append("\n");
}
bufferedReader.close();
return stringBuilder.toString();
}
finally{
urlConnection.disconnect();
}
}
catch(Exception e) {
return null;
}
}
protected void onPreExecute() {
}
protected void onPostExecute(String response) {
if(response != null) {
try {
AddressList addressList=new Gson().fromJson(response,AddressList.class);
List<Results> mList= addressList.getResults();
List<AddressComponent> mAddressList= mList.get(0).getAddressComponents();
StringBuilder sb = new StringBuilder();
for (AddressComponent addressComponent:mAddressList) {
if(addressComponent.getTypes().contains("street_number")){
sb.append(addressComponent.getShortName()).append(" ");
}
else if(addressComponent.getTypes().contains("route")){
sb.append(addressComponent.getShortName()).append(", ");
}
else if(addressComponent.getTypes().contains("locality")){
sb.append(addressComponent.getShortName()).append(", ");
}
else if(addressComponent.getTypes().contains("administrative_area_level_1")){
sb.append(addressComponent.getLongName());
}
}
mTxtAddress.setText(sb.toString());
textSpeech();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
private void textSpeech(){
textToSpeech = new TextToSpeech(this, new TextToSpeech.OnInitListener() {
#Override
public void onInit(int status) {
if (status == TextToSpeech.SUCCESS) {
int result = textToSpeech.setLanguage(Locale.ENGLISH);
if (result == TextToSpeech.LANG_MISSING_DATA ||
result == TextToSpeech.LANG_NOT_SUPPORTED) {
Toast.makeText(getApplicationContext(), "This language is not supported!",
Toast.LENGTH_SHORT);
} else {
textToSpeech.setOnUtteranceCompletedListener(VoiceActivity.this);
textToSpeech.setOnUtteranceProgressListener(new UtteranceProgressListener() {
#Override
public void onStart(String s) {
final String keyword = s;
runOnUiThread(new Runnable() {
#Override
public void run() {
if(mTxtAddress.getText().toString().equalsIgnoreCase(keyword)){
target = mTxtAddress.getSpannableTask(mTxtAddress.getText().toString());
target.runTask(3.5f);
}
}
});
}
#Override
public void onDone(final String keyword) {
runOnUiThread(new Runnable() {
#Override
public void run() {
if(mTxtAddress.getText().toString().equalsIgnoreCase(keyword)){
target.cancel();
}
}
});
}
#Override
public void onError(String s) {
runOnUiThread(new Runnable() {
#Override
public void run() {
Toast.makeText(getApplicationContext(), "Error ", Toast.LENGTH_SHORT).show();
}
});
}
});
speak();
}
}
}
});
}
private void speak() {
mPlayer.stop();
isSpeech=true;
String text = mTxtEmer.getText().toString();
HashMap<String, String> params = new HashMap<String, String>();
params.put(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID,text);
textToSpeech.speak(text, TextToSpeech.QUEUE_ADD, params);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
params.put(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID, mTxtAddress.getText().toString());
textToSpeech.speak(mTxtAddress.getText().toString(), TextToSpeech.QUEUE_ADD, params);
} else {
params.put(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID, mTxtAddress.getText().toString());
textToSpeech.speak(mTxtAddress.getText().toString(), TextToSpeech.QUEUE_ADD, params);
}
}
I am developing the chatbot app. I am using the RecycleView to render the chat of user and bot. I have to show the user listview or text response depend upon his query. All is working until my RecyclerView get's scroll. Whenever my RecyclerView gets scroll it changes the item position. I search a lot and applied every solution but not able to solve my issue.
here is my activity.java
public class HomeActivity extends AppCompatActivity implements AIListener,
View.OnClickListener {
private RecyclerView recyclerView;
private ChatAdapter mAdapter;
LinearLayoutManager layoutManager;
private ArrayList<Message> messageArrayList;
private EditText inputMessage;
private RelativeLayout btnSend;
Boolean flagFab = true;
PaytmPGService service = null;
Map<String, String> paytmparam = new HashMap<>();
PrefManager prefManager;
private AIService aiService;
AIDataService aiDataService;
AIRequest aiRequest;
Gson gson;
String food_dish = " ";
double price = 0;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home);
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.RECORD_AUDIO}, 1);
inputMessage = findViewById(R.id.editText_ibm);
btnSend = findViewById(R.id.addBtnibm);
recyclerView = findViewById(R.id.recycler_view_ibm);
messageArrayList = new ArrayList<>();
mAdapter = new ChatAdapter(this,messageArrayList);
prefManager = new PrefManager(this);
GsonBuilder gsonBuilder = new GsonBuilder();
gson = gsonBuilder.create();
layoutManager = new LinearLayoutManager(this);
layoutManager.setStackFromEnd(true);
recyclerView.setLayoutManager(layoutManager);
recyclerView.setHasFixedSize(true);
recyclerView.setItemAnimator(new DefaultItemAnimator());
mAdapter.registerAdapterDataObserver(new RecyclerView.AdapterDataObserver() {
#Override
public void onItemRangeInserted(int positionStart, int itemCount) {
super.onItemRangeInserted(positionStart, itemCount);
int msgCount = mAdapter.getItemCount();
int lastVisiblePosition = layoutManager.findLastCompletelyVisibleItemPosition();
if (lastVisiblePosition == -1 ||
(positionStart >= (msgCount - 1) &&
lastVisiblePosition == (positionStart - 1))) {
recyclerView.scrollToPosition(positionStart);
}
}
});
recyclerView.setAdapter(mAdapter);
this.inputMessage.setText("");
final AIConfiguration configuration = new AIConfiguration("cabc4b7b9c20409aa7ffb1b3d5fe1243",
AIConfiguration.SupportedLanguages.English,
AIConfiguration.RecognitionEngine.System);
aiService = AIService.getService(this, configuration);
aiService.setListener(this);
aiDataService = new AIDataService(configuration);
aiRequest = new AIRequest();
btnSend.setOnClickListener(this);
inputMessage.addTextChangedListener(new TextWatcher() {
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
ImageView fab_img = findViewById(R.id.fab_img_ibm);
Bitmap img = BitmapFactory.decodeResource(getResources(), R.drawable.ic_send_white_24dp);
Bitmap img1 = BitmapFactory.decodeResource(getResources(), R.drawable.ic_mic_white_24dp);
if (s.toString().trim().length() != 0 && flagFab) {
ImageViewAnimatedChange(HomeActivity.this, fab_img, img);
flagFab = false;
} else if (s.toString().trim().length() == 0) {
ImageViewAnimatedChange(HomeActivity.this, fab_img, img1);
flagFab = true;
}
}
#Override
public void afterTextChanged(Editable s) {
}
});
}
public void ImageViewAnimatedChange(Context c, final ImageView v, final Bitmap new_image) {
final Animation anim_out = AnimationUtils.loadAnimation(c, R.anim.zoom_out);
final Animation anim_in = AnimationUtils.loadAnimation(c, R.anim.zoom_in);
anim_out.setAnimationListener(new Animation.AnimationListener()
{
#Override public void onAnimationStart(Animation animation) {}
#Override public void onAnimationRepeat(Animation animation) {}
#Override public void onAnimationEnd(Animation animation)
{
v.setImageBitmap(new_image);
anim_in.setAnimationListener(new Animation.AnimationListener() {
#Override public void onAnimationStart(Animation animation) {}
#Override public void onAnimationRepeat(Animation animation) {}
#Override public void onAnimationEnd(Animation animation) {}
});
v.startAnimation(anim_in);
}
});
v.startAnimation(anim_out);
}
#Override
public void onClick(View v) {
final String inputmessage = this.inputMessage.getText().toString().trim();
if(!inputmessage.equals("")){
new AsyncTask<String, Void, AIResponse>(){
private AIError aiError;
#Override
protected AIResponse doInBackground(final String... params) {
final AIRequest request = new AIRequest();
String query = params[0];
if (!TextUtils.isEmpty(query))
request.setQuery(query);
try {
return aiDataService.request(request);
} catch (final AIServiceException e) {
aiError = new AIError(e);
return null;
}
}
#Override
protected void onPostExecute(final AIResponse response) {
if (response != null) {
onResult(response);
} else {
onError(aiError);
}
}
}.execute(inputmessage);
}else {
aiService.startListening();
}
inputMessage.setText("");
}
#Override
public void onResult(AIResponse response) {
int itemNumber = 0;
Log.d("dialogeflow response",response.toString());
try {
JSONObject AIResponse = new JSONObject(gson.toJson(response));
Log.d("json response",AIResponse.toString());
final JSONObject result = AIResponse.getJSONObject("result");
JSONArray contexts = result.getJSONArray("contexts");
final JSONObject fulfillment = result.getJSONObject("fulfillment");
if(contexts.length()>0) {
for(int i = 0;i<contexts.length();i++) {
JSONObject context_items = contexts.getJSONObject(i);
JSONObject paramters = context_items.getJSONObject("parameters");
if (paramters.has("Cuisine")) {
prefManager.setCuisinetype(paramters.getString("Cuisine"));
} else if (paramters.has("Restaurants_name")) {
prefManager.setRestaurant_name(paramters.getString("Restaurants_name"));
}
if (paramters.has("number") && !paramters.getString("number").equals("") && paramters.has("Food_Dishes") && !paramters.getString("Food_Dishes").equals("")) {
itemNumber = Integer.parseInt(paramters.getString("number"));
if (itemNumber <= 2 && price !=0) {
price = 300 + (int) (Math.random() * ((1400 - 300) + 1));
} else {
price = 600 + (int) (Math.random() * ((2200 - 600) + 1));
}
food_dish = paramters.getString("Food_Dishes");
}
}
}
final double finalPrice = price;
final int finalItemNumber = itemNumber;
if(!result.getString("resolvedQuery").matches("payment is done successfully")) {
Message usermsg = new Message();
usermsg.setMessage(result.getString("resolvedQuery"));
usermsg.setId("1");
messageArrayList.add(usermsg);
mAdapter.notifyDataSetChanged();
if (fulfillment.has("speech")) {
Log.d("response of speech", fulfillment.getString("speech"));
if (!fulfillment.getString("speech").equals("") && fulfillment.getString("speech") != null) {
final String speech = fulfillment.getString("speech");
if (fulfillment.getString("speech").matches("Redirecting you to the Pay-Tm site")) {
new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
#Override
public void run() {
Message outMessage = new Message();
outMessage.setMessage(speech);
outMessage.setId("2");
messageArrayList.add(outMessage);
mAdapter.notifyDataSetChanged();
getpaytm_params((int) price);
}
}, 2000);
} else {
new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
#Override
public void run() {
Message outMessage = new Message();
if (speech.contains("Your total bill is ₹")) {
Log.d("price", String.valueOf(price));
outMessage.setMessage("Please Confirm your order:- \n" +finalItemNumber +" "+food_dish+" from "+prefManager.getRestaurant_name()+" at Flat No: 20,Galaxy Apartment,Airport Authority Colony,Andheri,Mumbai,Maharashtra 400 047 \n Your total bill is ₹"+price+". \n Do you want to pay by Wallet or by PayTm");
}else{
outMessage.setMessage(speech);
}
outMessage.setId("2");
messageArrayList.add(outMessage);
Log.d("messgae",outMessage.getMessage());
mAdapter.notifyDataSetChanged();
}
}, 2000);
}
} else {
final JSONArray msg = fulfillment.getJSONArray("messages");
for (int i = 0; i < msg.length(); i++) {
if (i == 0) {
Message outMessage = new Message();
JSONObject speechobj = msg.getJSONObject(i);
JSONArray speech = speechobj.getJSONArray("speech");
Log.d("response of speech", speech.getString(0));
outMessage.setMessage(speech.getString(0));
outMessage.setId("2");
messageArrayList.add(outMessage);
} else {
final int itemposition = i;
new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
#Override
public void run() {
Message outMessage = new Message();
try {
JSONObject speechobj = msg.getJSONObject(itemposition);
JSONArray speech = speechobj.getJSONArray("speech");
Log.d("response of speech", speech.getString(0));
outMessage.setMessage(speech.getString(0));
outMessage.setId("2");
messageArrayList.add(outMessage);
mAdapter.notifyDataSetChanged();
} catch (JSONException e) {
e.printStackTrace();
}
}
}, 5000);
}
}
}
}
}else{
if (!fulfillment.getString("speech").equals("") && fulfillment.getString("speech") != null) {
final String speech = fulfillment.getString("speech");
new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
#Override
public void run() {
Message outMessage = new Message();
outMessage.setMessage(speech);
outMessage.setId("2");
messageArrayList.add(outMessage);
mAdapter.notifyDataSetChanged();
}
},2000);
}
}
} catch (JSONException e) {
e.printStackTrace();
}
}
#Override
public void onError(AIError error) {
}
#Override
public void onAudioLevel(float level) {
}
#Override
public void onListeningStarted() {
btnSend.setBackground(getDrawable(R.drawable.recording_bg));
}
#Override
public void onListeningCanceled() {
btnSend.setBackground(getDrawable(R.drawable.stedy_recording));
}
#Override
public void onListeningFinished() {
btnSend.setBackground(getDrawable(R.drawable.stedy_recording));
}
}`
my ChatAdapter.java class
public class ChatAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private int BOT = 100;
private int BOT_Restaurant_ListView = 101;
private int USER = 102;
private Activity activity;
private PrefManager prefManager;
private int itemposition = -1;
private int menu_itemposition = -1;
private List<Restaurant_List_Model> restaurant_list;
private ArrayList<Message> messageArrayList;
private RestaurantListViewAdapter restaurantListViewAdapter;
private TextToSpeech tts ;
public ChatAdapter(Activity activity, ArrayList<Message> messageArrayList) {
this.activity = activity;
this.messageArrayList = messageArrayList;
tts = new TextToSpeech(activity, new TextToSpeech.OnInitListener() {
#Override
public void onInit(int status) {
if(status != TextToSpeech.ERROR){
tts.setLanguage(Locale.ENGLISH);
}
}
});
prefManager = new PrefManager(activity.getApplicationContext());
setHasStableIds(true);
}
#NonNull
#Override
public RecyclerView.ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View itemview;
if(viewType == BOT){
itemview = LayoutInflater.from(parent.getContext()).inflate(R.layout.bot_msg_view,parent,false);
}else if(viewType == BOT_Restaurant_ListView){
itemview = LayoutInflater.from(parent.getContext()).inflate(R.layout.bot_msg_restaurant_listview,parent,false);
}else {
itemview = LayoutInflater.from(parent.getContext()).inflate(R.layout.user_msg_view,parent,false);
}
return new ViewHolder(itemview);
}
#Override
public int getItemViewType(int position) {
Message message = messageArrayList.get(position);
if(message.getId()!=null && message.getId().equals("2")){
if(message.getMessage().contains("restaurants") || message.getMessage().contains("restaurant")) {
return BOT_Restaurant_ListView;
}else {
return BOT;
}
}else{
return USER;
}
}
#Override
public void onBindViewHolder(#NonNull final RecyclerView.ViewHolder holder, int position) {
int pic_int = 1;
String filename = null;
final Message message = messageArrayList.get(position);
message.setMessage(message.getMessage());
if (holder.getItemViewType() == BOT_Restaurant_ListView) {
Log.d("inside bot listview msg", String.valueOf(BOT_Restaurant_ListView ));
Log.d("adapter position", String.valueOf(holder.getAdapterPosition()));
if(itemposition<holder.getAdapterPosition()){
itemposition = holder.getAdapterPosition();
Log.d("itemposition",String.valueOf(itemposition));
String jsonFileContent;
Log.d("cuisine value", prefManager.getCuisinetype());
if (message.getMessage().contains("restaurants")) {
if(!prefManager.getCuisinetype().equals("") && prefManager.getCuisinetype() != null){
Log.d("restauratn has drawn", "greate");
try {
restaurant_list = new ArrayList<>();
restaurantListViewAdapter = new RestaurantListViewAdapter(activity, restaurant_list);
((ViewHolder) holder).retaurant_listView.setVisibility(View.VISIBLE);
((ViewHolder) holder).retaurant_listView.setAdapter(restaurantListViewAdapter);
Log.d("cuisine value", prefManager.getCuisinetype());
if(message.getMessage().contains("Here are restaurants near you")){
String [] restaurant_Array ={
"indian","french","mexican","italian"
};
int randomNumber = (int) Math.floor(Math.random()*restaurant_Array.length);
filename = restaurant_Array[randomNumber];
Log.d("filename",filename);
jsonFileContent = readFile(activity.getResources().getIdentifier(filename, "raw", activity.getPackageName()));
}else {
filename = prefManager.getCuisinetype().toLowerCase() + "_restaurants";
Log.d("filename", filename);
jsonFileContent = readFile(activity.getResources().getIdentifier(filename, "raw", activity.getPackageName()));
}
JSONObject restaurantfile = new JSONObject(jsonFileContent);
JSONArray jsonArray = restaurantfile.getJSONArray("restaurants");
for (int i = 0; i < jsonArray.length(); i++) {
ImageRoundCorner imageRoundCorner = new ImageRoundCorner();
JSONObject restaurantList = jsonArray.getJSONObject(i);
Restaurant_List_Model restaurant_list_obj = new Restaurant_List_Model();
restaurant_list_obj.setName(restaurantList.getString("name"));
restaurant_list_obj.setLocation(restaurantList.getString("location"));
restaurant_list_obj.setImage_of_item(imageRoundCorner.getRoundedCornerBitmap(BitmapFactory.decodeResource(activity.getResources(), activity.getResources().getIdentifier("restaurant_" + pic_int, "drawable", activity.getPackageName()))));
pic_int++;
restaurant_list_obj.setRating(restaurantList.getLong("rating"));
restaurant_list.add(restaurant_list_obj);
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
tts.speak(message.getMessage(), TextToSpeech.QUEUE_FLUSH, null, null);
} else {
tts.speak(message.getMessage(), TextToSpeech.QUEUE_FLUSH, null);
}
prefManager.setCuisinetype("");
pic_int = 1;
} catch (IOException e) {
e.printStackTrace();
} catch (JSONException e) {
e.printStackTrace();
}
restaurantListViewAdapter.notifyDataSetChanged();
}
}else if(message.getMessage().contains("Here are some famous food items from "+prefManager.getRestaurant_name()+" restaurant")){
try {
Log.d("menu has draw","greate");
restaurant_list = new ArrayList<>();
restaurantListViewAdapter = new RestaurantListViewAdapter(activity, restaurant_list);
((ViewHolder) holder).retaurant_listView.setAdapter(restaurantListViewAdapter);
((ViewHolder) holder).retaurant_listView.setVisibility(View.VISIBLE);
Log.d("restaurant name value", prefManager.getRestaurant_name());
jsonFileContent = readFile(R.raw.restaurant_menu);
JSONObject menu_cuisine = new JSONObject(jsonFileContent);
ImageRoundCorner imageRoundCorner = new ImageRoundCorner();
if (menu_cuisine.has(prefManager.getRestaurant_name())) {
JSONObject restaurant_menu = menu_cuisine.getJSONObject("Dominos");
Log.d("Chili's American menu", restaurant_menu.toString());
JSONArray menu = restaurant_menu.getJSONArray("menu");
for (int j = 0; j < menu.length(); j++) {
JSONObject menu_obj = menu.getJSONObject(j);
Restaurant_List_Model restaurant_list_obj = new Restaurant_List_Model();
restaurant_list_obj.setName(menu_obj.getString("name"));
restaurant_list_obj.setLocation(menu_obj.getString("cuisine_type"));
restaurant_list_obj.setImage_of_item(imageRoundCorner.getRoundedCornerBitmap(BitmapFactory.decodeResource(activity.getResources(), activity.getResources().getIdentifier("menu_" + pic_int, "drawable", activity.getPackageName()))));
//restaurant_list_obj.setImage_of_item(imageRoundCorner.getRoundedCornerBitmap(BitmapFactory.decodeResource(activity.getResources(), activity.getResources().getIdentifier("menu_" + pic_int, "drawable", activity.getPackageName()))));
pic_int++;
restaurant_list_obj.setRating(menu_obj.getLong("rating"));
restaurant_list.add(restaurant_list_obj);
}
restaurantListViewAdapter.notifyDataSetChanged();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
tts.speak(message.getMessage(), TextToSpeech.QUEUE_FLUSH, null, null);
} else {
tts.speak(message.getMessage(), TextToSpeech.QUEUE_FLUSH, null);
}
pic_int = 1;
prefManager.setRestaurant_name("");
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
Log.d("user_message",message.getMessage());
tts.speak(message.getMessage(), TextToSpeech.QUEUE_FLUSH, null, null);
}else {
tts.speak(message.getMessage(), TextToSpeech.QUEUE_FLUSH, null);
}
pic_int = 1;
} catch (JSONException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
((ViewHolder) holder).retaurant_listView.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
int action = event.getAction();
switch (action) {
case MotionEvent.ACTION_DOWN:
v.getParent().requestDisallowInterceptTouchEvent(true);
break;
case MotionEvent.ACTION_UP:
v.getParent().requestDisallowInterceptTouchEvent(false);
break;
}
v.onTouchEvent(event);
return true;
}
});
}
} if(holder.getItemViewType()==BOT) {
Log.d("adapter position", String.valueOf(holder.getAdapterPosition()));
Log.d("inside bot msg", String.valueOf(BOT));
((ViewHolder) holder).bot_msg.setText(message.getMessage());
if(itemposition<holder.getAdapterPosition()) {
itemposition = holder.getAdapterPosition();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
tts.speak(message.getMessage(), TextToSpeech.QUEUE_FLUSH, null, null);
} else {
tts.speak(message.getMessage(), TextToSpeech.QUEUE_FLUSH, null);
}
}
}if(holder.getItemViewType() == USER) {
((ViewHolder) holder).user_message.setText(message.getMessage());
}
}
#Override
public void onViewRecycled(#NonNull RecyclerView.ViewHolder holder) {
super.onViewRecycled(holder);
if(holder.isRecyclable()){
Log.d("inside onViewRecycled","great");
// itemposition = holder.getAdapterPosition();
}
}
#Override
public long getItemId(int position) {
return super.getItemId(position);
}
#Override
public int getItemCount() {
return messageArrayList.size();
}
private String readFile(int id) throws IOException
{
BufferedReader reader = null;
reader = new BufferedReader(new InputStreamReader(activity.getResources().openRawResource(id)));
String content = "";
String line;
while ((line = reader.readLine()) != null)
{
content = content + line;
}
return content;
}
public class ViewHolder extends RecyclerView.ViewHolder{
private TextView user_message,bot_msg;
private ListView retaurant_listView;
ViewHolder(View itemView) {
super(itemView);
bot_msg = itemView.findViewById(R.id.bot_message);
user_message = itemView.findViewById(R.id.message);
retaurant_listView = itemView.findViewById(R.id.restaurant_items_list_ibm);
}
}
}
Please help me out with this issue.
In gif, you can see the lower list is swap with the upper list and then return back
In my app right now I am working with two lists. One is a List of an Object and the other the a List of Lists of the same object. I have a method in my Activity that transforms a list of Object into a List of Lists of object. And to my adapter I am passing the list of lists through this call:
mAdapter.swap(transformList(pipe.mList));
The method swap is responsible for passing the transformed list to my Adapter:
public void swap(List<List<Feed>> feedList) {
if (finallist == null) {
finallist = new ArrayList<>();
}
finallist.clear();
finallist.addAll(feedList);
}
The transformation checks if there are images in a row and puts all of them inside a single list (I am trying to implement something similar to WhatsApp image grouping). So I have a bunch of messages, they can be text messages, files, images, etc. In case of the last one, I group them in a single list.
Let me give a scenario as an example:
I have four images and 1 text message in my original array. The transformation puts all the four images into a single List of objects and de text message in another list of objects (both of them are inserted in my list of lists).
I thought about two ways to handle this transformation: 1 - do it inside the Adapter and 2 - do it in my Activity and pass the modified list to the Adapter. Each one of this solutions generated a different problem.
By following the steps in 1, I was able to display all of the content almost in the way I wanted. The grouping was working just fine! The problem is that if the original array had a length equals to 30, and the transformed array's length was decreased to 12. The RecyclerView would show all of the remaining 18 items as empty states (so after the transformation it wasn't handling the removing items properly).
By following the steps in 2, I was not able to display all of the content. Just the first element of my array. And I would get a IndexOutOfBoundsException in RecyclerView happens java.lang.IndexOutOfBoundsException: Inconsistency detected. Invalid view holder adapter positionViewHolder error message. But I was not able to identify the problem. I checked many questions here and none of them helped me.
This is my Adapter class:
public class FeedAdapter extends BaseSkeletonAdapter<Feed> implements FeedHolder.FeedHolderListener{
private static final int HOLDER_COMMENT = 1;
private static final int HOLDER_IMAGE = 2;
private static final int HOLDER_FILE = 3;
private static final int HOLDER_AUDIO = 4;
private static final int HOLDER_MARKER = 5;
private static final int HOLDER_EMPTY = 6;
private static final int HOLDER_GROUP = 7;
private final FeedItemListener mListener;
private final int mAvatarSize;
private final String mUserId;
private final int mPictureSize;
private final int mSkeletonColor;
public static List<List<Feed>> finallist;
public FeedAdapter(FeedItemListener listener, String userId, int avatarSize, int pictureSize, int skeletonColor) {
super(2);
mListener = listener;
mUserId = userId;
mAvatarSize = avatarSize;
mPictureSize = pictureSize;
mSkeletonColor = skeletonColor;
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
switch (viewType){
case HOLDER_COMMENT:
case HOLDER_IMAGE:
case HOLDER_FILE:
case HOLDER_MARKER:
case HOLDER_AUDIO:
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.adapter_feed, parent, false);
return new FeedHolder(view, this, mPictureSize);
case HOLDER_GROUP:
System.out.println("É um grupo!!!");
View viewGroup = LayoutInflater.from(parent.getContext()).inflate(R.layout.adapter_feed_group,parent,false);
return new FeedHolder(viewGroup, this, mPictureSize);
case HOLDER_EMPTY:
default:
View empty = LayoutInflater.from(parent.getContext()).inflate(R.layout.adapter_empty, parent, false);
return new EmptyPlaceholderViewHolder(empty, R.string.placeholder_feed_empty_title, R.string.placeholder_feed_empty_description, R.drawable.ic_feed_placeholder);
}
}
#Override
protected void onBind(RecyclerView.ViewHolder holder, int position) {
if(!(holder instanceof EmptyPlaceholderViewHolder)){
//Feed feed = finallist.get(position).get(0);
if (holder instanceof FeedHolder) {
if (position < finallist.size()) {
if (mUserId.equals(finallist.get(position).get(0).getCreatedById())) {
((FeedHolder) holder).onBind(finallist.get(position), mUserId, mAvatarSize);
} else {
((FeedHolder) holder).onBind(finallist.get(position), mUserId, mAvatarSize);
}
}
}
}
}
#Override
protected void onBind(RecyclerView.ViewHolder holder, int position, List<Object> payloads) {
if (payloads.isEmpty()) {
onBindViewHolder(holder, position);
}else {
if (holder instanceof FeedHolder) {
((FeedHolder) holder).onBind(finallist.get(position), payloads, mUserId, mAvatarSize);
}
}
}
#Override
protected void setHolderSkeleton(RecyclerView.ViewHolder holder) {
if (holder instanceof FeedHolder) {
((FeedHolder) holder).setHolderSkeleton(R.drawable.rounded_skeleton, mSkeletonColor);
}
}
#Override
protected void clearHolderSkeleton(RecyclerView.ViewHolder holder) {
if (holder instanceof FeedHolder) {
((FeedHolder) holder).clearHolderSkeleton();
}
}
#Override
public int getItemViewType(int position) {
if(mSkeletonMode){
return HOLDER_COMMENT;
} if (finallist != null && finallist.size() > 0 && position >= 0 && position < finallist.size()) {
System.out.println("Tamanho total: " + finallist.size());
if (finallist.get(position).size() > 1) {
System.out.println("Tamanho do grupo: " + finallist.get(position).size());
return HOLDER_GROUP;
} else {
Feed feed = finallist.get(position).get(0);
if (feed != null) {
String type = feed.getFeedType();
if (type != null) {
switch (type) {
case FEED_IMAGE:
return HOLDER_IMAGE;
case FEED_AUDIO:
return HOLDER_AUDIO;
case FEED_FILE:
return HOLDER_FILE;
case FEED_MARKER:
return HOLDER_MARKER;
case FEED_COMMENT:
default:
return HOLDER_COMMENT;
}
}
}
}
return HOLDER_COMMENT;
}else {
System.out.println("Tá vazia!");
return HOLDER_EMPTY;
}
}
public List<Feed> getItems() {
return returnList(finallist);
}
public List<List<Feed>> getListItems() {
return finallist;
}
public void swap(List<List<Feed>> feedList) {
if (finallist == null) {
finallist = new ArrayList<>();
}
finallist.clear();
finallist.addAll(feedList);
}
#Override
public void toggleLike(final int pos){
if(mListener != null && pos >= 0 && pos < finallist.size()){
mListener.toggleLike(finallist.get(pos).get(0));
}
}
#Override
public void onLongClick(final int pos, final View v) {
if (mListener != null && pos >= 0 && pos < finallist.size()) {
mListener.onLongClick(finallist.get(pos).get(0), v);
}
}
#Override
public int onAudioActionClicked(final int pos, final int progress) {
if (mListener != null) {
return mListener.onAudioActionClicked(pos, finallist.get(pos).get(0), progress);
}else {
return 0;
}
}
#Override
public void onClick(int pos) {
if (finallist!=null && pos >= 0 && pos<finallist.size()) {
Feed feed = finallist.get(pos).get(0);
if (feed != null && mListener != null) {
mListener.onClick(feed);
}
}
}
public interface FeedItemListener {
void toggleLike(#NonNull Feed feed);
void onLongClick(#NonNull Feed feed, #NonNull View v);
void onClick(#NonNull Feed feed);
int onAudioActionClicked(int pos, #NonNull Feed feed, final int progress);
}
private void transformList(List<Feed> mItems) {
finallist = new ArrayList<>();
for (int i = 0; i< mItems.size();i++) {
List<Feed> feed = new ArrayList<>();
feed.add(mItems.get(i));
finallist.add(feed);
}
int j = 0;
List<String> list = new ArrayList<>();
List<Integer> indexList = new ArrayList<>();
//System.out.println("Tamanho: " + mItems.size());
for (int i = 0; i < mItems.size(); i++) {
if (!mItems.get(i).getFeedType().equals("filePicture")) {
if (j >= 4) {
String temp = "";
for (int k = 0; k < j; k++) {
temp = temp + "->" + Integer.toString(i - (k+1));
if (k != 0) {
finallist.get(i - 1).add(finallist.get(i - (k + 1)).get(0));
indexList.add(i - (k+1));
}
}
list.add(temp);
}
j = 0;
} else {
j = j + 1;
}
if (i == mItems.size()-1) {
//System.out.println("Imagem por ultimo!");
if (j >= 4) {
//System.out.println("Grupo vem por ultimo!");
String temp = "";
for (int k = 0; k < j; k++) {
temp = temp + "->" + Integer.toString(i - (k));
if (k != 0) {
finallist.get(i).add(finallist.get(i - (k)).get(0));
indexList.add(i - (k));
}
}
list.add(temp);
}
}
}
Collections.sort(indexList);
int aux = 0;
for (int i = 0; i < indexList.size();i++) {
//System.out.println("Valor da posição: " + indexList.get(i)+ "\nTipo: "+ finallist.get((indexList.get(i).intValue())+aux).get(0).getFeedType()
// +"\nValor da posição + i: " + (indexList.get(i)+aux) + "\nAux: " + aux);
finallist.remove((indexList.get(i).intValue())+aux);
//notifyItemRangeRemoved(0, finallist.size());
//notifyDataSetChanged();
aux = aux - 1;
}
/*for (int i = 0; i< finallist.size(); i++){
if (finallist.get(i).size() > 1) {
System.out.println("groupImage: " + finallist.get(i).size());
} else {
System.out.println(finallist.get(i).get(0).getFeedType());
}
}*/
//returnList(finallist);
notifyItemRangeRemoved(0, returnList(finallist).size() - finallist.size() - 1);
//notifyItemRangeInserted(0, finallist.size());
}
public List<Feed> returnList(List<List<Feed>> lists) {
List<Feed> list = new ArrayList<>();
if (lists != null) {
for (int i = 0; i < lists.size(); i++) {
if (lists.get(i).size() > 1) {
for (int j = 0; j < lists.get(i).size(); j++) {
list.add(lists.get(i).get(j));
}
} else {
list.add(lists.get(i).get(0));
}
}
System.out.println("Tamanho de list: " + list.size());
}
return list;
}
}
And this is my Activity:
public abstract class FeedActivity extends UltraBaseActivity implements FeedAdapter.FeedItemListener, AudioManager.OnAudioFocusChangeListener, MediaPlayer.OnErrorListener, MediaPlayer.OnCompletionListener {
private static final String EXTRA_PROJECT_ID = "extra_project_id";
private static final String EXTRA_PROJECT_NAME = "extra_project_name";
private static final String EXTRA_RESOURCE_ID = "extra_resource_id";
private static final String EXTRA_RESOURCE_NAME = "extra_resource_name";
private static final String EXTRA_RESOURCE_KIND = "extra_resource_kind";
#BindView(R.id.swipeLayout) SwipeRefreshLayout mRefreshLayout;
#BindView(R.id.recyclerView) RecyclerView mRecyclerView;
#BindView(R.id.feedCreateFragment) View mFeedCreateLayout;
#BindView(R.id.mic) ImageView mMicView;
private WeakReference<FeedCreateFragment> mFeedCreateFragment;
protected FeedViewModel mViewModel;
protected FeedAdapter mAdapter;
private Feed mLongClick;
private Toolbar mToolbar;
protected int mScrollTo = -1;
protected WrapContentLinearLayoutManager mLayoutManager;
private String mPlayingFeedId;
private int mPlayingPos;
private int mActionResourcePause = R.drawable.ic_pause_black_24dp;
private int mActionResourcePlay = R.drawable.ic_play_black_24dp;
private MediaPlayer mPlayer;
private AudioManager mAudioManager;
protected Handler mAudioHandler;
protected Runnable mUpdateAudioHolderRunnable = new Runnable() {
#Override
public void run() {
try {
if (mPlayer != null && mPlayer.isPlaying()) {
notifyAdapterAudioUpdate(mPlayer.getCurrentPosition(), mActionResourcePause);
mAudioHandler.postDelayed(this, 100);
} else {
mAudioHandler.removeCallbacks(mUpdateAudioHolderRunnable);
}
} catch (IllegalStateException e){
MyLog.e(TAG, "Error while updating seed bar", e);
mAudioHandler.removeCallbacks(mUpdateAudioHolderRunnable);
}
}
};
public static void start(#NonNull Context context, #NonNull String projectId, #NonNull String projectName, #NonNull String resourceId, #NonNull String resourceName, #NonNull String resourceKind){
Intent intent = setIntent(context, projectId, projectName, resourceId, resourceName, resourceKind);
if (intent == null) return;
context.startActivity(intent);
}
public static void startForResult(#NonNull Fragment fragment, #NonNull String projectId, #NonNull String projectName, #NonNull String resourceId, #NonNull String resourceName, #NonNull String resourceKind){
Intent intent = setIntent(fragment.getContext(), projectId, projectName, resourceId, resourceName, resourceKind);
if (intent == null) return;
fragment.startActivityForResult(intent, Constants.Intents.INTENT_REQUEST_VIEW_FEED);
}
#Nullable
protected static Intent setIntent(#NonNull Context context, #NonNull String projectId, #NonNull String projectName, #NonNull String resourceId, #NonNull String resourceName, #NonNull String resourceKind) {
Intent intent;
if (resourceKind.equals(Task.ROUTE)) {
intent = new Intent(context, FeedTaskActivity.class);
}else if(resourceKind.equals(Chat.ROUTE)){
intent = new Intent(context, FeedChatActivity.class);
} else {
MyLog.e(TAG, "Error invalid resource Kind - " + resourceKind);
return null;
}
intent.putExtra(EXTRA_PROJECT_ID, projectId);
intent.putExtra(EXTRA_PROJECT_NAME, projectName);
intent.putExtra(EXTRA_RESOURCE_ID, resourceId);
intent.putExtra(EXTRA_RESOURCE_NAME, resourceName);
intent.putExtra(EXTRA_RESOURCE_KIND, resourceKind);
return intent;
}
public FeedActivity() {
super(R.layout.activity_feed);
}
#Override
protected void onCreate(Bundle savedInstanceState) {
isLogged();
init(getIntent(), savedInstanceState);
super.onCreate(savedInstanceState);
initAdapter();
mAudioManager = (AudioManager) getSystemService(AUDIO_SERVICE);
mAudioHandler = new Handler();
mViewModel.subscribe()
.compose(this.<Resource<List<Feed>>>bindUntilEvent(ActivityEvent.DESTROY))
.flatMap(flatMapDiffUtils())
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(onNext(), onError(), onCompleted());
}
#NonNull
private Func1<Resource<List<Feed>>, Observable<FeedViewModel.Pipe>> flatMapDiffUtils() {
return new Func1<Resource<List<Feed>>, Observable<FeedViewModel.Pipe>>() {
#Override
public Observable<FeedViewModel.Pipe> call(Resource<List<Feed>> r) {
if (mViewModel.hasResource()) {
List<Feed> old = mAdapter.getItems();
MyLog.i(TAG, "New length: " + (r.data != null ? r.data.size() : 0) + " - Old: " + old.size());
final FeedDiffCallback cb = new FeedDiffCallback(old, r.data, mUser.getId());
final DiffUtil.DiffResult result = DiffUtil.calculateDiff(cb);
return Observable.just(new FeedViewModel.Pipe(r.data, result, r.status == Status.LOADING && (r.data ==null || r.data.size() == 0)));
} else {
MyLog.i(TAG, "Loading resource from server");
return Observable.empty();
}
}
};
}
private Action1<? super FeedViewModel.Pipe> onNext() {
return new Action1<FeedViewModel.Pipe>() {
#Override
public void call(FeedViewModel.Pipe pipe) {
if (pipe != null) {
initFeedFragment();
mRefreshLayout.setRefreshing(false);
pipe.mDiffResult.dispatchUpdatesTo(mAdapter);
mAdapter.setSkeletonMode(pipe.mSkeletonMode);
//List<List<Feed>> list = new ArrayList<>();
//list = tranformList(pipe.mList);
mAdapter.swap(transformList(pipe.mList));
System.out.println("Tamanho desse troço: " + transformList(pipe.mList).size());
//mAdapter.notifyDataSetChanged();
//mAdapter.notifyItemRangeRemoved(0, pipe.mList.size());
if (mScrollTo == -1) {
mRecyclerView.scrollToPosition(mAdapter.getItemCount()-1);
}else {
mRecyclerView.scrollToPosition(mScrollTo);
}
updateMenuOptions();
showLoading(false);
}
}
};
}
protected Action0 onCompleted() {
return new Action0() {
#Override
public void call() {
MyLog.i(TAG, "Finishing feed activity");
finish();
}
};
}
protected Action1<Throwable> onError() {
return new Action1<Throwable>() {
#Override
public void call(Throwable throwable) {
MyLog.e(TAG, "Error", throwable);
}
};
}
#Override
protected void initToolbar() {
mToolbar = (Toolbar) findViewById(R.id.toolbar);
if(mToolbar !=null) {
if (mViewModel != null) {
mToolbar.setTitle(mViewModel.getProjectName());
mToolbar.setSubtitle(mViewModel.getResourceName());
}
mToolbar.setSubtitleTextColor(ContextCompat.getColor(this, R.color.palette_black));
mToolbar.setNavigationIcon(R.drawable.ic_action_back_black);
}
setSupportActionBar(mToolbar);
if (mToolbar != null) {
mToolbar.setNavigationOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
onBackPressed();
}
});
}
}
protected void updateTitle(){
if(mToolbar !=null && mViewModel != null) {
mToolbar.setTitle(mViewModel.getProjectName());
mToolbar.setSubtitle(mViewModel.getResourceName());
}
}
#Override
protected void userUpdated(User user) { }
private void init(Intent i, Bundle b){
if (i != null) {
initViewModel(
i.getStringExtra(EXTRA_PROJECT_ID),
i.getStringExtra(EXTRA_PROJECT_NAME),
i.getStringExtra(EXTRA_RESOURCE_ID),
i.getStringExtra(EXTRA_RESOURCE_NAME),
i.getStringExtra(EXTRA_RESOURCE_KIND));
}else if(b != null){
initViewModel(
b.getString(EXTRA_PROJECT_ID),
b.getString(EXTRA_PROJECT_NAME),
b.getString(EXTRA_RESOURCE_ID),
b.getString(EXTRA_RESOURCE_NAME),
b.getString(EXTRA_RESOURCE_KIND));
}else {
MyLog.i(TAG, "Error while initializing view model");
finish();
}
}
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putString(EXTRA_PROJECT_ID, mViewModel.getProjectId());
outState.putString(EXTRA_PROJECT_NAME, mViewModel.getProjectName());
outState.putString(EXTRA_RESOURCE_ID, mViewModel.getResourceId());
outState.putString(EXTRA_RESOURCE_NAME, mViewModel.getResourceName());
outState.putString(EXTRA_RESOURCE_KIND, mViewModel.getResourceKind());
}
private void initAdapter(){
mAdapter = new FeedAdapter(
this,
mUser.getId(),
getResources().getDimensionPixelSize(R.dimen.task_avatar_size),
(int) (AndroidUtils.getScreenWidth(this) * 0.6),
ContextCompat.getColor(this, R.color.bg_skeleton)
);
mRefreshLayout.setColorSchemeResources(R.color.yellow, android.R.color.darker_gray, R.color.yellow_edit_note, android.R.color.background_dark);
mRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
#Override
public void onRefresh() {
mScrollTo = -1;
mViewModel.reload();
}
});
mLayoutManager = new WrapContentLinearLayoutManager(this);
mRecyclerView.setLayoutManager(mLayoutManager);
mRecyclerView.setAdapter(mAdapter);
}
private void initFeedFragment(){
if(!(mFeedCreateFragment != null && mFeedCreateFragment.get() != null && getSupportFragmentManager().findFragmentById(R.id.feedCreateFragment) instanceof FeedCreateFragment)){
mFeedCreateFragment = new WeakReference<>(FeedCreateFragment.newInstance(mViewModel.getProjectId(), mViewModel.getResourceId(), mViewModel.getResourceKind(), mViewModel.getResourceUsers()));
getSupportFragmentManager()
.beginTransaction()
.add(R.id.feedCreateFragment, mFeedCreateFragment.get())
.commitAllowingStateLoss();
if (mViewModel.canCreateFeed()) {
mFeedCreateLayout.setVisibility(View.VISIBLE);
}else {
mFeedCreateLayout.setVisibility(View.GONE);
}
}
}
protected abstract void initViewModel(String projectId, String projectName, String resourceId, String resourceName, String resourceKind);
protected abstract void updateMenuOptions();
}
This is part of the Error (the text reached the maximum size):
10-18 17:29:14.702 23722-23722/com.construct.test E/WrapContentLinearLayoutManager: IndexOutOfBoundsException in RecyclerView happens
java.lang.IndexOutOfBoundsException: Inconsistency detected. Invalid view holder adapter positionViewHolder{615b449 position=3 id=-1, oldPos=0, pLpos:0 scrap [attachedScrap] tmpDetached no parent}
at android.support.v7.widget.RecyclerView$Recycler.validateViewHolderForOffsetPosition(RecyclerView.java:5297)
at android.support.v7.widget.RecyclerView$Recycler.tryGetViewHolderForPositionByDeadline(RecyclerView.java:5479)
at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:5440)
at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:5436)
at android.support.v7.widget.LinearLayoutManager$LayoutState.next(LinearLayoutManager.java:2224)
at android.support.v7.widget.LinearLayoutManager.layoutChunk(LinearLayoutManager.java:1551)
at android.support.v7.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1511)
at android.support.v7.widget.LinearLayoutManager.onLayoutChildren(LinearLayoutManager.java:595)
at com.construct.v2.adapters.WrapContentLinearLayoutManager.onLayoutChildren(WrapContentLinearLayoutManager.java:20)
My problem was caused by the BaseSkeletonAdapter<Feed> that my FeedAdapter was extending. BaseSkeletonAdapter was using the original list and not the List of Lists I had to use. So I created a new class SkeletonAdapterFeed that is basically equal to the previous one, but the new one is receiving a List of Lists instead of just the List.
I know that it sounds a little confusing. I don't have full understanding of the project I am working right now so that's why I don't know everything about the classes, etc.
I have a recycler view in which I load some data from the server when user scroll to bottom I want to show a progress bar and send another request to the server for more data. I have tried below code but it not able to load more data from the server. please help
private RecyclerView mRecyclerView;
private List<User> mUsers = new ArrayList<>();
private UserAdapter mUserAdapter;
private static String sz_RecordCount;
private static String sz_LastCount;
private final int m_n_DefaultRecordCount = m_kDEFAULT_RECORD_COUNT;
private static final int m_kDEFAULT_RECORD_COUNT = 5;
private ArrayList<CDealAppDatastorage> s_oDataset;
private String TAG = MainActivity.class.getSimpleName();
private CDealAppDatastorage item;
private static int arrayCount;
private Context context;
private PreferenceHelper m_oPreferenceHelper;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
context = MainActivity.this;
m_oPreferenceHelper = new PreferenceHelper(context);
sz_RecordCount = String.valueOf(m_n_DefaultRecordCount);// increment of record count
int intialLastCount = 0;
sz_LastCount = String.valueOf(intialLastCount);// increment of last count...
s_oDataset = new ArrayList<>();// making object of Arraylist
//initial request for data
initalDealListing();
mRecyclerView = (RecyclerView) findViewById(R.id.recycleView);
mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
mUserAdapter = new UserAdapter();
mUserAdapter.setOnLoadMoreListener(new OnLoadMoreListener() {
#Override
public void onLoadMore() {
Log.e("haint", "Load More");
mUsers.add(null);
mUserAdapter.notifyItemInserted(mUsers.size() - 1);
//Load more data for reyclerview
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
Log.e("haint", "Load More 2");
//Remove loading item
mUsers.remove(mUsers.size() - 1);
mUserAdapter.notifyItemRemoved(mUsers.size());
//sending request to server for more data
moreDealsRequest();
mUserAdapter.notifyDataSetChanged();
mUserAdapter.setLoaded();
}
}, 5000);
}
});
}
private void initalDealListing() {
String m = "9565656565";
String p = "D55A8077E0208A5C5B25176608EF84BD";
// 3. build jsonObject
try {
final JSONObject jsonObject = new JSONObject();// making object of Jsons.
jsonObject.put("agentCode", m.trim());// put mobile number
jsonObject.put("pin", p.trim());// put password
jsonObject.put("recordcount", sz_RecordCount.trim());// put record count
jsonObject.put("lastcountvalue", sz_LastCount.trim());// put last count
Log.e("CAppList:", sz_RecordCount);
Log.e("Capplist:", sz_LastCount);
Log.d(TAG, "Server Request:-" + jsonObject.toString());
final String m_DealListingURL = APIStorage.IREWARDS_URL + APIStorage.DEALLISTING_URL;
JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(Request.Method.POST, m_DealListingURL, jsonObject, new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
Log.d(TAG, "Server Response:-" + response);
try {
int nResultCodeFromServer = Integer.parseInt(response.getString(ServerResponseStorage.s_szRESULT_CODE));
if (nResultCodeFromServer == ConstantInt.m_kTRANSACTION_SUCCESS) {
JSONArray posts = response.optJSONArray(ServerResponseStorage.s_szDEAL_ARRAY);// get Deal list in array from response
s_oDataset.clear();
for (int i = 0; i < posts.length(); i++) {// loop for counting deals from server
try {
JSONObject post = posts.getJSONObject(i);// counting deal based on index
item = new CDealAppDatastorage();// creating object of DealAppdata storage
item.setM_szHeaderText(post.getString(ServerResponseStorage.s_szDEAL_NAME));// get deal name from response
item.setM_szsubHeaderText(post.getString(ServerResponseStorage.s_szDEAL_CODE));// get dealcode from response
s_oDataset.add(item);// add all items in ArrayList
} catch (Exception e) {
e.printStackTrace();
}
}
arrayCount = posts.length();
Log.d(TAG, "ArrayCount::" + arrayCount);
/*here we are storing no. of deals coming from server*/
// write
m_oPreferenceHelper.saveIntegerValue("LastCountLength", arrayCount);
if (!s_oDataset.isEmpty()) {// condition if data in arraylist is not empty
mRecyclerView.setAdapter(mUserAdapter);
}
}
} catch (JSONException e) {
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Log.d(TAG, "Server error:-" + error);
}
});
RequestQueue requestQueue = Volley.newRequestQueue(context);
jsonObjectRequest.setRetryPolicy(new DefaultRetryPolicy(ConstantInt.INITIAL_TIMEOUT_MS, DefaultRetryPolicy.DEFAULT_MAX_RETRIES, DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));
requestQueue.add(jsonObjectRequest);
} catch (JSONException e) {
e.printStackTrace();
}
}
/*This method send request to server for more deals*/
private void moreDealsRequest() {
try {
// 3. build jsonObject
final JSONObject jsonObject = new JSONObject();// making object of Jsons.
jsonObject.put(ServerRequestKeyStorage.s_szAGENT_CODE, "9565656565");// put mobile number
jsonObject.put(ServerRequestKeyStorage.s_szPASSWORD, "D55A8077E0208A5C5B25176608EF84BD");// put password
jsonObject.put(ServerRequestKeyStorage.s_szRECORD_COUNT, sz_RecordCount.trim());// put record count
jsonObject.put(ServerRequestKeyStorage.s_szLAST_COUNT, sz_LastCount.trim());// put last count
Log.e("CAppList:", sz_RecordCount);
Log.e("Capplist:", sz_LastCount);
// 4. convert JSONObject to JSON to String
Log.e(TAG, "Server Request:-" + jsonObject.toString());
RequestQueue requestQueue = Volley.newRequestQueue(context);
final String imgPath = APIStorage.IREWARDS_URL + APIStorage.DEAL_IMAGE_PATH;
final String m_DealListingURL = APIStorage.IREWARDS_URL + APIStorage.DEALLISTING_URL;
JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(Request.Method.POST, m_DealListingURL, jsonObject, new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
Log.e(TAG, "Server Response:-" + response);
try {
int nResultCodeFromServer = Integer.parseInt(response.getString(ServerResponseStorage.s_szRESULT_CODE));
if (nResultCodeFromServer == ConstantInt.m_kTRANSACTION_SUCCESS) {
// Select the last row so it will scroll into view...
JSONArray posts = response.optJSONArray(ServerResponseStorage.s_szDEAL_ARRAY);// GETTING DEAL LIST
for (int i = 0; i < posts.length(); i++) {
try {
JSONObject post = posts.getJSONObject(i);// GETTING DEAL AT POSITION AT I
item = new CDealAppDatastorage();// object create of DealAppdatastorage
item.setM_szHeaderText(post.getString(ServerResponseStorage.s_szDEAL_NAME));//getting deal name
item.setM_szsubHeaderText(post.getString(ServerResponseStorage.s_szDEAL_CODE));// getting deal code
s_oDataset.add(item);
} catch (Exception e) {
e.printStackTrace();
}
}
}
} catch (JSONException e) {
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Log.d(TAG, "Server Error::" + error);
}
});
jsonObjectRequest.setRetryPolicy(new DefaultRetryPolicy(ConstantInt.INITIAL_TIMEOUT_MS, DefaultRetryPolicy.DEFAULT_MAX_RETRIES, DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));
requestQueue.add(jsonObjectRequest);
} catch (JSONException e) {
e.printStackTrace();
}
}
static class UserViewHolder extends RecyclerView.ViewHolder {
public TextView tvName;
public TextView tvEmailId;
public UserViewHolder(View itemView) {
super(itemView);
tvName = (TextView) itemView.findViewById(R.id.tvName);
tvEmailId = (TextView) itemView.findViewById(R.id.tvEmailId);
}
}
static class LoadingViewHolder extends RecyclerView.ViewHolder {
public ProgressBar progressBar;
public LoadingViewHolder(View itemView) {
super(itemView);
progressBar = (ProgressBar) itemView.findViewById(R.id.progressBar1);
}
}
class UserAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private final int VIEW_TYPE_ITEM = 0;
private final int VIEW_TYPE_LOADING = 1;
private OnLoadMoreListener mOnLoadMoreListener;
private boolean isLoading;
private int visibleThreshold = 5;
private int lastVisibleItem, totalItemCount;
public UserAdapter() {
final LinearLayoutManager linearLayoutManager = (LinearLayoutManager) mRecyclerView.getLayoutManager();
mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
totalItemCount = linearLayoutManager.getItemCount();
lastVisibleItem = linearLayoutManager.findLastVisibleItemPosition();
if (!isLoading && totalItemCount <= (lastVisibleItem + visibleThreshold)) {
if (mOnLoadMoreListener != null) {
mOnLoadMoreListener.onLoadMore();
}
isLoading = true;
}
}
});
}
public void setOnLoadMoreListener(OnLoadMoreListener mOnLoadMoreListener) {
this.mOnLoadMoreListener = mOnLoadMoreListener;
}
#Override
public int getItemViewType(int position) {
return s_oDataset.get(position) == null ? VIEW_TYPE_LOADING : VIEW_TYPE_ITEM;
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (viewType == VIEW_TYPE_ITEM) {
View view = LayoutInflater.from(MainActivity.this).inflate(R.layout.layout_user_item, parent, false);
return new UserViewHolder(view);
} else if (viewType == VIEW_TYPE_LOADING) {
View view = LayoutInflater.from(MainActivity.this).inflate(R.layout.layout_loading_item, parent, false);
return new LoadingViewHolder(view);
}
return null;
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
if (holder instanceof UserViewHolder) {
CDealAppDatastorage user = s_oDataset.get(position);
UserViewHolder userViewHolder = (UserViewHolder) holder;
userViewHolder.tvName.setText(user.getM_szHeaderText());
userViewHolder.tvEmailId.setText(user.getM_szsubHeaderText());
} else if (holder instanceof LoadingViewHolder) {
LoadingViewHolder loadingViewHolder = (LoadingViewHolder) holder;
loadingViewHolder.progressBar.setIndeterminate(true);
}
}
#Override
public int getItemCount() {
return s_oDataset == null ? 0 : s_oDataset.size();
}
public void setLoaded() {
isLoading = false;
}
}
}
Use Below Code:
First Declare these global variables:
int visibleItemCount, totalItemCount = 1;
int firstVisiblesItems = 0;
int totalPages = 1; // get your total pages from web service first response
int current_page = 0;
boolean canLoadMoreData = true; // make this variable false while your web service call is going on.
LinearLayoutManager linearLayoutManager;
Assign Layout manager to your Recyclerview:
linearLayoutManager = new LinearLayoutManager(mActivity);
mRecyclerView.setLayoutManager(linearLayoutManager);
Scroll Listener of your recyclerview:
mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
if (dy > 0) //check for scroll down
{
visibleItemCount = linearLayoutManager.getChildCount();
totalItemCount = linearLayoutManager.getItemCount();
firstVisiblesItems = linearLayoutManager.findFirstVisibleItemPosition();
if (canLoadMoreData) {
if ((visibleItemCount + firstVisiblesItems) >= totalItemCount) {
if (current_page < totalPages) {
canLoadMoreData = false;
/**
* .
* .
* .
* .call your webservice with page index
* .
* .
*
*/
//After completion of web service make 'canLoadMoreData = true'
}
}
}
}
}
});
Too late but i'm also refer same way check with my code it work for me
Here is API call using retrofit and get listnotifications then in this method i create one more method for loadmore getMoreNotificationListApiCall()
public void getNotification()
{
if (listnotifications.size() > 0) {
notificationListAdapter = new NotificationListAdapter(NotificationListActivity.this, listnotifications, notificationListRecyclerview);
notificationListRecyclerview.setAdapter(notificationListAdapter);
notificationListAdapter.setOnLoadMoreListener(new OnLoadMoreListener() {
#Override
public void onLoadMore() {
Log.e("ad", "Load More");
listnotifications.add(null);
Handler handler = new Handler();
final Runnable r = new Runnable() {
public void run() {
if (listnotifications.size()>0) {
notificationListAdapter.notifyItemInserted(listnotifications.size() - 1);
}
}
};
handler.post(r);
try {
if (CommonUtils.isConnectingToInternet(NotificationListActivity.this)) {
// Internet Connection is Present
getMoreNotificationListApiCall();
} else {
//Remove loading item
if (listnotifications.size()>0) {
listnotifications.remove(listnotifications.size() - 1);
}
notificationListAdapter.notifyItemRemoved(listnotifications.size());
CommonUtils.commonToast(NotificationListActivity.this, getResources().getString(R.string.no_internet_exist));
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
}
}
getMoreNotificationListApiCall() method code in this method i increment startlimit means page index and remove null (i'm using retorfit for api call)
private void getMoreNotificationListApiCall() {
try {
if (CommonUtils.isConnectingToInternet(NotificationListActivity.this)) {
StartLimit = StartLimit + 10;
Call<NotificationBase> call = ApiHandler.getApiService().getNotificationListApi(notificationListJsonMap());
call.enqueue(new Callback<NotificationBase>() {
#Override
public void onResponse(Call<NotificationBase> registerCall, Response<NotificationBase> response) {
Log.e(TAG, " Full json gson => " + "Hi i am here");
try {
Log.e(TAG, " Full json gson => " + new Gson().toJson(response));
JSONObject jsonObj = new JSONObject(new Gson().toJson(response).toString());
Log.e(TAG, " responce => " + jsonObj.getJSONObject("body").toString());
if (response.isSuccessful()) {
int success = response.body().getSuccess();
if (success == 1) {
List<NotificationBean> moreNotication = response.body().getNotificatons();
//Remove loading item
if (listnotifications.size() > 0) {
listnotifications.remove(listnotifications.size() - 1);
}
notificationListAdapter.notifyItemRemoved(listnotifications.size());
for (int i = 0; i < moreNotication.size(); i++) {
listnotifications.add(moreNotication.get(i));
}
notificationListAdapter.notifyDataSetChanged();
notificationListAdapter.setLoaded();
} else if (success == 0) {
if (listnotifications.size() > 0) {
listnotifications.remove(listnotifications.size() - 1);
}
notificationListAdapter.notifyItemRemoved(listnotifications.size());
} else {
if (listnotifications.size() > 0) {
listnotifications.remove(listnotifications.size() - 1);
}
notificationListAdapter.notifyItemRemoved(listnotifications.size());
}
} else {
if (listnotifications.size() > 0) {
listnotifications.remove(listnotifications.size() - 1);
}
notificationListAdapter.notifyItemRemoved(listnotifications.size());
}
} catch (Exception e) {
e.printStackTrace();
try {
Log.e(TAG, "error=" + e.toString());
if (listnotifications.size() > 0) {
listnotifications.remove(listnotifications.size() - 1);
}
notificationListAdapter.notifyItemRemoved(listnotifications.size());
} catch (Resources.NotFoundException e1) {
e1.printStackTrace();
}
}
}
#Override
public void onFailure(Call<NotificationBase> call, Throwable t) {
try {
Log.e(TAG, "error" + t.toString());
if (listnotifications.size() > 0) {
listnotifications.remove(listnotifications.size() - 1);
}
notificationListAdapter.notifyItemRemoved(listnotifications.size());
} catch (Resources.NotFoundException e) {
e.printStackTrace();
}
}
});
} else {
CommonUtils.commonToast(NotificationListActivity.this, getResources().getString(R.string.no_internet_exist));
}
} catch (Resources.NotFoundException e) {
e.printStackTrace();
}
}
Here is my Adapter class in which i implement OnLoadMoreListener
public class NotificationListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
public static List<NotificationBean> mList;
private final int VIEW_TYPE_ITEM = 0;
private final int VIEW_TYPE_LOADING = 1;
FragmentActivity mFragmentActivity;
private OnLoadMoreListener mOnLoadMoreListener;
private boolean isLoading;
private int visibleThreshold = 5;
private int lastVisibleItem, totalItemCount;
public NotificationListAdapter(FragmentActivity fragmentActivity, List<NotificationBean> data, RecyclerView mRecyclerView) {
this.mList = data;
this.mFragmentActivity = fragmentActivity;
final LinearLayoutManager linearLayoutManager = (LinearLayoutManager) mRecyclerView.getLayoutManager();
mRecyclerView.addOnScrollListener( new RecyclerView.OnScrollListener() {
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
totalItemCount = linearLayoutManager.getItemCount();
lastVisibleItem = linearLayoutManager.findLastVisibleItemPosition();
if (!isLoading && totalItemCount <= (lastVisibleItem + visibleThreshold)) {
if (mOnLoadMoreListener != null) {
mOnLoadMoreListener.onLoadMore();
}
isLoading = true;
}
}
});
}
public void setOnLoadMoreListener(OnLoadMoreListener mOnLoadMoreListener) {
this.mOnLoadMoreListener = mOnLoadMoreListener;
}
#Override
public int getItemViewType(int position) {
return mList.get(position) == null ? VIEW_TYPE_LOADING : VIEW_TYPE_ITEM;
}
public void delete(int position) { //removes the row
Log.e("Position : ", "" + position);
mList.remove(position);
notifyItemRemoved(position);
notifyItemRangeChanged(position, mList.size());
}
// Return the size arraylist
#Override
public int getItemCount() {
return mList == null ? 0 : mList.size();
}
public void setLoaded() {
isLoading = false;
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (viewType == VIEW_TYPE_ITEM) {
// create a new view
View itemLayoutView = LayoutInflater.from(parent.getContext()).inflate(
R.layout.item_notification_list, parent, false);
return new ViewHolder(itemLayoutView);
} else if (viewType == VIEW_TYPE_LOADING) {
View itemLayoutView = LayoutInflater.from(parent.getContext()).inflate(
R.layout.loading_layout, parent, false);
return new LoadingViewHolder(itemLayoutView);
}
return null;
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, final int position) {
if (holder instanceof ViewHolder) {
try {
final ViewHolder viewHolder = (ViewHolder) holder;
viewHolder.singleBean = mList.get(position);
viewHolder.pos = position;
final NotificationBean list = mList.get(position);
String notificationTitle = list.getMessage();
String notificationTimeDate = list.getCreatedDatetime();
String notificationIsRead = list.getIsRead();
} catch (Exception e) {
e.printStackTrace();
}
} else if (holder instanceof LoadingViewHolder) {
LoadingViewHolder loadingViewHolder = (LoadingViewHolder) holder;
loadingViewHolder.progressBar.setIndeterminate(true);
}
}
static class LoadingViewHolder extends RecyclerView.ViewHolder {
public ProgressBar progressBar;
public LoadingViewHolder(View itemView) {
super(itemView);
progressBar = (ProgressBar) itemView.findViewById(R.id.progressBar1);
}
}
public class ViewHolder extends RecyclerView.ViewHolder {
public NotificationBean singleBean;
int pos;
TextView txt_notification_time_date;
CustomTextview checkbox_notification;
RelativeLayout rl_row_background;
public ViewHolder(final View v) {
super(v);
checkbox_notification = (CustomTextview) v.findViewById(R.id.checkbox_notification);
//checkbox_notification.setButtonDrawable(android.R.color.transparent);//custom_checkbox
// txt_notification_title= (TextView) v.findViewById(R.id.txt_notification_title);
txt_notification_time_date = (TextView) v.findViewById(R.id.txt_notification_time_date);
rl_row_background = (RelativeLayout) v.findViewById(R.id.rl_row_background);
}
}
public void refreshAdapter() {
notifyDataSetChanged();
}
}
here is xml file loading_layout.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:gravity="center_horizontal"
android:orientation="vertical">
<ProgressBar
android:id="#+id/progressBar1"
style="#style/Widget.AppCompat.ProgressBar.Horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_marginBottom="5dp"
android:layout_marginTop="5dp"
android:indeterminate="true" />
</LinearLayout>
Fetching the data from server is a Async Task. So you need to enclose the
updation code in a runOnUiThread runnable. to change UI.
runOnUiThread(new Runnable() {
#Override
public void run() {
mUsers.remove(mUsers.size() - 1);
mUserAdapter.notifyItemRemoved(mUsers.size());
//sending request to server for more data
moreDealsRequest();
mUserAdapter.notifyDataSetChanged();
mUserAdapter.setLoaded();
}});
I have a list view which is updated with items coming from server.
On this list view I have load more functionality and pull down to refresh both.
Everything is working fine but problem is when I pull down to refresh and and scrolls the listview fast it crashes what I am doing wrong I don't understand.
Here is my code
lv.setOnScrollListener(new AbsListView.OnScrollListener() {
#Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
}
#Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
//what is the bottom iten that is visible
int lastInScreen = firstVisibleItem + visibleItemCount;
if (lastInScreen != 0) {
if ((lastInScreen == totalItemCount) && !(isLoading)) {// && !(loadingMore)){
if (newsList.size() < total) {
if (isNetworkAvailable()) {
if (!isLoading) {
lv.addFooterView(footerView);
getNews();
}
}
} else {
lv.removeFooterView(footerView);
}
}
}
}
});
This is my OnRefresh method
#Override
public void onRefresh() {
super.onRefresh();
if (!isLoading) { // no query to server is executing
if (isNetworkAvailable()) {
isLoading = true;
clearList = true;
pageNumber = 0;
getNews();
} else {
toast(getString(R.string.no_internet));
swipeRefreshLayout.setRefreshing(false);
}
} else {// a query is already server is executing
swipeRefreshLayout.postDelayed(new Runnable() {
#Override
public void run() {
swipeRefreshLayout.setRefreshing(false);
}
}, 1000);
}
}
private void getNews() {
pageNumber += 1;
isLoading = true;
JsonObjectRequest jsonObjReq = new JsonObjectRequest(Request.Method.GET,
urlNews + pageNumber, null,
this, this);
applicationInstance.addToRequestQueue(jsonObjReq, "News");
}
#Override
public void onResponse(JSONObject jsonObject) {
super.onResponse(jsonObject);
new SaveData().execute(jsonObject);
}
public class SaveData extends AsyncTask<JSONObject, Void, Void> {
#Override
protected Void doInBackground(JSONObject... params) {
JSONObject jsonObject = params[0];
try {
if (jsonObject.getInt("success") == 1) {
if (clearList) {
newsList.clear();
}
JSONArray newsArray = jsonObject.getJSONArray("rooms");
total = jsonObject.getJSONObject("paging").getInt("total");
for (int a = 0; a < newsArray.length(); a++) {
JSONObject obj = newsArray.getJSONObject(a);
int roomID = obj.getInt("id");
String title = obj.getString("name");
String descr = obj.getString("descr");
RoomsData room = Select.from(RoomsData.class).where(Condition.prop("room_id").eq(roomID)).first();
if (room == null) {
room = new RoomsData(roomID, title, descr);
room.save();
} else {
room.name = title;
room.description = descr;
room.save();
}
JSONArray imagesArray = obj.getJSONArray("images");
for (int b = 0; b < imagesArray.length(); b++) {
JSONObject imageObj = imagesArray.getJSONObject(b);
String Imagename = imageObj.getString("name");
String url = imageObj.getString("url");
HotelImages.deleteAll(HotelImages.class, "room_id = ? and name = ? and url = ? ", roomID + "", Imagename, url);
HotelImages image = new HotelImages(0, roomID, 0, 0, 0, 0, 0, Imagename, url);
image.save();
room.imageList.add(image);
}
// tempList.add(room);
newsList.add(room);
}
store.setString(Constants.FACILITIES_AVAILABLE, jsonObject.getJSONArray("facilities").toString());
store.setString(Constants.BOOKING_EMAIL, jsonObject.getJSONObject("reservation").getString("email"));
}
} catch (Exception e) {
} finally {
}
return null;
}
#Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
runOnUiThread(new Runnable() {
#Override
public void run() {
setListView();
isLoading = false;
swipeRefreshLayout.setRefreshing(false);
}
});
}
}
private void setListView() {
if (newsList.size() == 1) {
Intent it = new Intent(RoomsActivity.this, RoomDetailActivity.class);
RoomsData pro = newsList.get(0);
it.putExtra("RoomID", pro.roomID);
//it.putExtra("rat",rat);
startActivity(it);
finish();
} else {
if (clearList) {
clearList = false;
adapterRooms = new AdapterRooms(this, newsList);
lv.setAdapter(adapterRooms);
if (adapterRooms == null) {
adapterRooms = new AdapterRooms(this, newsList);
lv.setAdapter(adapterRooms);
} else {
adapterRooms.notifyDataSetChanged();
}
} else {
adapterRooms.notifyDataSetChanged();
}
}
swipeRefreshLayout.setRefreshing(false);
lv.removeFooterView(footerView);
}
This is the exception i am getting
01-08 12:45:08.377 2373-2373/hotels.soulvant E/AndroidRuntime﹕ FATAL EXCEPTION: main
Process: hotels.soulvant, PID: 2373
java.lang.IndexOutOfBoundsException: Invalid index 5, size is 0
at java.util.ArrayList.throwIndexOutOfBoundsException(ArrayList.java:255)
at java.util.ArrayList.get(ArrayList.java:308)
at android.widget.HeaderViewListAdapter.getView(HeaderViewListAdapter.java:225)
at android.widget.AbsListView.obtainView(AbsListView.java:2346)
at android.widget.ListView.makeAndAddView(ListView.java:1875)
at android.widget.ListView.fillDown(ListView.java:702)
at android.widget.ListView.fillGap(ListView.java:666)
at android.widget.AbsListView.trackMotionScroll(AbsListView.java:5029)
at android.widget.AbsListView$FlingRunnable.run(AbsListView.java:4577)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:858)
at android.view.Choreographer.doCallbacks(Choreographer.java:670)
at android.view.Choreographer.doFrame(Choreographer.java:603)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:844)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5417)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)