Modify Navigation Fragment after Async Call - java

I have an Aync task
public class XmlNetwork extends AsyncTask< String, Void, List<PEMenuItem>
which essentially loads up an xml file into some objects that I want to use to change my navigation drawer menu items. it has an override function
protected void onPostExecute(List<PEMenuItem> result)
and so result is now a list of 3 objects i loaded from the xml.
at this point, i would like to make a call within my class
public class NavigationDrawerFragment extends Fragment
to build out the menu, add the onclicklisteners, etc.
i've previously learned how to add some callbacks, to call from the fragment out to my main activity, but how would i go about doing the inverse, calling from my Async class out to the fragment? i want to send the list along with it, something along the lines of
#Override
protected void onPostExecute(List<PEMenuItem> result) {
NavigationDrawerFragment fragment = (NavigationDrawerFragment) getFragment().modifyMenu(result);
}

The menu items in your NavigationDrawerFragment are usually just items in a ListView. As such, they are backed by an Adapter. Set your new items as that adapter's content and call notifyOnDatasetChanged on the adapter. This will cause the list to re-obtain the items from that adapter. For example you could use something like this as an adapter to your menu list (simplified):
public class MenuItemsAdapter extends BaseAdapter {
private List<String> menuItems;
public MenuItemsAdapter(Context context) {
this.context = context;
inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
//Empty for now
menuItems = new ArrayList<>();
}
public void setNewMenuItems(List<String> newMenuItems) {
this.menuItems = newMenuItems;
notifyDataSetChanged();
}
#Override
public int getCount() {
return menuItems.size();
}
#Override
public String getItem(int i) {
return menuItems.get(i);
}
#Override
public long getItemId(int i) {
return i;
}
#Override
public View getView(int i, View view, ViewGroup viewGroup) {
if(view == null) {
view = inflater.inflate(R.layout.your_menu_item_layout, viewGroup, false);
}
TextView menuItemText = view.findViewByIt(R.id.your_menu_item_text);
menuItemText = menuItems.get(position);
return view;
}
}

Related

Pass data from recyclerView to another in fragment

I want to pass data from recyclerview to another both in fragment, first adapter
for display item, and second adapter for basket fragment that want to put selected item in.
Adapter I want to take data from:
public class FruitItemAdapter extends RecyclerView.Adapter<FruitItemAdapter.viewHolder> {
ArrayList<FruitItem> fruitItems = new ArrayList<>();
private Context context;
public FruitItemAdapter(ArrayList<FruitItem> fruitItems, Context context) {
this.fruitItems = fruitItems;
this.context = context;
notifyDataSetChanged();
}
public FruitItemAdapter() {
}
#NonNull
#Override
public viewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view =
LayoutInflater.from(parent.getContext()).inflate(R.layout.fruits_item,parent,false);
viewHolder viewHolder = new viewHolder(view);
return viewHolder;
}
#Override
public void onBindViewHolder(#NonNull viewHolder holder, int position) {
final FruitItem data_position = fruitItems.get(position);
holder.fruit_img.setImageResource(fruitItems.get(position).getFruit_img());
holder.fruit_name.setText(fruitItems.get(position).getFruit_name());
holder.fruit_price.setText(fruitItems.get(position).getFruit_price());
}
#Override
public int getItemCount() {
return fruitItems.size();
}
public void setfruitItem(ArrayList<FruitItem> fruitItems) {
this.fruitItems = fruitItems;
}
public static class viewHolder extends RecyclerView.ViewHolder {
private ImageView fruit_img;
private TextView fruit_price, fruit_name;
public viewHolder(#NonNull View itemView) {
super(itemView);
fruit_img = itemView.findViewById(R.id.fruit_img);
fruit_price = itemView.findViewById(R.id.fruit_price);
fruit_name = itemView.findViewById(R.id.fruit_name)
}
}
}
this is adapter for basket fragment that I want to put the data in
public class Basket_Adapter extends RecyclerView.Adapter<Basket_Adapter.viewHolder> {
private Context context;
ArrayList<FruitItem> fruitItems = new ArrayList<>();
public Basket_Adapter(Context context, ArrayList<FruitItem> fruitItems) {
this.context = context;
this.fruitItems = fruitItems;
notifyDataSetChanged();
}
public Basket_Adapter(){
}
#NonNull
#Override
public Basket_Adapter.viewHolder onCreateViewHolder(#NonNull ViewGroup parent, int
viewType) {
View view=LayoutInflater.from(parent.getContext()).inflate(R.layout.fruits_item,parent,false);
viewHolder viewHolder = new viewHolder(view);
return viewHolder;
}
#Override
public void onBindViewHolder(#NonNull Basket_Adapter.viewHolder holder, int position) {
holder.fruit_img.setImageResource(fruitItems.get(position).getFruit_img());
holder.fruit_name.setText(fruitItems.get(position).getFruit_name());
holder.fruit_price.setText(fruitItems.get(position).getFruit_price());
}
#Override
public int getItemCount() {
return fruitItems.size();
}
public void setfruitItem(ArrayList<FruitItem> fruitItems) {
this.fruitItems = fruitItems;
}
public class viewHolder extends RecyclerView.ViewHolder {
private ImageView fruit_img;
private TextView fruit_name;
private TextView fruit_price;
public viewHolder(#NonNull View itemView) {
super(itemView);
fruit_img = itemView.findViewById(R.id.fruit_img);
fruit_name = itemView.findViewById(R.id.fruit_name);
fruit_price = itemView.findViewById(R.id.fruit_price);
}
}
Now, what I can use to pass data between them.
You can achieve this by using the delegation pattern. Basically you create an interface relative to the first adapter (you can put it inside the adapter class or outside depending on your coding style) and you require it as an argument inside the adapter constructor like this:
public class FruitItemAdapter extends RecyclerView.Adapter<FruitItemAdapter.viewHolder> {
private Delegate delegate;
ArrayList<FruitItem> fruitItems = new ArrayList<>();
private Context context;
public FruitItemAdapter(Delegate delegate, ArrayList<FruitItem> fruitItems, Context context) {
this.delegate = delegate;
this.fruitItems = fruitItems;
this.context = context;
notifyDataSetChanged();
}
...
interface Delegate {
public void passItem(FruitItem item);
}
}
As you can see the interface has the method you need, but there's no implementation yet.
In this class you can just pretend that your delegate works and do the magic for you, for example by setting a click listener on the root view of your item in onBindViewHolder that will call delegate.passItem(fruitItems.get(position)) on each click.
Let's move on to the fragment.
Here is the key part. The fragment must implement the interface we just created by overriding its methods. Like so:
class ExampleFragment extends Fragment implements FruitItemAdapter.Delegate {
...
#Override
public void passItem(FruitItem item) {
// here you pass the item in a list inside
// the shared preferences.
}
}
For your case the best way is to store your items in a database or in the shared preferences. We go with the shared preferences because is simpler, but keep in mind that shared preferences have limited memory capacity and you should use a database like Room instead.
Inside the override method you pass your item to a list stored in the shared preferences. Since your item is not a primitive object i suggest you to look at this answer that show how to store complex object as a string:
https://stackoverflow.com/a/18463758/18740763.
In your case the object that needs to be serialized is an Array or a List of objects.
Every time you need to put a new object in the list you need to follow these steps:
get the list from shared preferences
deserialize it
add the new item
serialize it again
put it back in the shared preferences under the same key
If you stored your items correctly now you should be able to access the shared list in every fragment or activity of your application. So simply access your list from the fragment that implements the second adapter, deserialize it, just addAll() the items the the adapter list and notifyDataSetChanged().

Removing an item from a nested RecyclerView

I've been duelling with this problem for a good few hours now. I have a nested RecyclerView (i.e. a RecyclerView that encompasses an inner Recycler view). Both the parent and child recycler view's are dynamic. The problem I encounter is that I cannot find a way to correctly notify the child (inner) recycler view when a CRUD, in particular a delete, occurs. At first it works ok, but then I get all sorts of random errors from "You must be a direct descend view" or getAdapterPosition returning -1 or just simply incorrect positions. I think my implementation is pretty standard so I ask what is the correct way to notify the inner recycler view.
I am pretty close to returning to my former implementation which involved an array of fragments each containing a recycling view, but I question about the performance of such design. My code is as follows:
Parent RecyclerView
public class RecipeRecyclerAdapter extends RecyclerView.Adapter<RecipeRecyclerAdapter.ViewHolder>
{
public interface OnRecipeRecyclerListener
{
//--------------------------- Proxy methods for OnDishRecyclerListener -----------------
void renameDish(int DishPosition, int RecipePosition);
void deleteDish(int DishPosition, int RecipePosition);
//--------------------------- OnRecipeRecyclerListener methods ----------------------------
void deleteRecipe(int RecipePosition);
void renameRecipe(int RecipePosition);
}
//Recycler Pool and tools
private RecyclerView.RecycledViewPool viewPool = new RecyclerView.RecycledViewPool();
//Recycler Parameters
private ArrayList<Recipe> allRecipes;
private Context context;
//Listener
#Setter
private OnRecipeRecyclerListener onRecipeRecyclerListener;
public RecipeRecyclerAdapter(Context context, ArrayList<Recipe> allRecipes)
{
this.allRecipes = allRecipes;
this.context = context;
}
#NonNull
#Override
public ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType)
{
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.card_Recipe, parent, false);
return new RecipeRecyclerAdapter.ViewHolder(view, onRecipeRecyclerListener, context);
}
#Override
public void onBindViewHolder(#NonNull ViewHolder holder, int position)
{
Recipe Recipe = allRecipes.get(position);
holder.RecipeName.setText(Utils.colourFirstLetter(context, Recipe.getRecipeName(), R.color.progressFxBar));
holder.RecipeDate.setText(Utils.getDate(Recipe.getTimestamp()));
// Create layout manager with initial prefetch item count
LinearLayoutManager layoutManager = new LinearLayoutManager(
holder.DishsRecycler.getContext(),
LinearLayoutManager.VERTICAL,
false
);
layoutManager.setInitialPrefetchItemCount(Recipe.getDishs().size());
DishRecyclerAdapter DishsRecyclerAdapter = new DishRecyclerAdapter(Recipe.getDishs(), holder, context);
holder.DishsRecycler.setLayoutManager(layoutManager);
holder.DishsRecycler.setAdapter(DishsRecyclerAdapter);
holder.DishsRecycler.setRecycledViewPool(viewPool);
}
#Override
public int getItemCount()
{
return allRecipes.size();
}
static class ViewHolder extends RecyclerView.ViewHolder implements DishRecyclerAdapter.OnDishRecyclerListener
private OnRecipeRecyclerListener onRecipeRecyclerListener;
private Context context;
TextView RecipeName, RecipeDate;
ImageView addDish;
//The Dishs Recycler
RecyclerView DishsRecycler;
public ViewHolder(#NonNull View itemView, OnRecipeRecyclerListener onRecipeRecyclerListener, Context context)
{
super(itemView);
this.onRecipeRecyclerListener = onRecipeRecyclerListener;
this.context = context;
RecipeName = itemView.findViewById(R.id.RecipeName);
RecipeDate = itemView.findViewById(R.id.RecipeDate);
addDish = itemView.findViewById(R.id.addDish);
DishsRecycler = itemView.findViewById(R.id.DishsRecyclerView);
loadListeners(itemView);
}
private void loadListeners(#NonNull View initView)
{
RecipeName.setOnClickListener(v ->
{
PopupMenu popup = new PopupMenu(context, v);
MenuInflater inflater = popup.getMenuInflater();
inflater.inflate(R.menu.Recipe_floating_menu, popup.getMenu());
popup.show();
popup.setOnMenuItemClickListener(item ->
{
switch (item.getItemId())
{
case R.id.menuDeleteRecipe:
onRecipeRecyclerListener.deleteRecipe(getAdapterPosition());
return true;
case R.id.menuRenameRecipe:
onRecipeRecyclerListener.renameRecipe(getAdapterPosition());
return true;
case R.id.menuRecipeProps:
onRecipeRecyclerListener.RecipeProps(getAdapterPosition());
return true;
default:
return false;
}
});
});
addDish.setOnClickListener(v ->
{
onRecipeRecyclerListener.addDish(getAdapterPosition());
});
}
//******************************* OnDishRecyclerListener *******************************
#Override
public void renameDish(int position)
{
onRecipeRecyclerListener.renameDish(position, getAdapterPosition());
}
#Override
public void deleteDish(int position)
{
onRecipeRecyclerListener.deleteDish(position, getAdapterPosition());
}
}
}
Child (inner) RecyclerView
public class DishRecyclerAdapter extends RecyclerView.Adapter<DishRecyclerAdapter.ViewHolder>
{
public interface OnDishRecyclerListener
{
void renameDish(int position);
void deleteDish(int position);
}
private OnDishRecyclerListener onDishRecyclerListener;
private ArrayList<Dish> allDishs;
private Context context;
public DishRecyclerAdapter(ArrayList<Dish> allDishs, OnDishRecyclerListener onDishRecyclerListener, Context context)
{
this.onDishRecyclerListener = onDishRecyclerListener;
this.allDishs = allDishs;
this.context = context;
}
#NonNull
#Override
public ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType)
{
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.card_Dishs, parent, false);
return new ViewHolder(context, view, onDishRecyclerListener);
}
#Override
public void onBindViewHolder(#NonNull ViewHolder holder, int position)
{
Dish Dish = allDishs.get(position);
holder.DishName.setText(Dish.getDishName());
}
#Override
public int getItemCount()
{
return allDishs.size();
}
public class ViewHolder extends RecyclerView.ViewHolder
{
private Context context;
TextView DishName; //plus a bunch of other Views I just removed for the sake of simplicity
OnDishRecyclerListener onDishRecyclerListener;
public ViewHolder(Context context, #NonNull View itemView, OnDishRecyclerListener onDishRecyclerListener)
{
super(itemView);
this.context = context;
DishName = itemView.findViewById(R.id.DishName);
this.onDishRecyclerListener = onDishRecyclerListener;
loadListeners(itemView);
}
private void loadListeners(#NonNull View v)
{
//Rename an Dish
DishName.setOnClickListener(view ->
{
PopupMenu popup = new PopupMenu(context, v);
MenuInflater inflater = popup.getMenuInflater();
inflater.inflate(R.menu.Dish_floating_menu, popup.getMenu());
popup.show();
popup.setOnMenuItemClickListener(item ->
{
switch (item.getItemId())
{
case R.id.menuDeleteDish:
onDishRecyclerListener.deleteDish(getAdapterPosition());
return true;
case R.id.menuRenameDish:
onDishRecyclerListener.renameDish(getAdapterPosition());
return true;
case R.id.menuDishProps:
return true;
default:
return false;
}
});
});
}
}
}
An extraction of the fragment calling the parent recycler view:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
View view = inflater.inflate(R.layout.fragment_Recipe_panel, container, false);
recyclerRecipe = view.findViewById(R.id.RecipeRecyclerView);
SimpleItemAnimator simpleItemAnimator = (SimpleItemAnimator) recyclerRecipe.getItemAnimator();
if(simpleItemAnimator !=null)
{
simpleItemAnimator.setSupportsChangeAnimations(true);
}
RecipeAdapter = new RecipeRecyclerAdapter(getContext(), allRecipes);
RecipeAdapter.setOnRecipeRecyclerListener(this);
//recyclerRecipe.setHasFixedSize(true);
recyclerRecipe.setLayoutManager(new LinearLayoutManager(getContext()));
recyclerRecipe.setAdapter(RecipeAdapter);
return view;
}
public void createRecipe(String RecipeName)
{
Recipe Recipe = new Recipe(RecipeName, getContext());
allRecipes.add(0,Recipe);
RecipeAdapter.notifyItemInserted(0);
}
#Override
public void deleteRecipe(int RecipePosition)
{
allRecipes.remove(RecipePosition);
RecipeAdapter.notifyItemRemoved(RecipePosition);
}
#Override
public void addDish(int RecipePosition)
{
allRecipes.get(RecipePosition).getDishs().add(new Dish(DishName));
RecipeAdapter.notifyItemChanged(RecipePosition);
}
#Override
public void deleteDish(int DishPosition, int RecipePosition)
{
Recipe Recipe = allRecipes.get(RecipePosition);
Dish Dish = Recipe.getDishs().get(DishPosition);
Dish.getTimer().destroyTimer();
Recipe.getDishs().remove(DishPosition);
RecipeAdapter.notifyItemChanged(RecipePosition);
}
I figured out what the problem was (after LOADS OF HOURS). I needed to notify first the parent recycler and then the child recycler in that order.
//adding an item to the inner list
recipeAdapter.notifyItemChanged(recipePosition);
dishsRecycler.getAdapter().notifyItemInserted(recipe.getDishs().size()-1);
//deleting an inner list item
recipeAdapter.notifyItemChanged(recipePosition);
dishsRecycler.getAdapter().notifyItemRemoved()
However the biggest culprit was having a common recyclerPool for all the inner recyclerviews, so removed this line from the code
//REMOVED THESE LINES
private RecyclerView.RecycledViewPool viewPool = new RecyclerView.RecycledViewPool();
holder.DishsRecycler.setRecycledViewPool(viewPool);
Also, I refrained from using notifyDataSet() as that for some reason throws NO_POSITION (-1).
I'm implementing a similar case.
I have 2 RecyclerViews, one nested. Where you can delete items either from nested or parent RecyclerView.
It guess you must update Recyclers every time an item changed or removed.
For comprehension I read this article first:
https://medium.com/android-news/recyclerview-optimisations-a4b141dd433d
And I agree answer by Ken John, when he said you need to notify RecyclerView updates first to parent then to nested; otherwise you get an error and your app will crash.
However, other important thing is how to do the notification updates.
For the nested RecyclerView, I used
// for items updated
notifyItemChanged(position);
// for items deleted
notifyItemRemoved(position);
but the mentioned above not working fine for parent RecyclerView, really I'm not sure why, but I solved as follow:
// for items updated
notifyItemChanged(position);
// for items deleted
notifyItemRemoved(position); // this line does not work for me
notifyDataSetChanged(); // it works fine
The last instruction spend a more bit of time, but works fine.
Note: I don't know yet why notifyItemRemoved(position) doesn't work for parent, and I have call notifyDataSetChanged()

listview always removes last item

I try to remove a specific item from a listView but it's always remove the last item.
I create a custom adapter to my listview.
I try to search for a solution and i found some posts about this problem but I still didn't success to solve the problem
custom adapter below:
public class ListViewAdapter extends BaseAdapter{
public ArrayList<HashMap<String, String>> list;
public static final String WORD_COLUMN="First";
public static final String TRAN_COLUMN="Second";
Activity activity;
TextView txtFirst;
TextView txtSecond;
public ListViewAdapter(Activity activity,ArrayList<HashMap<String, String>> list){
super();
this.activity=activity;
this.list=list;
}
#Override
public int getCount() {
return list.size();
}
#Override
public Object getItem(int position) {
return list.get(position);
}
#Override
public long getItemId(int position) {
return 0;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater=activity.getLayoutInflater();
if(convertView == null){
convertView=inflater.inflate(R.layout.column_row, null);
txtFirst=(TextView) convertView.findViewById(R.id.wordColumn);
txtSecond=(TextView) convertView.findViewById(R.id.tranColumn);
}
HashMap<String, String> map=list.get(position);
txtFirst.setText(map.get(WORD_COLUMN));
txtSecond.setText(map.get(TRAN_COLUMN));
return convertView;
}
}
activity code below:
public class MainActivity extends AppCompatActivity{
private ListView lv;
private ArrayList<HashMap<String, String>> hashList;
private ListViewAdapter adapter;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
lv = (ListView)findViewById(R.id.gvWords);
hashList = new ArrayList<HashMap<String, String>>();
adapter=new ListViewAdapter(this, hashList);
lv.setAdapter(adapter);
onClickButtons();
}
public void onClickButtons()
{
lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
hashList.remove(i);
adapter.notifyDataSetChanged();
}
});
}
Thank's :)
You can try to access and remove clicked object via getItemAtPosition(position) and then remove it from ArrayList via .remove(Object o)
Your listener will therefore look like this:
lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
hashList.remove(lv.getItemAtPosition(i));
adapter.notifyDataSetChanged();
}
});
This approach is mentioned in official doc: https://developer.android.com/reference/android/widget/AdapterView.OnItemClickListener.html
Implementers can call getItemAtPosition(position) if they need to access the data associated with the selected item.
after refreshing it's remove the right item
You've cached the two TextViews, which aren't updated as part of notifying the adapter.
Alter the convertView check and remove those fields, then lookup how to implement the ViewHolder pattern (or use a RecyclerView)
I found this problem,
and removed the if(convertView == null){ It's working,
Please let us know for this reason.

Interface value is always null

I am using custom recycler view and in adapter class i have implemented interface which is always null on button click. Here is my adapter class.
public class FeedListAdapter extends
RecyclerView.Adapter<AddtoCartHolder> {
private OnFeedItemClickListener onFeedItemClickListener;
public FeedListAdapter(Activity activity, ArrayList<CartItem> feedItems) {
this.activity = activity;
this.feedItems = feedItems;
this.filteredfeedItems = feedItems;
inflater = LayoutInflater.from(activity);
}
public void setOnFeedItemClickListener(OnFeedItemClickListener onFeedItemClickListener) {
this.onFeedItemClickListener = onFeedItemClickListener;
}
#Override
public AddtoCartHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(
R.layout.feed_item, parent, false);
AddtoCartHolder viewHolder = new AddtoCartHolder(v);
setupClickableViews(v, viewHolder);
return viewHolder;
}
#Override
public void onBindViewHolder(final AddtoCartHolder holder, int position) {
CartItem item = (CartItem) filteredfeedItems.get(position);
holder.price.setText((String.valueOf(item.getProductName()) + ""));
holder.location.setText((String.valueOf(item.getQuantity())) + "");
}
private void setupClickableViews(final View view, final AddtoCartHolder cellFeedViewHolder) {
cellFeedViewHolder.plus.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(onFeedItemClickListener !=null){
onFeedItemClickListener.onAddClick(v, cellFeedViewHolder.getAdapterPosition());
}
else{
Toast.makeText(activity, "Data is null", Toast.LENGTH_LONG).show();
}
}
});
}
public interface OnFeedItemClickListener {
void onAddClick(View v, int position);
}
#Override
public int getItemCount() {
return filteredfeedItems.size();
}
I am always getting null whenever clicking on button really down know why it is coming null...
Here is my fragment class which have implemented interface.
public class MyFragment extends Fragment implements FeedListAdapter.OnFeedItemClickListener{
// the method
#Override
public void onAddClick(View v, int position) {
// TODO Auto-generated method stub
Snackbar.make(clContent, "Product removed from cart!",
Snackbar.LENGTH_SHORT).show();
}
You must be instantiating a FeedListAdapter in your fragment correct buddy ???
Like using statement :
FeedListAdapter adapter = new FeedListAdapter(this.getActivity(),your_array_list)
After instantiating your adapter just call your adapter's setOnFeedItemClickListener with 'this' as argument :) That's all :)
adapter.setOnFeedItemClickListener(this)
Hope my answer helped you :) Happy coding buddy :)
By the looks of things your aren't setting your listener. Thus, onFeedItemClickListener is always null.
Also MyFragment isn't actually doing anything, you haven't inflated a view, overridden onCreateView(...), etc.
There's a few things that you could definitely change to improve your implementation. But to get your listener working:
Just get rid of MyFragment you don't appear to be using it properly.
Move your implements FeedListAdapter.OnFeedItemClickListener to your Activity. i.e. Make your Activity implement your OnFeedItemClickListener interface rather than MyFragment (which doesn't appear to be doing anything).
Make FeedListAdapter set the listener in its constructor:
public FeedListAdapter(Activity activity, ArrayList<CartItem> feedItems)
{
this.activity = activity;
// Assume we the activity implements OnFeedItemClickListener
setOnFeedItemClickListener((OnFeedItemClickListener)activity);
this.feedItems = feedItems;
this.filteredfeedItems = feedItems;
inflater = LayoutInflater.from(activity);
}
Please keep in mind that this is a pretty bad implementation and you can definitely improve on it but for the purpose of the question, it's sufficient.

pass data to another fragment by swipe view with tab android studio,not button

Is it possible to pass a data from fragment to fragment by swipe?
There are many articles teaching us how to pass the data from fragment to fragment, but most of the article or questions had implemented OnClickListener in their first fragment, which used to pass value to another fragment.
But my case is pass the data from two fragments without any button click and finally save them in different tables by clicking button in the last fragment. What can I do to achieve this??
The flow is Information >> WorkForce >>WorkDetailsTable and save them to different table by one button click.
I have tried to work it out but I get NULL value in SQLite. I think I have miss out a lot but have no idea. PLEASE help me...I've been stuck at here for more than two days...Thanks
Tab.java
public class Tab extends ActionBarActivity implements ActionBar.TabListener {
ViewPager Tab;
TabPagerAdapter TabAdapter;
ActionBar actionBar;
public static String name = null;
public static String subContractors = null;
// will be used for data communication
public static Force force_bean;;
public static Info info_bean;
public static Force getForce(){
return force_bean;
}
public static void setForce(Force force){
force_bean=force;
}
public static Info getInfo(){
return info_bean;
}
public static void setInfo(Info info){
info_bean=info;
}
final Activity mActivity = (Activity) this;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.tab1);
info_bean = new Info();
force_bean = new Force();
TabAdapter = new TabPagerAdapter(getSupportFragmentManager());
Tab = (ViewPager) findViewById(R.id.pager);
Tab.setOnPageChangeListener(
new ViewPager.SimpleOnPageChangeListener() {
#Override
public void onPageSelected(int position) {
actionBar = ((AppCompatActivity) mActivity).getSupportActionBar();
actionBar.setSelectedNavigationItem(position);
}
});
Tab.setAdapter(TabAdapter);
actionBar = ((AppCompatActivity) mActivity).getSupportActionBar();
//Enable Tabs on Action Bar
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
//Add New Tabs
actionBar.addTab(actionBar.newTab().setText("Information").setTabListener(this));
actionBar.addTab(actionBar.newTab().setText("Work Force").setTabListener(this));
actionBar.addTab(actionBar.newTab().setText("Work Details").setTabListener(this));
}
#Override
public void onTabSelected(ActionBar.Tab tab, android.support.v4.app.FragmentTransaction ft) {
}
#Override
public void onTabUnselected(ActionBar.Tab tab, android.support.v4.app.FragmentTransaction ft) {
}
#Override
public void onTabReselected(ActionBar.Tab tab, android.support.v4.app.FragmentTransaction ft) {
}
}
TabPagerAdapter.java
public class TabPagerAdapter extends FragmentStatePagerAdapter {
public TabPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int i) {
switch (i) {
case 0:
return Information.newInstance("name");
case 1:
return WorkForce.newInstance("SubCon");
case 2:
return WorkDetailsTable.newInstance();
}
return null ;
}
#Override
public int getCount() {
return 3; //No of Tabs you can give your number of tabs
}
Informmation.java
public class Information extends Fragment implements View.OnClickListener {
private Spinner spinner, spinner2, spinner3;
private static String a;
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
View info = inflater.inflate(R.layout.information, container, false);
dialog = new DateDialog();
spinner = (Spinner)info.findViewById(R.id.spinner);
addItemsOnSpinner();
a= spinner.getSelectedItem().toString();
return info;
}
public static Information newInstance(String a)
{
Information fragment=new Information();
Bundle bundle=new Bundle();
bundle.putString("a",a);
fragment.setArguments(bundle);
return fragment;
}
public void addItemsOnSpinner() {
List<String> list = new ArrayList<String>();
list.add("1 ");
list.add("2");
ArrayAdapter<String> adapter = new ArrayAdapter<String>(getActivity(), android.R.layout.simple_spinner_dropdown_item, list);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinner.setAdapter(adapter);
}
WorkForce.java
public class WorkForce extends Fragment {
private static EditText txt1;
private static String subCon;
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
View work = inflater.inflate(R.layout.workforce, container, false);
txt1 = (EditText) work.findViewById(R.id.editText);
subCon = txt1.getText().toString();
return work;
}
public static WorkForce newInstance(String subCon) {
WorkForce f = new WorkForce();
Bundle bundle = new Bundle();
bundle.putString("subCon", subCon);
f.setArguments(bundle);
return f;
}
}
WorkDetails.java
private com.example.project.project.API.InfoAPI ts;
private com.example.project.project.API.WorkDetailsAPI WD;
private com.example.project.project.API.WorkForceAPI WF;
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
View workDetails = inflater.inflate(R.layout.tableworkdetails, container, false);
getActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
spinnerTra = (Spinner) workDetails.findViewById(R.id.spinner6);
addItemsOnSpinner();
Button btn1 = (Button)workDetails.findViewById(R.id.button2);
WD = new com.example.project.project.API.WorkDetailsAPI(getActivity());
ts = new com.example.project.project.API.InfoAPI(getActivity());
WF = new com.example.project.project.API.WorkForceAPI(getActivity());
a1 = spinnerTra.getSelectedItem().toString();
Bundle bundle = new Bundle();
final String name = bundle.getString("a");
final String subContractors = bundle.getString("subCon");
btn1.setOnClickListener(new View.OnClickListener() {
public void onClick(View arg0) {
add(name, subContractors);
}
});
return workDetails;
}
public void add(String name,String subContractors)
{
Toast.makeText(getActivity(),+name+subContractors, Toast.LENGTH_SHORT).show();
ts.insertTimeSheet(name);
WF.insertWorkForce(subContractors);
}
Note: My case is pass the data from two fragments without any button click and finally save them in different tables by clicking button in the last fragment.
If I understand your problem correctly, you are essentially implementing something a little bit like a "Wizard" where each step passes information to the next step as you swipe between the tabs or select them.
So in reality your problem is how to get the information out of a fragment when it is deselected and into a fragment when selected.
At the simplest level I would suggest your activity holds the "master" copy of all of the information and passes it into/takes it from each fragment in your tab pager adapter.
You would need some kind of "Domain" object to hold all the information you need to collect. Each tab would only update the bits of information it cares about..
public class WorkData {
string information;
string subCon;
... etc..
}
You add an instance of this to hold the master copy to your "tab" activity:
public class Tab extends ActionBarActivity implements ActionBar.TabListener {
...
WorkData workData = new WorkData();
...
I would then suggest a simple interface that each of your "tab" fragments implement; something like:
public interface DataUpdate {
void setData(WorkData data);
WorkData getData();
}
Each of your tab fragments would implement this interface, updating the WorkData as required..
public class WorkForce extends Fragment implements DataUpdate {
...
private WorkData workData; // this fragment's "copy" of the data
...
#Override
public WorkData getData() {
this.workData.subCon = this.subCon; // Assuming subcon has been updated.. else use txt1.getText();
return this.workData;
}
#Override
public void setData(WorkData workData) {
this.workData = workData;
// Update this page's views with the workData...
// This assumes the fragment has already been created and txt1 is set to a view
txt1.setText(workData.subCon);
this.subCon = workData.subCon; // Actually could just use subCon in workData, but be aware that workData actually points to the Activity's copy (kinda makes getdata redundant.. but I like symmetry and couldn't be bothered making lots of copies of the object).
}
Then you just need to add the code to pass the data backwards and forwards.. in your "Tab" activity which looks like...
#Override
public void onTabSelected(ActionBar.Tab tab, android.support.v4.app.FragmentTransaction ft) {
int position = tab.getPosition();
DataUpdate dataUpdate = (DataUpdate) TabAdapter.getItem(position);
// Pass the master workdata to the selected fragment
dataUpdate.setData(this.workData);
}
#Override
public void onTabUnselected(ActionBar.Tab tab, android.support.v4.app.FragmentTransaction ft) {
int position = tab.getPosition();
DataUpdate dataUpdate = (DataUpdate) TabAdapter.getItem(position);
// Update the master workdata from the unselected fragment
this.workData = dataUpdate.getData();
}
#Override
public void onTabReselected(ActionBar.Tab tab, android.support.v4.app.FragmentTransaction ft) {
// This might be pointless, but we'll do it anyway..
int position = tab.getPosition();
DataUpdate dataUpdate = (DataUpdate) TabAdapter.getItem(position);
// Pass the master workdata to the selected fragment
dataUpdate.setData(this.workData);
}
An important thing to notice here is that your TabPagerAdapter will create a new fragment every time you call getItem().. that will mean that we will never get any updates because each time we try to get the fragment it returns a new, empty fragment. We need to change this so that the fragments are still created when first asked for, but only created once so that we don't keep throwing away our work.
public class TabPagerAdapter extends FragmentStatePagerAdapter {
private static final int NUMBER_OF_TABS = 3;
private Fragment[] tabList = new Fragment[NUMBER_OF_TABS];
public TabPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int i) {
if (tabList[i] != null) {
// Return a tab we created earlier..
return tabList[i];
} else {
switch (i) {
case 0:
tabList[0] = Information.newInstance("name");
return tabList[0];
case 1:
tabList[1] = WorkForce.newInstance("SubCon");
return tabList[1];
case 2:
tabList[2] = WorkDetailsTable.newInstance();
return tabList[2];
}
}
return null ;
}
#Override
public int getCount() {
return NUMBER_OF_TABS;
}
Hope this helps. Good luck :-)
Although C James provides good tips to solve your problems, I would like to introduce another way without using implementing of interfaces. Please check below link out. If you use an event bus library such a http://square.github.io/otto/, you can easily pass data you want to share among fragments and even activities. Additionally, you can reduce a lot of code line since it only requires Sender(PUBLISHING), Receiver(Subscriber) while implementation of interfaces requires additional lines of code.
Here is a tutorial of Otto libarary.
http://www.vogella.com/tutorials/JavaLibrary-EventBusOtto/article.html
Hope it helps :)
I would more go the Observer Pattern way.
Each Fragments changes an POJO with is rendered in your Fragments in some way. You simply have to Observe the pojo in your Fragments. Changing Fragments will notify interested observers without knowing them.
I believe that's a much cleaner way to implement this.
Fragment A -> PojoInstance.setXY("foo");
Fragment A -> informs the Observers which e.b Informs Fragment B:
Fragment B will see the change tru the Observer.
Because ViewPagers or other Components will cache Fragments thats a way to get information in already created Fragments, even when their are not seen.
You could also try to use an EventBus where you pass the POJO around.
To transfer data from one fragment to another fragment when swipe is performed ,firstly you should get the view of the each fragment.here is the sample code that can help you out a bit.
write this code in Activity:
mviewpager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(tabLayout));
mviewpager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
adapter = ((SOFragmentPagerAdapter) mviewpager.getAdapter());
//getting the view of fragments at positions
if(position==0)
{
View v = null;
Fragment1=(Fragment1)adapter.getFragment(position);
v=fragment1.getMyView();//this is how you get the view
ListView lv=(ListView)v.findViewById(R.id.lv_services);
ArrayAdapter<String> arrayAdapter=new ArrayAdapter<String>(SOListItemSelectedActivity.this,android.R.layout.simple_list_item_1,soRequestFragment.al_list_of_services);
lv.setAdapter(arrayAdapter);
}
if(position==1)
{
}
}
#Override
public void onPageSelected(int position) {
if(position==0)
{
View v = null;
soRequestFragment=(SORequestFragment)adapter.getFragment(position);
v=soRequestFragment.getMyView();
}
if(position==1)
{
}
}
#Override
public void onPageScrollStateChanged(int state) {
}
});
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) {
}
});
and create a FragmentPagerAdapter as:
public class SOFragmentPagerAdapter extends FragmentPagerAdapter {
HashMap<Integer,Fragment> mPageReferenceMap;
int mNumOfTabs;
public SOFragmentPagerAdapter(FragmentManager fm,int mNumOfTabs) {
super(fm);
this.mNumOfTabs=mNumOfTabs;
mPageReferenceMap=new HashMap<Integer,Fragment>();
}
#Override
public Fragment getItem(int position) {
switch (position)
{
case 0:
Fragment1 fragment1=new tFragment1();
mPageReferenceMap.put(position,fragment1);
return fragment1;
case 1:
Fragment2 fragment2=new Fragment2();
mPageReferenceMap.put(position,fragment2);
return fragment2;
default:
return null;
}
}
public Fragment getFragment(int key) {
return mPageReferenceMap.get(key);
}
#Override
public int getCount() {
return 2;
}}
In Fragments add the getmyview() which will return the view of that fragment as:
public void getmyview()
{
return myview;//myview is fragment view which you will return in oncreateview method
}
Note: Viewpager execute onpagescroll first and get the position 0,1 and when you scroll ,views at position 1,2 will execute and page selected 0 will execute.
For tabselections: Tabunselected,Tabselected Tab reselected is the sequence of execution.
so write accordingly in the respective positions of fragments.
Hope this helps you.

Categories