RecyclerView empty after data update - java

I am developing Android app which obtains information about restaurants from server and shows them in RecyclerView. When first package of information is obtained from server, everything works as expected, but, when I change search criteria and request new package of information from server, RecyclerView becomes blank. I used Toasts to debug what is coming from server and I am convinced that data is properly formatted. Also, variables that are used for accepting the data are also properly handled in code, according to my observations. Do you maybe know why my RecyclerView is empty when second package of data should be shown? Here is the code.
AfterLoginActivity.java
public class AfterLoginActivity extends AppCompatActivity {
/* interface main elements */
LinearLayout afterLoginLayout;
LinearLayout restaurantListLayout;
EditText restaurantEditText;
Button findRestaurantButton;
LoadingDialog loadingDialog;
AlphaAnimation loadingAnimation;
RecyclerView restaurantsRecyclerView;
int recycler_set = 0;
Button signOutButton;
GoogleSignInClient mGoogleSignInClient;
MyAdapter myAdapter = null;
/* server-client communication data */
public static String UploadUrl = "https://gdedakliknem.com/klopator.php";
public static String[] received;
String restaurants[] = new String[40];
String logos_as_strings[] = new String[40];
Bitmap logos[] = new Bitmap[40];
int num_of_elements = 0;
int data_received = 0;
/* user data */
String person_email;
String person_name;
String restaurant;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_after_login);
/* interface main elements */
afterLoginLayout = findViewById(R.id.afterLoginLayout);
restaurantListLayout = findViewById(R.id.restaurantListLayout);
restaurantEditText = findViewById(R.id.restaurantEditText);
findRestaurantButton = findViewById(R.id.findRestaurantButton);
restaurantsRecyclerView = findViewById(R.id.restaurantsRecyclerView);
signOutButton = findViewById(R.id.signOutButton);
loadingAnimation = new AlphaAnimation(1F, 0.8F);
loadingDialog = new LoadingDialog(AfterLoginActivity.this);
/* UPDATING INTERFACE ELEMENTS */
/* execution thread */
final Handler handler = new Handler();
final int delay = 2000; // 1000 milliseconds == 1 second
handler.postDelayed(new Runnable() {
public void run() {
/* check if recycler view is set */
if(recycler_set == 0){
/* if not, check if there is data to fil it with */
if(data_received == 1){
/* convert received strings to images */
for(int i = 0; i < num_of_elements; i++){
logos[i] = stringToBitmap(logos_as_strings[i]);
}
/* fill interface elements */
loadingDialog.dismissDialog();
myAdapter = new MyAdapter(AfterLoginActivity.this, restaurants, logos, num_of_elements);
restaurantsRecyclerView.setAdapter(myAdapter);
restaurantsRecyclerView.setLayoutManager(new LinearLayoutManager(AfterLoginActivity.this));
afterLoginLayout.setVisibility(View.GONE);
restaurantListLayout.setVisibility(View.VISIBLE);
recycler_set = 1;
}
}
handler.postDelayed(this, delay);
}
}, delay);
/* catch restaurant name from user's entry */
findRestaurantButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
restaurant = restaurantEditText.getText().toString();
if(!restaurant.isEmpty()){
view.startAnimation(loadingAnimation);
loadingDialog.startLoadingDialog();
sendRequest();
} else{
Toast.makeText(AfterLoginActivity.this, "Unesite naziv restorana!", Toast.LENGTH_LONG).show();
}
}
});
/* enable signing out */
GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
.requestEmail()
.build();
mGoogleSignInClient = GoogleSignIn.getClient(this, gso);
signOutButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.signOutButton:
signOut();
break;
}
}
});
/* obtaining email */
GoogleSignInAccount acct = GoogleSignIn.getLastSignedInAccount(this);
if (acct != null) {
person_email = acct.getEmail();
person_name = acct.getDisplayName();
}
}
#Override
public void onBackPressed() {
afterLoginLayout.setVisibility(View.VISIBLE);
restaurantsRecyclerView.setVisibility(View.GONE);
data_received = 0;
recycler_set = 0;
}
private void signOut() {
mGoogleSignInClient.signOut()
.addOnCompleteListener(this, new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
Toast.makeText(AfterLoginActivity.this, "Signed out", Toast.LENGTH_LONG).show();
finish();
}
});
}
public void sendRequest(){
StringRequest stringRequest = new StringRequest(Request.Method.POST, UploadUrl, new Response.Listener<String>() {
#Override
public void onResponse(String response) {
try {
JSONObject jsonObject = new JSONObject(response);
String Response = jsonObject.getString("response");
if (Response.equals("Restaurant not found")){
loadingDialog.dismissDialog();
Toast.makeText(getApplicationContext(), "Uneti restoran ne postoji u sistemu! Proverite da li ste dobro napisali naziv", Toast.LENGTH_LONG).show();
} else{
received = Response.split(";");
if (received.length > 0){
data_received = 1;
num_of_elements = received.length / 2;
//Toast.makeText(getApplicationContext(), "num of elements: " + num_of_elements, Toast.LENGTH_LONG).show();
for(int i = 0; i < num_of_elements; i++){
logos_as_strings[i] = received[i*2];
restaurants[i] = received[i*2+1];
//Toast.makeText(getApplicationContext(), "restaurants: " + restaurants, Toast.LENGTH_LONG).show();
}
} else{
loadingDialog.dismissDialog();
Toast.makeText(getApplicationContext(), "Greška u prijemu", Toast.LENGTH_LONG).show();
}
}
} catch (JSONException e) {
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(final VolleyError error) {
//volleyError = error;
}
})
{
#Override
protected Map<String, String> getParams() throws AuthFailureError {
//Toast.makeText(getApplicationContext(), "get params", Toast.LENGTH_LONG).show();
Map<String, String> params = new HashMap<>();
params.put("control", "find_restaurant");
params.put("restaurant", restaurant);
return params;
}
};
RequestQueue requestQueue = Volley.newRequestQueue(AfterLoginActivity.this);
requestQueue.add(stringRequest);
}
public static Bitmap stringToBitmap(String encodedString) {
try {
byte[] encodeByte = Base64.decode(encodedString, Base64.DEFAULT);
return BitmapFactory.decodeByteArray(encodeByte, 0, encodeByte.length);
} catch (Exception e) {
e.getMessage();
return null;
}
}
MyAdapter.java
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder> {
String restaurants[];
Bitmap logos[];
Context context;
int num_of_elements;
public MyAdapter(Context ct, String rests[], Bitmap lgs[], int num){
context = ct;
restaurants = rests;
logos = lgs;
num_of_elements = num;
Toast.makeText(context, Integer.toString(restaurants.length), Toast.LENGTH_LONG).show();
for(int i = 0; i < restaurants.length; i++){
Toast.makeText(context, restaurants[i], Toast.LENGTH_SHORT).show();
}
}
#NonNull
#Override
public MyViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
LayoutInflater layoutInflater = LayoutInflater.from(context);
View view = layoutInflater.inflate(R.layout.restaurant_item_layout, parent, false);
return new MyViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull MyAdapter.MyViewHolder holder, int position) {
holder.restaurantNameTextView.setText(restaurants[position]);
holder.restaurantLogoImageView.setImageBitmap(logos[position]);
holder.restaurantItemLayout.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent intent = new Intent(context, AfterPickingRestaurantActivity.class);
ByteArrayOutputStream bs = new ByteArrayOutputStream();
logos[position].compress(Bitmap.CompressFormat.PNG, 50, bs);
intent.putExtra("byteArray", bs.toByteArray());
intent.putExtra("picked_restaurant_name", restaurants[position]);
context.startActivity(intent);
}
});
}
#Override
public int getItemCount() {
/*
int i = 0;
if (restaurants != null){
while(restaurants[i] != null){
i++;
}
} else{
i = restaurants.length;
}
return i;
*/
return num_of_elements;
}
public class MyViewHolder extends RecyclerView.ViewHolder {
TextView restaurantNameTextView;
ImageView restaurantLogoImageView;
LinearLayout restaurantItemLayout;
public MyViewHolder(#NonNull View itemView) {
super(itemView);
restaurantNameTextView = itemView.findViewById(R.id.restaurantNameTextView);
restaurantLogoImageView = itemView.findViewById(R.id.restaurantLogoImageView);
restaurantItemLayout = itemView.findViewById(R.id.restaurantItemLayout);
}
}

Add this lines after getting new data
myAdapter.notifyDataSetChanged()

Your Adapter Already set with RecyclerView in OnCreate Method.
so when'er you click on findRestaurantButton you just get Resturent data from server but collected data not pass in adapter so thats why to getting blank adapter..
Just put this line in your onResponse after set data in array..
myAdapter.notifyDataSetChanged()

I found out where is the mistake. If you take a look at the section where overriding of back button click is happening, I by mistake set to GONE recyclerView itself:
restaurantsRecyclerView.setVisibility(View.GONE);
instead of LinearLayout in which recyclerView is contained. Desired action was:
restaurantListLayout.setVisibility(View.GONE);
P.S. Everything works without calling notifyDataSetChanged(), I just create a new instance of myAdapater each time when I receive new data. I hope Garbage Collector is doing its job :)
Thanks everyone on help!

Related

Why are my variables being reset to zero every time I reopen my Main activity

I am currently creating an app for a university project. Within the app I use two php scripts - one to set data from variables within the app to a MySQL data base, and the other to retrieve data from the database and set the variables within the app. The first script that sends the data to mySQL is working fine with no issues, however the script to retrieve the data from mySQL to set variables within the app is only working when ran through my webserver. When run within my app (on Activity Start and create) the variables are all set to zero. Any help would be amazing, Ive been stuck for weeks!
<?php
require "conn.php";
$username = "test";
$stmt = $conn->prepare("SELECT gold, goldMulti, xp, xpMulti, xpMax, xpMaxMulti, dmg, dmgMulti, bossCount, bossHp, bossHpMulti, level, backgroundCount FROM users WHERE username = '$username'");
$stmt ->execute();
$stmt ->bind_result($gold, $goldMulti, $xp, $xpMulti, $xpMax, $xpMaxMulti, $dmg, $dmgMulti, $bossCount, $bossHp, $bossHpMulti, $level, $backgroundCount);
$varaibles = array();
$stmt ->fetch();
$temp = array();
$temp['gold'] = $gold;
$temp['goldMulti'] = $goldMulti;
$temp['xp'] = $xp;
$temp['xpMulti'] = $xpMulti;
$temp['xpMax'] = $xpMax;
$temp['xpMaxMulti'] = $xpMaxMulti;
$temp['dmg'] = $dmg;
$temp['dmgMulti'] = $dmgMulti;
$temp['bossCount'] = $bossCount;
$temp['bossHp'] = $bossHp;
$temp['bossHpMulti'] = $bossHpMulti;
$temp['level'] = $level;
$temp['backgroundCount'] = $backgroundCount;
array_push($variables,$temp);
echo json_encode($temp);
?>
public class MainActivity extends AppCompatActivity {
// int variables for logic and functions ------------------------------------------------------
public int gold;
public int goldAwarded;
public int goldMultiplier;
public int xp;
public int xpAwarded;
public int xpMultiplier;
public int dmg;
public int dmgMultiplier;
public int bossCount;
public int bossHP;
public int bossHPMultiplier;
public int bossHPBase;
public int level;
public int xpMax;
public int bossCountFunc;
public int backgroundCount;
public int xpMaxMulti;
public int baseDmg;
// Widget variables -----------------------------------------------------------------------------
private TextView bossNumberText;
private TextView levelText;
private TextView goldText;
private TextView bossHealthText;
private ImageButton tapButton;
private ImageView bossImage;
private ImageView playerImage;
private ImageView bossImage2;
private ImageView bossImage3;
private ImageButton shopButton;
public String LoggedInUser = LogIn.getUser();
// Audio players --------------------------------------------------------------------------------
MediaPlayer mps;
MediaPlayer mpb;
MediaPlayer mpc;
MediaPlayer mpl;
MediaPlayer mpp;
// Websever php file URL to retrieve Data from user ----------------------------------------------
private static final String URL = "http://jg1104.brighton.domains/AppPhp/variablesretrieval.php";
private void getData(){
StringRequest stringRequest = new StringRequest(Request.Method.GET, URL, new Response.Listener<String>() {
#Override
public void onResponse(String response) {
try{
JSONArray array = new JSONArray(response);
for(int i = 0; i<array.length(); i++){
JSONObject object = array.getJSONObject(i);
gold = object.getInt("gold");
goldMultiplier = object.getInt("goldMulti");
xp = object.getInt("xp");
xpMultiplier = object.getInt("xpMulti");
xpMax = object.getInt("xpMax");
xpMaxMulti = object.getInt("xpMaxMulti");
dmg = object.getInt("dmg");
dmgMultiplier = object.getInt("dmgMulti");
bossCount = object.getInt("bossCount");
bossHP = object.getInt("bossHp");
bossHPMultiplier = object.getInt("bossHpMulti");
level = object.getInt("level");
backgroundCount = object.getInt("backgroundCount");
}
}catch (Exception e) {
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Toast.makeText(MainActivity.this,error.toString(), Toast.LENGTH_SHORT).show();
}
protected Map<String, String> getParams() throws AuthFailureError {
HashMap<String, String> param = new HashMap<>();
param.put("LoggedInUser", LoggedInUser);
return param;
}
}
);
Volley.newRequestQueue(MainActivity.this).add(stringRequest);
}
// On create -------------------------------------------------------------------------------------
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
bossNumberText = (TextView) findViewById(R.id.bossNumberText);
levelText = (TextView) findViewById(R.id.levelText);
goldText = (TextView) findViewById(R.id.goldText);
bossHealthText = (TextView) findViewById(R.id.bossHealthText);
tapButton = (ImageButton) findViewById(R.id.TapButton);
bossImage = (ImageView) findViewById(R.id.bossImage);
playerImage = (ImageView) findViewById(R.id.playerImage);
bossImage2 = (ImageView) findViewById(R.id.bossImage2);
bossImage3 = (ImageView) findViewById(R.id.bossImage3);
shopButton = (ImageButton) findViewById(R.id.shopButton);
mpb = MediaPlayer.create(this, R.raw.backgroundmusic);
mpc = MediaPlayer.create(this, R.raw.coin);
mpl = MediaPlayer.create(this, R.raw.levelup);
mpp = MediaPlayer.create(this, R.raw.pain);
mps = MediaPlayer.create(this, R.raw.shootingsound);
// retrieving data from database and setting TextViews -----------------------------------
getData();
// Set looping and start of background music ---------------------------------------------
mpb.setLooping(true);
mpb.start();
// Initialising variable values on create ------------------------------------------------
goldAwarded = 100;
xpAwarded = 100;
baseDmg = 1;
bossHPBase = 10;
bossCountFunc = 1;
shopButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
launchShop();
}
});
}
#Override
protected void onStart() {
// onclickListener for main button --------------------------------------------------------
super.onStart();
getData();
levelText.setText("Level: " + Integer.toString(level));
goldText.setText("Gold: " + Integer.toString(gold));
bossHealthText.setText("HP: " + Integer.toString(bossHP));
bossNumberText.setText("Boss: " + bossCount);
tapButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// shooting sound
mps.start();
// run method that looks to see if background needs to be changed
newBackground();
// handlers for enemy animations
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
bossImage.setImageDrawable(getResources().getDrawable(R.drawable.onezshot));
AnimationDrawable oneshotz = (AnimationDrawable) bossImage.getDrawable();
oneshotz.start();
}
}, 0);
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
bossImage2.setImageDrawable(getResources().getDrawable(R.drawable.twozshot));
AnimationDrawable twozshot = (AnimationDrawable) bossImage2.getDrawable();
twozshot.start();
}
}, 0);
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
bossImage3.setImageDrawable(getResources().getDrawable(R.drawable.threezshot));
AnimationDrawable threezshot = (AnimationDrawable) bossImage3.getDrawable();
threezshot.start();
}
}, 0);
// handler for shooting animation
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
playerImage.setImageDrawable(getResources().getDrawable(R.drawable.shooting));
AnimationDrawable shooting = (AnimationDrawable) playerImage.getDrawable();
shooting.start();
}
}, 0);
bossHP -= dmg;
bossHealthText.setText("HP: " + Integer.toString(bossHP));
// if boss dies
if (bossHP <= 1) {
mpp.start();
bossCount++;
bossCountFunc++;
backgroundCount++;
if (backgroundCount > 9) {
backgroundCount = 1;
}
if (bossCountFunc > 3) {
bossCountFunc = 1;
}
bossNumberText.setText("Boss: " + bossCount);
goldMultiplier++;
xpMultiplier++;
mpc.start();
gold += (goldAwarded * goldMultiplier);
goldText.setText("Gold: " + Integer.toString(gold));
xp += (xpAwarded * xpMultiplier);
bossHPMultiplier++;
// look for level up
if (xp >= xpMax) {
mpl.start();
level++;
dmgMultiplier++;
bossHPMultiplier *= 2;
dmg = (baseDmg * dmgMultiplier);
levelText.setText("lvl: " + Integer.toString(level));
xp = 0;
xpMax = xpMax * xpMaxMulti;
}
newBoss();
}
}
});
}
// Method to show or hide boss frames
public void newBoss(){
bossHP = bossHPBase * bossHPMultiplier;
if(bossCountFunc==1){
bossImage.setVisibility(View.VISIBLE);
bossImage2.setVisibility(View.INVISIBLE);
bossImage3.setVisibility(View.INVISIBLE);
}
if(bossCountFunc==2){
bossImage.setVisibility(View.INVISIBLE);
bossImage2.setVisibility(View.VISIBLE);
}
if(bossCountFunc==3){
bossImage2.setVisibility(View.INVISIBLE);
bossImage3.setVisibility(View.VISIBLE);
}
}
// method to check and change background
public void newBackground(){
ConstraintLayout layout = (ConstraintLayout) findViewById(R.id.constraintLayout);
if(backgroundCount<=3){
layout.setBackgroundResource(R.drawable.main);
}
if(backgroundCount>3 && backgroundCount<=6){
layout.setBackgroundResource(R.drawable.maintwo);
}
if(backgroundCount>6 && backgroundCount<=9){
layout.setBackgroundResource(R.drawable.mainthree);
}
}
public void launchShop(){
Intent intent = new Intent(this, Shop.class);
startActivity(intent);
}
private void setData(final String LoggedInUser, final int gold,final int goldMultiplier,final int xp,final int xpMultiplier
,final int xpMax,final int xpMaxMulti,final int dmg
,final int dmgMultiplier,final int bossCount,final int bossHP
,final int bossHPMultiplier,final int level,final int backgroundCount){
final ProgressDialog progressDialog = new ProgressDialog(MainActivity.this);
progressDialog.setCancelable(false);
progressDialog.setIndeterminate(false);
progressDialog.setTitle("Setting Data");
progressDialog.show();
String uRl = "http://jg1104.brighton.domains/AppPhp/setdata.php";
StringRequest request = new StringRequest(Request.Method.POST, uRl, new Response.Listener<String>() {
#Override
public void onResponse(String response) {
if(response.equals("Data set")){
progressDialog.dismiss();
Toast.makeText(MainActivity.this, response, Toast.LENGTH_SHORT).show();
}
else{
progressDialog.dismiss();
Toast.makeText(MainActivity.this, response, Toast.LENGTH_SHORT).show();
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
progressDialog.dismiss();
Toast.makeText(MainActivity.this, error.toString(), Toast.LENGTH_SHORT).show();
}
}){
#Override
protected Map<String, String> getParams() throws AuthFailureError {
HashMap<String, String> param = new HashMap<>();
param.put("LoggedInUser", LoggedInUser);
param.put("gold", Integer.toString(gold));
param.put("goldMulti", Integer.toString(goldMultiplier));
param.put("xp", Integer.toString(xp));
param.put("xpMulti", Integer.toString(xpMultiplier));
param.put("xpMax", Integer.toString(xpMax));
param.put("xpMaxMulti", Integer.toString(xpMaxMulti));
param.put("dmg", Integer.toString(dmg));
param.put("dmgMulti", Integer.toString(dmgMultiplier));
param.put("bossCount", Integer.toString(bossCount));
param.put("bossHp", Integer.toString(bossHP));
param.put("bossHpMulti", Integer.toString(bossHPMultiplier));
param.put("level", Integer.toString(level));
param.put("backgroundCount", Integer.toString(backgroundCount));
return param;
}
};
request.setRetryPolicy(new DefaultRetryPolicy(30000,DefaultRetryPolicy.DEFAULT_MAX_RETRIES,DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));
MySingleton.getmInstance(MainActivity.this).addToRequestQueue(request);
}
#Override
protected void onStop() {
super.onStop();
setData(LoggedInUser,gold,goldMultiplier,xp,xpMultiplier,xpMax,xpMaxMulti,dmg,dmgMultiplier,bossCount,bossHP,bossHPMultiplier,level,backgroundCount);
}
}
Since the script is working when used in my webserver, I am sure it is something to do with my java coding.
This code is your problem:
try{
JSONArray array = new JSONArray(response);
for(int i = 0; i<array.length(); i++){
JSONObject object = array.getJSONObject(i);
gold = object.getInt("gold");
goldMultiplier = object.getInt("goldMulti");
xp = object.getInt("xp");
xpMultiplier = object.getInt("xpMulti");
xpMax = object.getInt("xpMax");
xpMaxMulti = object.getInt("xpMaxMulti");
dmg = object.getInt("dmg");
dmgMultiplier = object.getInt("dmgMulti");
bossCount = object.getInt("bossCount");
bossHP = object.getInt("bossHp");
bossHPMultiplier = object.getInt("bossHpMulti");
level = object.getInt("level");
backgroundCount = object.getInt("backgroundCount");
}
} catch (Exception e) {
}
You should not leave the catch block empty. It's likely throwing and swallowing an error.
Do this:
} catch (Exception e) {
Log.e("MyApp", "Error parsing!", e);
}
(Some reading on Logcat https://developer.android.com/studio/debug/am-logcat)
or get rid of the try catch all together and let your app crash (fail fast)!!
Your actual error (or first error I can see anyway) is that you are attempting to parse a JSONarray when your server side response is a JSONObject. This line of code:
JSONArray array = new JSONArray(response);
And this response:
{
"gold":600, "goldMulti":3,
"xp":0, "xpMulti":3, "xpMax":0, "xpMaxMulti":0,
"dmg":3,"dmgMulti":3,
"bossCount":3,
"bossHp":80,
"bossHpMulti":14,
"level":3,
"backgroundCount":3
}
(from here) http://jg1104.brighton.domains/AppPhp/variablesretrieval.php
You should parse it as a JsonObject or wrap your server side returned response in an Array [].

Android Recycler view cannot return more than 8 items

I am having this issue for some time now, when I retrieved data from a database using volley and then show it in a recycler view, if the items are 8 or less than 8 then it shows them without any problem, but if I retrieve more than 8 items from database then the activity closes/crashes and goes back to the main activity. I don't get any error in the run console in android studio. I am retrieving 3 things from database for a single item, 2 strings and an image. I don't think the error is in the php file which is used to get the data as that I have checked and it retrieves without any issue. I have searched android documentation of recycler view but couldn't find anything
NOTE: I am getting image as string and then converting to bitmap.
if there is anything else needed then I can provide them without any issue.
the code is below:
Method which is used to call the recycler view activity which has problems.
public void onViewAttendanceButtonClick(int position, String courseCode,
String courseName, String batchName) {
if (MainActivity.teacherData != null) {
seeAttendanceDetails(MainActivity.teacherData.getEmail(),courseCode,
batchName, courseName, getDateAndTime);
}
}
private void seeAttendanceDetails(final String email,final String
courseCode, final String batchName,final String courseName, final String
date) {
StringRequest stringRequest = new StringRequest(Request.Method.POST,
seeAttendanceDetails, new Response.Listener<String>() {
#Override
public void onResponse(String response) {
try {
JSONArray jsonArray = new JSONArray(response);
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject data = jsonArray.getJSONObject(i);
String fullName = data.getString("full_name");
String Email = data.getString("email");
String photo = data.getString("photo");
Toast.makeText(CoursesActivity.this, courseCode,
Toast.LENGTH_LONG).show();
Attendance attendance1 = new Attendance(fullName, Email, photo);
attendanceArrayList.add(attendance1);
}
if (!attendanceArrayList.isEmpty()) {
Intent intent = new Intent(CoursesActivity.this,
ShowAttendanceActivity.class);
Bundle bundle = new Bundle();
bundle.putString("attendanceCourseCode",
courseCode);
bundle.putString("attendanceCourseName",
courseName);
bundle.putString("attendanceBatchName", batchName);
bundle.putSerializable("attendanceList",
attendanceArrayList);
intent.putExtras(bundle);
startActivity(intent);
}
else if (RegistrationActivity.teacherData != null) {
//
seeAttendanceDetails(RegistrationActivity.teacherData.getEmail(),
batchName,courseName, getDateAndTime);
// Toast.makeText(CoursesActivity.this,"No Record
Found",Toast.LENGTH_LONG).show();
}
} catch (Exception e) {
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Toast.makeText(CoursesActivity.this,
error.getMessage().toString(), Toast.LENGTH_SHORT).show();
}
}) {
public Map<String, String> getParams() {
Map<String, String> params = new HashMap<String, String>();
params.put("email", email);
params.put("batch", batchName);
params.put("date", date);
params.put("courseCode",courseCode);
return params;
}
};
RequestQueue requestQueue = Volley.newRequestQueue(this);
requestQueue.add(stringRequest);
}
}
<br/>
The recycler view activity code
public class ShowAttendanceActivity extends AppCompatActivity implements
ShowAttendanceActivityAdapter.RemoveAttendanceClickListener {
private RecyclerView recyclerView;
private String courseCode,courseName,batchName;
private ArrayList<Attendance> attendanceArrayList = new ArrayList<>();
private TextView
textViewCourseCode,textViewCourseName,textViewBatchName;
private String deleteStudentAttendance =
"https://asuiot.umargulzar.com/Teacher%20API%2
0Files/deleteStudentattendance.php";
int success;
private String TAG_SUCCESS = "success";
private String TAG_MESSAGE = "message";
private String getDateAndTime;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_show_attendance);
recyclerView = findViewById(R.id.attendance_details_recyclerView);
textViewCourseCode = findViewById(R.id.SA_textView_course_code);
textViewCourseName = findViewById(R.id.SA_textView_course_name);
textViewBatchName = findViewById(R.id.SA_textView_Batch);
LinearLayoutManager layoutManager = new LinearLayoutManager(this, RecyclerView.VERTICAL,false);
recyclerView.setLayoutManager(layoutManager);
Calendar calendar = Calendar.getInstance();
// SimpleDateFormat simpleDateFormat = new SimpleDateFormat("dd-MMM-yyy hh:mm:ss a");
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyy-MM-dd");
String dateTime = simpleDateFormat.format(calendar.getTime());
this.getDateAndTime = dateTime;
courseCode = (String) getIntent().getStringExtra("attendanceCourseCode");
courseName = (String) getIntent().getStringExtra("attendanceCourseName");
batchName = (String) getIntent().getStringExtra("attendanceBatchName");
attendanceArrayList = (ArrayList<Attendance>) getIntent().getExtras().getSerializable("attendanceList");
textViewCourseCode.setText(courseCode);
textViewCourseName.setText(courseName);
textViewBatchName.setText(batchName);
recyclerView.setAdapter(new ShowAttendanceActivityAdapter(attendanceArrayList,this));
}
#Override
public void onRemoveAttendanceClick(int position,String email) {
// Toast.makeText(ShowAttendanceActivity.this,"The Email of Student:"+email,Toast.LENGTH_LONG).show();
if(MainActivity.teacherData !=null){
deleteStudentAttendance(email,getDateAndTime,courseCode);
}
}
private void deleteStudentAttendance(final String email, final String getDateAndTime,final String courseCode) {
StringRequest stringRequest = new StringRequest(Request.Method.POST, deleteStudentAttendance, new Response.Listener<String>() {
#Override
public void onResponse(String response) {
try {
JSONObject jsonObject = new JSONObject(response);
success = jsonObject.getInt(TAG_SUCCESS);
if (success == 1) {
Toast.makeText(ShowAttendanceActivity.this, jsonObject.getString(TAG_MESSAGE)+" Plz refresh the page.", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(ShowAttendanceActivity.this, jsonObject.getString(TAG_MESSAGE), Toast.LENGTH_SHORT).show();
}
} catch (Exception e) {
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
}
}){
public Map<String, String> getParams() {
Map<String, String> params = new HashMap<String, String>();
params.put("Email", email);
params.put("Date",getDateAndTime);
params.put("CourseCode",courseCode);
return params;
}
};
RequestQueue requestQueue = Volley.newRequestQueue(this);
requestQueue.add(stringRequest);
}
}
the recycler view activity adapter
public class ShowAttendanceActivityAdapter extends RecyclerView.Adapter<ShowAttendanceActivityAdapter.AttendanceView> {
private ArrayList<Attendance> attendanceData;
Bitmap bitmap;
private RemoveAttendanceClickListener removeAttendanceClickListener;
public ShowAttendanceActivityAdapter(ArrayList<Attendance> attendanceData,RemoveAttendanceClickListener removeAttendanceClickListener){
this.attendanceData = attendanceData;
this.removeAttendanceClickListener = removeAttendanceClickListener;
}
#NonNull
#Override
public AttendanceView onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.show_attendance_data,parent,false);
return new AttendanceView(view,removeAttendanceClickListener);
}
#Override
public void onBindViewHolder(#NonNull AttendanceView holder, int position) {
Attendance attendance = attendanceData.get(position);
holder.textViewName.setText(attendance.getStudentName());
// holder.textViewEmail.setText(attendance.getStudentEmail());
holder.textViewEmail.setText(attendance.getStudentEmail());
decodeStringToImage(attendance.getStudentPhoto());
holder.imageViewPhoto.setImageBitmap(bitmap);
}
#Override
public int getItemCount() {
return attendanceData.size();
}
public void decodeStringToImage(String photo) {
// Bitmap bitmap = photo.
byte[] bytes = Base64.decode(photo, Base64.DEFAULT);
bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
}
public class AttendanceView extends RecyclerView.ViewHolder implements View.OnClickListener{
TextView textViewName, textViewEmail;
ImageView imageViewPhoto;
Button buttonRemoveCourse;
RemoveAttendanceClickListener removeAttendanceClickListener;
public AttendanceView(#NonNull View itemView,RemoveAttendanceClickListener removeAttendanceClickListener) {
super(itemView);
textViewName = itemView.findViewById(R.id.textView_name);
textViewEmail = itemView.findViewById(R.id.textView_Email);
imageViewPhoto = itemView.findViewById(R.id.textView_SA_Photo);
this.removeAttendanceClickListener = removeAttendanceClickListener;
buttonRemoveCourse = itemView.findViewById(R.id.btn_remove_attendance);
buttonRemoveCourse.setOnClickListener(this);
}
#Override
public void onClick(View v) {
switch (v.getId()){
case R.id.btn_remove_attendance:
removeAttendanceClickListener.onRemoveAttendanceClick(getAdapterPosition(),textViewEmail.getText().toString());
break;
}
}
}
public interface RemoveAttendanceClickListener{
void onRemoveAttendanceClick(int position,String email);
}
}
You are probably getting OutOfMemory exception while converting bytes array in to bitmap if the image sizes are huge.
Add try catch in your decodeStringToImage method where you are converting bitmaps and check the log when you load more than 8 images.

Selecting one from radio group value and scrolling down and some item selected automatically in Recycler View( beginner)

I am making an attendance system where I take the attendance using RadioGroup with two options. When I select some radio button and scroll down some other radio button gets auto-selected. If I change them upper ones also get changed.
Main class
public class TeacherAttendanceActivity extends AppCompatActivity implements AttendanceAdapter.AttendanceAdapterListner {
public static TeacherAttendanceActivity teacherAttendanceActivity;
private static final String TAG = TeacherAttendanceActivity.class.getSimpleName();
List<AttendanceModel> listItems;
private RecyclerView recyclerView;
private RecyclerView.Adapter adapter;
private AttendanceAdapter attendanceAdapter;
ProgressDialog progressDialog;
private SQLiteHandler db;
private SessionManager session;
private SearchView searchView;
Button btnSubmit;
JSONObject mainObj = new JSONObject();
// date
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
String currentDateandTime = sdf.format(new Date());
String class_id,title;
Boolean Error;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_teacher_attendance);
//get data from intent
class_id = super.getIntent().getExtras().getString("id"); //class_id
title = super.getIntent().getExtras().getString("title");
getSupportActionBar().setTitle("Class: "+title+", Date: "+currentDateandTime );
// SqLite database handler
db = new SQLiteHandler(getApplicationContext());
// session manager
session = new SessionManager(getApplicationContext());
btnSubmit=findViewById(R.id.buttonAttendanceSubmit);
btnSubmit.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Error=false;
Gson gson=new Gson();
final String newDataArray=gson.toJson(listItems); // dataarray is list aaray
for (int i = 0; i < AttendanceAdapter.listItems.size(); i++){
if(AttendanceAdapter.listItems.get(i).getAttendance()==null){
Toast.makeText(TeacherAttendanceActivity.this, "Check attendance at roll:"+AttendanceAdapter.listItems.get(i).getRoll(), Toast.LENGTH_SHORT).show();
Error =true;
break;
}
}
if (!Error){
request(class_id,currentDateandTime,newDataArray);
}
}
});
listItems = new ArrayList<>();
attendanceAdapter = new AttendanceAdapter(listItems, this, (AttendanceAdapter.AttendanceAdapterListner) this);
recyclerView = (RecyclerView) findViewById(R.id.list_attendance);
recyclerView.setLayoutManager(new LinearLayoutManager(TeacherAttendanceActivity.this));
progressDialog = new ProgressDialog(this);
teacherAttendanceActivity = this;
//refresh_list(class_id);
}
#Override
protected void onStart() {
refresh_list(class_id);
super.onStart();
}
#Override
public void onAttendanceAdapterSelected(AttendanceModel model) {
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.refresh, menu);
getMenuInflater().inflate(R.menu.tool_bar, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
switch (id){
case R.id.action_settings:
Toast.makeText(getApplicationContext(),"Sittings",Toast.LENGTH_LONG).show();
return true;
case R.id.action_logout:
logoutUser();
return true;
case R.id.action_about:
Toast.makeText(getApplicationContext(),"About",Toast.LENGTH_LONG).show();
return true;
case R.id.action_devinfo:
Toast.makeText(getApplicationContext(),"Dev info",Toast.LENGTH_LONG).show();
return true;
case R.id.refresh:
refresh_list(class_id);
return true;
default:
return super.onOptionsItemSelected(item);
}
}
void logoutUser() {
session.setLogin(false);
db.deleteUsers();
// Launching the login activity
Intent intent = new Intent(this, MainActivity.class);
startActivity(intent);
finish();
}
// refresh list
public void refresh_list(String id) {
// this method refresh list and get the json data
listItems.clear();
// adapter = new MyAdapter(listItems,getApplicationContext());
recyclerView.setAdapter(attendanceAdapter);
recyclerView.setItemAnimator(new DefaultItemAnimator());
progressDialog.setMessage("Loading");
progressDialog.show();
StringRequest stringRequest = new StringRequest(Request.Method.GET, ApiConfig.URL_TEACHER_ATTENDANCE+id, new Response.Listener<String>() {
#Override
public void onResponse(String response) {
progressDialog.dismiss();
try {
progressDialog.hide();
JSONObject jsonObject = new JSONObject(response);
JSONArray jsonArray = jsonObject.getJSONArray("Data"); // finding data
Log.d(TAG, String.valueOf(jsonObject));
int len = jsonArray.length();
for (int i = 0; i < len; i++) {
JSONObject o = jsonArray.getJSONObject(i);
AttendanceModel item = new AttendanceModel(
o.getString("id"),
o.getString("name"),
o.getString("roll"),
o.getString("class_id"),
o.getString("status"),
null
);
listItems.add(item);
//adapter = new MyAdapter(listItems,getApplicationContext());
recyclerView.setAdapter(attendanceAdapter); // setting them in list view
}
} catch (JSONException e) {
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
progressDialog.hide();
Toast.makeText(TeacherAttendanceActivity.this, "Failed", Toast.LENGTH_SHORT).show();
}
}) {
/** Passing some request headers* */
#Override
public Map getHeaders() throws AuthFailureError {
SQLiteHandler db = new SQLiteHandler(getApplicationContext());
HashMap<String,String> userDetail= db.getUserDetails();
String userToken = userDetail.get("token");
Log.d(TAG, String.valueOf(userToken));
HashMap headers = new HashMap();
headers.put("Accept", "application/json");
headers.put("Authorization", "Bearer "+userToken);
return headers;
}
};
stringRequest.setShouldCache(false);
VolleyRequest.getInstance(TeacherAttendanceActivity.this).addToRequestQueue(stringRequest);
}
// take attendance
private void request( final String classId,final String date,final String data ) {
progressDialog.setMessage("Taking attendance");
showDialog();
StringRequest strReq = new StringRequest(Request.Method.POST,
ApiConfig.URL_TEACHER_ATTENDANCE_STORE, new Response.Listener<String>() {
#Override
public void onResponse(String response) {
Log.d(TAG, "Login Response: " + response);
hideDialog();
try {
JSONObject jObj = new JSONObject(response);
boolean error = jObj.getBoolean("error");
// Check for error node in json
if (!error) {
String attendance = jObj.getString("Attendance");
Toast.makeText(TeacherAttendanceActivity.this, attendance, Toast.LENGTH_LONG).show();
finish();
} else {
// Error in login. Get the error message
String errorMsg = jObj.getString("message");
Toast.makeText(TeacherAttendanceActivity.this,
errorMsg, Toast.LENGTH_LONG).show();
}
} catch (JSONException e) {
// JSON error
e.printStackTrace();
Toast.makeText(TeacherAttendanceActivity.this, "Json error: " + e.getMessage(), Toast.LENGTH_LONG).show();
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Log.e(TAG, "Login Error: " + error.getMessage());
Toast.makeText(TeacherAttendanceActivity.this,
error.getMessage(), Toast.LENGTH_LONG).show();
hideDialog();
}
}) {
/** Passing some request headers* */
#Override
public Map getHeaders() throws AuthFailureError {
SQLiteHandler db = new SQLiteHandler(TeacherAttendanceActivity.this);
HashMap<String,String> userDetail= db.getUserDetails();
String userToken = userDetail.get("token");
Log.d(TAG, String.valueOf(userToken));
HashMap headers = new HashMap();
headers.put("Accept", "application/json");
headers.put("Authorization", "Bearer "+userToken);
return headers;
}
#Override
protected Map<String, String> getParams() {
// Posting parameters to login url
Map<String, String> params = new HashMap<String, String>();
params.put("class_id", classId);
params.put("date", date);
params.put("data", data);
return params;
}
};
strReq.setShouldCache(false);
// Adding request to request queue
VolleyRequest.getInstance(TeacherAttendanceActivity.this).addToRequestQueue(strReq);
}
private void showDialog() {
if (!progressDialog.isShowing())
progressDialog.show();
}
private void hideDialog() {
if (progressDialog.isShowing())
progressDialog.dismiss();
}
}
Model class
'model class for convenient '
public class AttendanceModel {
String id,name,roll,classId,previousAttendance,attendance;
public AttendanceModel(String id, String name,String roll, String classId,String previousAttendance,String attedance ){
this.id = id;
this.name = name;
this.classId =classId;
this.roll=roll;
this.attendance=attedance;
this.previousAttendance=previousAttendance;
}
public String getAttendance() {
return attendance;
}
public String getId() {
return id;
}
public String getName() {
return name;
}
public String getRoll() {
return roll;
}
public String getClassId() {
return classId;
}
public String getPreviousAttendance(){return previousAttendance;}
public void setId(String id) {
this.id = id;
}
public void setName(String name) {
this.name = name;
}
public void setRoll(String roll) {
this.roll = roll;
}
public void setClassId(String classId) {
this.classId = classId;
}
public void setPreviousAttendance(String previousAttendance) {
this.previousAttendance = previousAttendance;
}
public void setAttendance(String attendance) {
this.attendance = attendance;
}
}
Adapter class
' adapter class '
public class AttendanceAdapter extends RecyclerView.Adapter<AttendanceAdapter.ViewHolder> implements Filterable
{
// date
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
String currentDateandTime = sdf.format(new Date());
private static final String TAG = AttendanceAdapter.class.getSimpleName();
public static List<AttendanceModel> listItems;
private List<AttendanceModel> listItemsFiltered;
private Context context;
private ProgressDialog dialog;
private AttendanceAdapter.AttendanceAdapterListner listner;
private ProgressDialog pDialog;
private SQLiteHandler db;
public static JSONObject jo = new JSONObject();
public static JSONArray ja = new JSONArray();
public AttendanceAdapter(List<AttendanceModel> listItems, Context context, AttendanceAdapter.AttendanceAdapterListner listner) {
this.listItems = listItems;
this.listner=listner;
this.context = context;
this.listItemsFiltered =listItems;
// SqLite database handler
db = new SQLiteHandler(context);
// Progress dialog
pDialog = new ProgressDialog(context);
}
#Override
public Filter getFilter() {
return new Filter() {
#Override
protected FilterResults performFiltering(CharSequence charSequence) {
String charString = charSequence.toString();
if (charString.isEmpty()) {
listItemsFiltered = listItems;
} else {
List<AttendanceModel> filteredList = new ArrayList<>();
for (AttendanceModel row : listItems) {
// name match condition. this might differ depending on your requirement
// here we are looking for name or phone number match
if (row.getName().toUpperCase().contains(charSequence.toString().toUpperCase())||row.getName().toLowerCase().contains(charSequence.toString().toLowerCase())) {
filteredList.add(row);
}
}
listItemsFiltered = filteredList;
}
FilterResults filterResults = new FilterResults();
filterResults.values = listItemsFiltered;
return filterResults;
}
#Override
protected void publishResults(CharSequence charSequence, FilterResults filterResults) {
listItemsFiltered = (ArrayList<AttendanceModel>) filterResults.values;
notifyDataSetChanged();
}
};
}
public class ViewHolder extends RecyclerView.ViewHolder {
public TextView name;
public TextView roll;
public TextView previous;
RadioGroup radioAttendance;
RadioButton radioAttendancePresent,radioAttendanceAbsent;
public CardView card_view;
public ViewHolder(View itemView) {
super(itemView);
name= (TextView) itemView.findViewById(R.id.textViewAttendanceStudentName);
roll = (TextView) itemView.findViewById(R.id.textViewAttendanceStudentRoll);
previous = (TextView) itemView.findViewById(R.id.textViewAttendanceStudentPreviousStatus);
radioAttendance = itemView.findViewById(R.id.radioAttendance);
radioAttendancePresent =itemView.findViewById(R.id.radioAttendancePresent);
radioAttendanceAbsent =itemView.findViewById(R.id.radioAttendanceAbsent);
//card_view = (CardView) itemView.findViewById(R.id.class_card_view); // card view for on click method
itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick( View view) {
// send selected contact in callback
listner.onAttendanceAdapterSelected(listItemsFiltered.get(getAdapterPosition())); // selecting cardview and position (model)
}
});
radioAttendance.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(RadioGroup radioGroup, int i) {
//Toast.makeText(TeacherAttendanceActivity.this, toString(i), Toast.LENGTH_SHORT).show();
// Toast.makeText(context,"clicked at position"+i+" "+id+""+name,Toast.LENGTH_SHORT).show();
if(radioAttendancePresent.isChecked())
{
listItems.get(getAdapterPosition()).setAttendance("present");
}
else {
listItems.get(getAdapterPosition()).setAttendance("absent");
}
}
});
}
}
#Override
public AttendanceAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.attendance_list, parent, false);
return new AttendanceAdapter.ViewHolder(v);
}
#Override
public void onBindViewHolder (final AttendanceAdapter.ViewHolder holder, final int position) {
final AttendanceModel listItem = listItemsFiltered.get(position);
holder.name.setText(listItem.getName());
holder.roll.setText(listItem.getRoll());
holder.previous.setText(listItem.getPreviousAttendance());
}
public interface AttendanceAdapterListner {
void onAttendanceAdapterSelected(AttendanceModel model); // sending cardview to say the dialoge and model for sending context
}
#Override
public int getItemCount() {
return listItemsFiltered.size();
}
private void showDialog() {
if (!pDialog.isShowing())
pDialog.show();
}
private void hideDialog() {
if (pDialog.isShowing())
pDialog.dismiss();
}
}
Your problem would be solved by making small changes to your Recycler view adapter, please do not disable recyclable property, this makes your recycler view a glorified list view.
I can see you tried using a sparse boolean array to hold the state of the radio buttons, that is good but you do not need that too. The idea behind using a Sparse boolean array is to keep the state of each item in the recycler view so that when they are recycled you still have a reference to what the state of each item is.
In your adapter you already have something that we can use to know the state, that is the attendance property of your model, in that case, you can set the state of your checkboxes by checking if the attendance property is present or absent.
One more thing about your code is that you are using the onCheckChangedListener as a click event handler for your radio button, you should not use this because it responds to all check changed events, even if it is triggered from code and not from user action, so when you bind your view and you set any of your radio buttons as checked or unchecked, it calls this callback.
Here is a modified version of your ViewHolder class that solves this issue by applying the solution above.
public class ViewHolder extends RecyclerView.ViewHolder {
public TextView name;
public TextView roll;
public TextView previous;
RadioGroup radioAttendance;
RadioButton radioAttendancePresent, radioAttendanceAbsent;
public CardView card_view;
public ViewHolder(View itemView) {
super(itemView);
name = (TextView) itemView.findViewById(R.id.textViewAttendanceStudentName);
roll = (TextView) itemView.findViewById(R.id.textViewAttendanceStudentRoll);
previous = (TextView) itemView.findViewById(R.id.textViewAttendanceStudentPreviousStatus);
radioAttendance = itemView.findViewById(R.id.radioAttendance);
radioAttendancePresent = itemView.findViewById(R.id.radioAttendancePresent);
radioAttendanceAbsent = itemView.findViewById(R.id.radioAttendanceAbsent);
radioAttendancePresent.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
radioAttendancePresent.setChecked(true);
listItems.get(getAdapterPosition()).setAttendance("present");
}
});
radioAttendanceAbsent.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
radioAttendanceAbsent.setChecked(true);
listItems.get(getAdapterPosition()).setAttendance("absent");
}
});
}
void bind(int position) {
// use the sparse boolean array to check
if (listItems.get(position).getAttendance() != null) {
if (listItems.get(position).getAttendance().equals("present")) {
radioAttendancePresent.setChecked(true);
} else if (listItems.get(position).getAttendance().equals("absent")) {
radioAttendanceAbsent.setChecked(true);
}
} else {
radioAttendance.clearCheck();
}
name.setText(listItems.get(position).getName());
roll.setText(listItems.get(position).getRoll());
previous.setText(listItems.get(position).getPreviousAttendance());
}
}
Notice that we have separate click listener for each radio button and set the state in the list of items and just check that state when we are binding, also we have removed the onCheckChangedListener and the sparse boolean array, one last thing is that we made sure that when there is not state set for the attendance property, we just clear the radio buttons so that no one is selected the code is much simpler and works correctly now.
You have to initialize your RadioButton based on model state like below:
#Override
public void onBindViewHolder (final AttendanceAdapter.ViewHolder holder, final int position) {
final AttendanceModel listItem = listItemsFiltered.get(position);
holder.name.setText(listItem.getName());
holder.roll.setText(listItem.getRoll());
holder.previous.setText(listItem.getPreviousAttendance());
final String id =listItem.getId();
final String class_id =listItem.getClassId();
holder.radioAttendance.setOnCheckedChangeListener(null);
if(listItem.getAttendance().equalsIgnoreCase("present")) {
radioAttendancePresent.setChecked(true);
} else {
radioAttendancePresent.setChecked(false);
}
//Add listener here and remove from holder
holder.radioAttendance.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(RadioGroup radioGroup, int i) {
if(holder.radioAttendancePresent.isChecked()) {
listItemsFiltered.get(position).setAttendance("present");
} else {
listItemsFiltered.get(position).setAttendance("absent");
}
notifyDataSetChanged();
}
});
}

How to add new feed to recycleview at same time without scroll or refresh the view?

I have an activity in which I have used Recycle View to show all items as a list. On same activity I have given functionality to add new item. Everything is working fine. Items are adding in my database and its showing in list. I have added pagination on Recycle View it is also working fine. What I want that when user add new item at the same time when new data added to database but it is not updating in list. When user press back and again come on activity after that it is showing in list. I want to add add new item at same time without scroll the list or without go back.
TimelineActivity.java
public class TimelineActivity extends AppCompatActivity implements RecyclerView.OnScrollChangeListener {
private static final String TAG = MainActivity.class.getSimpleName();
private RecyclerView listView;
private RecyclerView.LayoutManager layoutManager;
private RecyclerView.Adapter adapter;
private TimeLineListAdapter listAdapter;
private List<TimeLineItem> timeLineItems;
private int requestCount = 1;
private ProgressDialog pDialog;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_timeline);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
listView = (RecyclerView) findViewById(R.id.list);
listView.setHasFixedSize(true);
layoutManager = new LinearLayoutManager(this);
listView.setLayoutManager(layoutManager);
btnPost = (Button) findViewById(R.id.btnPost);
//Adding an scroll change listener to recyclerview
listView.setOnScrollChangeListener(this);
// Progress dialog
pDialog = new ProgressDialog(this);
pDialog.setCancelable(false);
cd = new ConnectionDetector(this);
isInternetPresent = cd.isConnectingToInternet();
db = new SQLiteHandler(this);
// session manager
session = new SessionManager(this);
/*pref = getApplicationContext().getSharedPreferences("MayahudiPref", 0);
editor = pref.edit();*/
buttonClickEvent();
// Fetching user details from sqlite
HashMap<String, String> user = db.getUserDetails();
id = user.get("id");
token = user.get("token");
getData();
timeLineItems = new ArrayList<>();
adapter = new TimeLineListAdapter(timeLineItems, this);
listView.setAdapter(adapter);
Timer autoRefresh;
autoRefresh=new Timer();
autoRefresh.schedule(new TimerTask() {
#Override
public void run() {
runOnUiThread(new Runnable() {
public void run() {
getTimeLineData(token, "1");
}
});
}
}, 0, 2000);
}
public void getTimeLineData(final String token, final String page) {
String tag_string_req = "req_register";
// making fresh volley request and getting json
StringRequest strReq = new StringRequest(Request.Method.POST, AppConfig.timeline, new Response.Listener<String>() {
#Override
public void onResponse(String response) {
VolleyLog.d(TAG, "Response: " + response.toString());
if (response != null) {
try {
JSONObject jObj = new JSONObject(response);
boolean error = jObj.getBoolean("status");
String message = jObj.getString("message");
if (error) {
totalPages = jObj.getInt("totalPages");
pageCount = jObj.getInt("page");
int limit = jObj.getInt("limit");
parseJsonFeed(response);
}
} catch (Exception e) {
}
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
VolleyLog.d(TAG, "Error: " + error.getMessage());
}
}) {
#Override
protected Map<String, String> getParams() {
// Posting params to register url
Map<String, String> params = new HashMap<String, String>();
params.put("my_token", token);
params.put("page", page);
params.put("limit", "5");
return params;
}
};
// Adding request to request queue
AppController.getInstance().addToRequestQueue(strReq, tag_string_req);
}
private void parseJsonFeed(String response) {
try {
JSONObject jsonObj = new JSONObject(response);
JSONArray feedArray = jsonObj.getJSONArray("data");
for (int i = 0; i < feedArray.length(); i++) {
JSONObject feedObj = (JSONObject) feedArray.get(i);
TimeLineItem item = new TimeLineItem();
item.setId(feedObj.getInt("id"));
item.setName(feedObj.getString("name"));
item.setLname(feedObj.getString("lname"));
// Image might be null sometimes
String image = feedObj.isNull("image") ? null : feedObj
.getString("image");
if (image.equals("")) {
item.setImge(image);
} else {
item.setImge(AppConfig.storyPic + image);
}
item.setStatus(feedObj.getString("story_text"));
item.setProfilePic(AppConfig.profilePic + feedObj.getString("profile_pic"));
item.setTimeStamp(feedObj.getString("time_stamp"));
item.setIsLike(feedObj.getInt("is_like"));
item.setTotalLikes(feedObj.getString("total_likes"));
item.setTotalComment(feedObj.getString("total_comments"));
/*// url might be null sometimes
String feedUrl = feedObj.isNull("url") ? null : feedObj
.getString("url");
item.setUrl(feedUrl);*/
timeLineItems.add(item);
}
// notify data changes to list adapater
adapter.notifyDataSetChanged();
} catch (JSONException e) {
e.printStackTrace();
}
}
//This method will get data from the web API
private void getData() {
//Adding the method to the queue by calling the method getDataFromServer
getTimeLineData(token, String.valueOf(requestCount));
//Incrementing the request counter
requestCount++;
}
//This method would check that the recyclerview scroll has reached the bottom or not
private boolean isLastItemDisplaying(RecyclerView recyclerView) {
if (recyclerView.getAdapter().getItemCount() != 0) {
int lastVisibleItemPosition = ((LinearLayoutManager) recyclerView.getLayoutManager()).findLastCompletelyVisibleItemPosition();
if (lastVisibleItemPosition != RecyclerView.NO_POSITION && lastVisibleItemPosition == recyclerView.getAdapter().getItemCount() - 1)
return true;
}
return false;
}
#Override
public void onScrollChange(View v, int scrollX, int scrollY, int oldScrollX, int oldScrollY) {
//Ifscrolled at last then
if (isLastItemDisplaying(listView)) {
//Calling the method getdata again
getData();
}
}
public void buttonClickEvent() {
btnPost.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (isInternetPresent) {
String text = txtStatusBox.getText().toString().trim();
if (!text.isEmpty()) {
if (thumbnail != null) {
String image = getStringImage(thumbnail);
JSONObject student2 = new JSONObject();
try {
student2.put("size", "1000");
student2.put("type", "image/jpeg");
student2.put("data", image);
} catch (JSONException e) {
e.printStackTrace();
}
addStory(text, token, String.valueOf(student2));
} else {
addStory(text, token, "");
}
} else {
Toast.makeText(TimelineActivity.this, "Please add some text or image.", Toast.LENGTH_SHORT).show();
}
} else {
final SweetAlertDialog alert = new SweetAlertDialog(TimelineActivity.this, SweetAlertDialog.WARNING_TYPE);
alert.setTitleText("No Internet");
alert.setContentText("No connectivity. Please check your internet.");
alert.show();
}
}
});
btnCancel.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
txtStatusBox.setText("");
imgImageUpload.setImageBitmap(null);
imgImageUpload.setBackgroundResource(R.drawable.image);
Toast.makeText(TimelineActivity.this, message, Toast.LENGTH_SHORT).show();
slidingUpPanelLayout.setPanelState(SlidingUpPanelLayout.PanelState.COLLAPSED);
}
});
imgImageUpload.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
selectImage();
}
});
/*fab.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
myDialogFragment.show(getFragmentManager(), "MyDialogFragment");
//Toast.makeText(TimelineActivity.this, "Floating Button", Toast.LENGTH_SHORT).show();
}
});*/
}
private void addStory(final String story_text, final String token, final String image) {
// Tag used to cancel the request
String tag_string_req = "req_register";
pDialog.setMessage("Please wait ...");
showDialog();
StringRequest strReq = new StringRequest(Request.Method.POST, AppConfig.addStory, new Response.Listener<String>() {
#Override
public void onResponse(String response) {
hideDialog();
try {
JSONObject jObj = new JSONObject(response);
boolean error = jObj.getBoolean("status");
message = jObj.getString("message");
if (error) {
txtStatusBox.setText("");
imgImageUpload.setImageBitmap(null);
imgImageUpload.setBackgroundResource(R.drawable.image);
Toast.makeText(TimelineActivity.this, message, Toast.LENGTH_SHORT).show();
slidingUpPanelLayout.setPanelState(SlidingUpPanelLayout.PanelState.COLLAPSED);
} else {
// Error occurred in registration. Get the error
// message
String errorMsg = jObj.getString("message");
Toast.makeText(TimelineActivity.this, errorMsg, Toast.LENGTH_LONG).show();
}
} catch (JSONException e) {
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Toast.makeText(TimelineActivity.this, "Oops something went wrong...", Toast.LENGTH_LONG).show();
hideDialog();
}
}) {
#Override
protected Map<String
, String> getParams() {
// Posting params to register url
Map<String, String> params = new HashMap<String, String>();
params.put("my_token", token);
params.put("story_text", story_text);
params.put("image", image);
return params;
}
};
// Adding request to request queue
AppController.getInstance().addToRequestQueue(strReq, tag_string_req);
}
private void showDialog() {
if (!pDialog.isShowing())
pDialog.show();
}
private void hideDialog() {
if (pDialog.isShowing())
pDialog.dismiss();
}
}
TimeLineListAdapter.java
public class TimeLineListAdapter extends RecyclerView.Adapter<TimeLineListAdapter.ViewHolder> {
private List<TimeLineItem> timeLineItems;
String message, storyId, token;
private Context context;
ImageLoader imageLoader = AppController.getInstance().getImageLoader();
public TimeLineListAdapter(List<TimeLineItem> timeLineItems, Context context) {
super();
this.context = context;
this.timeLineItems = timeLineItems;
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.timeline_item, parent, false);
ViewHolder viewHolder = new ViewHolder(v);
return viewHolder;
}
#Override
public void onBindViewHolder(ViewHolder holder, final int position) {
//Getting the particular item from the list
TimeLineItem item = timeLineItems.get(position);
if (item.getTotalLikes().equals("0")){
holder.txtLike.setText("");
}else {
holder.txtLike.setText(item.getTotalLikes());
}
if (item.getTotalComment().equals("0")){
holder.txtComment.setText("");
}else {
holder.txtComment.setText("("+item.getTotalComment()+")");
}
if (item.getIsLike() == 0){
}else {
holder.imageLike.setImageBitmap(null);
holder.imageLike.setBackgroundResource(R.drawable.islike);
holder.txtLike.setTextColor(Color.parseColor("#3498db"));
}
holder.name.setText(item.getName() + " " + item.getLname());
/*Long.parseLong(item.getTimeStamp()),
System.currentTimeMillis(), DateUtils.SECOND_IN_MILLIS);*/
holder.timestamp.setText(item.getTimeStamp());
// Chcek for empty status message
if (!TextUtils.isEmpty(item.getStatus())) {
holder.statusMsg.setText(item.getStatus());
holder.statusMsg.setVisibility(View.VISIBLE);
} else {
// status is empty, remove from view
holder.statusMsg.setVisibility(View.GONE);
}
// Checking for null feed url
if (item.getUrl() != null) {
holder.url.setText(Html.fromHtml("<a href=\"" + item.getUrl() + "\">"
+ item.getUrl() + "</a> "));
// Making url clickable
holder.url.setMovementMethod(LinkMovementMethod.getInstance());
holder.url.setVisibility(View.VISIBLE);
} else {
// url is null, remove from the view
holder.url.setVisibility(View.GONE);
}
// user profile pic
holder.profilePic.setImageUrl(item.getProfilePic(), imageLoader);
// Feed image
if (item.getImge() != null) {
holder.feedImageView.setImageUrl(item.getImge(), imageLoader);
holder.feedImageView.setVisibility(View.VISIBLE);
holder.feedImageView
.setResponseObserver(new TimeLineImageView.ResponseObserver() {
#Override
public void onError() {
}
#Override
public void onSuccess() {
}
});
} else {
holder.feedImageView.setVisibility(View.GONE);
}
}
#Override
public int getItemCount() {
return timeLineItems.size();
}
class ViewHolder extends RecyclerView.ViewHolder{
TextView name, timestamp, statusMsg, url, txtLike, txtComment, txtCommentLabel;
NetworkImageView profilePic;
TimeLineImageView feedImageView;
ImageView imageLike;
//Initializing Views
public ViewHolder(View itemView) {
super(itemView);
name = (TextView) itemView.findViewById(R.id.name);
timestamp = (TextView) itemView.findViewById(R.id.timestamp);
statusMsg = (TextView) itemView.findViewById(R.id.txtStatusMsg);
url = (TextView) itemView.findViewById(R.id.txtUrl);
profilePic = (NetworkImageView) itemView.findViewById(R.id.profilePic);
feedImageView = (TimeLineImageView) itemView.findViewById(R.id.feedImage1);
imageLike = (ImageView) itemView.findViewById(R.id.imgLike);
txtLike = (TextView) itemView.findViewById(R.id.txtLike);
txtComment = (TextView) itemView.findViewById(R.id.txtComment);
txtCommentLabel = (TextView) itemView.findViewById(R.id.txtCommentLabel);
}
}
You have to notifiy dataset changed on listview when new feed is added so there are two things you can do :
Create a new TimeLineItem item when new feed is entered and add new item to it like this :
`
item.setStatus("New Status");
item.setProfilePic("New Profile Pic");
item.setTimeStamp("New TimeStamp");
item.setIsLike("True");
item.setTotalLikes("1000");
item.setTotalComment("2");
`
and then use timeLineItems.add(item) to add new item to ArrayList and call adapter.notifyDataSetChanged(); to get it in view .
2. Again create volley request and it will do it automatically but this is slower then above example.
If you have any query please ask .
You have to set this new list to the adapter.
You can create a setDataSet() method in your adapter and call it before notifydatasetchanged
Add below method in adapter
public void setDataSet(List<TimeLineItem> timeLineItems) {
this.timeLineItems = timeLineItems;
}
and call it before notifydatasetChanged like this:
adapter.setDataSet(timeLineItems);
adapter.notifyDataSetChanged();

I am using a git repo called LikeButton, but the state of my button keeps jumping around in my recyclerview?

I am using a git repo called LikeButton, but the state of my button keeps jumping around in my recyclerview? Here is the repo https://github.com/jd-alexander/LikeButton. Basically when I click on a recyclerview item, it sets a textview to the word true or false based on if the user liked the post or not, and this works. However, the state of my button is doing some weird stuff, it jumps around...
Here is my Adapter, is their anything wrong with it?
public class ViewpagerAdapter extends RecyclerView.Adapter<ViewpagerAdapter.ViewDashboard>{
private LayoutInflater mLayoutInflater;
private ArrayList<QuestionData> data = new ArrayList<>();
public ViewpagerAdapter(Context context) {
mLayoutInflater=LayoutInflater.from(context);
}
public void setBloglist(ArrayList<QuestionData> listBlogs) {
this.data = listBlogs;
notifyItemRangeChanged(0,listBlogs.size());
}
#Override
public ViewDashboard onCreateViewHolder(ViewGroup parent, int viewType) {
View view = mLayoutInflater.inflate(R.layout.customizejson, parent, false);
ViewDashboard viewholder = new ViewDashboard(view);
return viewholder;
}
#Override
public void onBindViewHolder(ViewDashboard holder, int position) {
QuestionData questionHolder = data.get(position);
holder.questionText.setText(questionHolder.getMtext());
//This sets the text, to a true or a false String
holder.mStudentVoted.setText(questionHolder.getVoters());
holder.mLikeButton.setTag(holder);
}
#Override
public int getItemCount() {
return data.size();
}
class ViewDashboard extends RecyclerView.ViewHolder {
private TextView questionText;
private LikeButton mLikeButton;
private TextView mStudentVoted;
public ViewDashboard(View itemView) {
super(itemView);
questionText = (TextView)itemView.findViewById(R.id.questionText);
mStudentVoted = (TextView)itemView.findViewById(R.id.studentVoted);
mLikeButton = (LikeButton)itemView.findViewById(R.id.like_button_viewpager);
mLikeButton.setOnLikeListener(new OnLikeListener() {
#Override
public void liked(LikeButton likeButton) {
Voting voting = new Voting(getAdapterPosition(),ViewpagerAdapter.this, questionId);
voting.onUpVote();
}
#Override
public void unLiked(LikeButton likeButton) {
Voting voting = new Voting(getAdapterPosition(),ViewpagerAdapter.this, questionId);
voting.onDownVote();
}
});
}
}
}
Voting Class
public class Voting {
private int adapterPosition;
private RecyclerView.Adapter adapter;
private String stringId;
private TextView studentVoted;
//TODO Trim Constructor
public Voting(int adapterPosition,final RecyclerView.Adapter adapter, TextView questionId, TextView studentVoted) {
stringId = questionId.getText().toString();
this.adapter = adapter;
this.studentVoted=studentVoted;
}
public void onUpVote() {
final RequestQueue mRequestQueue = VolleySingleton.getInstance().getRequestQueue();
StringRequest postVoteUp = new StringRequest(Request.Method.PUT, PUT_VOTE_UP, new Response.Listener<String>() {
#Override
public void onResponse(String response) {
System.out.println("Succesful Upvote The Students Value is " + studentVoted);
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
System.out.println("failed Upvote");
}
});
mRequestQueue.add(postVoteUp);
}
public void onDownVote() {
final RequestQueue mrequestQueue = VolleySingleton.getInstance().getRequestQueue();
//TODO Delete Token(inserted for student 3 for testing purposes)
StringRequest postVoteDown = new StringRequest(Request.Method.PUT, PUT_VOTE_DOWN, new Response.Listener<String>() {
#Override
public void onResponse(String response) {
//TODO OnResponse, must setLiked(False)
//Succesful downVote The Students Value is true
//studentVoted.setText("false");
System.out.println("Succesful downVote The Students Value is "+studentVoted);
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
System.out.println("failed downVote");
}
});
mrequestQueue.add(postVoteDown);
}
public void realTimeUpVoting(TextView textView){
String voteString= textView.getText().toString();
int voteNumber=Integer.parseInt(voteString)+1;
textView.setText("" + voteNumber);
}
public void realTimeDownVoting(TextView textView){
String voteString= textView.getText().toString();
int voteNumber=Integer.parseInt(voteString)-1;
textView.setText("" + voteNumber);
}
}
Json Request and Parsing Methods
public void JsonRequestMethod() {
mVolleySingleton = VolleySingleton.getInstance();
mRequestQueue = mVolleySingleton.getRequestQueue();
JsonArrayRequest request = new JsonArrayRequest(Request.Method.GET, URL_HOME, (String) null, new Response.Listener<JSONArray>() {
#Override
public void onResponse(JSONArray response) {
try {
mListblogs.clear();
mListblogs = new YourTask().execute(response).get();
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
}
});
mRequestQueue.add(request);
}
private ArrayList<QuestionData> parseJSONResponse(JSONArray response) {
if (!response.equals("")) {
try {
StringBuilder data = new StringBuilder();
for (int x = 0; x < response.length(); x++) {
JSONObject currentQuestions = response.getJSONObject(x);
JSONArray arrSubcategory = currentQuestions.optJSONArray("questions");
for (int y = 0; y < arrSubcategory.length(); y++) {
JSONObject objectSubcategory = arrSubcategory.getJSONObject(y);
String text = objectSubcategory.optString("text");
String studentId = objectSubcategory.optString("studentId");
String votes=objectSubcategory.optString("votes");
/*JSONArray cycles through the array of voters, when a user votes
their ID is added to the array.When they downvote, it is removed
*/
JSONArray voters= objectSubcategory.optJSONArray("voters");
QuestionData questionData = new QuestionData();
questionData.setMstudentId(studentId);
questionData.setMtext(text);
questionData.setVotes(votes);
questionData.setVoters(checkIfVoted(voters));
mQuestionDataArrayList.add(questionData);
}
}
} catch (JSONException e) {
e.printStackTrace();
}
}
return mQuestionDataArrayList;
}
private static String checkIfVoted(JSONArray jsonArray ) {
/*pass in a json Array, copy the array into ints, and if
the students Id is contained in the array return the string true
*/
int[] voteIds = new int[jsonArray.length()];
for(int i=0;i<voteIds.length;i++){
voteIds[i] = jsonArray.optInt(i);
}
for(int i=0;i<voteIds.length;i++){
if(voteIds[i]== Integer.parseInt(Login.getUserId())){
//TODO String was only used for Testing purposes, Convert to Boolean later
return "true";
}
}
return "false";
}
you are currently only updating the textview which is why your recycleview changes state when scrolling.
Should change your voting class and pass the question Data rather textview
public Voting(int adapterPosition,final RecyclerView.Adapter adapter, TextView questionId, TextView studentVoted) {
change to
public Voting(int adapterPosition,final RecyclerView.Adapter adapter, QuestionData questionData, TextView studentVoted) {
// make other changes for the data
and then in
public void realTimeUpVoting(QuestionData questionData){
data.votes++ //something like that. idont know your model
// now call back using interface the recyleview data changed method so it updates the count in recycleview automatically.
Edit
passing the question Data in click button
class ViewDashboard extends RecyclerView.ViewHolder {
public int position
public void onBindViewHolder(ViewDashboard holder, int position) {
holder.position = position
}
public void liked(LikeButton likeButton) {
QuestionData questionHolder = data.get(position);

Categories