This is my Activity:
public class HomeTimelineActivity extends AppCompatActivity {
private TwitterClient client;
Context mContext;
#BindView(R.id.rvTweets)
RecyclerView rvTweets;
List<Tweet> mTweets;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home_timeline);
Butterknife.bind(this);
client = TwitterApplication.getRestClient();
populateTimeline();
}
private void populateTimeline() {
client.getHomeTimeline(new JsonHttpResponseHandler() {
#Override
public void onSuccess(int statusCode, Header[] headers, JSONArray jsonArray) {
Log.d("DEBUG", jsonArray.toString());
mTweets = new ArrayList<Tweet>();
for (int i = 0; i < jsonArray.length(); i++) {
try {
JSONObject jsonTweet = jsonArray.getJSONObject(i);
Tweet tweet = new Tweet();
tweet.setBody(jsonTweet.getString("text"));
tweet.setUid(jsonTweet.getLong("id"));
tweet.setCreateAt(jsonTweet.getString("created_at"));
JSONObject jsonUser = jsonTweet.getJSONObject("user");
User user = new User();
user.setName(jsonUser.getString("name"));
user.setUid(jsonUser.getLong("id"));
user.setScreenname(jsonUser.getString("screen_name"));
user.setProfileImageurl(jsonUser.getString("profile_image_url"));
tweet.setUser(user);
mTweets.add(tweet);
runOnUiThread(new Runnable() {
#Override
public void run() {
TweetAdapter adapter = new TweetAdapter(mContext, mTweets);
rvTweets.setAdapter(adapter);
RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(mContext);
rvTweets.setLayoutManager(layoutManager);
}
});
} catch (JSONException e) {
e.printStackTrace();
continue;
}
}
}
#Override
public void onFailure(int statusCode, Header[] headers, Throwable throwable, JSONArray errorResponse) {
Log.d("DEBUT", errorResponse.toString());
}
});
}
}
This is my Adapter:
public class TweetAdapter extends RecyclerView.Adapter<TweetAdapter.TweetViewHolder>{
private Context mContext;
private List<Tweet> mTweets;
// Automatically add the Constructor here
public TweetAdapter(Context context, List<Tweet> tweets) {
mContext = context;
mTweets = tweets;
}
// Implements compulsory methods
#Override
public TweetViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.tweet_list_items,
parent, false);
TweetViewHolder viewHolder = new TweetViewHolder(view);
return viewHolder;
}
#Override
public void onBindViewHolder(TweetViewHolder holder, int position) {
holder.bindModel(mTweets.get(position));
}
#Override
public int getItemCount() {
return mTweets.size();
}
public class TweetViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{
// Hook the ID to new created Widget using ButterKnife
#BindView(R.id.imgUserProfile)
ImageView userProfile;
#BindView(R.id.tvUserName)
TextView userName;
#BindView(R.id.tvTweet)
TextView tweetText;
TweetViewHolder(View view) {
super(view);
ButterKnife.bind(this, view);
// Set the OnclickListener of an item in list
itemView.setOnClickListener(this);
}
void bindModel(Tweet tweet) {
// Use the Widget mVar and the model name to set_get info
tweetText.setText(tweet.getBody());
}
#Override
public void onClick(View view) {
// Add What happen with OnClick
}
}
}
I try to set the Adapter with the mTweets List. I used debugger to make sure that the getTweet method has returned enough Object
tweets = {ArrayList#5524} size = 25
0 = {Tweet#5530}
1 = {Tweet#5531}
2 = {Tweet#5532}
3 = {Tweet#5533}
4 = {Tweet#5534}
5 = {Tweet#5535}
6 = {Tweet#5536}
7 = {Tweet#5537}
8 = {Tweet#5538}
9 = {Tweet#5539}
10 = {Tweet#5540}
11 = {Tweet#5541}
However, when I try to set the Adapter, there is no data displayed and the app immediately stopped. Strange, the Logcat is blank without any information. It's simply black. The authentication with Twitter worked.
Anyone please help me with this.
There are some steps you need to follow to improve your code performance and get it up and running.
The main thing which you are missing is that you are setting the mTweets after every iteration in the loop. You should set mTweets in the Adapter only after the entire list is populated. Following that, you should call adapter notifyDataSetChanged().
Follow these:
step 1
// Class variable adapter...
private TweetAdapter adapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home_timeline);
client = TwitterApplication.getRestClient();
// Initially pass null as the mTweets since you don't have any tweets right now...
adapter = new TweetAdapter(mContext, null);
rvTweets.setAdapter(adapter);
RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(mContext);
rvTweets.setLayoutManager(layoutManager);
populateTimeline();
}
step 2
In your TweetAdapter, modify getItemCount method to handle the null checks on mTweets. Add a new Method addNewTweets to your Adapter.
#Override
public int getItemCount() {
return (mTweets !=null) ? mTweets.size() : 0;
}
public void setNewTweets(List<Tweet> newTweetList) {
this.mTweets = newTweetList;
}
step 3
Modify this method populateTimeline
private void populateTimeline() {
client.getHomeTimeline(new JsonHttpResponseHandler() {
#Override
public void onSuccess(int statusCode, Header[] headers, JSONArray jsonArray) {
Log.d("DEBUG", jsonArray.toString());
mTweets = new ArrayList<Tweet>();
for (int i = 0; i < jsonArray.length(); i++) {
try {
JSONObject jsonTweet = jsonArray.getJSONObject(i);
Tweet tweet = new Tweet();
tweet.setBody(jsonTweet.getString("text"));
tweet.setUid(jsonTweet.getLong("id"));
tweet.setCreateAt(jsonTweet.getString("created_at"));
JSONObject jsonUser = jsonTweet.getJSONObject("user");
User user = new User();
user.setName(jsonUser.getString("name"));
user.setUid(jsonUser.getLong("id"));
user.setScreenname(jsonUser.getString("screen_name"));
user.setProfileImageurl(jsonUser.getString("profile_image_url"));
tweet.setUser(user);
mTweets.add(tweet);
/* REMOVE THIS CODE!
runOnUiThread(new Runnable() {
#Override
public void run() {
TweetAdapter adapter = new TweetAdapter(mContext, mTweets);
rvTweets.setAdapter(adapter);
RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(mContext);
rvTweets.setLayoutManager(layoutManager);
}
});
*/
} catch (JSONException e) {
e.printStackTrace();
continue;
}
// NOW SET MTWEETS IN YOUR ADAPTER.
// NOTIFY the adapter that the data is changed.
adapter.setNewTweets(mTweets);
adapter.notifyDataSetChanged();
}
}
Related
I am trying to display data in a recycler view in android. i but it keeps displaying only the last datas and i dont know why.i seem to be doing everything right. And the recycler view has a view pager.
this is my
Myadapter class
public class MyAdapter extends RecyclerView.Adapter<MyHolder> {
Context c;
List<Getter> getter;
public MyAdapter(List<Getter> getter, Context c) {
super();
this.c = c;
this.getter = getter;
}
//INITIALIZE VIEWHODER
#Override
public MyHolder onCreateViewHolder(ViewGroup parent, int viewType) {
//VIEW OBJ
View v= LayoutInflater.from(parent.getContext()).inflate(R.layout.model,null);
//HOLDER
MyHolder holder=new MyHolder(v);
return holder;
}
//BIND VIEW TO DATA
#Override
public void onBindViewHolder(MyHolder holder, int position) {
String images[] = {getter.get(position).getUrl1(), getter.get(position).getUrl2()};
holder.gamename.setText(getter.get(position).getGame_name());
holder.cost.setText(getter.get(position).getCost());
holder.usname.setText(getter.get(position).getFull_name());
Picasso.with(c)
.load(getter.get(position).getPicture())
.placeholder(R.drawable.placeholder)
.error(R.drawable.error)
.transform(new CircleTransform())
.fit()
.into(holder.usimage);
CustomPagerAdapter mCustomPagerAdapter = new CustomPagerAdapter(c,images);
holder.mViewPager.setAdapter(mCustomPagerAdapter);
holder.indicator.setViewPager(holder.mViewPager);
holder.setItemClickListener(new ItemClickListener() {
#Override
public void onItemClick(View v, int pos) {
Snackbar.make(v,getter.get(pos).getGame_name(),Snackbar.LENGTH_SHORT).show();
}
});
}
#Override
public int getItemCount() {
return getter.size();
}
}
This is my mainactivty class
public class All_timeline extends Fragment {
SqlHandler sqlHandler;
RecyclerView rv;
MyAdapter adapter;
private List<Getter> getter;
public All_timeline() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View x = inflater.inflate(R.layout.all_timeline, container, false);
sqlHandler = new SqlHandler(getActivity());
//recycler
rv = (RecyclerView) x.findViewById(R.id.mRecycler);
getter= new ArrayList<>();
rv.setLayoutManager(new LinearLayoutManager(getActivity()));
rv.setItemAnimator(new DefaultItemAnimator());
rv.addItemDecoration(new SimpleDividerItemDecoration(getResources()));
registerUser("arinzeaco#gmail.com");
adapter=new MyAdapter(getter,getActivity());
rv.setAdapter(adapter);
return x;
}
public void registerUser(final String email) {
OkHttpClient client = new OkHttpClient();
RequestBody body = new FormBody.Builder()
.add("username", email)
.build();
Request request = new Request.Builder().url("http://www.thethinker.com.ng/gamer/allpost.php").post(body).build();
Call call = client.newCall(request);
call.enqueue(new Callback() {
#Override
public void onFailure(Call call, IOException e) {
Toast.makeText(getActivity(), "Registration failed",
Toast.LENGTH_SHORT).show();
}
#Override
public void onResponse(Call call, Response response) throws IOException {
final String myResponse = response.body().string();
getActivity().runOnUiThread(new Runnable() {
#Override
public void run() {
JSONObject jso;
Getter contactListItems = new Getter();
try {
jso = new JSONObject(myResponse);
JSONArray categories = jso.getJSONArray("posts");
for (int i = 0; i < categories.length(); i++) {
String image1 = categories.getJSONObject(i).getString("image_1");
String image2 = categories.getJSONObject(i).getString("image_2");
String username = categories.getJSONObject(i).getString("username");
String video_url = categories.getJSONObject(i).getString("video_url");
String liked = categories.getJSONObject(i).getString("liked");
String cost = categories.getJSONObject(i).getString("cost");
String following = categories.getJSONObject(i).getString("following");
String game_name = categories.getJSONObject(i).getString("game_name");
String full_name = categories.getJSONObject(i).getString("full_name");
String userimage = categories.getJSONObject(i).getString("userimage");
contactListItems.setUsername(username);
contactListItems.setGame_name(game_name);
contactListItems.setCost(cost);
contactListItems.setFollowing(following);
contactListItems.setLiked(liked);
contactListItems.setFull_name(full_name);
contactListItems.setVideo(video_url);
contactListItems.setUrl1(image1);
contactListItems.setUrl2(image2);
contactListItems.setPicture(userimage);
getter.add(contactListItems);
}
} catch (JSONException e) {
e.printStackTrace();
}
}});
}
});
}
}
I have also check other stackoverflow questions like RecyclerView displaying the last item in the adapter several times. Need all adapter items to show in RecyclerView. but i just don't get what i am doing wrong.
I think it related to concurrency issue, please try to call http method after you set adapter, and don't forget to call notifyDataSetChanged() after all data inserted. One more think, make sure you insert different Getter instance for every item
for example in onCreateView
adapter=new MyAdapter(getter,getActivity());
rv.setAdapter(adapter);
registerUser("arinzeaco#gmail.com");
in onResponse:
#Override
public void onResponse(Call call, Response response) throws IOException {
final String myResponse = response.body().string();
getActivity().runOnUiThread(new Runnable() {
#Override
public void run() {
JSONObject jso;
try {
jso = new JSONObject(myResponse);
JSONArray categories = jso.getJSONArray("posts");
for (int i = 0; i < categories.length(); i++) {
Getter contactListItems = new Getter();
String image1 = categories.getJSONObject(i).getString("image_1");
String image2 = categories.getJSONObject(i).getString("image_2");
String username = categories.getJSONObject(i).getString("username");
String video_url = categories.getJSONObject(i).getString("video_url");
String liked = categories.getJSONObject(i).getString("liked");
String cost = categories.getJSONObject(i).getString("cost");
String following = categories.getJSONObject(i).getString("following");
String game_name = categories.getJSONObject(i).getString("game_name");
String full_name = categories.getJSONObject(i).getString("full_name");
String userimage = categories.getJSONObject(i).getString("userimage");
contactListItems.setUsername(username);
contactListItems.setGame_name(game_name);
contactListItems.setCost(cost);
contactListItems.setFollowing(following);
contactListItems.setLiked(liked);
contactListItems.setFull_name(full_name);
contactListItems.setVideo(video_url);
contactListItems.setUrl1(image1);
contactListItems.setUrl2(image2);
contactListItems.setPicture(userimage);
getter.add(contactListItems);
}
adapter.notifyDataSetChanged();
} catch (JSONException e) {
e.printStackTrace();
}
}});
}
});
I m trying to extract android volley response to a member variable of the same class. I used callback interfaces to perform this task :
public void getData(MyCustomListener customListener) {
JsonArrayRequest arrayRequest = new JsonArrayRequest(Request.Method.POST, url,
response -> {
Log.i("response",response.toString());
customListener.onResponse(completeCart);
},
error -> Log.i("Volley_error", error.getMessage())) {
...
CustomerListener interface:
public interface MyCustomListener {
public void onResponse(Object response);
public void onError(String error_response);
}
And inside onCreateView method of the fragment :
getData(new MyCustomListener() {
#Override
public void onResponse(Object response) {
completeCartProItems.addAll((List<CompleteCartProItem>) response);
}
#Override
public void onError(String error_response) {}
});
When I put a debug pointer at completeCartProItems.addAll((List<CompleteCartProItem>) response); response is not empty but completeCartProItems arraylist is shown as empty.
Variables :
I need to pass this completeCartProItems to a Adapter named CartItem_ScrollerAdapter which has implemented to a RecycleView.
This implementation also inside the onCreateView of the fragment. right after calling getData() method :
cart_item_scrollerAdapter = new CartItem_ScrollerAdapter(getActivity(), completeCartProItems);
I put debug pointer inside the constructor of the CartItem_ScrollerAdapter as well.
But it also shows that the List parameter of the constructor is empty.
How to pass not empty ArrayList to the adapter given below ?? Any suggestions will be appreciable. Thank you.
UPDATE
Adapter class :
public class CartItem_ScrollerAdapter extends RecyclerView.Adapter<CartItem_ScrollerAdapter.CartItemViewHolder> {
private LayoutInflater inflater;
private List<CompleteCartProItem> completeCartProItems = new ArrayList<>();
private Context context;
public CartItem_ScrollerAdapter(Context context, List<CompleteCartProItem> completeCartProItems) {
this.inflater = LayoutInflater.from(context);
this.context = context;
this.completeCartProItems = completeCartProItems;
}
#Override
public CartItemViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = inflater.inflate(R.layout.cart_item, parent, false);
CartItemViewHolder cartItemViewHolder = new CartItemViewHolder(view);
return cartItemViewHolder;
}
#Override
public void onBindViewHolder(CartItemViewHolder holder, int position) {
CompleteCartProItem proItem = completeCartProItems.get(position);
CartDetails details = (CartDetails) MyApplication.getAndroidSession().getAttribute("cart");
holder.cart_pro_name.setText(proItem.getP_name());
holder.cart_pro_price.setText("Rs " + (proItem.getP_dscPer() != 0 ? details.getDiscountPrice(proItem.getP_price(), proItem.getP_dscPer()) : proItem.getP_price()));
holder.cart_pro_qnty.setText(details.getQntyOfProduct(proItem.getPid(), proItem.getP_size()) + "");
holder.cart_pro_size.setText(proItem.getP_size());
String image_url = "http://10.0.2.2:8080/ECommerceApp/" + proItem.getP_img();
Picasso.with(context).load(image_url).into(holder.cart_pro_img);
}
#Override
public int getItemCount() {
return completeCartProItems != null ? completeCartProItems.size() : 0;
}
class CartItemViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
TextView cart_pro_name;
TextView cart_pro_price;
TextView cart_pro_qnty;
TextView cart_pro_size;
ImageView cart_pro_img;
ImageButton cart_remove_btn;
Button cart_change;
public CartItemViewHolder(View itemView) {
super(itemView);
cart_pro_name = (TextView) itemView.findViewById(R.id.cart_item_product_name);
cart_pro_price = (TextView) itemView.findViewById(R.id.cart_item_product_price);
cart_pro_size = (TextView) itemView.findViewById(R.id.cart_item_size);
cart_pro_img = (ImageView) itemView.findViewById(R.id.cart_product_img);
cart_pro_qnty = (TextView) itemView.findViewById(R.id.cart_item_qnty);
//===============================================================================================
cart_remove_btn = (ImageButton) itemView.findViewById(R.id.remove_item_btn);
cart_change = (Button) itemView.findViewById(R.id.cart_item_change_btn);
cart_pro_img.setOnClickListener(this);
cart_remove_btn.setOnClickListener(this);
cart_change.setOnClickListener(this);
}
#Override
public void onClick(View v) {
}
}
}
Fragment :
public class CartFragment extends Fragment {
private RecyclerView cart_horizontal_scroller;
private CartItem_ScrollerAdapter cart_item_scrollerAdapter;
private Button purchase_button;
private List<CompleteCartProItem> completeCartProItems = new ArrayList<>();
public CartFragment() {
// Required empty public constructor
}
public void getData(MyCustomListener<CompleteCartProItem> customListener) {
if (MyApplication.getAndroidSession().getAttribute("cart") != null) {
Log.i("cart_null", "NOT null");
RequestQueue requestQueue = VolleySingleton.getsInstance().getRequestQueue();
CartDetails cartDetails = (CartDetails) MyApplication.getAndroidSession().getAttribute("cart");
CopyOnWriteArrayList<CartItem> jsonSendArray = cartDetails.getShoppingList();
final String jsonString = new Gson().toJson(jsonSendArray,
new TypeToken<CopyOnWriteArrayList<CartItem>>() {
}.getType());
Log.i("json_object", jsonString);
String url = "http://10.0.2.2:8080/ECommerceApp/getAllProductsAction";
JsonArrayRequest arrayRequest = new JsonArrayRequest(Request.Method.POST, url,
response -> {
List<CompleteCartProItem> completeCart = new Gson().fromJson(response.toString(),
new TypeToken<List<CompleteCartProItem>>() {
}.getType());
Log.i("response", completeCart.get(0).getP_name());
customListener.onResponse(completeCart);
}, error -> Log.i("Volley_error", error.getMessage())) {
#Override
public Map<String, String> getHeaders() throws AuthFailureError {
Map<String, String> params = new HashMap<>();
params.put("Content-Type", "application/json");
params.put("cartList", jsonString);
return params;
}
};
arrayRequest.setRetryPolicy(new RetryPolicy() {
#Override
public int getCurrentTimeout() {
return 5000;
}
#Override
public int getCurrentRetryCount() {
return 5000;
}
#Override
public void retry(VolleyError error) throws VolleyError {
}
});
requestQueue.add(arrayRequest);
} else {
Log.i("cart_null", "null");
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_cart, container, false);
cart_horizontal_scroller = (RecyclerView) view.findViewById(R.id.horizontal_scrollView_cart_items);
getData(new MyCustomListener<CompleteCartProItem>() {
#Override
public void onResponse(List<CompleteCartProItem> response) {
completeCartProItems.addAll(response);
//completeCartProItems.add(new CompleteCartProItem(1, 2340.0, "Extra Orient Top", "Orient", "", "S", 5));
Log.i("check", completeCartProItems.get(0).getP_name());
}
#Override
public void onError(String error_response) {
}
});
cart_item_scrollerAdapter = new CartItem_ScrollerAdapter(getActivity(), completeCartProItems);
cart_horizontal_scroller.setAdapter(cart_item_scrollerAdapter);
cart_horizontal_scroller.setLayoutManager(new LinearLayoutManager(getActivity(),
LinearLayoutManager.HORIZONTAL, false));
purchase_button = (Button) view.findViewById(R.id.purchase_btn);
purchase_button.setOnClickListener(v -> {
Toast t = Toast.makeText(getActivity(), "Worked", Toast.LENGTH_LONG);
t.show();
});
return view;
}
}
Ok. In reference to the comment above, I am writing some steps you should try since I do not have a clear picture of what might be wrong.
Let's start with your MyCustomListener. I do not know why are you setting the response type to Object. If it is to use this in multiple requests then you can modify it like the following with generics
public interface MyCustomListener<T> {
public void onResponse(T response);
public void onError(String error_response);
}
then use it like this when a callback is needed
getData(new MyCustomListener<List<CompleteCartProItem>>() {
#Override
public void onResponse(List<CompleteCartProItem> response) {
completeCartProItems.addAll(response);
}
#Override
public void onError(String error_response) {
//handle error
}
});
Also make sure you are not re-initialising completeCartProItems elsewhere after the callback.
Not really sure if the following will fix your issue but make sure that your callback is executed in the UI thread, too.
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 am working on a shopping cart app,Items are displayed as below.There is a plus, minus (+/-) buttons to choose the number of quantity.
If product quantity is changed, I need to pass "productname" and "quantity" to the main activity so that I could use them to prepare final cart. I got some suggestions to use database or some content providers,
I am not sure how to do it.., please help
MainActivity.java
public class MainActivity extends AppCompatActivity {
RecyclerView recyclerView;
RecycleAdapter recycleAdapter;
List<HashMap<String, String>> onlineData;
ProgressDialog pd;
Toolbar toolbar;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
recyclerView = (RecyclerView) findViewById(R.id.recyle_view);
toolbar= (Toolbar) findViewById(R.id.anim_toolbar);
setSupportActionBar(toolbar);
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getBaseContext());
recyclerView.setLayoutManager(linearLayoutManager);
recyclerView.setHasFixedSize(true);
final String url = "http://www.qa4.org/?json=get_recent_posts&count=45";
new AsyncHttpTask().execute(url);
}
public class AsyncHttpTask extends AsyncTask<String, Void, Integer> {
#Override
protected void onPreExecute() {
pd=new ProgressDialog(MainActivity.this);
pd.requestWindowFeature(Window.FEATURE_NO_TITLE);
pd.setMessage("Loading please wait...");
pd.setCancelable(false);
pd.show();
}
#Override
protected Integer doInBackground(String... params) {
Integer result = 0;
HttpURLConnection urlConnection;
try {
URL url = new URL(params[0]);
urlConnection = (HttpURLConnection) url.openConnection();
int statusCode = urlConnection.getResponseCode();
// 200 represents HTTP OK
if (statusCode == 200) {
BufferedReader r = new BufferedReader(new InputStreamReader(urlConnection.getInputStream()));
StringBuilder response = new StringBuilder();
String line;
while ((line = r.readLine()) != null) {
response.append(line);
}
parseResult(response.toString());
result = 1; // Successful
} else {
result = 0; //"Failed to fetch data!";
}
} catch (Exception e) {
e.printStackTrace();
}
return result; //"Failed to fetch data!";
}
#Override
protected void onPostExecute(Integer result) {
// Download complete. Let us update UI
pd.dismiss();
if (result == 1) {
recycleAdapter = new RecycleAdapter(MainActivity.this,onlineData);
recyclerView.setAdapter(recycleAdapter);
} else {
Toast.makeText(MainActivity.this, "Failed to fetch data!", Toast.LENGTH_SHORT).show();
}
}
}
private void parseResult(String result) {
try {
JSONObject response = new JSONObject(result);
JSONArray posts = response.optJSONArray("posts");
onlineData = new ArrayList<>();
for (int i = 0; i < posts.length(); i++) {
JSONObject post = posts.optJSONObject(i);
HashMap<String, String> item = new HashMap<>();
item.put("title", post.optString("title"));
JSONArray jsonArray = post.getJSONArray("attachments");
JSONObject jsonObject1 = jsonArray.getJSONObject(0);
JSONObject jsonArrayImages = jsonObject1.getJSONObject("images");
JSONObject jsonArrayThumb = jsonArrayImages.getJSONObject("thumbnail");
item.put("thump", jsonArrayThumb.optString("url"));
onlineData.add(item);
}
} catch (JSONException e) {
e.printStackTrace();
}
}
}
RecycleAdapter.java
public class RecycleAdapter extends RecyclerView.Adapter<RecycleAdapter.ViewHolderRec> {
List<HashMap<String, String>> onlineData;
SQLiteDatabase db;
Context context;
RecycleAdapter(Context context,List<HashMap<String, String>> onlineData){
this.onlineData = onlineData;
this.context=context;
}
#Override
public ViewHolderRec onCreateViewHolder(ViewGroup parent, int viewType) {
return new ViewHolderRec( LayoutInflater.from(parent.getContext()).inflate(R.layout.item_recycle, parent, false));
}
#Override
public void onBindViewHolder(ViewHolderRec holder, int position) {
HashMap<String,String> map =onlineData.get(position);
//Download image using picasso library
Picasso.with(context).load(map.get("thump"))
.error(R.drawable.placeholder)
.placeholder(R.drawable.placeholder)
.into(holder.iv);
holder.tv.setText(map.get("title"));
}
#Override
public int getItemCount() {
return onlineData.size();
}
public class ViewHolderRec extends RecyclerView.ViewHolder implements View.OnClickListener{
ImageView iv;
TextView tv, quantity;
ImageView Add_Cart;
ImageView Remove_Cart;
public ViewHolderRec(View itemView) {
super(itemView);
iv = (ImageView) itemView.findViewById(R.id.thumbnail);
tv = (TextView) itemView.findViewById(R.id.title);
quantity = (TextView)itemView.findViewById(R.id.cart_qty);
Add_Cart = (ImageView)itemView.findViewById(R.id.cart_add);
Remove_Cart = (ImageView)itemView.findViewById(R.id.cart_remove);
itemView.setOnClickListener(this);
Add_Cart.setOnClickListener(this);
Remove_Cart.setOnClickListener(this);
}
#Override
public void onClick(View v) {
if(v.getId() == Add_Cart.getId()){
increment();
}
else if(v.getId() == Remove_Cart.getId()){
decrement();
}
}
public void increment(){
int currentNos = Integer.parseInt(quantity.getText().toString()) ;
quantity.setText(String.valueOf(++currentNos));
}
public void decrement(){
int currentNos = Integer.parseInt(quantity.getText().toString()) ;
quantity.setText(String.valueOf(--currentNos));
}
}
}
How to do this,
You should create interface, and activity implements this interface.
public interface OnItemClick {
void onClick (String value);
}
When you create adapter (last parameter is this interface)
public class MainActivity extends AppCompatActivity implements OnItemClick {
recycleAdapter = new RecycleAdapter(MainActivity.this,onlineData, this);
recyclerView.setAdapter(recycleAdapter);
#Override
void onClick (String value){
// value this data you receive when increment() / decrement() called
}
// In Adapter
private OnItemClick mCallback;
RecycleAdapter(Context context,List<HashMap<String, String>> onlineData,OnItemClick listener){
this.onlineData = onlineData;
this.context = context;
this.mCallback = listener;
}
....
public void increment(){
int currentNos = Integer.parseInt(quantity.getText().toString()) ;
quantity.setText(String.valueOf(++currentNos));
mCallback.onClick(quantity.getText().toString());
}
public void decrement(){
int currentNos = Integer.parseInt(quantity.getText().toString()) ;
quantity.setText(String.valueOf(--currentNos));
mCallback.onClick(quantity.getText().toString());
}
I failed to do it with both Interface and Observer pattern. But Local Broadcast worked for me.
In Adapter
String ItemName = tv.getText().toString();
String qty = quantity.getText().toString();
Intent intent = new Intent("custom-message");
// intent.putExtra("quantity",Integer.parseInt(quantity.getText().toString()));
intent.putExtra("quantity",qty);
intent.putExtra("item",ItemName);
LocalBroadcastManager.getInstance(context).sendBroadcast(intent);
Main Activity
public void onCreate(Bundle savedInstanceState) {
...
// Register to receive messages.
// We are registering an observer (mMessageReceiver) to receive Intents
// with actions named "custom-message".
LocalBroadcastManager.getInstance(this).registerReceiver(mMessageReceiver,
new IntentFilter("custom-message"));
}
...
public BroadcastReceiver mMessageReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
// Get extra data included in the Intent
String ItemName = intent.getStringExtra("item");
String qty = intent.getStringExtra("quantity");
Toast.makeText(MainActivity.this,ItemName +" "+qty ,Toast.LENGTH_SHORT).show();
}
};
Three popular ways to solve this problem
Interfaces
Phuoc Huynh has already explained how to use interfaces to solves this.
Observer pattern.
Try googling around observer to understand how it works. We will register the classes who want to receive events with the type of events they want to receive. There will be a manager classes to manage registering and unregistering of receivers and also to send the events to all receivers
public class EventManager {
private static EventManager eventManager;
private static Object syncObject = new Object();
private HashMap<String, ArrayList<EventListener>> listeners = new HashMap<>();
private EventManager(){}
public static EventManager getInstance() {
if (eventManager == null) {
synchronized (syncObject) {
if (eventManager == null) {
eventManager = new EventManager();
}
}
}
return eventManager;
}
public synchronized void registerListener(String event, EventListener listener) {
if (listeners.containsKey(event)) {
listeners.get(event).add(listener);
} else {
ArrayList<EventListener> arrayList = new ArrayList<>();
arrayList.add(listener);
listeners.put(event, arrayList);
}
}
public synchronized void unRegisterListener(String event, EventListener listener) {
if (listeners.containsKey(event)) {
listeners.get(event).remove(listener);
if (listeners.get(event).size() == 0) {
listeners.remove(event);
}
}
}
public void sendEvent(String event, Object o) {
if (listeners.containsKey(event)) {
ArrayList<EventListener> listener = listeners.get(event);
for (EventListener eventListener : listener) {
eventListener.onEvent(o);
}
}
}
}
Your MainActivity will register itself as a receiver of increment and decrement events and also implement onEvent method of IEventListener
public class MainActivity extends AppCompatActivity implements IEventListener{
#Override
protected void onCreate(Bundle onSavedInstanceState) {
EventManager.getInstance().registerEvent("increment", this);
EventManager.getInstance().registerEvent("decrement", this)
}
#Override
public void onEvent(String event) {
if (event.equals("increment") {
//increment
} else if (event.equals("decrement") {
//decrement
}
}
#Override
protected void onDestroy() {
EventManager.getInstance().unRegisterEvent("increment", this);
EventManager.getInstance().unRegisterEvent("decrement", this)
}
}
In you adapter class send the events
EventManager.getInstance().sendEvent("increment");
EventManager.getInstance().sendEvent("decrement");
LocalBroadcasts
LocalBroadcasts works the same way as the above example. you have get Instance of LocalBroadcastManger and send Broadcast on it. Define a broadcast receiver in the onCreate of the activity and register it using registerReceiver() in the Activity. Pass an intent filter in the register receiver with actiontype same as the broadcasts you want your activity to receive. Make sure you unregister the broadcasts whenever you don't need them or in the onDestroy of the activity
Simple solution using interface:
Create an interface with method containing objects/data as parameters:
public interface RecyclerViewDataPass {
public void pass(String productName, String quantity);
}
Implement interface method in Activity & pass it through RecyclerView Adapter:
RecyclerViewDataPass recyclerViewDataPass = new RecyclerViewDataPass() {
#Override
public void pass(String productName, String quantity) {
//we get data from adapter here
//assign parameters to activity variables or do the needed operations
}
};
recycleAdapter = new RecycleAdapter(MainActivity.this,onlineData,recyclerViewDataPass);
recyclerView.setAdapter(recycleAdapter);
Edit adapter's constructor:
public class RecycleAdapter extends RecyclerView.Adapter<RecycleAdapter.ViewHolderRec> {
List<HashMap<String, String>> onlineData;
SQLiteDatabase db;
Context context;
RecyclerViewDataPass recyclerViewDataPass; //here is our data pass object
RecycleAdapter(Context context,List<HashMap<String, String>> onlineData, RecyclerViewDataPass recyclerViewDataPass){
this.onlineData = onlineData;
this.context=context;
this.recyclerViewDataPass=recyclerViewDataPass; //get data pass object from activity
}
Inside RecyclerView Adapter call pass function to send data to activity:
recyclerViewDataPass.pass(tv.getText().toString(), quantity.getText().toString());
Check out this. It works for me.
Just Paste in Your Activity or Fragment
rvSelectedProductList = Recyclerview
selcetedItemAdapter = RecyclerView Adapter
rvSelectedProductList.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
final int itemCount = selectedItemAdapter.getItemCount();
for (int i = 0; i < itemCount; i++) {
TextView tvSelling = rvSelectedProductList.getChildAt(i).findViewById(R.id.tvSelling);
TextView textViewDrawerTitle = rvSelectedProductList.getChildAt(i).findViewById(R.id.tvCartQty);
String totalamount = tvSelling.getText().toString();
String qty = textViewDrawerTitle.getText().toString();
System.out.println("qty" + qty);
System.out.println("total" + totalamount);
}
rvSelectedProductList.getViewTreeObserver().removeGlobalOnLayoutListener(this);
}
});
//Simply it works for me
//In onBindViewHolder of RecyclerAdapter write the following code on clickEvent of any view;
Intent intent = new Intent(tContext, TargetActivity.class);
intent.putExtra("key", "value");
tContext.startActivity(intent);
//TargetActivity.java
String str = getIntent().getStringExtra("key");
//You got the value as String :)
add these codes in onBindViewHolder
Intent intent = new Intent("message_subject_intent");
intent.putExtra("name" , String.valueOf(messageSubject.getname()));
LocalBroadcastManager.getInstance(context).sendBroadcast(intent);
Add on MainActivity
public BroadcastReceiver mMessageReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String name= intent.getStringExtra("name");
Toast.makeText(MainActivity.this, name, Toast.LENGTH_SHORT).show();
}
};
LocalBroadcastManager.getInstance(this).registerReceiver(mMessageReceiver,new IntentFilter("message_subject_intent"));
when I conduct onRefresh, my recyclerView adds on another copy to my current recyclerView instead of refreshing it, by looking at my code below does anyone know what the problem is?I have tried everything but nothing seems to work?
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
mParam1 = getArguments().getString(ARG_PARAM1);
mParam2 = getArguments().getString(ARG_PARAM2);
}
//send our volley JSON Request
//Initialize VolleySingleton
mVolleySingleton = VolleySingleton.getInstance();
//intitalize Volley Singleton request key
mRequestQueue = mVolleySingleton.getRequestQueue();
//2 types of requests an Array request and an Object Request
JSONArrayRequest();
}
private void JSONArrayRequest() {
JsonArrayRequest request = new JsonArrayRequest(Request.Method.GET, URL_API, (String) null, new Response.Listener<JSONArray>() {
#Override
public void onResponse(JSONArray response) {
listblogs=parseJSONResponse(response);
mAdapterDashBoard.setBloglist(listblogs);
System.out.println("it worked!!!");
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
ToastTest.t(getActivity(), error.toString());
}
});
mRequestQueue.add(request);
}
private ArrayList<Blogs> parseJSONResponse(JSONArray response) {
if (!response.equals("")) {
ArrayList<Blogs> blogsArrayList = new ArrayList<>();
try {
StringBuilder data = new StringBuilder();
for (int i = 0; i < response.length(); i++) {
JSONObject currentQuestions = response.getJSONObject(i);
String text = currentQuestions.getString("text");
String points = currentQuestions.getString("points");
String ID=currentQuestions.getString("id");
String courseId = currentQuestions.getString("courseId");
String studentId = currentQuestions.getString("studentId");
data.append(text + "\n" + points + "\n" + courseId + "\n");
System.out.println(data);
Blogs blogs = new Blogs();
blogs.setId(ID);
blogs.setMstudentId(studentId);
blogs.setMtext(text);
blogs.setPoints(points);
listblogs.add(blogs);
}
} catch (JSONException e) {
e.printStackTrace();
}
}
return listblogs;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view=inflater.inflate(R.layout.fragment_dashboard,container,false);
mRecyclerView=(RecyclerView)view.findViewById(R.id.fragment_dashboard);
mRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
mAdapterDashBoard=new AdapterDashBoard(getActivity());
mRecyclerView.setAdapter(mAdapterDashBoard);
mPullToRefreshView = (PullToRefreshView)view.findViewById(R.id.pull_to_refresh);
mPullToRefreshView.setOnRefreshListener(new PullToRefreshView.OnRefreshListener() {
#Override
public void onRefresh() {
mPullToRefreshView.postDelayed(new Runnable() {
#Override
public void run() {
mPullToRefreshView.setRefreshing(false);
JSONArrayRequest();
}
}, REFRESH_DELAY);
}
});
return view;
}
}
public class AdapterDashBoard extends RecyclerView.Adapter<AdapterDashBoard.ViewDashboard>{
private LayoutInflater mLayoutInflater;
private ArrayList<Blogs> listblogs=new ArrayList<>();
public AdapterDashBoard(Context context){
mLayoutInflater=LayoutInflater.from(context);
}
public void setBloglist(ArrayList<Blogs> listBlogs){
this.listblogs=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) {
Blogs currentBlog=listblogs.get(position);
holder.questionText.setText(currentBlog.getMtext().toString());
holder.points.setText(currentBlog.getPoints().toString());
holder.id.setText(currentBlog.getId().toString());
}
#Override
public int getItemCount() {
return listblogs.size();
}
static class ViewDashboard extends RecyclerView.ViewHolder{
private ImageView thumbnail;
private TextView questionText;
private TextView points;
private TextView id;
public ViewDashboard (View itemView){
super(itemView);
//thumbnail=(ImageView)itemView.findViewById(R.id.thumbnail);
questionText=(TextView)itemView.findViewById(R.id.questionText);
points=(TextView)itemView.findViewById(R.id.points);
id=(TextView)itemView.findViewById(R.id.ID);
}
}
}
You need to clear your listblogs list before adding new items. This is why you get duplicated values.
Also you're already adding new items to listblogs in parseJSONResponse() method, so there is no need for listblogs=parseJSONResponse(response); in onResponse() method, while its the same list.
Change your onResponse() method to:
#Override
public void onResponse(JSONArray response) {
listblogs.clear(); // here you clear the old data
parseJSONResponse(response);
mAdapterDashBoard.setBloglist(listblogs);
System.out.println("it worked!!!");
}