I am developing a welcome screen which will show four slides. I have created the adapter and set it in the activity. Every thing is working fine but the problem is the screen only showing first and third slide. But if I scroll manually I can see all the screens. I am not able to figure out why this is happening.
Here is my activity class:
public class ProgramLandingActivity extends AppCompatActivity implements View.OnClickListener {
private String TAG = ProgramLandingActivity.class.getSimpleName();
ActivityProgramLandingBinding binding;
private ViewPager viewPager;
private MyViewPagerAdapter myViewPagerAdapter;
private int[] layouts = {
R.drawable.slider3,
R.drawable.slider1,
R.drawable.slider2,
R.drawable.slider4};
private int[] icons = {
R.drawable.note,
R.drawable.mic,
R.drawable.up_arrow,
R.drawable.weight};
private String[] text = {
"Personalized Running Programs \n and flexible calender",
"Audio tips in Hindi and English \n From your mentors,\n Gul Panag and Milind Soman",
"Track your running, see achievements and share daily progress","includes weight loss and running performance nutrition plans"};
private ArrayList<Integer> layoutArray = new ArrayList<Integer>();
private ArrayList<Integer> layouticons = new ArrayList<Integer>();
private ArrayList<String> layouttext = new ArrayList<String>();
private static int currentPage = 0;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = DataBindingUtil.setContentView(this,R.layout.activity_program_landing);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
}
intializeViews();
setAdapter();
}
private void setAdapter() {
for (int i = 0; i < layouts.length; i++) {
layoutArray.add(layouts[i]);
layouticons.add(icons[i]);
layouttext.add(text[i]);
myViewPagerAdapter = new MyViewPagerAdapter(this, layoutArray,layouticons,layouttext);
viewPager.setAdapter(myViewPagerAdapter);
CirclePageIndicator indicator = (CirclePageIndicator) findViewById(R.id.indicator);
indicator.setViewPager(viewPager);
Log.d("laypou_length", String.valueOf(layouts.length));
// Auto start of viewpager
final Handler handler = new Handler();
final Runnable Update = new Runnable() {
public void run() {
if (currentPage == layouts.length) {
currentPage = 0;
}
viewPager.setCurrentItem(currentPage++, true);
}
};
Timer swipeTimer = new Timer();
swipeTimer.schedule(new TimerTask() {
#Override
public void run() {
handler.post(Update);
}
}, 2500, 2500);
indicator.setOnPageChangeListener(new ViewPager.OnPageChangeListener(){
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
#Override
public void onPageSelected(int position) {
currentPage = position;
}
#Override
public void onPageScrollStateChanged(int state) {
}
});
}
}
private void intializeViews() {
viewPager = (ViewPager) findViewById(R.id.view_pager);
}
My adapter class:
class MyViewPagerAdapter extends PagerAdapter {
private ArrayList<Integer> layouts;
private ArrayList<Integer> icons;
private ArrayList<String> text;
private LayoutInflater inflater;
private Context context;
public MyViewPagerAdapter(Context context,ArrayList<Integer> layouts, ArrayList<Integer> icons,ArrayList<String> text ) {
this.context = context;
this.layouts=layouts;
this.icons = icons;
this.text=text;
inflater = LayoutInflater.from(context);
}
#Override
public Object instantiateItem(ViewGroup container, int position) {
View myImageLayout = inflater.inflate(R.layout.slider,container,false);
ImageView myImage = (ImageView) myImageLayout.findViewById(R.id.image1);
ImageView icon = (ImageView)myImageLayout.findViewById(R.id.icon);
TextViewWithFont slider_text = (TextViewWithFont)myImageLayout.findViewById(R.id.text_program_landing_body);
myImage.setImageResource(layouts.get(position));
icon.setImageResource(icons.get(position));
slider_text.setText(text.get(position));
container.addView(myImageLayout, 0);
return myImageLayout;
}
#Override
public int getCount() {
return layouts.size();
}
#Override
public boolean isViewFromObject(View view, Object object) {
return view == object;
}
#Override
public void destroyItem(ViewGroup container, int position, Object object) {
View view = (View) object;
container.removeView(view);
}
}
Can someone tell me what I am doing wrong?
try this
you can user time for auto scroll like this
Timer timer;
timer = new Timer();
timer.scheduleAtFixedRate(new RemindTask(), 0, 3000); // delay*/
private class RemindTask extends TimerTask {
int current = viewPager.getCurrentItem();
#Override
public void run() {
runOnUiThread(new Runnable() {
public void run() {
if (current < layouts.length) {
viewPager.setCurrentItem(current);
current += 1;
} else {
timer.cancel();
}
}
});
}
}
Looks like the problem is in the 'viewpager.setCurrentPage' put prints for the 'currentPage' there and see if it is getting called twice.
Let me know the observation in the comments.
Cheers :)
Related
I am using viewpager in my application and i want to make only one view Swipeable . Is it possible to do so.
I don't want the buttons at the bottom move when i swipe i only want the textview to change.
Any way can anyone help i searched a lot but couldn't find anything.
Here is my code.
There is a lot of code i can't paste all of it here.
Here is the link to the rest of it.
ViewPagerAdapter.java
public class ViewPagerAdapter extends PagerAdapter {
private Activity activity;
private Cursor cursor;
private int i = 0;
private int f = 0;
OnItemClickListener mOnItemClickListener;
public ViewPagerAdapter(Activity activity, Cursor cursor) {
this.activity = activity;
this.cursor = cursor;
}
public void setOnItemClickListener(OnItemClickListener onItemClickListener) {
mOnItemClickListener = onItemClickListener;
}
#Override
public int getCount() {
return cursor.getCount();
}
#Override
public boolean isViewFromObject(#NonNull View view, #NonNull Object object) {
return view == object;
}
#NonNull
#Override
public Object instantiateItem(#NonNull final ViewGroup container, final int position) {
final Context context = container.getContext();
LayoutInflater inflater = LayoutInflater.from(context);
View v = inflater.inflate(R.layout.quote_detail_viewpager, container, false);
final TextView tvQuotes;
final ImageButton favouriteBtn, shareBtn, copyBtn, bgBtn, fontBtn;
tvQuotes = v.findViewById(R.id.vp_quotes);
favouriteBtn = v.findViewById(R.id.vp_fav);
shareBtn = v.findViewById(R.id.vp_share);
copyBtn = v.findViewById(R.id.vp_copy);
bgBtn = v.findViewById(R.id.vp_bg);
fontBtn = v.findViewById(R.id.vp_font);
int[] fonts = {
R.font.architects_daughter, R.font.artifika, R.font.carter_one,
R.font.expletus_sans, R.font.fredoka_one, R.font.graduate, R.font.jose,
R.font.magnolia, R.font.oswald, R.font.quicksand_bold, R.font.righteous,
R.font.salsa, R.font.schoolbell, R.font.sofadi_one
};
cursor.moveToPosition(position);
String id = cursor.getString(0);
String quote = cursor.getString(1);
String author = cursor.getString(2);
String text = quote + "\n \n - "+ author;
if (new DatabaseHelper(context).isFavourite(id)) {
favouriteBtn.setImageResource(R.drawable.ic_favorite);
}
tvQuotes.setText(text);
tvQuotes.setTypeface(PrefUtils.getTypefaceFromPrefs(context));
favouriteBtn.setOnClickListener(view ->
UtilsHelper.addOrDeleteFavourite(context, favouriteBtn, id, quote, author));
shareBtn.setOnClickListener(view -> UtilsHelper.shareTextIntent(context, text));
copyBtn.setOnClickListener(view -> UtilsHelper.copyText(context, text));
bgBtn.setOnClickListener(view -> mOnItemClickListener.onItemClick(view));
fontBtn.setOnClickListener(view -> {
int j = f++;
if (j < fonts.length) {
PrefUtils.setTypefaceFromPrefs(context, fonts[j]);
tvQuotes.setTypeface(PrefUtils.getTypefaceFromPrefs(context));
notifyDataSetChanged();
}
if (f == fonts.length) {
f = 0;
}
});
container.addView(v);
return v;
}
#Override
public int getItemPosition(#NonNull Object object) {
return POSITION_NONE;
}
#Override
public void destroyItem(ViewGroup container, int position, #NonNull Object object) {
container.removeView((View) object);
}
public interface OnItemClickListener {
void onItemClick(View view);
}
}
DetailActivity.java
public class QuoteDetailActivity extends AppCompatActivity {
// Max swipe ad interval
private final int MAX_AD_COUNT = 10;
// count swipes
private int SWIPE_COUNT = 0;
// Min swipe ad interval
private int MIN_AD_COUNT = 6;
private int i = 0;
private InterstitialAd mInterstitialAd;
ViewPagerAdapter pagerAdapter;
RelativeLayout rootLayout;
int[] backgrounds;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS,
WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS);
Objects.requireNonNull(getSupportActionBar()).hide(); //hide the title bar
setContentView(R.layout.activity_quote_detail);
showInterstitialAd();
// String extras
String incomingActivity = getIntent().getStringExtra(Constants.STRING_EXTRA_INCOMING_ACTIVITY);
int position = getIntent().getIntExtra(Constants.STRING_EXTRA_ADAPTER_POSITION, 0);
DatabaseHelper mDBHelper = new DatabaseHelper(this);
ViewPager viewPager = findViewById(R.id.single_quote_viewpager);
backgrounds = BackgroundUtils.getAllBackgrounds();
rootLayout = findViewById(R.id.root_container);
rootLayout.setBackgroundResource(BackgroundUtils.getBackground(position));
FrameLayout adContainerView = findViewById(R.id.ad_view_container);
adContainerView.post(() ->
AdHelper.loadBanner(this, adContainerView, viewPager));
assert incomingActivity != null;
if (incomingActivity.contains(Constants.ACTIVITY_QUOTES)) {
pagerAdapter = new ViewPagerAdapter(this, mDBHelper.getAllQuotes());
} else if (incomingActivity.contains(Constants.ACTIVITY_FAVOURITE)) {
pagerAdapter = new ViewPagerAdapter(this, mDBHelper.getFavourites());
}
viewPager.setAdapter(pagerAdapter);
viewPager.setCurrentItem(position); // Setup recycleView Item position
pagerAdapter.setOnItemClickListener(new ViewPagerAdapter.OnItemClickListener() {
#Override
public void onItemClick(View view) {
changeBackground();
}
});
viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
#Override
public void onPageSelected(int position) {
int count = SWIPE_COUNT++;
if (count >= MIN_AD_COUNT) {
if (mInterstitialAd != null) {
mInterstitialAd.show(QuoteDetailActivity.this);
SWIPE_COUNT = 0;
}
}
}
#Override
public void onPageScrollStateChanged(int state) {
}
});
}
private void changeBackground() {
int j = i++;
if (j < backgrounds.length) {
rootLayout.setBackgroundResource(backgrounds[j]);
}
if (i == backgrounds.length) {
i = 0;
}
}
private void showInterstitialAd() {
MobileAds.initialize(this, initializationStatus -> {
});
AdRequest adRequest = new AdRequest.Builder().build();
InterstitialAd.load(this, getString(R.string.interstitial_ad_unit),
adRequest, new InterstitialAdLoadCallback() {
#Override
public void onAdLoaded(#NonNull InterstitialAd interstitialAd) {
// The mInterstitialAd reference will be null until
// an ad is loaded.
mInterstitialAd = interstitialAd;
mInterstitialAd.setFullScreenContentCallback(new FullScreenContentCallback() {
#Override
public void onAdDismissedFullScreenContent() {
// Called when fullscreen content is dismissed.
if (MIN_AD_COUNT < MAX_AD_COUNT) {
MIN_AD_COUNT++;
}
}
#Override
public void onAdShowedFullScreenContent() {
// Called when fullscreen content is shown.
// Make sure to set your reference to null so you don't
// show it a second time.
mInterstitialAd = null;
}
});
}
#Override
public void onAdFailedToLoad(#NonNull LoadAdError loadAdError) {
// Handle the error
mInterstitialAd = null;
}
});
}
}
Sure, something like the below pseudo_xml
<Parent View> -- background set to image
<ViewPager> -- only this part is swipable
<View Containing Buttons Fixed To The Bottom Of Parent/>
</Parent View>
I am receiving new item data from server and set it to adapter of my RecyclerView. When I first start the async-task to get data then the fetched data is displayed from top. But when I start async-task again to get new data then the new data is attached below the (invisible) old ones, although I am setting adapter = null before I start server request.
General Process:
1) start Activity and AsyncTask to get data from server: asynctask.execute();
2) call mRecyclerView.setAdapter(mAdapter); and mAdapter.notifyDataSetChanged(); and data will be shown from top on
3) initate asynctask again: first set mAdapter = null; and load another data
Problem in 3): now new loaded data will not be shown from top on, rather below the data that were there in 1) but no more visible because of mAdapter = null;. It is like RecyclerView did not "delete" the space of the old data that were shown in 1).
This is weird, has somebody any idea why this behavior occurs?
Code:
a) My Adapter:
public class Adapter_New extends RecyclerView.Adapter<Adapter_New.CustomViewHolder> {
private List<Data_B> feedItemList;
private Context mContext;
private int lastPosition = -1, b_height;
int width, height, targetHeight;
private ViewHolderState viewHolderState = ViewHolderState.getInstance();
public Adapter_New(Context context, List<Data_B> feedItemList) {
this.feedItemList = feedItemList;
this.mContext = context;
}
#Override
public CustomViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
DisplayMetrics metrics = mContext.getResources().getDisplayMetrics();
int calc_width= metrics.widthPixels;
int calc_height=metrics.heightPixels;
int dens=metrics.densityDpi;
double wi=(double)calc_width/(double)dens;
double hi=(double)calc_height/(double)dens;
double x = Math.pow(wi,2);
double y = Math.pow(hi,2);
double screenInches = Math.sqrt(x + y);
if (screenInches >= 7.0){
width = metrics.widthPixels/3;
height = metrics.heightPixels / 4;
}else{
width = metrics.widthPixels/2;
height = metrics.heightPixels / 4;
}
View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.list_item_grid, null);
CustomViewHolder viewHolder = new CustomViewHolder(view);
return viewHolder;
}
#Override
public void onViewDetachedFromWindow(CustomViewHolder holder) {
super.onViewDetachedFromWindow(holder);
((CustomViewHolder) holder).clearAnimation();
((CustomViewHolder) holder).cleanup();
}
#Override
public void onBindViewHolder(final CustomViewHolder customViewHolder, int i) {
Data_Borrow data = feedItemList.get(i);
final Target target = new Target() {
#Override
public void onPrepareLoad(Drawable placeHolderDrawable) {
}
#Override
public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
b_height = bitmap.getHeight();
customViewHolder.frame.getLayoutParams().height = b_height; //setting height dynamically
customViewHolder.imageView.getLayoutParams().height = b_height; //setting height dynamically
customViewHolder.imageView.setImageBitmap(bitmap);
}
#Override
public void onBitmapFailed(Drawable errorDrawable) {
}
};
customViewHolder.imageView.setTag(target);
Picasso.with(mContext)
.load(data.getImageUrl())
.resize(width, height)
.into(target);
// Animation apply
setAnimation(customViewHolder.rel_container, i);
}
//Animation
private void setAnimation(View viewToAnimate, int position) {
// If the bound view wasn't previously displayed on screen, it's animated
if (position > lastPosition) {
Animation animation = AnimationUtils.loadAnimation(mContext, R.anim.slide_in_up);
viewToAnimate.startAnimation(animation);
lastPosition = position;
}
}
#Override
public int getItemCount() {
return (null != feedItemList ? feedItemList.size() : 0);
}
public void add_new(List<Data_Borrow> datas) {
//feedItemList.clear();
feedItemList.addAll(datas);
notifyDataSetChanged();
}
public void clear() {
feedItemList.clear();
notifyDataSetChanged();
}
public class CustomViewHolder extends RecyclerView.ViewHolder {
protected ImageView imageView;
protected RelativeLayout rel_container;
protected FrameLayout frame;
protected CardView card_view;
public CustomViewHolder(View view) {
super(view);
this.imageView = (ImageView) view.findViewById(R.id.thumbnail);
this.title = (TextView) view.findViewById(R.id.title);
this.rel_container = (RelativeLayout) view.findViewById(R.id.rel_grid_item);
this.frame = (FrameLayout) view.findViewById(R.id.frame_current);
this.frame.getLayoutParams().width = width; //setting width dynamically
this.card_view = (CardView) view.findViewById(R.id.card_view);
}
public void cleanup() {
Picasso.with(mContext)
.cancelRequest(imageView);
}
public void clearAnimation() {
rel_container.clearAnimation();
}
}
}
b) My Activity:
public class MyActivity extends AppCompatActivity implements FetchDataListener, SearchView.OnQueryTextListener, AdapterView.OnItemSelectedListener {
private List<Data_B> feedsList = null;
private RecyclerView mRecyclerView;
private Adapter_New mAdapter;
StaggeredGridLayoutManager StaggeredGridLayoutManager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.my_activity);
StaggeredGridLayoutManager = new StaggeredGridLayoutManager(3, 1);
StaggeredGridLayoutManager.setGapStrategy(StaggeredGridLayoutManager.GAP_HANDLING_NONE);
mRecyclerView.setAdapter(new Data_Borrow_Adapter_New(this, feedsList)); // first add empty adapter
mRecyclerView.setLayoutManager(StaggeredGridLayoutManager);
initView(); //start initView when activity starts
//******* WHEN I CLICK TO GET NEW FILTERED DATA, then new data is not shown from top on ****//
btn_start_filtered_asynctask = (Button) findViewById(R.id.btn_filter);
btn_start_filtered_asynctask.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
initViewFilterd();
}
});
}
private void initView() {
String url = "http://xxx/xx.php";
String show_from = "0";
FetchDataTask_ALL task = new FetchDataTask_ALL(this);
task.execute(url, show_from);
loading = true;
}
private void initViewFilterd() {
String url = "http://xxx/xx.php";
String show_from = "0";
String result_category_pos = "2";
FetchDataTask_Filtered task = new FetchDataTask_Filtered(this);
task.execute(url, result_category_pos, show_from);
mAdapter = null; //setting adapter null
loading = true;
}
#Override
public void onFetchComplete(List<Data_B> data) {
if (mAdapter == null)
{
mAdapter = new Adapter_New(getApplicationContext(), data);
mRecyclerView.setAdapter(mAdapter);
mAdapter.notifyDataSetChanged();
} else {
mAdapter.add_new(data);
}
searchItem.collapseActionView();
loading = false;
mRecyclerView.setVisibility(View.VISIBLE);
}
}
you should not set adapter to null, you should update the data in the adapter (in your case, add the new item at the beginning of the datasource (list, array, anything) and then call notifyDataSetChanged()
EDIT: I suggest to change this two methods: remove adapter = null, and always add item first. (you may need to add that method to the adapter)
private void initViewFilterd() {
String url = "http://xxx/xx.php";
String show_from = "0";
String result_category_pos = "2";
FetchDataTask_Filtered task = new FetchDataTask_Filtered(this);
task.execute(url, result_category_pos, show_from);
loading = true;
}
#Override
public void onFetchComplete(List<Data_B> data) {
mAdapter.addFirstAndUpdate(data);
searchItem.collapseActionView();
loading = false;
mRecyclerView.setVisibility(View.VISIBLE);
}
In adapter:
public void addFirstAndUpdate(List<Data_Borrow> datas) {
// TODO: add data in feedItemList
notifyDataSetChanged();
}
I'm facing a few problems for a while now which I'm having trouble to solve. So I refer to the Realm and RecyclerView geniuses among the community.
I'm woking on a ToDo-List that sets completed tasks back to the ToDo-List after 2 days. The app uses a ViewPager with two tabs: "TODO" & "DONE".
1. RecyclerView
1.1. I want the completed Tasks from fragment 1 to be sent back to fragment 0 automatically after 2 days.
The Problem: If the counter is at 0 (or below) the item gets sent to fragment 0.
If I delte the item in the next line I get an exception error: "java.lang.IllegalStateException: Cannot call this method while RecyclerView is computing a layout or scrolling"
So I put the delete function into a handler. Then it's working BUT only if ONE gets sent back. If many items get sent back simultaneously the app crashes. When I reopen the app everything is working because it was successfully saved in realm but one item is always saved twice.
Where's the Problem (in DoneAdapter.java)?
2. Realm
2.1. When I add an Item to the RecyclerView (and simultaneously to Realm), the item gets added at the bottom. But I want to add every new item at position 0.
(I know how to achieve this wih an ArrayList, but I want the items to be stored and displayed when I reopen the app, so I'm using Realm DB.)
Do you have any suggestions to achieve this?
2.2. Is it possible to implement later on the onLongClickListener for dragging and droping items and rearranging the position with Realm?
(I want to use this https://www.youtube.com/watch?v=tNgevYpyA9E)
2.3. I want to add some nice animations when I add and check an item. Realm doesn't support mRecyclerView.setItemAnimator(...); but I heard it is possible by adding mAdapter.setHasStableIds(true);. Unfortunately it throws an Exception: java.lang.IllegalStateException: Cannot change whether this adapter has stable IDs while the adapter has registered observers. (You can see this in my code below)
Do you have any solutions for that?
(optionally 1.4. Can you recommend me any Online DBs (e.g. Firebase) which I can sync with Realm or more generally: is it possible to sync an Online DB with Realm? Do you know any Tutorials (Udemy, YouTube) for setting up this sync process?)
Lastly: I want to update the Database with a background service every Midnight, so the counter in the completed section updates automatically. Does anyone know how to do this as well? Maybe with protected void onHandleIntent(Intent intent)?
Do you also know if there's an option in debugging mode to simulate passing time?
Here is the code:
MainActivity.java
public class MainActivity extends AppCompatActivity implements ToOtherFragmentCommunicator {
private ViewPagerAdapter mViewPagerAdapter;
private ViewPager mViewPager;
private static final int DONE = 1;
private static final int TODO = 0;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
mViewPagerAdapter = new ViewPagerAdapter(getSupportFragmentManager());
mViewPager = (ViewPager) findViewById(R.id.container);
mViewPager.setAdapter(mViewPagerAdapter);
TabLayout tabLayout = (TabLayout) findViewById(R.id.tabs);
tabLayout.setupWithViewPager(mViewPager);
tabLayout.setOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
#Override
public void onTabSelected(TabLayout.Tab tab) {
mViewPager.setCurrentItem(tab.getPosition());
}
#Override
public void onTabUnselected(TabLayout.Tab tab) {
}
#Override
public void onTabReselected(TabLayout.Tab tab) {
}
});
RealmConfiguration configuration = new RealmConfiguration.Builder(this).build();
Realm.setDefaultConfiguration(configuration);
}
#Override
public void itemToOtherFragment(String data, int fragment) {
if (DONE == fragment) {
Done done = (Done) mViewPagerAdapter.getItem(fragment);
done.createDoneItem(data);
} else if (TODO == fragment) {
ToDo toDo = (ToDo) mViewPagerAdapter.getItem(fragment);
toDo.createToDoItem(data);
}
}
}
ToDo.java
public class ToDo extends Fragment {
private RecyclerView mRecyclerView;
private ToDoAdapter mAdapter;
private EditText taskInput;
private String taskName;
private Realm mRealm;
private RealmResults<ListItems> mResults;
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View toDoView = inflater.inflate(R.layout.todo_layout, container, false);
mRecyclerView = (RecyclerView) toDoView.findViewById(R.id.todo_rv);
mRealm = Realm.getDefaultInstance();
mResults = mRealm.where(ListItems.class).equalTo("fragment", 0).findAllAsync();
setRecyclerView();
mRecyclerView.setItemAnimator(null);
//TODO add product to shopping list
final Handler handler = new Handler();
taskInput = (EditText) toDoView.findViewById(R.id.task_input);
taskInput.setOnKeyListener(new View.OnKeyListener() {
#Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
if (taskInput.getText().length() > 0 && (event.getAction() == KeyEvent.ACTION_DOWN) &&
(keyCode == KeyEvent.KEYCODE_ENTER)) {
// Perform action on key press
taskName = taskInput.getText().toString();
//Problem 2.1
//Code for adding item at the top with mRealm?
mRealm.beginTransaction();
createToDoItem(taskName);
mRealm.commitTransaction();
// mRecyclerView.scrollToPosition(0);
taskInput.setText(null);
handler.postDelayed(new Runnable() {
#Override
public void run() {
taskInput.setFocusableInTouchMode(true);
taskInput.setFocusable(true);
taskInput.requestFocus();
}
}, 200);
return true;
} else if (taskInput.length() == 0 && (event.getAction() == KeyEvent.ACTION_DOWN) &&
(keyCode == KeyEvent.KEYCODE_ENTER)) {
taskInput.clearFocus();
InputMethodManager imm = (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(taskInput.getWindowToken(), 0);
return true;
}
return false;
}
});
return toDoView;
}
//TODO creates the shopping list item in DB
public void createToDoItem(String taskName) {
ListItems item = mRealm.createObject(ListItems.class);
long now = System.currentTimeMillis();
item.setAddedTime(now);
item.setFragment(0);
item.setTaskName(taskName);
mRealm.copyToRealmOrUpdate(item);
}
public void setRecyclerView() {
mRecyclerView.setHasFixedSize(true);
LinearLayoutManager mLayoutManager = new LinearLayoutManager(getActivity());
mRecyclerView.setLayoutManager(mLayoutManager);
mAdapter = new ToDoAdapter(getActivity(), mRealm, mResults);
mRecyclerView.setAdapter(mAdapter);
//Problem 2.3.
//Produces "java.lang.IllegalStateException: Cannot change whether this adapter has stable IDs while the adapter has registered observers."
// mAdapter.setHasStableIds(true);
}
private RealmChangeListener mChangeListener = new RealmChangeListener() {
#Override
public void onChange() {
mAdapter.updateItems(mResults);
}
};
#Override
public void onStart() {
super.onStart();
mResults.addChangeListener(mChangeListener);
}
#Override
public void onStop() {
super.onStop();
mResults.removeChangeListener(mChangeListener);
}
}
ToDoAdapter.java
public class ToDoAdapter extends RecyclerView.Adapter<ListItemsViewHolder> {
private Context mContext;
private Realm mRealm;
private RealmResults<ListItems> mResults;
private int focusedItem = 0;
ToOtherFragmentCommunicator comm;
ToDoAdapter(Context context, Realm realm, RealmResults<ListItems> mResults) {
this.mContext = context;
this.mRealm = realm;
updateItems(mResults);
}
public void updateItems(RealmResults<ListItems> mResults) {
this.mResults = mResults;
notifyDataSetChanged();
}
//Problem 2.3.
//needed for mAdapter.setHasStableIds(true); in ToDo.java
// #Override
// public long getItemId(int position) {
// if (position < mResults.size()) {
// return mResults.get(position).getAddedTime();
// } else {
// return RecyclerView.NO_ID;
// }
// }
#Override
public ListItemsViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.todo_item, parent, false);
comm = (ToOtherFragmentCommunicator) mContext;
return new ListItemsViewHolder(v);
}
#Override
public void onBindViewHolder(final ListItemsViewHolder holder, final int position) {
final ListItems items = mResults.get(position);
holder.taskName.setText(items.getTaskName());
holder.itemView.setSelected(focusedItem == position);
holder.getLayoutPosition();
holder.itemCheckbox.setOnCheckedChangeListener(null);
holder.itemCheckbox.setChecked(items.isSelected());
holder.itemCheckbox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
mRealm.beginTransaction();
items.setSelected(isChecked);
//send item to Done
comm.itemToOtherFragment(items.getTaskName(), 1);
removeItem(position);
mRealm.commitTransaction();
}
});
}
#Override
public int getItemCount() {
return (mResults != null ? mResults.size() : 0);
}
private void removeItem(int position) {
mResults.get(position).removeFromRealm();
notifyDataSetChanged();
}
}
Done.java
public class Done extends Fragment {
private RecyclerView mRecyclerView;
private DoneAdapter mAdapter;
private Calendar calendar = Calendar.getInstance();
private Date date = new Date();
private SimpleDateFormat simpleDateFormat = new SimpleDateFormat("dd.MM.yyyy");
private Realm mRealm;
private RealmResults<ListItems> mResults;
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View doneView = inflater.inflate(R.layout.done_layout, container, false);
mRecyclerView = (RecyclerView) doneView.findViewById(R.id.done_rv);
mRealm = Realm.getDefaultInstance();
mResults = mRealm.where(ListItems.class).equalTo("fragment", 1).findAllAsync();
setRecyclerView();
mRecyclerView.setItemAnimator(null);
return doneView;
}
//TODO creates the fridge item in DB
public void createDoneItem(String taskName) {
TimeZone.getDefault();
ListItems item = mRealm.createObject(ListItems.class);
long now = System.currentTimeMillis();
item.setAddedTime(now);
item.setFragment(1);
item.setTaskName(taskName);
item.setInputDate(simpleDateFormat.format(calendar.getTime()));
calendar.add(Calendar.DATE, 2);
item.setRenewDate(simpleDateFormat.format(calendar.getTime()));
//reset time to current date after adding days
calendar.setTime(date);
item.getRenewDate();
mRealm.copyToRealmOrUpdate(item);
}
public void setRecyclerView() {
mRecyclerView.setHasFixedSize(true);
LinearLayoutManager mLayoutManager = new LinearLayoutManager(getActivity());
mRecyclerView.setLayoutManager(mLayoutManager);
mAdapter = new DoneAdapter(getActivity(), mRealm, mResults, Done.this);
mRecyclerView.setAdapter(mAdapter);
}
private RealmChangeListener mChangeListener = new RealmChangeListener() {
#Override
public void onChange() {
mAdapter.updateItems(mResults);
}
};
#Override
public void onStart() {
super.onStart();
mResults.addChangeListener(mChangeListener);
}
#Override
public void onStop() {
super.onStop();
mResults.removeChangeListener(mChangeListener);
}
}
DoneAdapter.java
public class DoneAdapter extends RecyclerView.Adapter<ListItemsViewHolder> {
private Context mContext;
private Done done;
private Realm mRealm;
private RealmResults<ListItems> mResults;
private int focusedItem = 0;
protected ToOtherFragmentCommunicator comm;
DoneAdapter(Context context, Realm realm, RealmResults<ListItems> results, Done done) {
this.mContext = context;
this.mRealm = realm;
this.done = done;
updateItems(results);
}
public void updateItems(RealmResults<ListItems> mResults) {
this.mResults = mResults;
notifyDataSetChanged();
}
#Override
public ListItemsViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.done_item, parent, false);
comm = (ToOtherFragmentCommunicator) mContext;
return new ListItemsViewHolder(v);
}
#TargetApi(Build.VERSION_CODES.JELLY_BEAN)
#Override
public void onBindViewHolder(final ListItemsViewHolder holder, final int position) {
final ListItems items = mResults.get(position);
holder.taskName.setText(items.getTaskName());
try {
if (items.getRenewCounter() == 1) {
holder.renewCounter.setText(mContext.getString(R.string.show_days_till_renew, items.getRenewCounter(), mContext.getString(R.string.day)));
} else {
holder.renewCounter.setText(mContext.getString(R.string.show_days_till_renew, items.getRenewCounter(), mContext.getString(R.string.days)));
}
holder.renewCounter.setTextColor(ContextCompat.getColor(mContext, R.color.colorAccent));
if (items.getRenewCounter() <= 0) {
mRealm.beginTransaction();
//Problem 1.1.
//send item back to todo list
comm.itemToOtherFragment(items.getTaskName(), 0);
// Produces "java.lang.IllegalStateException: Cannot call this method while RecyclerView is computing a layout or scrolling" if there is no Handler
Handler handler = new Handler();
final Runnable r = new Runnable() {
public void run() {
mRealm.beginTransaction();
removeItem(position);
mRealm.commitTransaction();
}
};
handler.post(r);
mRealm.commitTransaction();
}
} catch (ParseException e) {
e.printStackTrace();
}
holder.itemView.setSelected(focusedItem == position);
holder.getLayoutPosition();
}
#Override
public int getItemCount() {
return (mResults != null ? mResults.size() : 0);
}
private void removeItem(int position) {
mResults.get(position).removeFromRealm();
notifyDataSetChanged();
}
}
ListItems.java
public class ListItems extends RealmObject {
public ListItems(long addedTime, String taskName, String inputDate, String renewDate, int fragment) {
this.addedTime = addedTime;
this.taskName = taskName;
this.inputDate = inputDate;
this.renewDate = renewDate;
this.fragment = fragment;
}
#PrimaryKey
private long addedTime;
private int fragment;
#Ignore
private long renewCounter;
private String taskName, inputDate, renewDate;
private boolean selected;
public ListItems() {
}
public long getAddedTime() {
return addedTime;
}
public void setAddedTime(long addedTime) {
this.addedTime = addedTime;
}
public int getFragment() {
return fragment;
}
public void setFragment(int fragment) {
this.fragment = fragment;
}
public String getTaskName() {
return taskName;
}
public void setTaskName(String taskName) {
this.taskName = taskName;
}
public String getInputDate() {
return inputDate;
}
public void setInputDate(String inputDate) {
this.inputDate = inputDate;
}
public String getRenewDate() {
return renewDate;
}
public void setRenewDate(String renewDate) {
this.renewDate = renewDate;
}
public boolean isSelected() {
return selected;
}
public void setSelected(boolean selected) {
this.selected = selected;
}
public long getRenewCounter() throws ParseException {
TimeZone.getDefault();
SimpleDateFormat dateFormat = new SimpleDateFormat("dd.MM.yyyy");
Date todayDate = new Date();
Date exDate = dateFormat.parse(renewDate);
this.renewCounter = daysBetween(todayDate, exDate);
return renewCounter;
}
private static long daysBetween(Date startDate, Date endDate) {
Calendar sDate = getDatePart(startDate);
Calendar eDate = getDatePart(endDate);
long daysBetween = 0;
while (sDate.before(eDate)) {
sDate.add(Calendar.DAY_OF_MONTH, 1);
daysBetween++;
}
while (eDate.before(sDate)) {
eDate.add(Calendar.DAY_OF_MONTH, 1);
daysBetween--;
}
return daysBetween;
}
private static Calendar getDatePart(Date date) {
Calendar cal = Calendar.getInstance(); // get calendar instance
cal.setTime(date);
cal.set(Calendar.HOUR_OF_DAY, 0); // set hour to midnight
cal.set(Calendar.MINUTE, 0); // set minute in hour
cal.set(Calendar.SECOND, 0); // set second in minute
cal.set(Calendar.MILLISECOND, 0); // set millisecond in second
return cal; // return the date part
}
}
Here's a Screenshot on how the app looks like:
DailyTaskRepeater
That's it! It would mean the world to me if someone could help me with all that (especially Problem 1.1!).
Thank you!
The current practice Realm supports is to add an index (e.g. timestamp) and to reverse sort your list for having the latest item at the top and achiving the rearranging effect you are seeking for.
Please consider taking a reference from an adapter example provided in the official repository.
I try to use AsyncTaskLoader in Fragment that is a child of ViewPager. Below a code of my DayFragment:
public class DayFragment extends Fragment
implements LoaderManager.LoaderCallbacks<DayAdapter.DayItem[]> {
private static final int CONTENT_LOADER = 0;
private DayAdapter mAdapter = null;
private int mWeekNumber = 1;
private int mDayCode = 1;
private Table.Timetable mTimetable;
private RecyclerView mRVContent;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
final MainActivity mainActivity = (MainActivity) getActivity();
View v = inflater.inflate(R.layout.content, container, false);
mRVContent = (RecyclerView) v.findViewById(R.id.rvContent);
RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(mainActivity);
mRVContent.setLayoutManager(layoutManager);
mAdapter = new DayAdapter(getActivity());
mRVContent.setAdapter(mAdapter);
//Initialize the cursor loader
getLoaderManager().initLoader(CONTENT_LOADER, null, this).forceLoad();
return v;
}
#Override
public Loader<DayAdapter.DayItem[]> onCreateLoader(final int id, Bundle args) {
if(CONTENT_LOADER == id) {
return new ContentLoader(getContext(), mWeekNumber, mDayCode, mTimetable);
}
return null;
}
#Override
public void onLoadFinished(Loader loader, DayAdapter.DayItem[] items) {
if(CONTENT_LOADER == loader.getId()) {
mAdapter.setIs24HourFormat(SettingsManager.is24HourFormat(getContext()));
mAdapter.clear();
for (DayAdapter.DayItem item : items) {
mAdapter.add(item);
}
mAdapter.notifyDataSetChanged();
if (items.length == 0) {
mRVContent.setBackgroundResource(R.drawable.bg_lesson_empty);
} else {
mRVContent.setBackgroundColor(0xFFFFFFFF);
}
}
}
#Override
public void onLoaderReset(Loader loader) {
}
private static final class ContentLoader extends AsyncTaskLoader<DayAdapter.DayItem[]> {
private final int mWeekNumber;
private final int mDayCode;
private final Table.Timetable mTimetable;
public ContentLoader(Context context, final int weekNumber, final int dayCode,
Table.Timetable timetable) {
super(context);
mWeekNumber = weekNumber;
mDayCode = dayCode;
mTimetable = timetable;
}
#Override
public DayAdapter.DayItem[] loadInBackground() {
DatabaseHandler db = new DatabaseHandler(getContext());
db.openReadable();
List<Table.Lesson> lessons = db.findLessons(mDayCode, mWeekNumber, mTimetable.getId());
DayAdapter.DayItem[] items = new DayAdapter.DayItem[lessons.size()];
for (int i = 0; i < items.length; ++i) {
Table.Lesson lesson = lessons.get(i);
Table.Subject subject = db.getSubject(lesson.getSubjectId());
Table.Teacher teacher = db.getTeacher(lesson.getTeacherId());
if (teacher == null) {
teacher = new Table.Teacher(""); //Empty name
}
items[i] = new DayAdapter.DayItem()
.setId(lesson.getId())
.setTitle(subject.getTitle())
.setSubtitle(teacher.getName()));
}
db.close();
return items;
}
}
}
PageAdapater
public class PageAdapter extends FragmentStatePagerAdapter {
public static final int PAGE_COUNT = 7;
private int mWeekNumber;
private final int[] mDayCodes;
private final String[] mDays;
private final DayFragment[] mFragments = new DayFragment[7];
private Table.Timetable mTimetable;
private boolean mIsRebuildMode = false;
public PageAdapter(Context context, FragmentManager fm,
Table.Timetable timetable, final int weekNumber) {
super(fm);
//Initialize class members
}
#Override
public Fragment getItem(int position) {
DayFragment dayFragment;
if (mFragments[position] == null) {
dayFragment = new DayFragment();
Bundle args = new Bundle();
args.putSerializable(Keys.TIMETABLE, mTimetable);
dayFragment.setArguments(args);
dayFragment.setWeekNumber(mWeekNumber);
dayFragment.setDayCode(mDayCodes[position]);
mFragments[position]= dayFragment;
} else {
dayFragment = mFragments[position];
}
return dayFragment;
}
#Override
public void restoreState(Parcelable arg0, ClassLoader arg1) {
//do nothing here! no call to super.restoreState(arg0, arg1);
}
public void setWeekNumber(final int weekNumber) {
mWeekNumber = weekNumber;
Arrays.fill(mFragments, null);
}
public void setIsRebuildMode(final boolean isRebuildMode) {
mIsRebuildMode = isRebuildMode;
}
#Override
public CharSequence getPageTitle(final int position) {
return mDays[position];
}
#Override
public int getCount() {
return PAGE_COUNT;
}
#Override
public int getItemPosition(Object object) {
if(mIsRebuildMode) {
return POSITION_NONE;
}
return super.getItemPosition(object);
}
}
But it doesn't call onLoadFinished method. I checked Log output... LoaderManager calls onCreateLoader but it never calls onLoadFinished except first run (when app started and ViewPager shows a first page (Fragment)). It's all! After if I switch a page to a next and a next and return to a first page LoaderManager doesn't call onLoadFinished for the first page too. But it creates loader calling onCreateLoader and resets loader calling onLoaderReset. Is it a joke from Google?
See fragment lifecycle. ViewPager don't re create fragment, just swipe them
-- Start ViewPager
: create
: createView
: start
: resume
not changed if you swipe fragments
--- sleep smartphone
: pause
: stop
--- wakeup smartphone
: start
: resume
: pause
--- Close ViewPager
: stop
: detach
I am trying to create a vertical viewpager with scrollview in one of its fragment. The problem is when i am swiping up, i am not going into second fragment. I have uploaded my code in Github(https://github.com/RajuMandala/verticalviewpager). Please let me know, if i am doing anything wrong. Thanks for your time.
My FirstFragment.java code is below,
public class FirstFragment extends Fragment {
// Scrolling code
private LinearLayout verticalOuterLayout;
private ScrollView verticalScrollview;
private TextView verticalTextView;
private int verticalScrollMax;
private Timer scrollTimer = null;
private TimerTask clickSchedule;
private TimerTask scrollerSchedule;
private TimerTask faceAnimationSchedule;
private int scrollPos = 0;
private Boolean isFaceDown = true;
private Timer clickTimer = null;
private Timer faceTimer = null;
private Button clickedButton = null;
private String[] nameArray = {"Apple", "Banana", "Grapes", "Orange", "Strawberry","Apple", "Banana","Grapes"};
private String[] imageNameArray = {"apple", "banana", "grapes", "orange", "strawberry","apple", "banana","grapes"};
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.first_frag,container,false);
// Scrolling code
verticalScrollview = (ScrollView) v.findViewById(R.id.vertical_scrollview_id);
verticalOuterLayout = (LinearLayout) v.findViewById(R.id.vertical_outer_layout_id);
//addImagesToView();
addTextsToView();
ViewTreeObserver vto = verticalOuterLayout.getViewTreeObserver();
/*vto.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
verticalOuterLayout.getViewTreeObserver().re
getScrollMaxAmount();
startAutoScrolling();
}
});*/
vto.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
//
// mycode
//
if (Build.VERSION.SDK_INT<16) {
removeLayoutListenerPre16(verticalOuterLayout.getViewTreeObserver(),this);
} else {
removeLayoutListenerPost16(verticalOuterLayout.getViewTreeObserver(), this);
}
getScrollMaxAmount();
startAutoScrolling();
}
});
verticalOuterLayout.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
v.getParent().requestDisallowInterceptTouchEvent(true);
return true;
}
});
return v;
}
#SuppressWarnings("deprecation")
private void removeLayoutListenerPre16(ViewTreeObserver observer, ViewTreeObserver.OnGlobalLayoutListener listener){
observer.removeGlobalOnLayoutListener(listener);
}
#TargetApi(16)
private void removeLayoutListenerPost16(ViewTreeObserver observer, ViewTreeObserver.OnGlobalLayoutListener listener){
observer.removeOnGlobalLayoutListener(listener);
}
// Scrolling code
public void addTextsToView(){
for (int i=0;i<nameArray.length;i++){
final TextView textView = new TextView(getActivity());
textView.setText(nameArray[i]);
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(256,256);
textView.setLayoutParams(params);
verticalOuterLayout.addView(textView);
}
}
public void getScrollMaxAmount(){
int actualWidth = (verticalOuterLayout.getMeasuredHeight()-(256*3));
verticalScrollMax = actualWidth;
}
public void startAutoScrolling(){
if (scrollTimer == null) {
scrollTimer = new Timer();
final Runnable Timer_Tick = new Runnable() {
public void run() {
moveScrollView();
}
};
if(scrollerSchedule != null){
scrollerSchedule.cancel();
scrollerSchedule = null;
}
scrollerSchedule = new TimerTask(){
#Override
public void run(){
getActivity().runOnUiThread(Timer_Tick);
}
};
scrollTimer.schedule(scrollerSchedule, 30, 30);
}
}
public void moveScrollView(){
scrollPos = (int) (verticalScrollview.getScrollY() + 1.0);
if(scrollPos >= verticalScrollMax){
scrollPos = 0;
}
verticalScrollview.scrollTo(0,scrollPos);
}
public void onDestroy(){
clearTimerTaks(clickSchedule);
clearTimerTaks(scrollerSchedule);
clearTimerTaks(faceAnimationSchedule);
clearTimers(scrollTimer);
clearTimers(clickTimer);
clearTimers(faceTimer);
clickSchedule = null;
scrollerSchedule = null;
faceAnimationSchedule = null;
scrollTimer = null;
clickTimer = null;
faceTimer = null;
super.onDestroy();
}
private void clearTimers(Timer timer){
if(timer != null) {
timer.cancel();
timer = null;
}
}
private void clearTimerTaks(TimerTask timerTask){
if(timerTask != null) {
timerTask.cancel();
timerTask = null;
}
}
}
Please see the screenshot of first fragment below,