I'm implementing Swipe stack demo from here. Now I want track progress of swiped cards. I already made my own logic, and it's working pretty fine. but I've one more functionality, which is while clicking on previous button, user can see one by one all swiped cards in reverse order.
But my swiped card progress stack is not working in that case. How can I do this?
Explain: not total swiped cards count, but which one card is currently I'm seeing like 4 Out of 10
DisplayCardActivity:
package com.jimmytrivedi.cardswipedemo.Activity;
import android.app.ProgressDialog;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.ImageButton;
import android.widget.TextView;
import android.widget.Toast;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import com.jimmytrivedi.cardswipedemo.Adapter.SwipeStackAdapter;
import com.jimmytrivedi.cardswipedemo.Data.FetchDataFromUriAsyncTask;
import com.jimmytrivedi.cardswipedemo.Listener.JSONDataListener;
import com.jimmytrivedi.cardswipedemo.R;
import com.jimmytrivedi.cardswipedemo.View.SwipeStack;
import java.util.ArrayList;
import butterknife.BindView;
import butterknife.ButterKnife;
public class DisplayCardActivity extends BaseActivity implements SwipeStack.SwipeStackListener, View.OnClickListener, JSONDataListener {
public static final String TAG = DisplayCardActivity.class.getSimpleName();
#BindView(R.id.previous)
ImageButton mPrevious;
#BindView(R.id.next)
ImageButton mNext;
#BindView(R.id.swipe_stack)
SwipeStack mSwipeStack;
#BindView(R.id.fab)
FloatingActionButton mFAB;
#BindView(R.id.card_progress)
TextView cardProgress;
private FetchDataFromUriAsyncTask dataFromUriAsyncTask;
private ProgressDialog progressDialog;
private ArrayList<String> mData;
private ArrayList<String> mTempData;
private int mCurrentCardPosition = 1, lastSwipedPosition = 0;
#Override
protected void onCreate(Bundle savedInstanceState) {
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
super.onCreate(savedInstanceState);
init();
}
#Override
protected int getLayoutResource() {
return R.layout.activity_display_card;
}
private void init() {
ButterKnife.bind(this);
setClickListener();
mTempData = new ArrayList<>();
mPrevious.setEnabled(false);
mPrevious.setColorFilter(getResources().getColor(R.color.colorGray));
dataFromUriAsyncTask = new FetchDataFromUriAsyncTask(this, this);
dataFromUriAsyncTask.setJSONDataListener(this);
progressDialog = new ProgressDialog(this);
loadDataFromUrl();
}
private void setClickListener() {
mPrevious.setOnClickListener(this);
mNext.setOnClickListener(this);
mFAB.setOnClickListener(this);
}
private void loadDataFromUrl() {
//Showing progress dialog
progressDialog.setMessage("Fetching Data from...");
progressDialog.setCancelable(false);
progressDialog.show();
dataFromUriAsyncTask.execute();
}
private void changePreviousButtonStatus(int positionValue) {
if (lastSwipedPosition == positionValue) {
mPrevious.setEnabled(false);
mPrevious.setColorFilter(getResources().getColor(R.color.colorGray));
} else {
mPrevious.setEnabled(true);
mPrevious.setColorFilter(getResources().getColor(R.color.colorBlack));
}
}
#Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.previous:
changePreviousButtonStatus(1);
lastSwipedPosition = lastSwipedPosition - 1;
if (lastSwipedPosition >= 0) {
mTempData.clear();
for (int i = lastSwipedPosition; i < mData.size(); i++) {
mTempData.add(mData.get(i));
}
mSwipeStack.resetStack();
setCurrentCardPosition(lastSwipedPosition);
} else {
lastSwipedPosition = 0;
}
break;
case R.id.next:
changePreviousButtonStatus(1);
mSwipeStack.swipeTopViewToRight();
break;
case R.id.fab:
mPrevious.setEnabled(false);
mPrevious.setColorFilter(getResources().getColor(R.color.colorGray));
lastSwipedPosition = 0;
mTempData.clear();
mTempData.addAll(mData);
mSwipeStack.resetStack();
if (mData != null)
cardProgress.setText(getResources().getString(R.string.default_count) + mData.size());
break;
}
}
#Override
public void onViewSwipedToLeft(int position) {
mCurrentCardPosition = position + 2;
setCurrentCardPosition(mCurrentCardPosition);
lastSwipedPosition = position + 1;
changePreviousButtonStatus(0);
}
#Override
public void onViewSwipedToRight(int position) {
mCurrentCardPosition = position + 2;
setCurrentCardPosition(mCurrentCardPosition);
lastSwipedPosition = position + 1;
changePreviousButtonStatus(0);
}
#Override
public void onStackEmpty() {
cardProgress.setText("No card in stack");
}
#Override
public void onClickData(ArrayList<String> getData) {
// Dismiss the progress dialog
if (progressDialog.isShowing())
progressDialog.dismiss();
mData = new ArrayList<>(getData);
mTempData.addAll(mData);
setCurrentCardPosition(mCurrentCardPosition);
SwipeStackAdapter mAdapter = new SwipeStackAdapter(mTempData);
mSwipeStack.setAdapter(mAdapter);
mSwipeStack.setListener(this);
}
#Override
public void onJSONParsingError(String error) {
if (progressDialog.isShowing())
progressDialog.dismiss();
showToast(getString(R.string.user_error), Toast.LENGTH_LONG);
}
private void showToast(String message, int length) {
Toast.makeText(this, message, length).show();
}
private void showLog(String msg) {
Log.d(TAG, msg);
}
private void setCurrentCardPosition(int currentPosition) {
cardProgress.setText(currentPosition + " Out of " + mData.size());
}
}
Adapter:
package com.jimmytrivedi.cardswipedemo.Adapter;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;
import com.jimmytrivedi.cardswipedemo.R;
import java.util.List;
public class SwipeStackAdapter extends BaseAdapter {
public static final String TAG = SwipeStackAdapter.class.getSimpleName();
private List<String> mData;
public SwipeStackAdapter(List<String> data) {
this.mData = data;
}
#Override
public int getCount() {
return mData.size();
}
#Override
public String getItem(int position) {
return mData.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
convertView = LayoutInflater.from(parent.getContext()).inflate(R.layout.card, parent, false);
TextView textViewCard = convertView.findViewById(R.id.textViewCard);
textViewCard.setText(mData.get(position));
return convertView;
}
private void showLog(String msg) {
Log.d(TAG, msg);
}
}
Problem:
Use case: I've 10 cards (001, 002..010). And there are total 5 things.
1. Left swipe
2. Right seipe
3. Previous button
4. Next button
5. Reset button
If I start right swiping 001 then 002 now I pressed next button for 003 and 004. Now I pressed previous button then again next and again previous,. That time order is not mainting.
Hold a global variable and increment it on SwipeLeft and SwipeRight callback
private int totalCardsSwiped = 0;
#Override
public void onViewSwipedToLeft(int position) {
totalCardsSwiped++; }
#Override
public void onViewSwipedToRight(int position) {
totalCardsSwiped++; }
Why are you doing this in swiped callback methods?
mCurrentCardPosition = position + 2;
I think here is the problem.
or you can call this setCurrentCardPosition() method with the current position
#Override
public void onViewSwipedToLeft(int position) {
mCurrentCardPosition = position + 2;
setCurrentCardPosition(position);
lastSwipedPosition = position + 1;
changePreviousButtonStatus(0);
}
#Override
public void onViewSwipedToRight(int position) {
mCurrentCardPosition = position + 2;
setCurrentCardPosition(position);
lastSwipedPosition = position + 1;
changePreviousButtonStatus(0);
}
Edited
int currentPosition = 1;
After Adding Data in list
txtCardProgress.setText("1 out of " + mData.size());
in onClick
#Override
public void onClick(View v) {
if (v.equals(mButtonLeft)) {
swipedLastPosition = swipedLastPosition - 1;
currentPosition =currentPosition -1;
if (swipedLastPosition >= 0) {
mTempData.clear();//clear all data
for (int i = swipedLastPosition; i < mData.size(); i++) {
mTempData.add(mData.get(i));
}
mSwipeStack.resetStack();
if (swipedLastPosition == 0) {
Toast.makeText(this, "hide back button", Toast.LENGTH_SHORT).show();
}
currentPosition =currentPosition -1;
setCardProgress(currentPosition);
} else {
swipedLastPosition = 0;
currentPosition = 0;
setCardProgress(currentPosition);
}
} else if (v.equals(mButtonRight)) {
mSwipeStack.swipeTopViewToRight();
} else if (v.equals(mFab)) {
swipedLastPosition = 0;
mTempData.clear();
mTempData.addAll(mData);
mSwipeStack.resetStack();
setCardProgress(swipedLastPosition);
}
Callback Methods
#Override
public void onViewSwipedToRight(int position) {
swipedLastPosition = position + 1;
setCardProgress(position);
}
#Override
public void onViewSwipedToLeft(int position) {
swipedLastPosition = position;
setCardProgress(position);
}
Update Progress method
void setCardProgress(int position) {
if (position == mData.size()-1) {
currentPosition = mData.size();
txtCardProgress.setText(currentPosition + " out of " + mData.size());
} else {
currentPosition++;
txtCardProgress.setText(currentPosition + " out of " + mData.size());
}
}
Related
I am trying to implement a dynamic list update to FragmentStatePagerAdapter. I have a list of few fragments which have radio buttons, edit text, and different other fragments having just a single view.
Now the logic revolves around radio button fragment, so lets suppose you have a list having 10 elements and the list item showing the radio button is 6, and there are 2 options for the user to select on the radio button fragment. If user selects 1st option then 8th item should be shown and 7th should be skipped and if 2nd option is selected then 7th should be shown and then 9th.
I have added a view pager, and have an associated FragmentStatePagerAdapter associated with it. Now I was able to populate the list based on the option but when I refresh list in the adapter, it does not hops from 6th to 8th and still shows 7th.
Can someone help me around it on how can I implement the hopping mechanism on FragmentStatePagerAdapter?
Adapter
import android.support.annotation.NonNull;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.app.FragmentStatePagerAdapter;
import android.view.ViewGroup;
import java.util.List;
public class OrderDetailsAdapter extends FragmentPagerAdapter {
private final Logger log = LoggerFactory.getLogger(OrderDetailsAdapter.class);
private List<IndexedFragments> adapterList;
private FragmentManager fragmentManager;
public OrderDetailsAdapter(FragmentManager fragmentManager, List<IndexedFragments> adapterList) {
super(fragmentManager);
this.fragmentManager = fragmentManager;
this.adapterList = adapterList;
}
#Override
public Fragment getItem(int position) {
final IndexedFragments indexedFragment = adapterList.get(position);
return indexedFragment.getFragment();
}
#Override
public int getCount() {
if (adapterList.isEmpty()) {
return 0;
} else {
return adapterList.size();
}
}
#Override
public int getItemPosition(#NonNull Object object) {
return POSITION_NONE;
}
#Override
public void destroyItem(ViewGroup container, int position, Object object) {
log.debug("Destroying fragment position {}", position);
}
public void updateList(List<IndexedFragments> indexedFragments) {
adapterList.clear();
log.debug("Fragment List OrderDetailsAdapter after clearing {} on {}", adapterList.size(), adapterList);
adapterList.addAll(indexedFragments);
log.debug("Fragment List OrderDetailsAdapter after adding indexed fragments {} on {}", adapterList.size(), adapterList);
notifyDataSetChanged();
}
}
Model Class
import android.support.v4.app.Fragment;
import java.io.Serializable;
public class IndexedFragments implements Serializable {
private final static long serialVersionUID = -304520750038118996L;
private Integer index;
private Fragment fragment;
private boolean isSkippedRequested = false;
public Integer getIndex() {
return index;
}
public void setIndex(Integer index) {
this.index = index;
}
public Fragment getFragment() {
return fragment;
}
public void setFragment(Fragment fragment) {
this.fragment = fragment;
}
public boolean isSkippedRequested() {
return isSkippedRequested;
}
public void setSkippedRequested(boolean skippedRequested) {
isSkippedRequested = skippedRequested;
}
}
FormsActivity
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v4.view.ViewPager;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.Toast;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import javax.inject.Inject;
import dagger.Binds;
import dagger.Module;
import dagger.Subcomponent;
import dagger.android.ActivityKey;
import dagger.android.AndroidInjection;
import dagger.android.AndroidInjector;
import dagger.multibindings.IntoMap;
public class FormsActivity extends AppCompatActivity implements FragmentNavigationListener {
private static String CHECK_BOX = "checkbox";
private static String RADIO_BUTTON = "radio";
private static String TEXT_INPUT = "text";
private static String NUMERIC_INPUT = "numeric";
private static String VIDEO_VIEW = "video";
private static String IMAGE_VIEW = "image";
private final Logger log = LoggerFactory.getLogger(FormsActivity.class);
public LinkedHashMap<String, String> stringLinkedHashMap;
#Inject
protected BaseRetrofit restRequests;
#Inject
protected AppUtils appUtils;
private FormData formData;
private ViewPager viewPager;
private ProgressBar progressBar;
private Button submitButton;
private Toolbar toolbar;
private List<Frmdtl> formDataList;
private List<IndexedFragments> fragmentList;
private Context context;
private OrderDetailsAdapter orderDetailsAdapter;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
AndroidInjection.inject(this);
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_forms);
context = this;
Intent intent = getIntent();
if (intent != null) {
formData = (FormData) intent.getSerializableExtra(AppConstants.FORMS_ACTIVITY);
}
restRequests.setContext(this);
initializeViews();
populateFragments(formData);
}
#Override
public void onBackPressed() {
showAlertDialog();
}
private void initializeViews() {
submitButton = findViewById(R.id.submit_button);
toolbar = findViewById(R.id.toolbar_main_activity);
setSupportActionBar(toolbar);
progressBar = findViewById(R.id.progress_bar_layout);
}
private void showAlertDialog() {
Dialog dialog = new AlertDialogFragment().createWarningDialog(context, getString(R.string.warning),
getString(R.string.saved_form_data_lost),
R.string.ok,
new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialogInterface, int which) {
appUtils.getFormAnswersList().clear();
finish();
}
});
dialog.setCanceledOnTouchOutside(true);
dialog.show();
}
#SuppressLint("ClickableViewAccessibility")
private void populateFragments(FormData formData) {
formDataList = formData.getOrderDetails().getFrmdtl();
fragmentList = new ArrayList<>();
for (Frmdtl frmdtl : formDataList) {
Fragment fragment = null;
if (frmdtl.getFieldType().equalsIgnoreCase(TEXT_INPUT)) {
fragment = createTextFieldFragment(frmdtl, null);
} else if (frmdtl.getFieldType().equalsIgnoreCase(NUMERIC_INPUT)) {
fragment = createTextFieldFragment(frmdtl, NUMERIC_TYPE);
} else if (frmdtl.getFieldType().equalsIgnoreCase(CHECK_BOX)) {
fragment = createCheckBoxFragment(frmdtl);
} else if (frmdtl.getFieldType().equalsIgnoreCase(RADIO_BUTTON)) {
fragment = createRadioButtonFragment(frmdtl);
} else if (frmdtl.getFieldType().equalsIgnoreCase(VIDEO_VIEW)) {
fragment = createVideoViewFragment(frmdtl);
} else if (frmdtl.getFieldType().equalsIgnoreCase(IMAGE_VIEW)) {
fragment = createImageViewFragment(frmdtl);
}
if (fragment != null) {
IndexedFragments indexedFragments = new IndexedFragments();
indexedFragments.setFragment(fragment);
indexedFragments.setIndex(frmdtl.getIndex());
fragmentList.add(indexedFragments);
}
}
viewPager = findViewById(R.id.fragment_view_pager);
orderDetailsAdapter = new OrderDetailsAdapter(getSupportFragmentManager(), fragmentList);
viewPager.setAdapter(orderDetailsAdapter);
viewPager.setOffscreenPageLimit(0);
}
private Fragment createTextFieldFragment(Frmdtl formData, String inputType) {
FormEditTextFragment formEditTextFragment = new FormEditTextFragment();
Bundle bundle = new Bundle();
bundle.putSerializable(FORM_DATA, formData);
bundle.putString(INPUT_TYPE, inputType);
formEditTextFragment.setArguments(bundle);
log.debug("Form Data Id for text {}", formData.getId());
return formEditTextFragment;
}
private Fragment createCheckBoxFragment(Frmdtl formData) {
FormCheckBoxFragment formCheckBoxFragment = new FormCheckBoxFragment();
Bundle bundle = new Bundle();
bundle.putSerializable(FORM_DATA, formData);
formCheckBoxFragment.setArguments(bundle);
log.debug("Form Data Id for check {}", formData.getId());
return formCheckBoxFragment;
}
private Fragment createRadioButtonFragment(Frmdtl frmdtl) {
FormRadioButtonFragment formRadioButtonFragment = new FormRadioButtonFragment();
Bundle bundle = new Bundle();
bundle.putSerializable(FORM_DATA, frmdtl);
bundle.putSerializable(ORDER_DETAILS, formData.getOrderDetails());
formRadioButtonFragment.setArguments(bundle);
log.debug("Form Data Id for radio {}", frmdtl.getId());
return formRadioButtonFragment;
}
private Fragment createVideoViewFragment(Frmdtl formData) {
FormVideoFragment formVideoFragment = new FormVideoFragment();
Bundle bundle = new Bundle();
bundle.putSerializable(FORM_DATA, formData);
formVideoFragment.setArguments(bundle);
log.debug("Form Data Id for video {}", formData.getId());
return formVideoFragment;
}
private Fragment createImageViewFragment(Frmdtl formData) {
FormImageFragment formImageFragment = new FormImageFragment();
Bundle bundle = new Bundle();
bundle.putSerializable(FORM_DATA, formData);
formImageFragment.setArguments(bundle);
log.debug("Form Data Id for image {}", formData.getId());
return formImageFragment;
}
private void navigateBetweenFragments(int navigation, List<String> stringList, Integer currentIndex) {
if (navigation == NEXT_NAVIGATION) {
if (stringList != null && !stringList.isEmpty() && currentIndex != null) {
processLogicBasedFragments(stringList, currentIndex);
viewPager.setCurrentItem(viewPager.getCurrentItem() + 1);
return;
}
if (viewPager.getCurrentItem() == fragmentList.size() - 1) {
log.debug("FormData list size {}", formDataList.size());
log.debug("Moving to {} form", viewPager.getCurrentItem() + 1);
submitButton.setVisibility(View.VISIBLE);
submitButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
progressBar.setVisibility(View.VISIBLE);
attemptFormUpload();
}
});
} else {
viewPager.setCurrentItem(viewPager.getCurrentItem() + 1);
}
}
if (navigation == PREVIOUS_NAVIGATION) {
viewPager.setCurrentItem(viewPager.getCurrentItem() - 1);
}
}
private void processLogicBasedFragments(List<String> stringList, Integer currentIndex) {
List<IndexedFragments> indexedFragmentsList = new ArrayList<>();
for (int i = 0; i < fragmentList.size(); i++) {
Integer index = fragmentList.get(i).getIndex();
if (index.compareTo(currentIndex) <= 0) {
indexedFragmentsList.add(fragmentList.get(i));
}
}
for (int i = 0; i < fragmentList.size(); i++) {
IndexedFragments indexedFragments = fragmentList.get(i);
if (stringList.contains(String.valueOf(indexedFragments.getIndex()))) {
indexedFragmentsList.add(indexedFragments);
} else if (!stringList.contains(String.valueOf(indexedFragments.getIndex()))
&& fragmentList.get(i).getIndex().compareTo(currentIndex) > 0) {
indexedFragments.setSkippedRequested(true);
indexedFragmentsList.add(indexedFragments);
}
}
fragmentList.clear();
log.debug("Fragment List Forms Activity after clearing {} on {}", fragmentList.size(), fragmentList);
fragmentList.addAll(indexedFragmentsList);
log.debug("Fragment List Forms Activity after adding indexed fragments {} on {}", fragmentList.size(), fragmentList);
orderDetailsAdapter.updateList(indexedFragmentsList);
}
private void attemptFormUpload() {
try {
if (appUtils.isNetworkConnected(context)) {
uploadForm();
} else {
preserveFormDataForFutureUpload();
Toast.makeText(context, R.string.no_connection, Toast.LENGTH_LONG).show();
progressBar.setVisibility(GONE);
finish();
}
} catch (IOException e) {
log.error("Error in attempting to upload form {}", e.fillInStackTrace());
}
}
private void uploadForm() throws UnsupportedEncodingException {
restRequests.uploadForm(formData.getOrderDetails().getId(),
String.valueOf(formData.getOrderDetails().getFormId()),
formData.getOrderDetails().getLatitude(),
formData.getOrderDetails().getLongitude(),
appUtils.getFormAnswersList(), new RestRequestListener() {
#Override
public void onSuccessResponse(String response) {
appUtils.getFormAnswersList().clear();
progressBar.setVisibility(GONE);
finish();
}
#Override
public void onErrorResponse(Throwable t) {
appUtils.getFormAnswersList().clear();
progressBar.setVisibility(GONE);
finish();
}
});
}
private void preserveFormDataForFutureUpload() throws IOException {
OfflineSubmittedOrder offlineSubmittedOrder = new OfflineSubmittedOrder();
List<FormAnswers> formAnswers = new ArrayList<>(appUtils.getFormAnswersList());
offlineSubmittedOrder.setFormAnswersList(formAnswers);
offlineSubmittedOrder.setOrderDetail(formData.getOrderDetails());
appUtils.getFormAnswersList().clear();
appUtils.getOfflineSubmittedOrders().add(offlineSubmittedOrder);
appUtils.writeObject(getApplicationContext(), FORM_ANSWER_LIST_CACHE, appUtils.getOfflineSubmittedOrders());
appUtils.setSubmissionPending(true);
}
#Override
public void onFragmentNavigationTriggered(int navigation, List<String> stringList, Integer currentIndex) {
navigateBetweenFragments(navigation, stringList, currentIndex);
}
#Subcomponent
public interface FormsActivitySubcomponent extends AndroidInjector<FormsActivity> {
#SuppressWarnings({"InnerClassTooDeeplyNested", "ClassNameSameAsAncestorName"})
#Subcomponent.Builder
abstract class Builder extends AndroidInjector.Builder<FormsActivity> {
}
}
#SuppressWarnings("InterfaceNeverImplemented")
#Module(subcomponents = FormsActivity.FormsActivitySubcomponent.class)
public interface FormsActivityModule {
#Binds
#IntoMap
#ActivityKey(FormsActivity.class)
AndroidInjector.Factory<? extends Activity>
bindFormsActivityInjectorFactory(FormsActivity.FormsActivitySubcomponent.Builder builder);
}
}
I'm working with Firebase data and RecyclerView Adapter.
The scenario is when user click the list, the initial status was UNREAD will be change to READ so the TypeFace should be change from BOLD to NORMAL.
My current back-end process to change the status from UNREAD to READ is working and updated to Firebase, however the interface of my specific RecyclerView item does not change from BOLD to NORMAL.
What I thought is no need to recall back the Firebase data in order to read the status but the interface should change based on user click.
Anyone can help me?
NotificationActivity.java:
package com.myapp.activity.notification;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.view.ActionMode;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.Toolbar;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.Toast;
import com.google.android.gms.tasks.OnCompleteListener;
import com.google.android.gms.tasks.Task;
import com.google.firebase.auth.FirebaseAuth;
import com.google.firebase.database.DataSnapshot;
import com.google.firebase.database.DatabaseError;
import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.FirebaseDatabase;
import com.google.firebase.database.ValueEventListener;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.material.nereeducation.R;
import com.material.nereeducation.adapter.AdapterNotification;
import com.material.nereeducation.model.Notification;
import com.material.nereeducation.utils.Tools;
import com.material.nereeducation.widget.LineItemDecoration;
import java.util.ArrayList;
import java.util.List;
public class NotificationActivity extends AppCompatActivity {
private RecyclerView recyclerView;
private AdapterNotification mAdapter;
private ActionModeCallback actionModeCallback;
private ActionMode actionMode;
private Toolbar toolbar;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_notification);
initToolbar();
initComponent();
Tools.setSystemBarColor(this, R.color.black);
}
private void initToolbar() {
toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
getSupportActionBar().setTitle("Notifications");
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
}
private List<Notification> items = new ArrayList<>();
private LinearLayout messageEmptyList;
private void initComponent() {
messageEmptyList = findViewById(R.id.messageEmptyList);
recyclerView = findViewById(R.id.recyclerView);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
recyclerView.addItemDecoration(new LineItemDecoration(this, LinearLayout.VERTICAL));
recyclerView.setHasFixedSize(true);
//set data and list adapter
mAdapter = new AdapterNotification(this, items);
recyclerView.setAdapter(mAdapter);
mAdapter.setOnClickListener(new AdapterNotification.OnClickListener() {
#Override
public void onItemClick(View view, Notification obj, int pos) {
if (mAdapter.getSelectedItemCount() > 0) {
enableActionMode(pos);
} else {
// read the inbox which removes bold from the row
Notification notification = mAdapter.getItem(pos);
Toast.makeText(getApplicationContext(), "Read: " + notification.sender_id, Toast.LENGTH_SHORT).show();
updateStatus(notification.notificationId,"read",pos);
}
}
#Override
public void onItemLongClick(View view, Notification obj, int pos) {
enableActionMode(pos);
}
});
actionModeCallback = new ActionModeCallback();
getNotificationData();
}
private void getNotificationData()
{
items.clear();
GsonBuilder builder = new GsonBuilder();
final Gson gson = builder.create();
FirebaseAuth firebaseAuth = FirebaseAuth.getInstance();
String uuid = firebaseAuth.getUid();
FirebaseDatabase firebaseDatabase = FirebaseDatabase.getInstance();
DatabaseReference databaseReference = firebaseDatabase.getReference();
databaseReference.child("notifications/"+uuid+"/data_notification").orderByChild("status").startAt("read").endAt("unread").addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if(dataSnapshot.getValue() != null)
{
for(DataSnapshot snapshot: dataSnapshot.getChildren())
{
String dataReceived = gson.toJson(snapshot.getValue());
Notification notificationItems = gson.fromJson(dataReceived, Notification.class);
items.add(notificationItems);
}
mAdapter.notifyDataSetChanged();
}else
{
messageEmptyList.setVisibility(View.VISIBLE);
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
private void updateStatus(final String notificationId, String status, final int position) {
FirebaseAuth firebaseAuth = FirebaseAuth.getInstance();
String uuid = firebaseAuth.getUid();
FirebaseDatabase firebaseDatabase = FirebaseDatabase.getInstance();
DatabaseReference databaseReference = firebaseDatabase.getReference();
databaseReference.child("notifications/"+uuid+"/data_notification").child(notificationId).child("status").setValue(status
).addOnCompleteListener(new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
mAdapter.notifyItemChanged(position); //Problem here - how to update text from BOLD to NORMAL for this item?
}
});
}
private void enableActionMode(int position) {
if (actionMode == null) {
actionMode = startSupportActionMode(actionModeCallback);
}
toggleSelection(position);
}
private void toggleSelection(int position) {
mAdapter.toggleSelection(position);
int count = mAdapter.getSelectedItemCount();
if (count == 0) {
actionMode.finish();
} else {
actionMode.setTitle(String.valueOf(count));
actionMode.invalidate();
}
}
private class ActionModeCallback implements ActionMode.Callback {
#Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
mode.getMenuInflater().inflate(R.menu.menu_delete, menu);
return true;
}
#Override
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
return false;
}
#Override
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
int id = item.getItemId();
if (id == R.id.action_delete) {
deleteInboxes();
mode.finish();
return true;
}
return false;
}
#Override
public void onDestroyActionMode(ActionMode mode) {
mAdapter.clearSelections();
actionMode = null;
}
}
private void deleteInboxes() {
List<Integer> selectedItemPositions = mAdapter.getSelectedItems();
for (int i = selectedItemPositions.size() - 1; i >= 0; i--) {
mAdapter.removeData(selectedItemPositions.get(i));
}
mAdapter.notifyDataSetChanged();
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == android.R.id.home) {
finish();
} else {
Toast.makeText(getApplicationContext(), item.getTitle(), Toast.LENGTH_SHORT).show();
}
return super.onOptionsItemSelected(item);
}
}
AdapterNotification.java:
package com.myapp.adapter;
import android.content.Context;
import android.graphics.Color;
import android.graphics.PorterDuff;
import android.graphics.Typeface;
import android.support.v7.widget.RecyclerView;
import android.text.format.DateUtils;
import android.util.SparseBooleanArray;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;
import com.material.nereeducation.R;
import com.material.nereeducation.helper.AlphabetColor;
import com.material.nereeducation.model.Notification;
import com.material.nereeducation.utils.Tools;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
public class AdapterNotification extends RecyclerView.Adapter<AdapterNotification.ViewHolder> {
private Context ctx;
private List<Notification> items;
private OnClickListener onClickListener = null;
private SparseBooleanArray selected_items;
private int current_selected_idx = -1;
private AlphabetColor alphabetColor;
public void setOnClickListener(OnClickListener onClickListener) {
this.onClickListener = onClickListener;
}
public class ViewHolder extends RecyclerView.ViewHolder {
public TextView from, title, message, date, image_letter;
public ImageView image;
public RelativeLayout lyt_checked, lyt_image;
public View lyt_parent;
public ViewHolder(View view) {
super(view);
from = view.findViewById(R.id.from);
title = view.findViewById(R.id.title);
message = view.findViewById(R.id.message);
date = view.findViewById(R.id.date);
image_letter = view.findViewById(R.id.image_letter);
image = view.findViewById(R.id.image);
lyt_checked = view.findViewById(R.id.lyt_checked);
lyt_image = view.findViewById(R.id.lyt_image);
lyt_parent = view.findViewById(R.id.lyt_parent);
}
}
public AdapterNotification(Context mContext, List<Notification> items) {
this.ctx = mContext;
this.items = items;
selected_items = new SparseBooleanArray();
alphabetColor = new AlphabetColor(mContext);
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_notification, parent, false);
return new ViewHolder(itemView);
}
#Override
public void onBindViewHolder(final ViewHolder holder, final int position) {
final Notification notification = items.get(position);
// displaying text view data
System.out.println("sender type:"+notification.sender_type);
Character firstLetter;
if(notification.sender_type.equals("1")) //Admin
{
String admin = ctx.getString(R.string.admin_name);
holder.from.setText(admin);
firstLetter = admin.substring(0, 1).charAt(0);
holder.image_letter.setText(String.valueOf(firstLetter));
}else
{
holder.from.setText(notification.senderName);
firstLetter = notification.senderName.substring(0, 1).charAt(0);
holder.image_letter.setText(String.valueOf(firstLetter));
}
if(notification.status.equals("unread"))
{
holder.from.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD));
holder.title.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD));
}
holder.title.setText(notification.title);
holder.message.setText(notification.message);
holder.date.setText(getDate(Long.parseLong(notification.date)));
holder.lyt_parent.setActivated(selected_items.get(position, false));
holder.lyt_parent.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (onClickListener == null) return;
onClickListener.onItemClick(v, notification, position);
}
});
holder.lyt_parent.setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(View v) {
if (onClickListener == null) return false;
onClickListener.onItemLongClick(v, notification, position);
return true;
}
});
toggleCheckedIcon(holder, position);
displayImage(holder, notification, firstLetter);
}
private void displayImage(ViewHolder holder, Notification notification, Character firstLetter) {
if (notification.image != null) {
Tools.displayImageRound(ctx, holder.image, notification.image);
holder.image.setColorFilter(null);
holder.image_letter.setVisibility(View.GONE);
} else {
holder.image.setImageResource(R.drawable.shape_circle);
holder.image.setColorFilter(alphabetColor.getColorByAlphabet(firstLetter), PorterDuff.Mode.MULTIPLY);
holder.image_letter.setVisibility(View.VISIBLE);
}
}
private String getDate(long time) {
Date date = new Date();
long currentTime = date.getTime();
String result = (String) DateUtils.getRelativeTimeSpanString(time, currentTime, 0);
return result;
}
private void toggleCheckedIcon(ViewHolder holder, int position) {
if (selected_items.get(position, false)) {
holder.lyt_image.setVisibility(View.GONE);
holder.lyt_checked.setVisibility(View.VISIBLE);
if (current_selected_idx == position) resetCurrentIndex();
} else {
holder.lyt_checked.setVisibility(View.GONE);
holder.lyt_image.setVisibility(View.VISIBLE);
if (current_selected_idx == position) resetCurrentIndex();
}
}
public Notification getItem(int position) {
return items.get(position);
}
#Override
public int getItemCount() {
return items.size();
}
public void toggleSelection(int pos) {
current_selected_idx = pos;
if (selected_items.get(pos, false)) {
selected_items.delete(pos);
} else {
selected_items.put(pos, true);
}
notifyItemChanged(pos);
}
public void clearSelections() {
selected_items.clear();
notifyDataSetChanged();
}
public int getSelectedItemCount() {
return selected_items.size();
}
public List<Integer> getSelectedItems() {
List<Integer> items = new ArrayList<>(selected_items.size());
for (int i = 0; i < selected_items.size(); i++) {
items.add(selected_items.keyAt(i));
}
return items;
}
public void removeData(int position) {
items.remove(position);
resetCurrentIndex();
}
private void resetCurrentIndex() {
current_selected_idx = -1;
}
public interface OnClickListener {
void onItemClick(View view, Notification obj, int pos);
void onItemLongClick(View view, Notification obj, int pos);
}
}
You need to handle ELSE too for this condition
if(notification.status.equals("unread")){
holder.from.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD));
holder.title.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD));
}else{
holder.from.setTypeface(Typeface.defaultFromStyle(Typeface.NORMAL));
holder.title.setTypeface(Typeface.defaultFromStyle(Typeface.NORMAL));
}
if you want to set textview different typeface or color in adapter you need to check for every position so in your case you only setting typeface bold for textview you have to set typeface again normal for default textview typeface.
Set your typeface Normal also in adapter.
set text default typeface Normal for textview like below.
holder.from.setTypeface(Typeface.defaultFromStyle(Typeface.NORMAL));
holder.title.setTypeface(Typeface.defaultFromStyle(Typeface.NORMAL));
and then check item status for unread
if(notification.status.equals("unread")){
holder.from.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD));
holder.title.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD));
}
So I guess your problem is that the state (read/unread) is applied on the database, but not reflected on the recycler view.
If this is the problem it is mainly because, you didnt handle the data change method of your list (and update it with the new values).
You are currently using this to get data:
databaseReference.child("notifications/"+uuid+"/data_notification").orderByChild("status").startAt("read").endAt("unread").addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {.....
This won't help you to control the item changed too.
Possible solution
A way solve it is to use (FirebaseUI) database instead of custom adapter.
FirebaseUI will listen to changes and update the list.
EDIT 2
use ChildEventListener instead of Listener For Single Value event
instead of this:
databaseReference.child("notifications/"+uuid+"/data_notification").orderByChild("status").startAt("read").endAt("unread").addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {.....
use this:
databaseReference.child("notifications/"+uuid+"/data_notification").orderByChild("status").startAt("read").endAt("unread").addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot) {.....
//add items to list (like you did)
#Override
public void onChildChanged(DataSnapshot dataSnapshot) {.....
//set the items again to the list (update them here) and notify
//data set changed (so values update in your list).
I believe you should set the font like this:
if ("unread".equals(notification.status)) {
holder.from.setTypeface(null, Typeface.BOLD);
holder.title.setTypeface(null, Typeface.BOLD);
} else {
holder.from.setTypeface(null, Typeface.NORMAL);
holder.title.setTypeface(null, Typeface.NORMAL);
}
The view is being reused by RecyclerView so once you set font to bold you need to set it back to normal next time it will be used.
Been trying to load data from sqlite and display it on viewpager without much success.
I have a viewpager with two tabs which should hold data based on the tag_id passed as a parameter of newInstance. There is also an action bar navigation spinner with a list of counties that is used for filter data displayed based on the county_id.
Am able to fetch data from server and save it in the sqlite db but displaying it is the problem. Data is not dispalyed on the first page of the viewpager but it exists in the sqlite. Data for the second is the only one laoded.
Below is my implementation;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.os.Parcelable;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.app.FragmentStatePagerAdapter;
import android.support.v4.app.ListFragment;
import android.support.v4.app.LoaderManager.LoaderCallbacks;
import android.support.v4.content.Loader;
import android.support.v4.view.ViewPager;
import android.support.v4.view.ViewPager.OnPageChangeListener;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v4.widget.SwipeRefreshLayout.OnRefreshListener;
import android.support.v7.app.ActionBar;
import android.support.v7.app.ActionBar.OnNavigationListener;
import android.support.v7.app.ActionBarActivity;
import android.util.Log;
import android.view.ContextThemeWrapper;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
import com.android.volley.AuthFailureError;
import com.android.volley.DefaultRetryPolicy;
import com.android.volley.NetworkError;
import com.android.volley.NoConnectionError;
import com.android.volley.ParseError;
import com.android.volley.Response;
import com.android.volley.ServerError;
import com.android.volley.TimeoutError;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.JsonArrayRequest;
import com.app.adapter.CustomCountySpinnerAdapter;
import com.app.adapter.TendersAdapter;
import com.app.database.DBFunctions;
import com.app.externallib.AppController;
import com.app.model.CountyModel;
import com.app.model.PostsModel;
import com.app.utils.AppConstants;
import com.app.utils.PostsListLoader;
import com.nhaarman.listviewanimations.appearance.simple.SwingBottomInAnimationAdapter;
import com.viewpagerindicator.TabPageIndicator;
public class PublicTendersFragment extends Fragment{
private static List<PubliTenders> public_tenders;
public PublicTendersFragment newInstance(String text) {
PublicTendersFragment mFragment = new PublicTendersFragment();
Bundle mBundle = new Bundle();
mBundle.putString(AppConstants.TEXT_FRAGMENT, text);
mFragment.setArguments(mBundle);
return mFragment;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
public_tenders = new ArrayList<PubliTenders>();
public_tenders.add(new PubliTenders(14, "County"));
public_tenders.add(new PubliTenders(15, "National"));
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
final Context contextThemeWrapper = new ContextThemeWrapper(
getActivity(), R.style.StyledIndicators);
LayoutInflater localInflater = inflater
.cloneInContext(contextThemeWrapper);
View v = localInflater.inflate(R.layout.fragment_tenders, container,
false);
FragmentPagerAdapter adapter = new TendersVPAdapter(
getFragmentManager());
ViewPager pager = (ViewPager) v.findViewById(R.id.pager);
pager.setAdapter(adapter);
TabPageIndicator indicator = (TabPageIndicator) v
.findViewById(R.id.indicator);
indicator.setViewPager(pager);
return v;
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
setHasOptionsMenu(true);
}
class TendersVPAdapter extends FragmentPagerAdapter{
public TendersVPAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Parcelable saveState() {
return null;
}
#Override
public Fragment getItem(int position) {
switch (position) {
case 0:
return Tenders.newInstance(public_tenders.get(position).tag_id);
case 1:
return Tenders.newInstance(public_tenders.get(position).tag_id);
default:
return null;
}
}
#Override
public CharSequence getPageTitle(int position) {
return public_tenders.get(position).tender_type.toUpperCase(Locale
.getDefault());
}
#Override
public int getCount() {
return public_tenders.size();
}
}
public class PubliTenders {
public int tag_id;
public String tender_type;
public PubliTenders(int tag_id, String tender_type) {
this.tag_id = tag_id;
this.tender_type = tender_type;
}
}
public static class Tenders extends ListFragment implements
OnNavigationListener, LoaderCallbacks<ArrayList<PostsModel>> {
boolean mDualPane;
int mCurCheckPosition = 0;
// private static View rootView;
private SwipeRefreshLayout swipeContainer;
private ListView lv;
private View rootView;
private DBFunctions mapper;
private CustomCountySpinnerAdapter spinadapter;
private TendersAdapter mTendersAdapter;
private static final String ARG_TAG_ID = "tag_id";
private int tag_id;
private int mycounty;
private static final int INITIAL_DELAY_MILLIS = 500;
private static final String DEBUG_TAG = "BlogsFragment";
private final String TAG_REQUEST = "BLOG_TAG";
private JsonArrayRequest jsonArrTendersRequest;
// private OnItemSelectedListener listener;
public static Tenders newInstance(int tag_id) {
Tenders fragment = new Tenders();
Bundle b = new Bundle();
b.putInt(ARG_TAG_ID, tag_id);
fragment.setArguments(b);
return fragment;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
tag_id = getArguments().getInt(ARG_TAG_ID);
}
#Override
public void onStart() {
super.onStart();
getLoaderManager().initLoader(0, null, this);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
rootView = inflater.inflate(R.layout.fragment_headlines_blog,
container, false);
swipeContainer = (SwipeRefreshLayout) rootView
.findViewById(R.id.swipeProjectsContainer);
lv = (ListView) rootView.findViewById(android.R.id.list);
lv.setOnScrollListener(new AbsListView.OnScrollListener() {
#Override
public void onScrollStateChanged(AbsListView view,
int scrollState) {
}
#Override
public void onScroll(AbsListView view, int firstVisibleItem,
int visibleItemCount, int totalItemCount) {
int topRowVerticalPosition = (lv == null || lv
.getChildCount() == 0) ? 0 : lv.getChildAt(0)
.getTop();
swipeContainer.setEnabled(topRowVerticalPosition >= 0);
}
});
swipeContainer.setOnRefreshListener(new OnRefreshListener() {
#Override
public void onRefresh() {
fetchPublicTenders(mycounty);
}
});
swipeContainer.setColorSchemeResources(R.color.blue_dark,
R.color.irdac_green, R.color.red_light,
R.color.holo_red_light);
return rootView;
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
setHasOptionsMenu(true);
mapper = new DBFunctions(getActivity());
mapper.open();
// initialize AB Spinner
populateSpinner();
fetchPublicTenders(mycounty);
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
}
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt("curChoice", mCurCheckPosition);
}
private void populateSpinner() {
try {
List<CountyModel> counties = new ArrayList<CountyModel>();
counties = mapper.getAllCounties();
ActionBar actBar = ((ActionBarActivity) getActivity())
.getSupportActionBar();
actBar.setDisplayShowTitleEnabled(true);
actBar.setNavigationMode(ActionBar.NAVIGATION_MODE_LIST);
spinadapter = new CustomCountySpinnerAdapter(getActivity(),
android.R.layout.simple_spinner_dropdown_item, counties);
actBar.setListNavigationCallbacks(spinadapter, this);
} catch (NullPointerException exp) {
}
}
#Override
public Loader<ArrayList<PostsModel>> onCreateLoader(int arg0,
Bundle arg1) {
Log.v(DEBUG_TAG, "On Create Loader");
return new PostsListLoader(getActivity(), mycounty, tag_id);
}
#Override
public void onLoadFinished(Loader<ArrayList<PostsModel>> arg0,
ArrayList<PostsModel> data) {
// System.out.println("results " + data.size());
addToAdapter(data);
}
#Override
public void onLoaderReset(Loader<ArrayList<PostsModel>> arg0) {
lv.setAdapter(null);
}
#Override
public boolean onNavigationItemSelected(int pos, long arg1) {
CountyModel mo = spinadapter.getItem(pos);
this.mycounty = mo.getId();
refresh(mo.getId());
return false;
}
#Override
public void onListItemClick(ListView l, View v, int position, long id) {
TextView txtTitle = (TextView) v.findViewById(R.id.tender_title);
TextView txtRefNo = (TextView) v.findViewById(R.id.ref_no);
TextView txtExpiryDate = (TextView) v
.findViewById(R.id.expiry_date);
TextView txtOrg = (TextView) v.findViewById(R.id.dept_or_org);
Intent intTenderFullDetails = new Intent(getActivity(),
TenderDetailsActivity.class);
intTenderFullDetails.putExtra(TenderDetailsActivity.TENDER_TITLE,
txtTitle.getText().toString().trim());
intTenderFullDetails.putExtra(TenderDetailsActivity.TENDER_REF_NO,
txtRefNo.getText().toString().trim());
intTenderFullDetails.putExtra(
TenderDetailsActivity.TENDER_EXPIRY_DATE, txtExpiryDate
.getText().toString().trim());
intTenderFullDetails.putExtra(TenderDetailsActivity.TENDER_ORG,
txtOrg.getText().toString().trim());
// intTenderFullDetails.putExtra(TenderDetailsActivity.TENDER_DESC,
// Lorem);
startActivity(intTenderFullDetails);
}
private void fetchPublicTenders(final int county_id) {
swipeContainer.setRefreshing(true);
Uri.Builder builder = Uri.parse(AppConstants.postsUrl).buildUpon();
builder.appendQueryParameter("tag_id", Integer.toString(tag_id));
System.out.println("fetchPublicTenders with tag_id " + tag_id
+ " and county_id " + county_id);
jsonArrTendersRequest = new JsonArrayRequest(builder.toString(),
new Response.Listener<JSONArray>() {
#Override
public void onResponse(JSONArray response) {
if (response.length() > 0) {
for (int i = 0; i < response.length(); i++) {
try {
JSONObject tender_item = response
.getJSONObject(i);
mapper.createPost(
tender_item.getInt("id"),
tender_item.getInt("tag_id"),
tender_item.getInt("county_id"),
tender_item.getInt("sector_id"),
tender_item.getString("title"),
tender_item.getString("slug"),
tender_item.getString("content"),
tender_item
.getString("reference_no"),
tender_item
.getString("expiry_date"),
tender_item
.getString("organization"),
tender_item
.getString("image_url"),
tender_item
.getString("created_at"));
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
swipeContainer.setRefreshing(false);
refresh(county_id);
}
} else {
if (swipeContainer.isShown()) {
swipeContainer.setRefreshing(false);
}
try {
Toast.makeText(getActivity(),
"Sorry! No results found",
Toast.LENGTH_LONG).show();
} catch (NullPointerException npe) {
System.out.println(npe);
}
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
if (error instanceof NetworkError) {
try {
Toast.makeText(
getActivity(),
"Network Error. Cannot refresh list",
Toast.LENGTH_SHORT).show();
} catch (NullPointerException npe) {
System.err.println(npe);
}
if (swipeContainer.isShown()) {
swipeContainer.setRefreshing(false);
}
refresh(county_id);
} else if (error instanceof ServerError) {
try {
Toast.makeText(
getActivity(),
"Problem Connecting to Server. Try Again Later",
Toast.LENGTH_SHORT).show();
} catch (NullPointerException npe) {
System.err.println(npe);
}
if (swipeContainer.isShown()) {
swipeContainer.setRefreshing(false);
}
} else if (error instanceof AuthFailureError) {
} else if (error instanceof ParseError) {
} else if (error instanceof NoConnectionError) {
try {
Toast.makeText(getActivity(),
"No Connection", Toast.LENGTH_SHORT)
.show();
} catch (NullPointerException npe) {
System.err.println(npe);
}
} else if (error instanceof TimeoutError) {
try {
Toast.makeText(
getActivity()
.getApplicationContext(),
"Timeout Error. Try Again Later",
Toast.LENGTH_SHORT).show();
} catch (NullPointerException npe) {
System.err.println(npe);
}
}
if (swipeContainer.isShown()) {
swipeContainer.setRefreshing(false);
}
}
}) {
#Override
public Map<String, String> getHeaders() throws AuthFailureError {
HashMap<String, String> headers = new HashMap<String, String>();
headers.put("Accept", "application/json");
return headers;
}
};
// Set a retry policy in case of SocketTimeout & ConnectionTimeout
// Exceptions. Volley does retry for you if you have specified the
// policy.
jsonArrTendersRequest.setRetryPolicy(new DefaultRetryPolicy(
(int) TimeUnit.SECONDS.toMillis(20),
DefaultRetryPolicy.DEFAULT_MAX_RETRIES,
DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));
jsonArrTendersRequest.setTag(TAG_REQUEST);
AppController.getInstance().addToRequestQueue(jsonArrTendersRequest);
}
public void refresh(int county_id) {
Bundle b = new Bundle();
b.putInt("myconty", county_id);
if (isAdded()) {
getLoaderManager().restartLoader(0, b, this);
}
}
private void addToAdapter(ArrayList<PostsModel> plist) {
mTendersAdapter = new TendersAdapter(rootView.getContext(), plist);
SwingBottomInAnimationAdapter swingBottomInAnimationAdapter = new SwingBottomInAnimationAdapter(
mTendersAdapter);
swingBottomInAnimationAdapter.setAbsListView(lv);
assert swingBottomInAnimationAdapter.getViewAnimator() != null;
swingBottomInAnimationAdapter.getViewAnimator()
.setInitialDelayMillis(INITIAL_DELAY_MILLIS);
setListAdapter(swingBottomInAnimationAdapter);
mTendersAdapter.notifyDataSetChanged();
}
}
}
And this is the PostsListLoader class
import java.util.ArrayList;
import java.util.List;
import android.content.Context;
import android.support.v4.content.AsyncTaskLoader;
import com.app.database.DBFunctions;
import com.app.model.PostsModel;
public class PostsListLoader extends AsyncTaskLoader<ArrayList<PostsModel>> {
private DBFunctions mapper;
private ArrayList<PostsModel> myPostsModel;
private int county_id;
private int tag_id;
public PostsListLoader(Context context, int county_id, int tag_id) {
super(context);
mapper = new DBFunctions(getContext());
mapper.open();
this.county_id = county_id;
this.tag_id = tag_id;
}
#Override
public ArrayList<PostsModel> loadInBackground() {
String query_string = AppConstants.KEY_COUNTY_ID + " = " + county_id
+ " AND " + AppConstants.KEY_TAG_ID + " = " + tag_id;
myPostsModel = mapper.getPosts(query_string);
return myPostsModel;
}
#Override
public void deliverResult(ArrayList<PostsModel> data) {
if (isReset()) {
// An async query came in while the loader is stopped. We
// don't need the result.
if (data != null) {
onReleaseResources(data);
}
}
List<PostsModel> oldNews = data;
myPostsModel = data;
if (isStarted()) {
// If the Loader is currently started, we can immediately
// deliver its results.
super.deliverResult(data);
}
// At this point we can release the resources associated with
// 'oldNews' if needed; now that the new result is delivered we
// know that it is no longer in use.
if (oldNews != null) {
onReleaseResources(oldNews);
}
}
/**
* Handles a request to start the Loader.
*/
#Override
protected void onStartLoading() {
if (myPostsModel != null) {
// If we currently have a result available, deliver it
// immediately.
deliverResult(myPostsModel);
}
if (takeContentChanged() || myPostsModel == null) {
// If the data has changed since the last time it was loaded
// or is not currently available, start a load.
forceLoad();
}
}
/**
* Handles a request to stop the Loader.
*/
#Override
protected void onStopLoading() {
// Attempt to cancel the current load task if possible.
cancelLoad();
}
/**
* Handles a request to cancel a load.
*/
#Override
public void onCanceled(ArrayList<PostsModel> news) {
super.onCanceled(news);
// At this point we can release the resources associated with 'news'
// if needed.
onReleaseResources(news);
}
/**
* Handles a request to completely reset the Loader.
*/
#Override
protected void onReset() {
super.onReset();
// Ensure the loader is stopped
onStopLoading();
// At this point we can release the resources associated with 'apps'
// if needed.
if (myPostsModel != null) {
onReleaseResources(myPostsModel);
myPostsModel = null;
}
}
/**
* Helper function to take care of releasing resources associated with an
* actively loaded data set.
*/
protected void onReleaseResources(List<PostsModel> news) {
}
}
What could I be doing wrong?
Any help will be appreciated.
Thanks
I'm doing some background processing in my activity and have a ListView that shows the progress. I 'update' the listView with
adapter.notifyDataSetChanged();
However when I leave the activity and then come back, the background processes are still running, but the list view isn't updated. This is presumably because it's a new object, not the previous one. How do I maintain my list view object between activity loads?
This is my activity. I think the issue is that the 'adapter' variable that the download uses to bind to to show updates, is recreated in the onCreate method of the activity, and the 'adapter' variable that the download originally bound to is not in the activity anymore.
import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.net.ConnectivityManager;
import android.os.Bundle;
import android.os.Handler;
import android.preference.PreferenceManager;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
import com.amazonaws.auth.AWSCredentials;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.services.s3.model.ProgressEvent;
import com.amazonaws.services.s3.model.ProgressListener;
import com.amazonaws.services.s3.transfer.TransferManager;
//import com.amazonaws.auth.AWSCredentials;
//import com.amazonaws.auth.BasicAWSCredentials;
public class VideosActivity extends Activity {
ListView video_list;
CustomList adapter;
File storage_dir;
SharedPreferences completed_downloads; //http://developer.android.com/guide/topics/data/data-storage.html
SharedPreferences downloaded_data; //maps position to percent downloaded
SharedPreferences queue; //holds which fiiles are awaiting download
String images[]; //holds references to all thumnails for vids
String volume; //something like vol1 or vol2
String s3_dir; //the directory after the boucket that the files are stored in (do not add first slash)
String s3_bucket = "com--apps";
Handler handler = new Handler(); //'tunnel' through whci other threads communicate with main thread
Map<String, String[][]> video_config = new HashMap<String, String[][]>(); //holds info about video thumbs and filenames for all apps
ArrayList<String> arr_videos = new ArrayList<String>(); //holds video names
DownloadQueue queue_manager = new DownloadQueue();
#Override
public void onCreate(Bundle savedInstanceState) {
Log.v("dev", "onCreateCalled");
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
volume = getPackageName().split("\\.")[2]; //something like vol1 or vol2
s3_dir = "android/" + volume + "/"; //the directory after the boucket that the files are stored in (do not add first slash)
completed_downloads = getSharedPreferences("completed_downloads", 0);
downloaded_data = getSharedPreferences("downloaded_data", 0);
queue = getSharedPreferences("queue", 0);
storage_dir = getApplicationContext().getExternalFilesDir(null); //private to app, removed with uninstall
adapter = new CustomList(this, R.layout.customlist, arr_videos);
video_list = (ListView)findViewById(R.id.list);
video_list.setAdapter(adapter); //set adapter that specifies list contents
ensureStorageDirExists( storage_dir ); //make sure storage dir exists
set_video_data(); //store vid dat in array
ensure_connection_or_warn();
}
public boolean ensure_connection_or_warn()
{
if(have_connection())
{
return true;
}
else
{
Toast.makeText(this, "No Internet connection", Toast.LENGTH_LONG).show();
return false;
}
}
protected void ensureStorageDirExists( File dir )
{
if (!dir.exists())
{
dir.mkdirs();
}
}
public void set_video_data()
{
config_video_data(); //run config
images = video_config.get(getPackageName())[0]; //set images
for (String name : video_config.get(getPackageName())[1] ) { //set video info, this should be streamlined but is due to legacy code and my crap Java skills, consider doing like this: http://developer.android.com/guide/topics/resources/more-resources.html#TypedArray
arr_videos.add(name);
}
}
public SharedPreferences stored_vals()
{
return PreferenceManager.getDefaultSharedPreferences(this);
}
public boolean have_connection()
{
ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
if(cm.getActiveNetworkInfo()!=null && cm.getActiveNetworkInfo().isConnected() && cm.getActiveNetworkInfo().isAvailable())
{
Log.v("dev", "have internet connection");
return true;
}
else
{
Log.v("dev", "No internet connection");
return false;
}
}
public class DownloadQueue
{
protected void process()
{
if (queue.size() > 0 && queue.get(0).download_status == "queued") //this is meant to force one download at a time
{
queue.get(0).start();
adapter.notifyDataSetChanged();
}
}
protected void add(Integer position)
{
queue.edit.putInt(position+"");
d.download_status = "queued";
adapter.notifyDataSetChanged();
}
protected boolean position_is_queued(Integer position)
{
for (Download d : queue ) {
if(d.position == position)
{
return true;
}
}
return false;
}
protected void remove(Download d)
{
queue.remove(d);
adapter.notifyDataSetChanged();
}
}
public class CustomList extends ArrayAdapter<String>
{
View view;
int position;
Button btn;
public CustomList(Context context, int layout_id, ArrayList<String> objects)
{
super(context, layout_id, objects);
}
#Override
public View getView(final int position, View convertView, ViewGroup view_group)
{
set_view(convertView);
this.position = position;
TextView text_view = (TextView) view.findViewById(R.id.name);
ImageView image = (ImageView) view.findViewById(R.id.img);
btn = (Button) view.findViewById(R.id.play);
prepare_btn();
text_view.setText( list_text() );
image.setImageResource(
getResources().getIdentifier(images[position], "drawable", getPackageName())
);
return view;
}
public String list_text()
{
String s = arr_videos.get( position ).replace("_", " ").replace(".m4v", "");
s = s.substring(2, s.length());
return s;
}
public void set_view(View convertView)
{
if(convertView == null)
{
LayoutInflater inflater = getLayoutInflater();
view = inflater.inflate(R.layout.customlist, null);
}
else
{
view = convertView;
}
}
public Boolean is_downloaded()
{
return completed_downloads.getBoolean(position + "", false);
}
public void prepare_btn()
{
btn.setTag((Integer) position);
if(is_downloaded() == true)
{
btn.setText("Play ");
btn.setEnabled(true);
btn.setOnClickListener( new OnClickListener()
{
public void onClick(View btn)
{
int position = (Integer) btn.getTag();
Intent i = new Intent(VideosActivity.this, PlayVideoActivity.class);
String video_path = storage_dir + "/" + arr_videos.get(position);
Log.v("video_path", video_path);
i.putExtra("video_path", video_path);
startActivity(i);
}
});
}
else if( downloaded_data.contains(position+"") ) //it it's currently being downloaded
{
btn.setText(downloaded_data.getInt(position+"", 0) + "%");
btn.setEnabled(false);
}
else if( queue_manager.position_is_queued(position) ) //it's in the queue
{
btn.setText("Queued");
btn.setEnabled(false);
}
else
{
btn.setText("Download");
btn.setEnabled(true);
btn.setOnClickListener( new OnClickListener()
{
public void onClick(View btn)
{
int position = (Integer) btn.getTag();
btn.setEnabled(false);
queue_manager.add(position);
}
});
}
}
}
public class Download
{
File new_video_file;
int position;
String download_status;
com.amazonaws.services.s3.transfer.Download download;
protected void queue(int position)
{
this.position = position;
queue_manager.add(this);
queue_manager.process();
//put this download in the queue
//start downloading if it's the only one in the queue
}
protected void start()
{
if(!ensure_connection_or_warn())
{
return;
}
this.download_status = "started";
this.new_video_file = new File(storage_dir, arr_videos.get(position)); //local file to be writtent to
TransferManager tx = new TransferManager(credentials);
//http://stackoverflow.com/questions/6976317/android-http-connection-exception
this.download = tx.download(s3_bucket, s3_dir + arr_videos.get(position), new_video_file);
download.addProgressListener(new ProgressListener()
{
public void progressChanged(final ProgressEvent pe)
{
handler.post( new Runnable()
{
#Override
public void run()
{
if ( pe.getEventCode() == ProgressEvent.COMPLETED_EVENT_CODE )
{
Download.this.onComplete();
}
else
{
Download.this.onProgressUpdate();
}
}
});
}
});
}
//protected void onProgressUpdate(Double progress)
protected void onProgressUpdate()
{
this.download_status = "downloading";
Double progress = this.download.getProgress().getPercentTransfered();
Integer percent = progress.intValue();
//Log.v("runnable", percent + "");
downloaded_data.edit().putInt(position+"", percent).commit();
adapter.notifyDataSetChanged();
}
protected void onComplete()
{
Log.v("dev", "download complete!!!");
//downloaded_data.remove(position);
this.download_status = "complete";
completed_downloads.edit().putBoolean(position + "", true).commit();
queue_manager.remove(this);
queue_manager.process();
adapter.notifyDataSetChanged();
// this.download.abort();
}
}
}
Not exactly sure what happens during background processing and what do you mean by ListView state, but my suggestion would be:
try the following:
#Override
protected void onResume() {
super.onResume();
yourAdapter.clear();
yourAdapter.addAll(yourData); // API level [1..10] use for(..){ yourAdapter.add(yourData.get(index)) }
yourAdapter.notifyDataSetChanged();
}
Reason:
An adapter keeps a copy of all the elements, so when you call notifyDataSetChanged, it checks its own copy of the elements
I have a ViewPager, and lets imagine, that i am on page 0.
I have a button on this page, and on this button click, i want to show a dialog, and change page to the page 1.
When my page changes to page 1, i want the dialog to dissapear.
When i did it, i didn't see the dialog, it was appearing and dissapearing when page was changed, but i am sure, that i have 1000ms delay between this actions.
Please help, how can i show the dialog?
package com.example.ViewPagerDialog;
import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Context;
import android.os.Bundle;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.TextView;
public class MyActivity extends Activity {
private int currentPage;
/**
* Called when the activity is first created.
*/
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
final MyViewPager viewPager = (MyViewPager) findViewById(R.id.view_pager);
final Button leftSwitcher = (Button) findViewById(R.id.left_switcher);
final Button rightSwitcher = (Button) findViewById(R.id.right_switcher);
final ProgressDialog progressDialog = new ProgressDialog(this);
leftSwitcher.setVisibility(View.GONE);
progressDialog.setTitle("Wait...");
viewPager.setAdapter(new MyPagerAdapter(this));
viewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
public void onPageScrolled(int i, float v, int i2) {
}
public void onPageSelected(int i) {
progressDialog.dismiss();
currentPage = i;
if (i == 0) {
leftSwitcher.setVisibility(View.GONE);
} else if (i == 1) {
leftSwitcher.setVisibility(View.VISIBLE);
rightSwitcher.setVisibility(View.VISIBLE);
} else if (i == 2) {
rightSwitcher.setVisibility(View.GONE);
}
}
public void onPageScrollStateChanged(int i) {
}
});
leftSwitcher.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
progressDialog.show();
sleepThread();
viewPager.setCurrentItem(currentPage - 1);
}
});
rightSwitcher.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
progressDialog.show();
sleepThread();
viewPager.setCurrentItem(currentPage + 1);
}
});
}
private void sleepThread() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private class MyPagerAdapter extends PagerAdapter {
View[] views = new View[3];
public MyPagerAdapter(Context context) {
TextView view1 = new TextView(context);
TextView view2 = new TextView(context);
TextView view3 = new TextView(context);
view1.setText("View 1");
view2.setText("View 2");
view3.setText("View 3");
views[0] = view1;
views[1] = view2;
views[2] = view3;
}
#Override
public int getCount() {
return views.length;
}
#Override
public boolean isViewFromObject(View view, Object o) {
return (view.equals(o));
}
#Override
public Object instantiateItem(ViewGroup collection, int position) {
collection.addView(views[position]);
return views[position];
}
#Override
public void destroyItem(android.view.ViewGroup container, int position, java.lang.Object object) {
container.removeView(views[position]);
}
}
}
First of all, never block the UI thread with Thread.sleep() like you do. By using Thread.sleep() you'll basically set the show command for the dialog(which will happen after you return from the onCLick() method), sleep one second(and your app will freeze) and then set the page on the ViewPager which will trigger the listener, dismissing the dialog. Instead you could use a Handler to
private Handler mHandler = new Handler();
// in the onClick method
progressDialog.show();
mHandler.postDelayed(new Runnable() {
#Override
public void run() {
viewPager.setCurrentItem(currentPage - 1);
}
}, 1000);