Update and control multiple CountDownTimer in RecyclerView (pause, resume, delete) - android

I've implemented to my Android app multiple countdown timers with Service.
CountDownTimer is running with service, thus data to fragment is being passed with BroadcastReceiver.
I would like to add each timer as a separate item to the RecyclerView in the fragment and be able to update it as timer is ticking and also to control it - pause, resume, add 1 min and delete.
At the moment the problem is that each second that timer is running, new item is added to RecyclerView and I'm not able to control it - pause, resume and ect.
Service Class:
public int onStartCommand(Intent intent, int flags, int startId) {
if (intent.getAction().equals(Constants.ACTION.START_FOREGROUND_ACTION)){
HandlerThread thread = new HandlerThread("ServiceStartArguments",
android.os.Process.THREAD_PRIORITY_BACKGROUND);
thread.setName(nameOfFood);
thread.start();
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
#Override
public void handleMessage(Message msg) {
// Normally we would do some work here, like download a file.
Thread.currentThread().setName(nameOfFood);
try {
showCountDownTimer(enteredTimeFormatted);
} catch (Exception e) {
// Restore interrupt status.
Thread.currentThread().interrupt();
}
stopSelf(msg.arg1);
}
private void showCountDownTimer(long number) {
String normalStartTime = String.format(
"%02d:%02d:%02d",
TimeUnit.MILLISECONDS.toHours(number),
TimeUnit.MILLISECONDS.toMinutes(number) -
TimeUnit.HOURS.toMinutes(TimeUnit.MILLISECONDS.toHours(number)),
TimeUnit.MILLISECONDS.toSeconds(number) -
TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(number)));
Intent timerStartInfoIntent = new Intent(TIMER_START_INFO);
timerStartInfoIntent.putExtra("VALUE", normalStartTime);
timerStartInfoIntent.putExtra("NAME_FOOD", nameOfFood);
LocalBroadcastManager.getInstance(NotificationService.this).sendBroadcast(timerStartInfoIntent);
CountDownTimer timer = new CountDownTimer(number, 1000) {
#Override
public void onTick(long millisUntilFinished) {
timeLeft = millisUntilFinished;
counter = millisUntilFinished / 1000;
normalTime = String.format(
"%02d:%02d:%02d",
TimeUnit.MILLISECONDS.toHours(timeLeft),
TimeUnit.MILLISECONDS.toMinutes(timeLeft) -
TimeUnit.HOURS.toMinutes(TimeUnit.MILLISECONDS.toHours(timeLeft)),
TimeUnit.MILLISECONDS.toSeconds(timeLeft) -
TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(timeLeft)));
Intent timerInfoIntent = new Intent(TIME_INFO);
timerInfoIntent.putExtra("VALUE", normalTime);
timerInfoIntent.putExtra("NAME_FOOD", nameOfFood);
LocalBroadcastManager.getInstance(NotificationService.this).sendBroadcast(timerInfoIntent);
}
#Override
public void onFinish() {
counter = 0;
Intent timerFinishInfoIntent = new Intent(TIMER_FINISH_INFO);
LocalBroadcastManager.getInstance(NotificationService.this).sendBroadcast(timerFinishInfoIntent);
}
};
timer.start();
}
Adapter Class:
public class TimerRecyclerViewAdapter extends RecyclerView.Adapter<TimerRecyclerViewAdapter.MyViewHolder> {
final private Context mContext;
public List<ModelTimer> mModelTimerList;
private final List<MyViewHolder> listHolder;
public TimerRecyclerViewAdapter(List<ModelTimer> modelTimerList, Context context) {
super();
this.mContext = context;
this.mModelTimerList = modelTimerList;
listHolder = new ArrayList<>();
}
public class MyViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
public final TextView nameTextView;
public final TextView timerTextView;
public final Button pauseBtn;
public final Button addMinBtn;
public final Button deleteBtn;
ModelTimer mModelTimer;
public MyViewHolder(View itemView) {
super(itemView);
nameTextView = (TextView) itemView.findViewById(R.id.active_timer_name);
timerTextView = (TextView) itemView.findViewById(R.id.active_timer_timeLeft);
pauseBtn = (Button) itemView.findViewById(R.id.active_timer_btn_pause);
pauseBtn.setOnClickListener(this);
addMinBtn = (Button) itemView.findViewById(R.id.active_timer_btn_addMin);
addMinBtn.setOnClickListener(this);
deleteBtn = (Button) itemView.findViewById(R.id.active_timer_btn_delete);
deleteBtn.setOnClickListener(this);
}
public void setData (ModelTimer modelTimer){
this.mModelTimer = modelTimer;
timerTextView.setText(modelTimer.expirationTime);
nameTextView.setText(modelTimer.name);
}
#Override
public void onClick(View v) {
// TODO
}
}
#Override
public TimerRecyclerViewAdapter.MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (parent instanceof RecyclerView) {
View v = LayoutInflater.from(parent.getContext()).inflate(
R.layout.item_active_timer,
parent,
false);
v.setFocusable(true);
return new MyViewHolder(v);
} else {
throw new RuntimeException("No bound to RecyclerViewSelection");
}
}
#Override
public void onBindViewHolder(TimerRecyclerViewAdapter.MyViewHolder holder, int position) {
holder.setData(mModelTimerList.get(position));
synchronized (listHolder){
listHolder.add(holder);
}
}
#Override
public int getItemCount() {
return mModelTimerList.size();
}
Here I tried to create a method that will be upgrading each second a timer on specific position instead of adding new item to RecyclerView each time that timer is ticking.
public void swap(List<ModelTimer> modelTimerList){
mModelTimerList.clear();
mModelTimerList.addAll(modelTimerList);
notifyItemChanged(???);
}
public void delete() {
mModelTimerList.clear();
notifyDataSetChanged();
}
}
Fragment with RecyclerView:
public class ActiveTimersFragment extends Fragment {
private RecyclerView mRecyclerView;
private TimerRecyclerViewAdapter mAdapter;
private ArrayList<ModelTimer> listOfTimers;
private TimerStatusReceiver mTimerStatusReceiver;
private static final String ARG_SECTION_NUMBER = "section_number";
public ActiveTimersFragment() {
}
public static ActiveTimersFragment newInstance(int sectionNumber) {
ActiveTimersFragment activeTimersFragment = new ActiveTimersFragment();
Bundle args = new Bundle();
args.putInt(ARG_SECTION_NUMBER, sectionNumber);
activeTimersFragment.setArguments(args);
return activeTimersFragment;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_active_timers, container, false);
mRecyclerView = (RecyclerView) view.findViewById(R.id.fragment_active_timers_recycler_view);
mTimerStatusReceiver = new TimerStatusReceiver();
listOfTimers = new ArrayList<>();
return view;
}
#Override
public void onResume() {
super.onResume();
LocalBroadcastManager.getInstance(getActivity()).registerReceiver(
mTimerStatusReceiver, new IntentFilter(NotificationService.TIME_INFO));
LocalBroadcastManager.getInstance(getActivity()).registerReceiver(
mTimerStatusReceiver, new IntentFilter(NotificationService.TIMER_START_INFO));
LocalBroadcastManager.getInstance(getActivity()).registerReceiver(
mTimerStatusReceiver, new IntentFilter(NotificationService.TIMER_FINISH_INFO));
}
#Override
public void onPause() {
super.onPause();
LocalBroadcastManager.getInstance(getActivity()).unregisterReceiver(mTimerStatusReceiver);
}
private class TimerStatusReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if (intent != null && intent.getAction().equals(NotificationService.TIME_INFO)) {
ModelTimer modelTimer = new ModelTimer();
if (intent.hasExtra("VALUE")) {
modelTimer.setexpirationTime(intent.getStringExtra("VALUE"));
}
if (intent.hasExtra("NAME_FOOD")) {
modelTimer.setName(intent.getStringExtra("NAME_FOOD"));
}
listOfTimers.add(modelTimer);
mAdapter = new TimerRecyclerViewAdapter(listOfTimers, getActivity());
mRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
// Not working
// mAdapter.swap(listOfTimers);
mRecyclerView.setAdapter(mAdapter);
}
if (intent != null && intent.getAction().equals(NotificationService.TIMER_FINISH_INFO)) {
mAdapter.delete();
}
}
}
}

Your whole implementation of recyclerview adapter is wrong. In onBindViewHolder() you are adding new item. onBindViewHolder is called when RecyclerView tries to show new item. So it keeps on iterating, if you add new item in onBindViewHolder. Also, you should use the onBindViewHolder to set the views values in ViewHolder class. Check the whole adapter implementation.
public class TimerRecyclerViewAdapter extends RecyclerView.Adapter<TimerRecyclerViewAdapter.MyViewHolder> {
final private Context mContext;
public List<ModelTimer> mModelTimerList;
public TimerRecyclerViewAdapter(List<ModelTimer> modelTimerList, Context context) {
super();
this.mContext = context;
this.mModelTimerList = modelTimerList;
}
public class MyViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
public final TextView nameTextView;
public final TextView timerTextView;
public final Button pauseBtn;
public final Button addMinBtn;
public final Button deleteBtn;
public MyViewHolder(View itemView) {
super(itemView);
nameTextView = (TextView) itemView.findViewById(R.id.active_timer_name);
timerTextView = (TextView) itemView.findViewById(R.id.active_timer_timeLeft);
pauseBtn = (Button) itemView.findViewById(R.id.active_timer_btn_pause);
pauseBtn.setOnClickListener(this);
addMinBtn = (Button) itemView.findViewById(R.id.active_timer_btn_addMin);
addMinBtn.setOnClickListener(this);
deleteBtn = (Button) itemView.findViewById(R.id.active_timer_btn_delete);
deleteBtn.setOnClickListener(this);
}
#Override
public void onClick(View v) {
// TODO
}
}
#Override
public TimerRecyclerViewAdapter.MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (parent instanceof RecyclerView) {
View v = LayoutInflater.from(parent.getContext()).inflate(
R.layout.item_active_timer,
parent,
false);
v.setFocusable(true);
return new MyViewHolder(v);
} else {
throw new RuntimeException("No bound to RecyclerViewSelection");
}
}
#Override
public void onBindViewHolder(TimerRecyclerViewAdapter.MyViewHolder holder, int position) {
ModelTimer modelTimer=mModelTimerList.get(position);
holder.timerTextView.setText(modelTimer.expirationTime);
holder.nameTextView.setText(modelTimer.name);
}
#Override
public int getItemCount() {
return mModelTimerList.size();
}

Related

How can i get the all value of Recyclerview on Button click?

public class MainActivity extends Activity implements
GetDataContract.View,RecyclerItemClickListener {
private Presenter mPresenter;
RecyclerView recyclerView;
LinearLayoutManager linearLayoutManager;
CountryAdapter countryAdapter;
EditText etEnterName;
Button btAddItem;
List<CountryRes> allCountriesEditValue;
List<CountryRes> allCountriesData;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
getView();
}
private void getView() {
/*presentator */
mPresenter = new Presenter(this);
/*initiliaze of id*/
recyclerView = (RecyclerView) findViewById(R.id.recycler);
etEnterName = (EditText) findViewById(R.id.etEnterName);
btAddItem = (Button) findViewById(R.id.btAddItem);
linearLayoutManager = new LinearLayoutManager(this);
/*initiliaze the arraylist*/
allCountriesData=new ArrayList<>();
recyclerView.setLayoutManager(linearLayoutManager);
btAddItem.setOnClickListener(new AddButtonClick());
}
#Override
public void onGetDataFailure(String message) {
Log.d("Status", message);
}
#Override
public void onGetDataSuccess(String message, List<CountryRes>
allCountriesData) {
/*add the value mannulay*/
CountryRes countryRes = new CountryRes();
countryRes.setName(etEnterName.getText().toString());
allCountriesData.add(countryRes);
countryAdapter = new CountryAdapter(getApplicationContext(),
allCountriesData, (RecyclerItemClickListener) this);
recyclerView.setAdapter(countryAdapter);
/*set the data in the room*/
AppDataBase database = AppDataBase.getAppDatabase(this);
DataGenerator.with(database).generateCats(allCountriesData);
Logger.displayCatsInLog(database.catDao().loadAll());
countryAdapter.notifyDataSetChanged();
}
/*on item click*/
#Override
public void onDashBoardItemClick(String pos) {
Bundle bundle = new Bundle();
bundle.putString("TABVALUE", pos);
Intent intent = new Intent(getApplicationContext(),
DynamicTabsActivity.class);
intent.putExtras(bundle);
startActivity(intent);
}
private class AddButtonClick implements View.OnClickListener {
#Override
public void onClick(View view) {
mPresenter.getDataFromURL(getApplicationContext(), "");
}
}
}
class adapter
public class CountryAdapter extends
RecyclerView.Adapter<CountryAdapter.MyViewHolder> {
private Context context;
private List<CountryRes> list = new ArrayList<>();
private List<CountryRes> list_edit = new ArrayList<>();
private RecyclerItemClickListener onRecyclerItemClickListener;
public CountryAdapter(Context context, List<CountryRes> list,
RecyclerItemClickListener onRecyclerItemClickListener) {
this.context = context;
this.list = list;
this.onRecyclerItemClickListener = onRecyclerItemClickListener;
}
#Override
public CountryAdapter.MyViewHolder onCreateViewHolder(ViewGroup parent,
int viewType) {
View layoutView;
layoutView =
LayoutInflater.from(parent.getContext()).inflate(R.layout.card_item, parent,
false);
return new FooterViewHolder(layoutView,
onRecyclerItemClickListener);
}
#Override
public void onBindViewHolder(CountryAdapter.MyViewHolder holder, int
position) {
holder.tvCountryName.setText(list.get(position).getName());
}
#Override
public int getItemCount() {
return list.size();
}
public class MyViewHolder extends RecyclerView.ViewHolder {
TextView tvCountryName;
LinearLayout llListItem;
public MyViewHolder(View itemView) {
super(itemView);
tvCountryName = (TextView)
itemView.findViewById(R.id.tv_country_name);
llListItem = (LinearLayout)
itemView.findViewById(R.id.llListItem);
}
}
private class FooterViewHolder extends MyViewHolder {
public FooterViewHolder(View layoutView, final
RecyclerItemClickListener onRecyclerItemClickListener) {
super(layoutView);
llListItem.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (onRecyclerItemClickListener != null) {
onRecyclerItemClickListener.onDashBoardItemClick(tvCountryName.getText().toS
tring());
}
}
});
}
}
}
Interface
public interface RecyclerItemClickListener {
void onDashBoardItemClick(String pos);
}
Case 1: Inside ViewHolder if you need to understand exactly position of clicked item you could call getAdapterPosition().
Case 2: You just need to receive all items of adapter. It is simple, make getter method which will return the items.
Case 3: Send info to activity, first make some specific event listener of your view inside ViewHolder, then event triggers (user clicks or other) and you call your interface method which you passed inside adapter, that was implemented in activity.
Tell me if you need an example, i will do it.
Try this one,
Button button= (Button) findViewById(R.id.your_button_id);
button.setOnClickListener( new OnClickListener() {
#Override
public void onClick(View v) {
//create new ArrayList.
//ArrayList<CountryRes> showList=new ArrayList<>;
//now, put all stored data of a list in this arraylist.
showList.addAll(allCountriesData);
}
});

How update recyclerviews other items when click on an item?

I have an application that uses MediaPlayer class to play musics from internet. I used recyclerview, and on the each item , it has a play/puse button to start playing and pause the sound. How to change the play button to pause button when the user clicks on another items play button?
public class Adapter extends RecyclerView.Adapter<Adapter.Viewholder> {
private List<Track> tracks;
private Context context;
public Adapter(List<Track> tracks, Context context) {
this.tracks = tracks;
this.context = context;
}
#NonNull
#Override
public Viewholder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.track_item, parent, false);
return new Viewholder(view);
}
#Override
public void onBindViewHolder(#NonNull final Viewholder holder, final int position) {
holder.title.setText(tracks.get(position).getTitle());
holder.id.setText(tracks.get(position).getId());
Glide.with(context).load(tracks.get(position).getImgurl()).into(holder.trackImage);
holder.btnPlay.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
holder.btnPause.setVisibility(View.VISIBLE);
Intent intent = new Intent(context, Player.class);
intent.putExtra("URL", tracks.get(position).getMusicurl());
context.startService(intent);
}
});
holder.btnPause.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Player.killMediaPlayer();
holder.btnPause.setVisibility(View.INVISIBLE);
}
});
}
#Override
public int getItemCount() {
return tracks.size();
}
public static class Viewholder extends RecyclerView.ViewHolder {
TextView title, id;
ImageView trackImage;
ImageButton btnPlay;
public Viewholder(View itemView) {
super(itemView);
title = itemView.findViewById(R.id.title);
id = itemView.findViewById(R.id.id);
trackImage = itemView.findViewById(R.id.trackImage);
btnPlay = itemView.findViewById(R.id.play);
}
}
}
Very simple just loop through your entire dataset and set all of them to pause except the current one.Then call notifyDatasetChanged();
your can use notifyDataSetChange() - it will update all recyclerView items
use notifyItemChanged(poition) - it will update the particular position.
NOTE : Suppose if your mobile screen has 8 items display at a moment and you
made 1th position as pause, the 9th position will show as pause.
To overcome this, try to compare the song_title/artist name before
notifying
you have to use notifyDataSetChanged() - it will reset all recyclerView items
then
using notifyItemChanged(poition) or mList.get(getAdapterPosition()) - it will update the specific position.
Here is sample code :
public class MainActivity extends AppCompatActivity {
private TrackAdapter trackAdapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
RecyclerView recyclerView = findViewById(R.id.reycleView);
((SimpleItemAnimator) recyclerView.getItemAnimator()).setSupportsChangeAnimations(false);
trackAdapter = new TrackAdapter();
trackAdapter.setCallBack(new CallBackImpl());
trackAdapter.setTracks(getTracks());
RecyclerView.LayoutManager mLayoutManager = new LinearLayoutManager(this);
recyclerView.setLayoutManager(mLayoutManager);
recyclerView.setHasFixedSize(true);
recyclerView.setAdapter(trackAdapter);
}
private List<Track> tracks;
private List<Track> getTracks() {
tracks = new ArrayList<>();
for (int i = 0; i < 50; i++) {
Track track = new Track();
track.setTrackName(" Track " + i);
track.setPlaying(false);
tracks.add(track);
}
return tracks;
}
int currentPosition = -1;
private class CallBackImpl implements TrackAdapter.CallBack {
#Override
public void clicked(int position) {
Track track = tracks.get(position);
tracks.get(position).setPlaying(!track.isPlaying());
if (currentPosition >-1) {
track = tracks.get(currentPosition);
tracks.get(currentPosition).setPlaying(!track.isPlaying());
}
trackAdapter.setTracks(tracks);
trackAdapter.notifyItemChanged(currentPosition);
trackAdapter.notifyItemChanged(position);
currentPosition = position;
}
}
}
TrackAdapter.java
public class TrackAdapter extends RecyclerView.Adapter<TrackAdapter.VH> {
private int current;
public void setCallBack(CallBack callBack) {
this.callBack = callBack;
}
private CallBack callBack;
interface CallBack
{
void clicked(int position);
}
public void setTracks(List<Track> tracks) {
this.tracks = tracks;
}
private List<Track> tracks;
#Override
public VH onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.layout, parent, false);
return new VH(view);
}
#Override
public void onBindViewHolder(VH holder, int position) {
holder.setData(tracks.get(position));
}
#Override
public int getItemCount() {
if (tracks == null) {
return 0;
} else {
return tracks.size();
}
}
class VH extends RecyclerView.ViewHolder {
TextView textView;
TextView playView;
public VH(View itemView) {
super(itemView);
textView = itemView.findViewById(R.id.track);
playView = itemView.findViewById(R.id.trackplay);
playView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (callBack!=null)
{
callBack.clicked(getAdapterPosition());
}
}
});
}
void updateState(boolean isPlaying) {
if (isPlaying) {
current = getAdapterPosition();
playView.setText("Playing");
} else {
playView.setText("Stopped");
}
}
void setData(Track data) {
textView.setText(data.getTrackName());
updateState(data.isPlaying());
}
}
}
Track .java
public class Track {
private boolean isPlaying;
public String getTrackName() {
return trackName;
}
public void setTrackName(String trackName) {
this.trackName = trackName;
}
private String trackName;
public boolean isPlaying() {
return isPlaying;
}
public void setPlaying(boolean playing) {
isPlaying = playing;
}
}
layout.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:orientation="vertical"
android:layout_height="wrap_content">
<TextView
android:id="#+id/track"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:id="#+id/trackplay"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
Click is implemented on Stopped Text.
holder.btnPlay.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(Track.isPlaying()){
notifyItemChanged(currentItem, holder );
}
Track.setPlaying(true);
currentItem = holder.getAdapterPosition();
Log.i("TAG", "Position : " + currentItem);
holder.equalizer.setVisibility(View.VISIBLE);
holder.btnPause.setVisibility(View.VISIBLE);
holder.btnPlay.setVisibility(View.INVISIBLE);
Intent intent = new Intent(context, Player.class);
intent.putExtra("URL", tracks.get(position).getMusicurl());
intent.putExtra("ID", tracks.get(position).getId());
context.startService(intent);
}
});

Removing recyclerview items from the Adapter

I have two tabs (fragments), NewOrders and FinishedOrders, I'm populating the orders via Volley requests, now each item inside the New Orders tab has a SwipeLayout which show a clickable textview that makes the order finished, and move it to the other tab (backend stuff..), and I got this working perfectly,
The problem is when I click to finish, the recyclerview isn't updated once the request sent successfully, I have to do pull-to-refresh so it would update..! it seems easy to solve, but the issue is handling the swipelayout listener done inside onBindView method inside the adapter..!! that's only place to access it according to the library I'm using (I guess)..! on the other hand refreshing and populating the list happens in the NewOrder tab fragment..!
So how can I make the item to be removed from the list after the click and becomes updated..?!
Any thoughts..!?
My Adapter Class + ViewHolder
Note: the implemented methods in the adapter are required because of the interface of SwipeLayout library
public class OrdersDataAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
implements SwipeAdapterInterface, SwipeItemMangerInterface {
protected SwipeItemRecyclerMangerImpl mItemManger = new SwipeItemRecyclerMangerImpl(this);
public Context context;
ArrayList<OrderPresenter> orders;
public OrdersDataAdapter(ArrayList<OrderPresenter> orders, Context context) {
this.orders = orders;
this.context = context;
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.order_card, parent, false);
return new NewOrderVH(v);
}
#Override
public void onBindViewHolder(final RecyclerView.ViewHolder holder, final int position) {
final OrderPresenter order = this.orders.get(position);
final NewOrderVH vh1 = (NewOrderVH) holder;
vh1.setData(orders.get(position));
mItemManger.bindView(vh1.itemView, position);
vh1.swipeLayout.setShowMode(SwipeLayout.ShowMode.PullOut);
vh1.swipeLayout.addDrag(SwipeLayout.DragEdge.Left,
vh1.swipeLayout.findViewById(R.id.bottom_wrapper));
if (order.isFinished()) {
vh1.swipeLayout.setSwipeEnabled(false);
vh1.setBadge("DONE");
vh1.setBadgeColor(order.getBadgeColor());
} else {
vh1.finish.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
// get the clicked item position?
final int position = vh1.getAdapterPosition();
// these responsible for the request which make the order finished
OrderPresenter order = orders.get(position);
OrderRepository.setOrderFinURL(order.getID());
OrderRepository.FinishOrder(order.getID(), context);
/*the commented three lines below didn't help with the problem*/
// notifyItemChanged(position);
// notifyItemRemoved(position);
// notifyDataSetChanged();*/
order.setStatus(order.getStatusText(Order.FINISHED));
}
});
}
}
#Override
public int getItemCount() {
return orders.size();
}
public class NewOrderVH extends RecyclerView.ViewHolder {
SwipeLayout swipeLayout;
private TextView finish;
private CardView orderCard;
TextView Badge;
private ImageView cusPic;
private TextView cusName;
private TextView CusAdress;
private TextView vendorsNum;
private TextView itemsNum;
private TextView time;
private TextView emptyView;
public NewOrderVH(View itemView) {
super(itemView);
Badge = (TextView) itemView.findViewById(R.id.badge);
swipeLayout = (SwipeLayout) itemView.findViewById(R.id.swipe);
finish = (TextView) itemView.findViewById(R.id.finish);
orderCard = (CardView) itemView.findViewById(R.id.OrderCard);
cusPic = (ImageView) itemView.findViewById(R.id.cusPic);
cusName = (TextView) itemView.findViewById(R.id.cusName);
CusAdress = (TextView) itemView.findViewById(R.id.CusAdress);
vendorsNum = (TextView) itemView.findViewById(R.id.vendorsNum);
itemsNum = (TextView) itemView.findViewById(R.id.itemsNum);
time = (TextView) itemView.findViewById(R.id.time);
emptyView = (TextView) itemView.findViewById(R.id.empty_view);
orderCard.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent = new Intent(v.getContext(), OrderDetails.class);
v.getContext().startActivity(intent);
}
});
}
public void setData(final OrderPresenter data) {
time.setText(data.getOrderTime());
cusName.setText(data.getFullName());
vendorsNum.setText(data.getVendorsCount());
itemsNum.setText(data.getItemsCount());
CusAdress.setText(data.getFullAddress());
Picasso.with(context).load(data.getCustomerPicture()).into(cusPic);
}
public void setBadgeColor(int drawable) {
this.Badge.setBackgroundResource(drawable);
}
public void setBadge(String badge) {
this.Badge.setText(badge);
}
}
#Override
public int getSwipeLayoutResourceId(int position) {
return R.id.swipe;
}
#Override
public void openItem(int position) {
}
#Override
public void closeItem(int position) {
}
#Override
public void closeAllExcept(SwipeLayout layout) {
}
#Override
public void closeAllItems() {
}
#Override
public List<Integer> getOpenItems() {
return null;
}
#Override
public List<SwipeLayout> getOpenLayouts() {
return null;
}
#Override
public void removeShownLayouts(SwipeLayout layout) {
}
#Override
public boolean isOpen(int position) {
return false;
}
#Override
public Attributes.Mode getMode() {
return null;
}
#Override
public void setMode(Attributes.Mode mode) {
}
}
My NewOrder Fragment
Note: the FinishedOrders tab (fragment) does the same thing as new order but filters the current the Finished status.
public class NewOrdersTab extends Fragment {
RecyclerView recyclerView;
OrdersDataAdapter adapter;
private SwipeRefreshLayout swiperefresh;
private TextView emptyView;
ArrayList<OrderPresenter> modelData;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
final View rootView = inflater.inflate(R.layout.new_orders_tab_frag, container, false);
modelData = new ArrayList<>();
recyclerView = (RecyclerView) rootView.findViewById(R.id.recyclerView);
swiperefresh = (SwipeRefreshLayout) rootView.findViewById(R.id.swiperefresh);
recyclerView.setLayoutManager(new LinearLayoutManager(this.getActivity()));
swiperefresh.setColorSchemeResources(R.color.colorPrimary, R.color.color_error, R.color.colorInfo);
adapter = new OrdersDataAdapter(modelData, getActivity());
emptyView = (TextView) rootView.findViewById(R.id.empty_view);
recyclerView.setAdapter(adapter);
adapter.setMode(Attributes.Mode.Single);
OrderRepository.fetchOrders("awaiting-shipment", getActivity(), new DataFetch() {
#Override
public void onResponse(ArrayList<OrderPresenter> data) {
swiperefresh.setRefreshing(true);
if (data.size() != 0) {
swiperefresh.setRefreshing(true);
emptyView.setVisibility(View.GONE);
modelData.clear();
modelData.addAll(data);
adapter.notifyDataSetChanged();
} else {
emptyView.setVisibility(View.VISIBLE);
emptyView.setText(getString(R.string.No_New_Orders));
}
swiperefresh.setRefreshing(false);
}
});
return rootView;
}
}
I figured it out, I just added these two lines after I make the request..!
orders.remove(position);
notifyItemRemoved(position);
//notifyDataSetChanged(position);

Android - Recycler View item get swapped when scrolled

Can somebody explain what is the problem.
I have a recycler grid view with each item consisting countdown timer and view which changes after a countdown time is completed.
But the problem arises when I do scroll to down and back to top, my items were change for other items in the list, and if I do scroll again, the items again are changed.
This is my adapter.
public class TableTransactionRecyclerView extends RecyclerView.Adapter<TableTransactionRecyclerView.ViewHolder> {
private ArrayList<TableInfo> tableList;
private OnItemClickListener listener;
private static Context context;
private static SharedPreferences preferences;
private static List<ViewHolder> lstHolders;
public Runnable updateRemainingTimeRunnable = new Runnable() {
#Override
public void run() {
synchronized (lstHolders) {
for (ViewHolder holder : lstHolders) {
holder.updateTimeRemaining();
}
}
}
};
public TableTransactionRecyclerView(Context context, ArrayList<TableInfo> tableList, OnItemClickListener listener) {
this.tableList = tableList;
this.listener = listener;
this.context = context;
preferences = context.getSharedPreferences(CommonConsts.MY_PREFERENCES, Context.MODE_PRIVATE);
lstHolders = new ArrayList<>();
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
ViewHolder vh;
View itemView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.table_transaction_row_layout, parent, false);
vh = new ViewHolder(itemView);
synchronized (lstHolders) {
lstHolders.add(vh);
}
return vh;
}
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
holder.bind(tableList, position, listener);
}
#Override
public int getItemCount() {
return tableList.size();
}
public static class ViewHolder extends RecyclerView.ViewHolder {
private TextView textView;
public ImageButton popupMenuBtn;
private ProgressBar showLoadingImage;
private ImageView successTick;
private ImageView tableIcon;
private LinearLayout processingLayout;
private View lineView;
private LatoTextView transactionAmountTextView;
private LatoTextView timerCountTextView;
private ArrayList<TableInfo> tableList;
private int position;
public ViewHolder(View itemView) {
super(itemView);
textView = (TextView) itemView.findViewById(R.id.table_id_text_view);
popupMenuBtn = (ImageButton) itemView.findViewById(R.id.pop_menu_btn);
showLoadingImage = (ProgressBar) itemView.findViewById(R.id.show_loading_image);
successTick = (ImageView) itemView.findViewById(R.id.success_image_view);
lineView = itemView.findViewById(R.id.view_id);
tableIcon = (ImageView) itemView.findViewById(R.id.table_icon);
processingLayout = (LinearLayout) itemView.findViewById(R.id.processing_layout);
transactionAmountTextView = (LatoTextView) itemView.findViewById(R.id.transaction_amount_text_view);
timerCountTextView = (LatoTextView) itemView.findViewById(R.id.timer_count_down_id);
}
public void bind(final ArrayList<TableInfo> tableList, final int position, final OnItemClickListener listener) {
TableInfo item = tableList.get(position);
this.tableList = tableList;
this.position = position;
textView.setText(item.getTableNumber());
if (item.getIsProcessing()) {
showLoadingImage.setVisibility(View.VISIBLE);
successTick.setVisibility(View.GONE);
tableIcon.setVisibility(View.GONE);
processingLayout.setVisibility(View.VISIBLE);
transactionAmountTextView.setText(Utils.setFormattedText(String.valueOf(item.getTransactionAmt())));
synchronized (lstHolders) {
updateTimeRemaining();
}
} else {
showLoadingImage.setVisibility(View.GONE);
tableIcon.setVisibility(View.VISIBLE);
processingLayout.setVisibility(View.GONE);
}
setLayout(tableList, position, item.getIsProcessing(), item.isLastTransactionSuccess());
}
public void setLayout(final ArrayList<TableInfo> tableList, final int position, boolean isTransaction, boolean isSuccess) {
final TableInfo item = tableList.get(position);
if(isTransaction){
item.setHandler(null);
item.setUIChangeCompletedSuccess(true);
showLoadingImage.setVisibility(View.VISIBLE);
tableIcon.setVisibility(View.GONE);
processingLayout.setVisibility(View.VISIBLE);
transactionAmountTextView.setText(Utils.setFormattedText(String.valueOf(item.getTransactionAmt())));
lineView.setBackgroundDrawable(context.getResources().getDrawable(R.drawable.txn_view_drawable));
}else{
showLoadingImage.setVisibility(View.GONE);
tableIcon.setVisibility(View.VISIBLE);
processingLayout.setVisibility(View.GONE);
if(item.isUIChangeCompletedSuccess()) {
item.setUIChangeCompletedSuccess(false);
if (isSuccess) {
successTick.setVisibility(View.VISIBLE);
lstHolders.get(position).lineView.setBackgroundDrawable(context.getResources().getDrawable(R.drawable.txn_success_view_drawable));
Handler handler;
if (item.getHandler() == null) {
handler = new Handler();
item.setHandler(handler);
handler.postDelayed(new Runnable() {
#Override
public void run() {
lstHolders.get(position).lineView.setBackgroundDrawable(context.getResources().getDrawable(R.drawable.txn_view_drawable));
successTick.setVisibility(View.GONE);
item.setHandler(null);
}
}, 25000);
}
} else {
successTick.setVisibility(View.GONE);
lstHolders.get(0).lineView.setBackgroundDrawable(context.getResources().getDrawable(R.drawable.txn_unsuccess_view_drawable));
Handler handler;
if (item.getHandler() == null) {
handler = new Handler();
item.setHandler(handler);
handler.postDelayed(new Runnable() {
#Override
public void run() {
lstHolders.get(position).lineView.setBackgroundDrawable(context.getResources().getDrawable(R.drawable.txn_view_drawable));
successTick.setVisibility(View.GONE);
item.setHandler(null);
}
}, 25000);
}
}
}
}
}
public void updateTimeRemaining() {
timerCountTextView.setText(preferences.getString(tableList.get(position).getTableId(), ""));
}
}
}
and i have set adapter like this:
mAdapter = new TableTransactionRecyclerView(this, tableList, this);
RecyclerView.LayoutManager mLayoutManager = new GridLayoutManager(getApplicationContext(), 4, GridLayoutManager.VERTICAL, false);
recyclerView.setLayoutManager(mLayoutManager);
recyclerView.setItemAnimator(new DefaultItemAnimator());
recyclerView.setHasFixedSize(true);
recyclerView.setAdapter(mAdapter);
I have also looked at the problem in following links which didnot solved my problem.
Recyclerview changing items when is scrolled
Recyclerview Changing Items During Scroll
Try overriding the following:
#Override
public int getItemViewType(int position) {
return position;
}

update data from intentservice on an activity

I have an activity with the following code and I am trying to update the data from IntentService by creating the instance of the class and calling the method to update but it's crashing with a null pointer exception at mAdapter. Is this the right way to pass data from IntentService to an activity?
COde:
public class MainActivity extends Activity {
RecyclerView rv;
SimpleStringRecyclerViewAdapter mAdapter;
public static final TypedValue mTypedValue = new TypedValue();
public static int mBackground;
public static List<String> mValues;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.cheesecake_homepage_fragment_cheese_list);
rv = (RecyclerView) findViewById(R.id.recyclerview);
setupRecyclerView(rv);
send_msg("");
}
public void setupRecyclerView(RecyclerView recyclerView) {
mAdapter = new SimpleStringRecyclerViewAdapter(getBaseContext(),
getRandomSublist(Cheeses.sCheeseStrings, 3));
recyclerView.setLayoutManager(new LinearLayoutManager(recyclerView.getContext()));
recyclerView.setAdapter(mAdapter);
}
private List<String> getRandomSublist(String[] array, int amount) {
ArrayList<String> list = new ArrayList<>(amount);
Random random = new Random();
while (list.size() < amount) {
list.add(array[random.nextInt(array.length)]);
}
return list;
}
public static class SimpleStringRecyclerViewAdapter
extends RecyclerView.Adapter<SimpleStringRecyclerViewAdapter.ViewHolder> {
public static class ViewHolder extends RecyclerView.ViewHolder {
public String mBoundString;
public final View mView;
public final ImageView mImageView;
public final TextView mTextView;
public ViewHolder(View view) {
super(view);
mView = view;
mImageView = (ImageView) view.findViewById(R.id.avatar);
mTextView = (TextView) view.findViewById(android.R.id.text1);
}
#Override
public String toString() {
return super.toString() + " '" + mTextView.getText();
}
}
public String getValueAt(int position) {
return mValues.get(position);
}
public SimpleStringRecyclerViewAdapter(Context context, List<String> items) {
context.getTheme().resolveAttribute(R.attr.selectableItemBackground, mTypedValue, true);
mBackground = mTypedValue.resourceId;
mValues = items;
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.cheesecake_homepage_list_item, parent, false);
view.setBackgroundResource(mBackground);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(final ViewHolder holder, int position) {
holder.mBoundString = mValues.get(position);
holder.mTextView.setText(mValues.get(position));
holder.mView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Context context = v.getContext();
/*Intent intent = new Intent(context, CheeseDetailActivity.class);
intent.putExtra(CheeseDetailActivity.EXTRA_NAME, holder.mBoundString);
context.startActivity(intent);*/
}
});
}
#Override
public int getItemCount() {
return mValues.size();
}
}
public void send_msg( String set_text){
new Handler(Looper.getMainLooper()).post(new Runnable() {
#Override
public void run() {
List<String> uu = getRandomSublist(Cheeses.sCheeseStrings, 1);
mValues.addAll(uu);
mAdapter.notifyDataSetChanged();
}
});
}
}
In intent service:
MainActivity test = new MainActivity();
test.send_msg("");
You can not use MainActivity instance like that in your Intent service code.
There are multiple approach to update UI from service like, LocalBroadcastReceivers, Messengers, BoundedService etc.
You can find an example to update UI from service using LocalBroadcastManager here
update data from intentservice on an activity
By creating Object of class which is extending Activity or any other main application component is not right way for communication between components.
For with in process communication(as in your case want to send data from IntentService to Activity) use LocalBroadcastManager

Categories

Resources