I want a help from you guys can anybody solve this problem i am trying to insert three rows into mysql table but right here only two rows are visible and third on get visible on scrolling down so when i click submit it gets me an error it inserts 2 visible rows on the screen and throws a null pointer expection on the 3 row that is not visible can some one help me to get the data from the view that is not visible i know its recyclerview and it re uses the view i know the mechanism i just want the solution from some that so that the 3 row that is not visible can get added successfully to the database
Here is an image for that :
https://imgur.com/a/rkARs
My recyclerview adapter code:
public class MyAdapterClosing extends RecyclerView.Adapter<MyAdapterClosing.myViewHolder> {
private Context context;
private List<DataofClosing> student;
public MyAdapterClosing(Context context, List<DataofClosing> student){
this.context = context;
this.student = student;
}
#Override
public myViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.layoutclosing,parent,false);
return new myViewHolder(itemView);
}
#Override
public void onBindViewHolder(myViewHolder holder, int position) {
DataofClosing s = student.get(position);
holder.brand.setText(s.Brandname);
}
public void updateList(List<RecyclerviewWholesale> student)
{
student = student;
notifyDataSetChanged();
}
public void addItem(int position, DataofClosing stud)
{
student.add(position, stud);
notifyItemInserted(position);
}
public void removeItem(int position) {
student.remove(position);
notifyItemRemoved(position);
notifyItemRangeChanged(position, student.size());
}
#Override
public int getItemCount() {
return student.size();
}
#Override
public int getItemViewType(int position) {
return position;
}
public class myViewHolder extends RecyclerView.ViewHolder{
TextView brand;
EditText qts,pts,nip,ml90;
public myViewHolder(View itemView) {
super(itemView);
brand = (TextView) itemView.findViewById(R.id.brand);
qts = (EditText) itemView.findViewById(R.id.qts);
pts = (EditText) itemView.findViewById(R.id.pts);
nip = (EditText) itemView.findViewById(R.id.nip);
ml90 = (EditText) itemView.findViewById(R.id.ml90);
String qtss = qts.getText().toString();
String ptss = pts.getText().toString();
String nipp = nip.getText().toString();
String ml900 = ml90.getText().toString();
DataofClosing dataofClosing = new DataofClosing();
dataofClosing.qts = qtss;
dataofClosing.pts = ptss;
dataofClosing.nip = nipp;
dataofClosing.ml90 = ml900;
}
}
}
Inserting code in the main activity is:
class Insertclosing extends AsyncTask<String, String, String> {
/**
* Before starting background thread Show Progress Dialog
*/
#Override
protected void onPreExecute() {
super.onPreExecute();
}
/**
* Creating product
*/
protected String doInBackground(String... args) {
for (int i = 0; i < mAdapter.getItemCount(); i++) {
rcData = data.get(i);
View view1 = closingService.getChildAt(i);
EditText nameEditText = (EditText) view1.findViewById(R.id.qts);
String name = nameEditText.getText().toString();
EditText ptss = (EditText) view1.findViewById(R.id.pts);
String pts = ptss.getText().toString();
EditText nipp = (EditText) view1.findViewById(R.id.nip);
String nip = nipp.getText().toString();
EditText ml900 = (EditText) view1.findViewById(R.id.ml90);
String ml90 = ml900.getText().toString();
// Building Parameters
List<NameValuePair> params = new ArrayList<NameValuePair>();
params.add(new BasicNameValuePair("brand", rcData.Brandname));
params.add(new BasicNameValuePair("quantity", name));
params.add(new BasicNameValuePair("discount",pts));
params.add(new BasicNameValuePair("ammount",nip ));
// getting JSON Object
// Note that create product url accepts POST method
JSONObject json = jsonParser.makeHttpRequest(url_insert_product_sales,
"POST", params);
// check log cat fro response
Log.d("Create Response", json.toString());
// check for success tag
try {
int success = json.getInt(TAG_SUCCESS);
if (success == 1) {
/*runOnUiThread(new Runnable() {
public void run() {
Toast.makeText(ChangeAddress.this, "Order Placed Successfully", Toast.LENGTH_SHORT).show();
}
});*/
} else {
runOnUiThread(new Runnable() {
public void run() {
Toast.makeText(closing.this, "Try Again", Toast.LENGTH_SHORT).show();
}
}); // failed to create product
}
} catch (JSONException e) {
e.printStackTrace();
}
}
return null;
}
/**
* After completing background task Dismiss the progress dialog
**/
protected void onPostExecute(String file_url) {
Toast.makeText(closing.this, "Closing added Successfully", Toast.LENGTH_SHORT).show();
}
}
I found a solution for this.
adapter has two methods
onViewAttachedToWindow(RecyclerView.ViewHolder holder){}
and
onViewDetachedFromWindow(RecyclerView.ViewHolder holder){}
Cretae a HashMap in your adapter
public HashMap<Integer, RecyclerView.ViewHolder> holderHashMap = new HashMap<>();
and add holder into it in onDetach and remove the same onAttach. Like this.
#Override
public void onViewDetachedFromWindow(RecyclerView.ViewHolder holder) {
holderHashMap.put(holder.getAdapterPosition(),holder);
super.onViewDetachedFromWindow(holder);
}
#Override
public void onViewAttachedToWindow(RecyclerView.ViewHolder holder) {
holderHashMap.remove(holder.getAdapterPosition());
super.onViewAttachedToWindow(holder);
}
to access all viewHolders including the invisible ones use this in you activity.
for(int i =0; i<recyclerView.getItemCount();i++){
RecyclerView.ViewHolder holder = surveyQuestionList.findViewHolderForAdapterPosition(i);
if(holder == null){
holder = adapter.holderHashMap.get(i);
}
}
This is the best solution so far I have come up with.
Let me know if it works for you.
Related
I am designing a live quiz app that fetches data from server and question are displayed in a RecyclerView that contains a question and four options. Now when I select one option for a given question, it is selected properly but at the same time, the corresponding option for other question is selected automatically.
Screenshot of the item selection issue is the following.
I have designed Data Model Class and RecylerView Adapter (with the help of #Reaz Murshed) but have been stuck with the code
My Data Model Class is :
//DmLiveQuiz
public class DmLiveQuiz {
String testId;
int questionId;
String question;
String optA;
String optB;
String optC;
String optD;
String answer;
String explain;
...
}
My Adapter Class is //LiveTestAdapter
public class LiveTestAdapter extends RecyclerView.Adapter<LiveTestAdapter.CustomViewHolder> {
private List<DmLiveQuiz> questionList;
private int[] answerList; // Get a list of your answers here.
private DmLiveQuiz questionsList;
private Context context;
public List<Integer> myResponse = new ArrayList<Integer>();
public int qno;
public LiveTestAdapter(List<DmLiveQuiz> questionList, Context context) {
this.questionList = questionList;
this.context = context;
}
#NonNull
#Override
public CustomViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.live_quiz_display_format, parent, false);
return new CustomViewHolder(itemView);
}
#Override
public void onBindViewHolder(#NonNull final CustomViewHolder holder, int position) {
questionsList = questionList.get(holder.getAdapterPosition());
holder.tvQNo.setText(questionsList.getQuestionId() + "");
holder.tvquestion.getLayoutParams().width = LinearLayout.LayoutParams.WRAP_CONTENT;
holder.tvquestion.setText(questionsList.getQuestion());
holder.optA.setText(questionsList.getOptA());
holder.optB.setText(questionsList.getOptB());
holder.optC.setText(questionsList.getOptC());
holder.optD.setText(questionsList.getOptD());
// Now you need to modify the backgrounds of your option buttons like the following.
if (answerList[position] == 1) holder.optA.setBackgroundResource(R.drawable.button_border);
else holder.optA.setBackgroundResource(R.drawable.button_question_style);
if (answerList[position] == 2) holder.optB.setBackgroundResource(R.drawable.button_border);
else holder.optB.setBackgroundResource(R.drawable.button_question_style);
if (answerList[position] == 3) holder.optC.setBackgroundResource(R.drawable.button_border);
else holder.optC.setBackgroundResource(R.drawable.button_question_style);
if (answerList[position] == 4) holder.optD.setBackgroundResource(R.drawable.button_border);
else holder.optD.setBackgroundResource(R.drawable.button_question_style);
holder.optA.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
holder.optA.setBackgroundResource(R.drawable.button_border);
answerList[position] = 1; // Selected first option which is A
});
holder.optB.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
holder.optB.setBackgroundResource(R.drawable.button_border);
answerList[position] = 2; // Selected second option which is B
Toast.makeText(context, "Position :" + holder.getAdapterPosition(), Toast.LENGTH_SHORT).show();
}
});
holder.optC.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
holder.optC.setBackgroundResource(R.drawable.button_border);
answerList[position] = 3; // Selected third option which is C
Toast.makeText(context, "Position :" + holder.getAdapterPosition(), Toast.LENGTH_SHORT).show();
}
});
holder.optD.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
holder.optD.setBackgroundResource(R.drawable.button_border);
answerList[position] = 4; // Selected fourth option which is D
Toast.makeText(context, "Position :" + holder.getAdapterPosition(), Toast.LENGTH_SHORT).show();
}
});
holder.tvClear.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
holder.optA.setBackgroundResource(R.drawable.button_question_style);
holder.optB.setBackgroundResource(R.drawable.button_question_style);
holder.optC.setBackgroundResource(R.drawable.button_question_style);
holder.optD.setBackgroundResource(R.drawable.button_question_style);
answerList[position] = 0; // Clear the value in the answerList
}
});
}
// Use this function to set the question list in the adapter
public void setQuestionList(List<DmLiveQuiz> questionList) {
this.questionList = questionList;
this.answerList = new int[questionList.size()]; // This initializes the answer list having the same size as the question list
notifyDataSetChanged();
}
#Override
public int getItemCount() {
return questionList.size();
}
public class CustomViewHolder extends RecyclerView.ViewHolder {
TextView tvquestion, tvClear, tvQNo;
Button optA, optB, optC, optD;
public CustomViewHolder(View itemView) {
super(itemView);
tvQNo = (TextView) itemView.findViewById(R.id.tvLiveQuizQuestionNo);
tvquestion = (TextView) itemView.findViewById(R.id.tvLiveQuizQuestion);
optA = (Button) itemView.findViewById(R.id.buttonOptionA);
...///
}
}
}
And The Activity where Recyclerview is implemented is
recyclerView = (RecyclerView) findViewById(R.id.recyclerViewLiveTest);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
quizList = new ArrayList<>();
adapter = new LiveTestAdapter(quizList, getApplicationContext());
linearLayoutManager = new LinearLayoutManager(this);
linearLayoutManager.setOrientation(LinearLayoutManager.VERTICAL);
dividerItemDecoration = new DividerItemDecoration(recyclerView.getContext(), linearLayoutManager.getOrientation());
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(linearLayoutManager);
// recyclerView.addItemDecoration(dividerItemDecoration);
recyclerView.setAdapter(adapter);
getData();
......
The method for fetching JSON data is getdata() as given below which fetches data from server correctly...
private void getData() {
JsonArrayRequest jsonArrayRequest = new JsonArrayRequest(quiz_url, new Response.Listener<JSONArray>() {
#Override
public void onResponse(JSONArray response) {
for (int i = 0; i < response.length(); i++) {
try {
JSONObject jsonObject = response.getJSONObject(i);
DmLiveQuiz liveQuiz = new DmLiveQuiz();
...
...
quizList.add(liveQuiz);
} catch (JSONException e) {
e.printStackTrace();
progressDialog.dismiss();
}
}
adapter.notifyDataSetChanged();
..........
}
Now When I run App, it shows index=0 i.e. ArrayOutOfIndexException is generated.. I am not able to call public void setQuestionList(List<DmLiveQuiz> questionList) method of LiveQuizAdapter class from my activity.. Please Help
Initially you are setting empty list in the adapter. After getting value from JsonArrayRequest then need to update adapter using new list.
Update onBindViewHolder:
#Override
public void onBindViewHolder(#NonNull final CustomViewHolder holder, int position) {
DmLiveQuiz dmLiveQuiz= questionList.get(position);
if(dmLiveQuiz!=null){
// do whatever you want. put all code here.}
}
Update your adapter:
#Override
public void onResponse(JSONArray response) {
for (int i = 0; i < response.length(); i++) {
// put all code here
quizList.add(liveQuiz);}
adapter.setQuestionList(quizList);
adapter.notifyDataSetChanged();
}
you have to add a boolean value in DmLiveQuiz model class :-
boolean isSelected ;
and then set a check in your adapter while your are showing the answer is selected or not :-
if(DmLiveQuiz.isSelectd){
// this is the selected answer
}else {
// in case don't selected
}
and change the boolean value on adapter item Click
I have a RecyclerView and each row has a EditText also. I am adding item to RecyclerView by searching them and then I type the quantity in the edit text. Then I send it to the server to store using json format. Item add is working perfectly. There is no edit text value swapping problem also when scrolling. I can display 5 rows in the screen.
Problem is when I send item to the server, edit text values in bottom rows get the same after 5th row.
These are the rows I am adding to the recyclerview.Printed List that send to the server.
Item : 7.50-15 10PR FM CEAT Quantity : 1
Item : 5.60-15 04PR K 511 CEAT Quantity : 2
Item : 2.75-18 04PR SECURA F85 CEAT (F) Quantity : 3
Item : 3.00-17 06PR SECURA ZOOM CEAT (R) Quantity : 4
Item : 6.50-14 10PR FM CEAT Quantity : 5
Item : 5.00-12 04PR GRIP MASTER CEAT Quantity : 5
Item : 4.00-08 06PR AUTO RAJA RPG Quantity : 5
Item : 9.00-20 14PR CEAT CLT LUG Quantity : 5
Item : 8.25-20 14PR TR PLUS SUNTRAC Quantity : 5
Item : 7.00-15 12PR FM CEAT Quantity : 5
After the 5th position Quantity is the same. My input value is not coming.
This is my SelectItem class -
public class SelectItem extends AppCompatActivity implements SelectItemAdapter.OnItemClickListener {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.select_item);
vollySingleton = VollySingleton.getsInstance();
requestQueue = vollySingleton.getmRequestQueue();
toolbar = (Toolbar) findViewById(R.id.app_bar);
setSupportActionBar(toolbar);
getSupportActionBar().setHomeButtonEnabled(false);
getSupportActionBar().setDisplayHomeAsUpEnabled(false);
myRecyclerView = (RecyclerView) findViewById(R.id.selectedItemRecyclerView);
linearLayoutManager = new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false);
spinner = (Spinner) findViewById(R.id.selectDistribChannel);
arrayAdapter = new ArrayAdapter<String>(this, R.layout.spinner_item, YourDealerListFragment.disChannel);
arrayAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinner.setAdapter(arrayAdapter);
selectedDisChannel = spinner.getSelectedItem().toString();
sqLiteHandler = new SQLiteHandler(getApplicationContext());
myRecyclerViewAdapter = new SelectItemAdapter(this);
myRecyclerViewAdapter.setOnItemClickListener(this);
myRecyclerView.setAdapter(myRecyclerViewAdapter);
myRecyclerView.setLayoutManager(linearLayoutManager);
myRecyclerViewAdapter.notifyDataSetChanged();
dealerName = DealerListAdapter.getDealerName();
dealerID = DealerListAdapter.getDealerID();
repID = DealerListAdapter.getRepID();
//order number
orderId = "70000001";
if (newOrderId == null) {
newOrderId = orderId;
}
bAdd = (Button) findViewById(R.id.bAdd);
bAdd.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (myRecyclerViewAdapter.getItemCount() != 0) {
new AlertDialog.Builder(SelectItem.this)
.setTitle("Confirmation")
.setMessage("Do you want to send?")
.setIcon(android.R.drawable.ic_dialog_alert)
.setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
checkOrderNo();
}
})
.setNegativeButton(android.R.string.no, null).show();
} else {
Toast.makeText(getApplicationContext(), "Empty List", Toast.LENGTH_SHORT).show();
}
}
});
//textView.setText(dealerName);
getSupportActionBar().setTitle(dealerName);
final AutoCompleteTextView acTextView = (AutoCompleteTextView) findViewById(R.id.autoCompleteTextView);
adapter = new MaterialSuggestionAdapter(getApplicationContext());
acTextView.setAdapter(adapter);
acTextView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Product result = adapter.getItem(position);
String newName = result.getMatName().toString();
String newQty = String.valueOf(result.getMatQuantity());
String newPCode = result.getMatNo().toString();
String newPlant = result.getMatPlant().toString();
if (!newName.equals("")) {
if (myRecyclerViewAdapter.getItemCount() > 0) {
if (!isPresent(newPlant, newPCode, myRecyclerViewAdapter)) {
myRecyclerViewAdapter.add(1, newName, newQty, newPCode, newPlant);
} else {
Toast.makeText(getApplicationContext(), "Product Already in the List", Toast.LENGTH_SHORT).show();
}
} else {
myRecyclerViewAdapter.add(0, newName, newQty, newPCode, newPlant);
}
} else {
Toast.makeText(getApplicationContext(), "Invalied Item!", Toast.LENGTH_SHORT).show();
}
acTextView.setText("");
}
});
}
private boolean isPresent(String newPlant, String newPCode, SelectItemAdapter myRecyclerViewAdapter) {
boolean isPresent = false;
for (int i = 0; i < myRecyclerViewAdapter.getItemCount(); i++) {
if (newPCode.equalsIgnoreCase(myRecyclerViewAdapter.getItemPCode(i).toString()) && newPlant.equalsIgnoreCase(myRecyclerViewAdapter.getItemPlant(i).toString())) {
isPresent = true;
break;
}
}
return isPresent;
}
//send items for one order
private class SendItemAsync extends AsyncTask<Void, Void, Void> {
#Override
protected void onPreExecute() {
}
#Override
protected Void doInBackground(Void... arg0) {
//Create JSON string start
json_string = "{\"sending_items\":[";
for (int i = 0; i < myRecyclerViewAdapter.getItemCount(); i++) {
/* if (myRecyclerView.findViewHolderForLayoutPosition(i) instanceof SelectItemAdapter.ItemHolder) {
SelectItemAdapter.ItemHolder childHolder = (SelectItemAdapter.ItemHolder) myRecyclerView.findViewHolderForLayoutPosition(i);
numberPickerNumber = childHolder.getQtyNumber();
}*/
getNumPicNumber(i);
//Repeat and loop this until all objects are added (and add try+catch)
try {
JSONObject obj_new = new JSONObject();
obj_new.put("order_no", orderIdForItemTable);
obj_new.put("items", myRecyclerViewAdapter.getItemName(i).toString());
obj_new.put("items_no", myRecyclerViewAdapter.getItemPCode(i).toString());
obj_new.put("plant", myRecyclerViewAdapter.getItemPlant(i).toString());
obj_new.put("quantity", numberPickerNumber);
json_string = json_string + obj_new.toString() + ",";
} catch (JSONException e) {
e.printStackTrace();
}
}
//Close JSON string
json_string = json_string.substring(0, json_string.length() - 1);
json_string += "]}";
HttpParams httpParams = new BasicHttpParams();
HttpConnectionParams.setConnectionTimeout(httpParams, 3500);
HttpConnectionParams.setSoTimeout(httpParams, 1000);
HttpClient client = new DefaultHttpClient(httpParams);
String url = AppConfig.URL_ITEMS_SEND;
HttpPost request = new HttpPost(url);
try {
request.setEntity(new ByteArrayEntity(json_string.getBytes("UTF8")));
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
request.setHeader("json", json_string);
request.setHeader("Accept", "application/json");
request.setHeader("Content-Type", "application/json");
Log.i("", "excuting request");
HttpResponse response = null;
try {
response = client.execute(request);
Log.d("HTTP Response", response.getStatusLine().toString());
try {
String responseBody = EntityUtils.toString(response.getEntity());
Log.d("Server Response", responseBody);
} catch (IOException e) {
e.printStackTrace();
}
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(Void aVoid) {
finish();
Bundle basket = new Bundle();
basket.putString("dealerName", dealerName);
basket.putString("orderNo", newOrderId);
basket.putString("jsonString", json_string);
Intent intent = new Intent(SelectItem.this, ItemCart.class);
intent.putExtras(basket);
startActivity(intent);
finish();
//Toast.makeText(getApplicationContext(), json_string, Toast.LENGTH_LONG).show();
}
}
private String getNumPicNumber(int i) {
if (myRecyclerView.findViewHolderForLayoutPosition(i) instanceof SelectItemAdapter.ItemHolder) {
SelectItemAdapter.ItemHolder childHolder = (SelectItemAdapter.ItemHolder) myRecyclerView.findViewHolderForLayoutPosition(i);
numberPickerNumber = childHolder.getQtyNumber();
}
return numberPickerNumber;
}
#Override
public void onItemClick(SelectItemAdapter.ItemHolder item, int position) {
Toast.makeText(this,
"Remove " + position + " : " + item.getItemName(),
Toast.LENGTH_SHORT).show();
myRecyclerViewAdapter.remove(position);
}
private void checkOrderNo() {
showDialog();
DateFormat df = new SimpleDateFormat("yyyy/MM/dd hh:mm:ss");
final String nowDate = df.format(new Date());
//final day of the month
Date today = new Date();
Calendar calendar = Calendar.getInstance();
calendar.setTime(today);
calendar.add(Calendar.MONTH, 1);
calendar.set(Calendar.DAY_OF_MONTH, 1);
calendar.add(Calendar.DATE, -1);
Date lastDayOfMonth = calendar.getTime();
DateFormat sdf = new SimpleDateFormat("yyyy/MM/dd");
final String lastDate = sdf.format(lastDayOfMonth);
Log.d("Last day ", sdf.format(lastDayOfMonth) + " // Today" + nowDate);
// Tag used to cancel the insert
String tag_string_req = "req_insert";
final StringRequest strReq = new StringRequest(Request.Method.POST,
AppConfig.URL_ITEM_DETAILS_SEND, new Response.Listener<String>() {
#Override
public void onResponse(String response) {
hideDialog();
try {
JSONObject jObj = new JSONObject(response);
if (jObj.names().get(0).equals("found")) {
newOrderId = jObj.getString("found").toString();
orderIdForItemTable = newOrderId;
new SendItemAsync().execute();
Log.d(TAG, "newOrderId: " + newOrderId);
Log.d(TAG, "New repID 2 inserted into sqlite: " + newOrderId + " " + nowDate);
sqLiteHandler.addItemDetails(newOrderId, repID, dealerID, nowDate, lastDate, selectedDisChannel);
} else {
Toast.makeText(getApplicationContext(), "Invalied Request", Toast.LENGTH_SHORT).show();
}
} catch (JSONException e) {
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Log.e(TAG, "Inserting Error: " + error.getMessage());
Toast.makeText(getApplicationContext(), error.getMessage(), Toast.LENGTH_LONG).show();
}
}) {
#Override
protected Map<String, String> getParams() {
// Posting params to register url
Map<String, String> params = new HashMap<String, String>();
params.put("order_no", orderId);
params.put("repID", repID);
params.put("dealerID", dealerID);
params.put("nowDate", nowDate);
params.put("lastDate", lastDate);
params.put("disChannel", selectedDisChannel);
return params;
}
};
strReq.setRetryPolicy(new DefaultRetryPolicy(6000, 1,
DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));
// Adding request to request queue
AppController.getInstance().addToRequestQueue(strReq, tag_string_req);
}
}
My Adapter class.
public class SelectItemAdapter extends RecyclerView.Adapter<SelectItemAdapter.ItemHolder> {
private List<String> itemsName, itemsQty, itemsPCode, itemPlant;
private OnItemClickListener onItemClickListener;
private LayoutInflater layoutInflater;
private RecyclerView myRecyclerview;
public SelectItemAdapter(Context context) {
layoutInflater = LayoutInflater.from(context);
itemsName = new ArrayList<String>();
itemsQty = new ArrayList<String>();
itemsPCode = new ArrayList<String>();
itemPlant = new ArrayList<String>();
}
#Override
public SelectItemAdapter.ItemHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = layoutInflater.inflate(R.layout.custom_row_selected_item, parent, false);
return new ItemHolder(itemView, this);
}
#Override
public void onBindViewHolder(SelectItemAdapter.ItemHolder holder, int position) {
holder.setItemName(itemsName.get(position));
holder.setItemQty(itemsQty.get(position));
holder.setItemPCode(itemsPCode.get(position));
holder.setItemPlant(itemPlant.get(position));
}
#Override
public int getItemViewType(int position) {
return position;
}
#Override
public int getItemCount() {
return itemsName.size();
}
public Object getItemName(int position) {
return itemsName.get(position);
}
public Object getItemPCode(int position) {
return itemsPCode.get(position);
}
public Object getItemPlant(int position) {
return itemPlant.get(position);
}
public void setOnItemClickListener(OnItemClickListener listener) {
onItemClickListener = listener;
}
public OnItemClickListener getOnItemClickListener() {
return onItemClickListener;
}
public interface OnItemClickListener {
public void onItemClick(ItemHolder item, int position);
}
public void add(int location, String iName, String iQty, String iPCode, String iPlant) {
itemsName.add(location, iName);
itemsQty.add(location, iQty);
itemsPCode.add(location, iPCode);
itemPlant.add(location, iPlant);
notifyItemInserted(location);
}
public void remove(int location) {
if (location >= itemsName.size())
return;
itemsName.remove(location);
notifyItemRemoved(location);
}
public static class ItemHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
private SelectItemAdapter parent;
TextView textItemName, txtPCode, txtAvailableQty, txtTempQty, txtPlant;
Button bRemove;
EditText numPicker;
public ItemHolder(View itemView, SelectItemAdapter parent) {
super(itemView);
this.parent = parent;
textItemName = (TextView) itemView.findViewById(R.id.txtProductName);
txtAvailableQty = (TextView) itemView.findViewById(R.id.txtAvailbleQty);
txtPCode = (TextView) itemView.findViewById(R.id.txtPCode);
txtPlant = (TextView) itemView.findViewById(R.id.txtPlant);
bRemove = (Button) itemView.findViewById(R.id.bRemove);
numPicker = (EditText) itemView.findViewById(R.id.numberPicker);
bRemove.setOnClickListener(this);
}
public void setItemName(CharSequence name) {
textItemName.setText(name);
}
public void setItemQty(CharSequence name) {
txtAvailableQty.setText(name);
}
public void setItemPCode(CharSequence name) {
txtPCode.setText(name);
}
public void setItemPlant(CharSequence name) {
txtPlant.setText(name);
}
public String getQtyNumber() {
return numPicker.getText().toString();
}
public CharSequence getItemName() {
return textItemName.getText();
}
public CharSequence getItemPCode() {
return txtPCode.getText();
}
#Override
public void onClick(View v) {
final OnItemClickListener listener = parent.getOnItemClickListener();
if (listener != null) {
listener.onItemClick(this, getPosition());
}
}
}
}
#Override
public void onBindViewHolder(#NonNull MyViewHolder holder, int position, #NonNull List<Object> payloads) {
super.onBindViewHolder(holder, position, payloads);
holder.setIsRecyclable(false);// set this in your adapter class as like it is
}
Override getItemViewType method
override fun getItemViewType(position: Int): Int {
return position
}
RecyclerView creates only as many view holders as are needed to display the on-screen portion of the dynamic content, plus a few extra. As the user scrolls through the list, the RecyclerView takes the off-screen views and rebinds them to the data which is scrolling onto the screen
// Items for recycler View
//binding data
private ArrayList<Data> Items;
//HashMap to store editText text afterTextChanged
//each editext in RecyclerView contains Unique Key And Value
private HashMap<String,String> sourceData=new HashMap<>();
Refer This RecyclerView Program
public class DataRecyclerView extends RecyclerView.Adapter<DataRecyclerView.DataViewHolder> {
private Context context;
// Items for recycler View
//binding data
private ArrayList<Data> Items;
private LayoutInflater layoutInflater;
//HashMap to store editText text afterTextChanged
//each editext in RecyclerView contains Unique Key And Value
private HashMap<String,String> sourceData=new HashMap<>();
DataRecyclerView(Context context,ArrayList<Data> Items)
{
this.Items=Items;
this.context=context;
layoutInflater=LayoutInflater.from(context);
}
#NonNull
#Override
public DataViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
//DataBinding is used to bind Data
DataViewHolderBinding binding= DataBindingUtil.inflate(layoutInflater, R.layout.template,parent,false);
return new DataViewHolder(binding);
}
#Override
public void onBindViewHolder(#NonNull DataViewHolder holder, int position) {
//Pass Data pojo to Holder
holder.bindData(Items.get(position));
}
#Override
public int getItemCount() {
return Items.size();
}
class DataViewHolder extends RecyclerView.ViewHolder {
private EditText amount;
DataViewHolder(DataViewHolderBinding itemView) {
super(itemView.getRoot());
binding=itemView;
amount=binding.PayAmount;
}
void bindData(Data data)//Data pojo for DataBinding
{
if(binding!=null) {
// data will automatically set to textViews In DataBinding
binding.setData(data);
//every time data binds to views
//get text of respective edittext and assign to that current edittext
if (sourceData.containsKey((String.valueOf(getAdapterPosition())))) {// checks current editText key is availible or not
if (data.getIDNumber().equals(Items.get(getAdapterPosition()).getData.getIDNumber())) { //
amount.setText(sourceData.get((String.valueOf(getAdapterPosition()))).getAmount());
}else
{
if (data.getIDNumber().equals(Items.get(getAdapterPosition()).getData.getIDNumber())) { //
amount.setText(null);
}
amount.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) {
}
#Override
public void afterTextChanged(Editable s) {
//when user enter text into edittext
//editetext key already availible in sourceData
// then update the value to hashmap sourceData
if (sourceData.containsKey(String.valueOf(getAdapterPosition()))) {
if (data.getIDNumber().equals(Items.get(getAdapterPosition()).getData.getIDNumber())) { //
if (!s.toString().trim().isEmpty()) {
if (!s.toString().trim().equals("0")) {
sourceData.put(String.valueOf(getAdapterPosition()),s.toString().trim());
} else {
sourceData.put(String.valueOf(getAdapterPosition()), s.toString().trim();
}
} else {
sourceData.put(String.valueOf(getAdapterPosition()),null );
}
}
}
else {
//when user enter text into edittext for the first time
//check for current Data pojo IDNumber with getAdapterPosition Items Data pojo IDNumber
//if it equal
//then we store text into hashmap for specific edittext by using adapterPosition as key
if (data.getIDNumber().equals(Items.get(getAdapterPosition()).getData.getIDNumber())) { //
if (!s.toString().trim().isEmpty()) {
if (!s.toString().trim().equals("0")) {
sourceData.put(String.valueOf(getAdapterPosition()),s.toString().trim());
} else {
sourceData.put(String.valueOf(getAdapterPosition()), s.toString().trim();
}
} else {
sourceData.put(String.valueOf(getAdapterPosition()),null );
}
}
}
}
});
}
}
}
}
### Image Reference I can't show proper Image but Its Look Like this
The rows in RecyclerView is reusing while scrolling. So you need to create an array for save each EditText value
Then addTextChangedListener to your EditText to save the EditText value while you input
public void onBindViewHolder(SelectItemAdapter.ItemHolder holder, int position) {
...
holder.numPicker.setText(arrayForSaveEditTextValue[position]);
holder.numPicker.addTextChangedListener(new TextWatcher() {
#Override
public void onTextChanged(CharSequence arg0, int arg1, int arg2, int arg3) {
// TODO Auto-generated method stub
}
#Override
public void beforeTextChanged(CharSequence arg0, int arg1, int arg2,
int arg3) {
// TODO Auto-generated method stub
}
#Override
public void afterTextChanged(Editable arg0) {
// TODO Auto-generated method stub
arrayForSaveEditTextValue[position] = arg0.toString();
}
});
...
}
I have an app that calling an API its resulting around 500 rows creation.In my app the row content can update in the detail page. So after update is there any possibility to update the row in the Recycler View without calling the API again.
Activity
AsyncHttpClient client = new AsyncHttpClient();
client.get("URL", new AsyncHttpResponseHandler() {
#Override
public void onSuccess(int statusCode, Header[] headers, byte[] responseBody) {
try {
String jsonStr = new String(responseBody, "UTF-8");
if (jsonStr != null) {
try {
JSONArray jsonArray = new JSONArray(jsonStr);
JSONObject cStatus = jsonArray.getJSONObject(jsonArray.length()-1);
for (int i = 0; i < jsonArray.length(); i++)
{
JSONObject c = jsonArray.getJSONObject(i);
String firstName = c.getString("firstName");
String subDistributerId = c.getString("subDistributerId");
SubdistributorItem item = new SubdistributorItem();
item.setSubDistributorName(firstName);
item.setSubDistributorId(subDistributerId);
ubdistributorItemList.add(item);
}
} catch (JSONException e) {
e.printStackTrace();
}
}
Collections.sort(subdistributorItemList, new Comparator<SubdistributorItem>() {
public int compare(SubdistributorItem o1, SubdistributorItem o2) {
return o1.getSubDistributorName().compareToIgnoreCase(o2.getSubDistributorName());
}
});
adapter = new SubdistributorRecyclerAdapter(getActivity(),subdistributorItemList);
mRecyclerView.setAdapter(adapter);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
});
Adapter Class
public class SubdistributorRecyclerAdapter extends RecyclerView.Adapter<SubdistributorListRowHolder> {
private List<SubdistributorItem> subdistributorItems;
private Context mContext;
private ArrayList<SubdistributorItem> arraylist;
public SubdistributorRecyclerAdapter(Context context, List<SubdistributorItem> subdistributorItems) {
this.subdistributorItems = subdistributorItems;
this.mContext = context;
this.arraylist = new ArrayList<SubdistributorItem>();
this.arraylist.addAll(subdistributorItems);
}
#Override
public SubdistributorListRowHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.subdistributor_list_item, null);
SubdistributorListRowHolder mh = new SubdistributorListRowHolder(v);
layout_subdistributor.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(final View v) {
Intent i = new Intent(mContext, SubdistributorDetail.class);
Log.e("Tag shop ", "ShopKeeper Detail called");
i.putExtra("subDistributorStatus", txt_RechargeSubdistributor.getText().toString());
i.putExtra("subDistributorId", txt_subDistributorId.getText().toString());
mContext.startActivity(i);
}
});
return mh;
}
#Override
public void onBindViewHolder(SubdistributorListRowHolder subDistributorListRowHolder, int i) {
SubdistributorItem subdistributorItem = subdistributorItems.get(i);
Log.e("Tag ", "adapter "+ subdistributorItem.getSubDistributorName());
}
#Override
public int getItemCount() {
return (null != subdistributorItems ? subdistributorItems.size() : 0);
}
}
So can any one please help me to update a single row in a list without calling the API again.
Try using this method, to update a single row.
notifyItemChanged(int position)
Update item in your list subdistributorItems. Then call adapter.notifyItemChanged(int position). You can get a position in ClickListener using
layout_subdistributor.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(final View v) {
if (mh.getAdapterPosition() != RecyclerView.NO_POSITION) {
int position = mh.getAdapterPosition();
// edit your object by calling subdistributorItems.get(position)
}
}
});
Change this
public static class SubdistributorListRowHolder extends RecyclerView.ViewHolder {
private TextView textView_alphabet;
private TextView textView_name;
private TextView textView_tag;
private ImageView imageViewUserImage;
private ImageView imageViewMoreButton;
private LinearLayout linearLayoutMainContent;
public ViewHolder(View itemLayoutView) {
super(itemLayoutView);
textView_alphabet = (TextView) itemLayoutView.findViewById(R.id.textView_alphabet);
textView_name = (TextView) itemLayoutView.findViewById(R.id.textView_name);
textView_tag = (TextView) itemLayoutView.findViewById(R.id.textView_tag);
imageViewUserImage = (ImageView) itemLayoutView.findViewById(R.id.imageViewUserImage);
linearLayoutMainContent = (LinearLayout) itemLayoutView.findViewById(R.id.linearLayoutMainContent);
}
}
#Override
public void onBindViewHolder(SubdistributorListRowHolder subDistributorListRowHolder, int i) {
SubdistributorItem subdistributorItem = subdistributorItems.get(i);
Log.e("Tag ", "adapter "+ subdistributorItem.getSubDistributorName());
subDistributorListRowHolder.itemLayoutView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Log.e("Tag ", "Position "+ i);
}
});
}
Over here itemLayoutView is the mail layout which is clickable
Modify the SubdistributorListRowHolder like this put all your layout component and find view by id.
getViewForPosition(int position)
Obtain a view initialized for the given position. This method should be used by RecyclerView.LayoutManager implementations to obtain views to represent data from an RecyclerView.Adapter.
The Recycler may reuse a scrap or detached view from a shared pool if one is available for the correct view type. If the adapter has not indicated that the data at the given position has changed, the Recycler will attempt to hand back a scrap view that was previously initialized for that data without rebinding.
description here
Its simple.
Make the changes in the ArrayList that is bonded with the recycler view and call notifyDataSetChanged() on the Recycler View.
I'm new in Android and I have following code that shows the list of item in Adapter.
I have Four Different Adapter from where I am calling one comman AsyncTask to update Result. I have implemented one Interface ApiResponse and overrides apiResponseProcessing() to get result.
In Item of List "Add to Cart" Button Added in every row. OnClick of that button I am requesting to server. On Success of that response i want to update Button with "Added To Cart".
I have question How to update that string which is binded in onBindViewHolder(). I am getting success in that method but dont know how to update clicked Button from that method.
Here's my Adapter
/**
* Adapter
**/
public class AlbumPhotoDetailAdapter
extends RecyclerView.Adapter<AlbumPhotoDetailAdapter.ViewHolder> implements ApiResponse {
private final ArrayList<Photo> mValues;
Album album;
private Activity mContext;
private int mMemberId;
public AlbumPhotoDetailAdapter(Activity context, ArrayList<Photo> items) {
mValues = items;
this.mContext = context;
mMemberId = MemberPreference.getMemberId(mContext);
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.album_photo_detail_sub_view, parent, false);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(final ViewHolder holder, final int position) {
final Photo photo = mValues.get(position);
/**
* Album Owner Name
*/
String mOwnerName = photo.getOwnerName();
String mOwnerProfilePic = photo.getOwnerImage();
String mDateTime = photo.getDatetime();
String mPrice = String.valueOf(photo.getPrice());
/**
* Price String
*/
String priceStr = String.format(mContext.getString(R.string.string_dollar_price), mPrice);
holder.mAlbumPhotoDetailPhotoPrice.setText(priceStr);
/**
* Main Image
*/
Picasso.with(mContext).load(photo.getLink())
.error(R.drawable.ic_place_holder_circle)
.placeholder(R.drawable.ic_place_holder_circle)
.transform(new ImageTransformation(holder.mAlbumPhotoDetailSubMainImage))
.into(holder.mAlbumPhotoDetailSubMainImage);
/**
* Owner Name and Profile Pic
*/
holder.mAlbumPhotoDetailSubOwnerNameTextView.setText(mOwnerName);
Picasso.with(mContext).load(mOwnerProfilePic)
.error(R.drawable.ic_place_holder_circle)
.placeholder(R.drawable.ic_place_holder_circle)
.resize(100, 100)
.transform(new CircleTransform())
.into(holder.mAlbumPhotoDetailSubOwnerImage);
mDateTime = mDateTime != null ? DateUtils.getNiceTime(mDateTime) : "----";
holder.mAlbumPhotoDetailSubOwnerPostedTimeTextView.setText(mDateTime);
// Photo Add to cart.
holder.mAddToCartButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(InternetConnection.checkConnection(mContext)) {
new BackgroundAsyncTask(mContext, (ApiResponse) mContext, mMemberId, photo.getId()).execute();
} else {
DailyStudio.noInternetConnectionToast(mContext);
}
}
});
}
#Override
public int getItemCount() {
return mValues.size();
}
#Override
public void apiResponseProcessing(String response) {
Log.i(TAG,"Api Response : "+response);
if(response.equals(Fields.JSON_SUCCESS)) {
}
}
/**
* View Holder
*/
public static class ViewHolder extends RecyclerView.ViewHolder {
public final View mView;
private ImageView mAlbumPhotoDetailSubOwnerImage;
private ImageView mAlbumPhotoDetailSubMainImage;
private TextView mAlbumPhotoDetailSubOwnerNameTextView;
private TextView mAlbumPhotoDetailSubOwnerPostedTimeTextView;
private TextView mAlbumPhotoDetailPhotoPrice;
private TextView mAlbumPhotoDetailSubDescription;
private Button mAddToCartButton;
public ViewHolder(View view) {
super(view);
mView = view;
mAlbumPhotoDetailSubOwnerImage = (ImageView) view.findViewById(R.id.album_photo_detail_sub_owner_image);
mAlbumPhotoDetailSubMainImage = (ImageView) view.findViewById(R.id.album_photo_detail_sub_main_image);
mAlbumPhotoDetailSubOwnerNameTextView = (TextView) view.findViewById(R.id.album_photo_detail_sub_owner_name_text_view);
mAlbumPhotoDetailSubOwnerPostedTimeTextView = (TextView) view.findViewById(R.id.album_photo_detail_sub_owner_posted_time_text_view);
mAlbumPhotoDetailPhotoPrice = (TextView) view.findViewById(R.id.album_photo_detail_photo_price);
mAlbumPhotoDetailSubDescription = (TextView) view.findViewById(R.id.album_photo_detail_sub_description);
mAddToCartButton = (Button) view.findViewById(R.id.album_photo_detail_photo_add_to_cart_button);
}
}
}
Here's my Interface
/**
* Interface..
*/
public interface ApiResponse {
public void apiResponseProcessing(String response);
}
Here's my Background AsyncTask
/**
* Background AsyncTask...
*/
public class BackgroundAsyncTask extends AsyncTask<Void, Void, String> {
private Context context;
private String accessToken;
private int memberId;
private int photoId;
private ApiResponse objIBaseApi;
public BackgroundAsyncTask(Context context, ApiResponse apiResponse, int memberId, int photoId) {
this.context = context;
this.memberId = memberId;
this.photoId = photoId;
accessToken = MemberPreference.getAccessToken(context);
this.objIBaseApi = apiResponse;
}
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected String doInBackground(Void... params) {
JSONObject json = JSONParser.addToCartPhoto(accessToken, memberId, photoId);
if(json != null) {
Log.i(TAG,"First Json : "+json.toString());
try {
if (json.getString(Fields.RESULT).equalsIgnoreCase(Fields.JSON_SUCCESS)) {
return Fields.JSON_SUCCESS;
} else if(json.getString(Fields.JSON_ERROR).equalsIgnoreCase(Fields.ERROR_ACCESS_DENIED)) {
String refreshToken = MemberPreference.getRefreshToken(context);
JSONObject newJSONObject = JSONParser.loginMemberWithRefreshToken(refreshToken, Integer.toString(memberId));
if(newJSONObject != null) {
if(newJSONObject.getString(Fields.JSON_ERROR).equalsIgnoreCase(Fields.ERROR_ACCESS_DENIED)) {
return Fields.ERROR_ACCESS_DENIED;
} else {
return Fields.JSON_SUCCESS;
}
} else
return Fields.ERROR_ACCESS_DENIED;
} else {
return Fields.JSON_ERROR;
}
} catch (JSONException e) {
e.printStackTrace();
return Fields.JSON_ERROR;
}
}
return Fields.JSON_ERROR;
}
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
objIBaseApi.apiResponseProcessing(result);
}
}
Is there any solution or better way to do like this?
Your help would be appreciated. Thank you.
You Can keep one flag isAddedToCart variable in you bean class which you are using in your adapter(Photo). Now just pass the position in your asynctask once user click on "add to cart" button. On getting the successful you just need to find the bean from the list of bean you passed in adapter and change the flag isAddedToCart to true and notify your adapter thats it. Here is the code snippet:-
Photo Class
public class Photo{
private boolean isAddedToCart;
public void setAddedTOCart(boolean isAdded){
isAddedToCart = isAdded;
}
public boolean isAddedToCart(){
return isAddedToCart;
}
}
AlbumPhotoDetailAdapter onBindViewHolder
#Override
public void onBindViewHolder(final ViewHolder holder, final int position) {
final Photo photo = mValues.get(position);
/**
* Album Owner Name
*/
String mOwnerName = photo.getOwnerName();
String mOwnerProfilePic = photo.getOwnerImage();
String mDateTime = photo.getDatetime();
String mPrice = String.valueOf(photo.getPrice());
String isAdded = photo.isAddedToCart();
/**
* Price String
*/
String priceStr = String.format(mContext.getString(R.string.string_dollar_price), mPrice);
holder.mAlbumPhotoDetailPhotoPrice.setText(priceStr);
/**
* Main Image
*/
Picasso.with(mContext).load(photo.getLink())
.error(R.drawable.ic_place_holder_circle)
.placeholder(R.drawable.ic_place_holder_circle)
.transform(new ImageTransformation(holder.mAlbumPhotoDetailSubMainImage))
.into(holder.mAlbumPhotoDetailSubMainImage);
/**
* Owner Name and Profile Pic
*/
holder.mAlbumPhotoDetailSubOwnerNameTextView.setText(mOwnerName);
Picasso.with(mContext).load(mOwnerProfilePic)
.error(R.drawable.ic_place_holder_circle)
.placeholder(R.drawable.ic_place_holder_circle)
.resize(100, 100)
.transform(new CircleTransform())
.into(holder.mAlbumPhotoDetailSubOwnerImage);
mDateTime = mDateTime != null ? DateUtils.getNiceTime(mDateTime) : "----";
holder.mAlbumPhotoDetailSubOwnerPostedTimeTextView.setText(mDateTime);
if(isAdded){
holder.mAddToCartButton.setText("Added TO Cart");
}else{
holder.mAddToCartButton.setText("Add TO Cart");
}
// Photo Add to cart.
holder.mAddToCartButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(InternetConnection.checkConnection(mContext)) {
new BackgroundAsyncTask(mContext, (ApiResponse) mContext, mMemberId, photo.getId(),position).execute();
} else {
DailyStudio.noInternetConnectionToast(mContext);
}
}
});
}
your Interface
public interface ApiResponse {
public void apiResponseProcessing(String response,int position);
}
Your Adapter apiResponceProcessing()
#Override
public void apiResponseProcessing(String response,int position) {
Log.i(TAG,"Api Response : "+response);
if(response.equals(Fields.JSON_SUCCESS)) {
mValues.get(position).setAddedTOCart(true);
notifyDataSetChange();
}
}
And finally your
BackgroundAsyncTask
public class BackgroundAsyncTask extends AsyncTask<Void, Void, String> {
private Context context;
private String accessToken;
private int memberId;
private int photoId;
private int mPosition;
private ApiResponse objIBaseApi;
public BackgroundAsyncTask(Context context, ApiResponse apiResponse, int memberId, int photoId,int position) {
this.context = context;
this.memberId = memberId;
this.photoId = photoId;
accessToken = MemberPreference.getAccessToken(context);
this.objIBaseApi = apiResponse;
this.mPosition = position;
}
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected String doInBackground(Void... params) {
JSONObject json = JSONParser.addToCartPhoto(accessToken, memberId, photoId);
if(json != null) {
Log.i(TAG,"First Json : "+json.toString());
try {
if (json.getString(Fields.RESULT).equalsIgnoreCase(Fields.JSON_SUCCESS)) {
return Fields.JSON_SUCCESS;
} else if(json.getString(Fields.JSON_ERROR).equalsIgnoreCase(Fields.ERROR_ACCESS_DENIED)) {
String refreshToken = MemberPreference.getRefreshToken(context);
JSONObject newJSONObject = JSONParser.loginMemberWithRefreshToken(refreshToken, Integer.toString(memberId));
if(newJSONObject != null) {
if(newJSONObject.getString(Fields.JSON_ERROR).equalsIgnoreCase(Fields.ERROR_ACCESS_DENIED)) {
return Fields.ERROR_ACCESS_DENIED;
} else {
return Fields.JSON_SUCCESS;
}
} else
return Fields.ERROR_ACCESS_DENIED;
} else {
return Fields.JSON_ERROR;
}
} catch (JSONException e) {
e.printStackTrace();
return Fields.JSON_ERROR;
}
}
return Fields.JSON_ERROR;
}
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
objIBaseApi.apiResponseProcessing(result,mPosition);
}
}
Firstly in my opinion adapter should not care about network request. But
giving an answer in substance, you can try pass anonymous class for your apiResponseProcessing in same manner as you create OnClickListener for your button. It can look like this:
holder.mAddToCartButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(InternetConnection.checkConnection(mContext)) {
new BackgroundAsyncTask(
mContext,
new ApiResponse() {
#Override
public void apiResponseProcessing(String response) {
Log.i(TAG,"Api Response : "+response);
if(response.equals(Fields.JSON_SUCCESS)) {
// Here you can access you holder till it final
}
}
},
mMemberId,
photo.getId()).execute();
} else {
DailyStudio.noInternetConnectionToast(mContext);
}
}
});
But code like this looks messy and spaghetti. As i say at the beginning there are exist at least one different approach to handle changes for buttons inside listview/recivleview. I use method, where adapter only care about building interface with given data and delegate buttons clicks to someone else (in most cases activity that contains listview). An easy way notify activity about button click is Bus messaging pattern. I use Otto event library. When delegate receive notification about button click, it can initiate data changing according current task and then initiate listview reloading or partial update only required rows.
Additional comments
Try to write beautiful code. Constructor AlbumPhotoDetailAdapter has different syntax to assign instance variables. One with this keyword and other without. Usually you should use one way.
public AlbumPhotoDetailAdapter(Activity context, ArrayList<Photo> items) {
this.values = items;
this.context = context;
this.memberId = MemberPreference.getMemberId(context);
}
album instance variable have no access modifiers indication. You should know, that in java programming language omitting access specifiers is not the same as private modifier.
I have a problem with the recycler view and card view. I'm using asynctask to get info from API, and for now I'm getting only a name - which means, I display in my card view only a text view. however, when I'm loading the list, it is awfully slow. in the log cat I can see that the app is getting the data pretty fast, but it takes a lot of time to show it in the recycler view.
I'm adding few samples - from the adapter of the recycler view and the fragment that holds the recycler view in. maybe I did something wrong in the adapter.
Thank you for your help!
Adapter:
public class PlacesListAdapter extends RecyclerView.Adapter<PlacesListAdapter.ListViewHolder>{
ArrayList<PlaceItem> items;
Context context;
public PlacesListAdapter(Context context,ArrayList<PlaceItem> placeItems){
this.context = context;
this.items = placeItems;
}
public void swap(ArrayList<PlaceItem> places){
items.clear();
items.addAll(places);
notifyDataSetChanged();
}
#Override
public ListViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(context).inflate(R.layout.card_view, parent, false);
return new ListViewHolder(v);
}
#Override
public void onBindViewHolder(ListViewHolder holder, int position) {
PlaceItem item = items.get(position);
holder.bindData(item);
}
#Override
public int getItemCount() {
return items.size();
}
public class ListViewHolder extends RecyclerView.ViewHolder{
TextView title;
PlaceItem placeItem;
public ListViewHolder(View itemView) {
super(itemView);
title = (TextView) itemView.findViewById(R.id.txtTitlePlace);
}
public void bindData(PlaceItem item){
this.placeItem = item;
title.setText(placeItem.getTitle());
}
}
}
Fragment:
public class FragmentListPlaces extends Fragment implements View.OnClickListener {
ArrayList<PlaceItem> placeItems;
PlacesListAdapter adapter;
RecyclerView list;
EditText editName;
public FragmentListPlaces() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View v = inflater.inflate(R.layout.fragment_list_places, container, false);
editName = (EditText) v.findViewById(R.id.editPlaceName);
v.findViewById(R.id.btnGetLocations).setOnClickListener(this);
v.findViewById(R.id.btnSearchByText).setOnClickListener(this);
placeItems = new ArrayList<>();
placeItems.add(new PlaceItem("Example"));
adapter = new PlacesListAdapter(getContext(), placeItems);
list = (RecyclerView) v.findViewById(R.id.placesList);
list.setLayoutManager(new LinearLayoutManager(getContext()));
list.setAdapter(adapter);
return v;
}
#Override
public void onClick(View v) {
switch (v.getId()){
case R.id.btnGetLocations:
GetUserLocation location = new GetUserLocation();
location.getLocation(getActivity());
adapter.swap(placeItems);
break;
case R.id.btnSearchByText:
// this is the method loading data with user input
String getNameFromUser = editName.getText().toString();
searchPlaceByText(getNameFromUser);
adapter.swap(placeItems);
break;
}
}
public void searchPlaceByText(String place){
// instantiate the asynctask here
LocationDetailsByText locationDetailsByText = new LocationDetailsByText(placeItems);
locationDetailsByText.execute("http://api.v3.factual.com/t/places-il?q=" + place + "&KEY=AFvDryDJmPkkgXohbpFdqkRQelT9w0HKtyEqXy3G");
}
Loading of data from the web:
public class LocationDetailsByText extends AsyncTask<String, Void, String> {
ArrayList<PlaceItem> placeItems = new ArrayList<>();
public LocationDetailsByText(ArrayList<PlaceItem> places){
this.placeItems = places;
}
#Override
protected String doInBackground(String... params) {
StringBuilder result = new StringBuilder();
BufferedReader reader;
HttpURLConnection connection = null;
URL url;
String query = (params[0]);
try {
url = new URL(query);
connection = (HttpURLConnection)url.openConnection();
if(connection.getResponseCode() != 200){
return "Error!";
}
reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
String line = "";
while((line = reader.readLine())!= null){
result.append(line);
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
connection.disconnect();
}
return result.toString();
}
#Override
protected void onPostExecute(String s) {
PlaceItem placeItem;
try {
JSONObject root = new JSONObject(s);
JSONObject response = root.getJSONObject("response");
JSONArray data = response.getJSONArray("data");
for(int i = 0; i < data.length(); i++){
JSONObject getData = data.getJSONObject(i);
String title = getData.getString("name");
placeItem = new PlaceItem(title);
placeItems.add(placeItem);
}
} catch (JSONException e) {
e.printStackTrace();
}
}
Apart from the issue that #M G pointed out that messes up the behavior in general.
you have 2 other major flaws that I can see of which 1) is affecting you mostly.
1) you do all the Json parsing + moving the data to your POJO(PlaceItem[]) onPostExecute. this is wrong!
this can be very heavy on computation
this way you create 2 many intermediate objects lots of GC
I suggest move these to background and use Gson.
2) it seems that you do lots of network calls that could happen quite frequently. This needs better managing of concurrent requests, network connections, threads, streams and data arrays obtained form the network stream. This can cause lots of GC.
I would recommend to use some networking library made for this purpose such as retrofit, volley or jus. These all can handle also parsing network data straight to your POJO in the background and minimizing GC and performance in general.
Few issues with your code
searchPlaceByText(getNameFromUser);
adapter.swap(placeItems);
adapter.swap(placeItems); starts right after you start your AsyncTask but you didn't download anything yet. This is wrong. You should remove adapter.swap(placeItems); from here and do something like this instead:
#Override
public void onClick(View v) {
switch (v.getId()){
case R.id.btnGetLocations:
GetUserLocation location = new GetUserLocation();
location.getLocation(getActivity());
adapter.swap(placeItems);//also here probably
break;
case R.id.btnSearchByText:
// this is the method loading data with user input
String getNameFromUser = editName.getText().toString();
searchPlaceByText(getNameFromUser);
break;
}
}
public void searchPlaceByText(final String place) {
// instantiate the asynctask here
LocationDetailsByText locationDetailsByText = new LocationDetailsByText(placeItems) {
#Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
adapter.swap(placeItems);
}
};
locationDetailsByText.execute("http://api.v3.factual.com/t/places-il?q=" + place + "&KEY=AFvDryDJmPkkgXohbpFdqkRQelT9w0HKtyEqXy3G");
}
Next thing is that you clear your list
items.clear();
items.addAll(places);
Which is basically also removing everything from your placeItems because erlier in this class you set this.items = placeItems;. So in PlacesListAdapter just do
public void swap(ArrayList<PlaceItem> places){
notifyDataSetChanged();
}
In Your Asynctask, in OnPostExcute, at the end of it notify your adapter about the changes in your data, that's why you cant see your data unless you click on edit text again.