I'm currently working in my own project of dental application, i would like to ask if how to pass a certain data from a custom dialog and show or add it to the target fragment?
Appreciate for any help.
This is the Custom Dialog Screenshot:
CustomDialog.java
package com.bloxofcode.multipletabs;
import android.app.Activity;
import android.app.Dialog;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.RequiresApi;
import android.view.View;
import android.view.Window;
import android.widget.Button;
import android.widget.CompoundButton;
import android.widget.EditText;
import android.widget.Toast;
import android.widget.ToggleButton;
import com.bloxofcode.multipletabs.Tab1;
public class CustomDialog extends Dialog implements
View.OnClickListener {
public Activity c;
public CustomDialog d;
public Button yes, no;
ToggleButton btnGenderMale,btnGenderFemale;
Button btnCancel, btnAccept;
EditText eText;
public CustomDialog(Activity a) {
super(a);
// TODO Auto-generated constructor stub
this.c = a;
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
getWindow().setBackgroundDrawableResource(android.R.drawable.dialog_holo_light_frame);
}
else{
getWindow().setBackgroundDrawableResource(android.R.drawable.alert_light_frame);
}
setContentView(R.layout.activity_dialog);
btnGenderFemale = (ToggleButton) findViewById(R.id.toggleButtonFemale);
btnGenderMale = (ToggleButton) findViewById(R.id.toggleButtonMale);
btnCancel = (Button) findViewById(R.id.btnCancel);
btnAccept = (Button) findViewById(R.id.btnAccept);
eText = (EditText) findViewById(R.id.editText);
btnGenderMale.setChecked(true);
btnGenderMale.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonMale, boolean b) {
// Toast.makeText(getApplicationContext(),
// String.valueOf(buttonMale.isChecked()), Toast.LENGTH_SHORT).show();
if(buttonMale.isChecked()){
btnGenderMale.setEnabled(false);
btnGenderFemale.setEnabled(true);
btnGenderFemale.setChecked(false);
}else{
}
}
});
btnGenderFemale.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonFemale, boolean b) {
// Toast.makeText(getApplicationContext(),
// String.valueOf(buttonFemale.isChecked()), Toast.LENGTH_SHORT).show();
if(buttonFemale.isChecked()){
btnGenderMale.setEnabled(true);
btnGenderFemale.setEnabled(false);
btnGenderMale.setChecked(false);
}else{
}
}
});
btnCancel.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
dismiss();
}
});
btnAccept.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Toast.makeText(getContext(),"Sample",Toast.LENGTH_LONG).show();
}
});
}
#Override
public void onClick(View v) {
dismiss();
}
}
How to achieve this Expected Result:
Tab1.java
package com.bloxofcode.multipletabs;
import android.content.ContentValues;
import android.database.Cursor;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.RequiresApi;
import android.support.v4.app.Fragment;
import android.support.v4.widget.CursorAdapter;
import android.support.v4.widget.SimpleCursorAdapter;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageButton;
import android.widget.ListView;
import com.bloxofcode.multipletabs.database.DBOpenHelper;
import com.bloxofcode.multipletabs.database.NotesProvider;
/**
* A simple {#link Fragment} subclass.
*/
public class Tab1 extends Fragment {
private ImageButton imgButton;
private CustomDialog customDialog;
View v;
#RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
v =inflater.inflate(R.layout.tab_1,container,false);
imgButton = (ImageButton) v.findViewById(R.id.imageButton);
//Creating ImageButton
imgButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
// Toast.makeText(getActivity(),"Hello Image Button!",Toast.LENGTH_LONG).show();
customDialog = new CustomDialog(getActivity());
customDialog.show();
}
});
press();
return v;
}
#RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
public void press() {
insertNote("Juan Dela Cruz");
Cursor cursor = getActivity().getContentResolver().query(NotesProvider.CONTENT_URI,
DBOpenHelper.ALL_COLUMNS, null, null, null, null);
String[] from = {DBOpenHelper.NOTE_TEXT};
int[] to = {android.R.id.text1};
CursorAdapter cursorAdapter = new SimpleCursorAdapter(getActivity(),
android.R.layout.simple_list_item_1,cursor,from,to,0);
ListView list = (ListView) v.findViewById(android.R.id.list);
list.setAdapter(cursorAdapter);
}
private void insertNote(String noteText) {
ContentValues values = new ContentValues();
values.put(DBOpenHelper.NOTE_TEXT,noteText);
Uri noteUri =getActivity().getContentResolver().insert(NotesProvider.CONTENT_URI,values);
Log.d("MainActivity","Inserted note " + noteUri.getLastPathSegment());
}
}
ViewPagerAdapter.java
package com.bloxofcode.multipletabs;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentStatePagerAdapter;
public class ViewPagerAdapter extends FragmentStatePagerAdapter{
CharSequence Titles[]; // This will Store the Titles of the Tabs which are Going to be passed when ViewPagerAdapter is created
int NumbOfTabs; // Store the number of tabs, this will also be passed when the ViewPagerAdapter is created
// Build a Constructor and assign the passed Values to appropriate values in the class
public ViewPagerAdapter(FragmentManager fm,CharSequence mTitles[], int mNumbOfTabsumb) {
super(fm);
this.Titles = mTitles;
this.NumbOfTabs = mNumbOfTabsumb;
}
//This method return the fragment for the every position in the View Pager
#Override
public Fragment getItem(int position) {
if(position == 0) // if the position is 0 we are returning the First tab
{
Tab1 tab1 = new Tab1();
return tab1;
}
else if(position == 1)
{
Tab2 tab2 = new Tab2();
return tab2;
}
else // As we are having 3 tabs if the position is now 0 it must be 1 so we are returning second tab
{
Tab3 tab3 = new Tab3();
return tab3;
}
}
// This method return the titles for the Tabs in the Tab Strip
#Override
public CharSequence getPageTitle(int position) {
return Titles[position];
}
// This method return the Number of tabs for the tabs Strip
#Override
public int getCount() {
return NumbOfTabs;
}
}
TabsActivity.java
package com.bloxofcode.multipletabs;
import android.os.Build;
import android.support.v4.view.ViewPager;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.Toolbar;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Toast;
public class TabsActivity extends AppCompatActivity {
// Declaring Your View and Variables
Toolbar toolbar;
ViewPager pager;
ViewPagerAdapter adapter;
SlidingTabLayout tabs;
CharSequence Titles[]={"Patient","Appointment","Backup"};
int Numboftabs =3;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_tabs);
// Creating The Toolbar and setting it as the Toolbar for the activity
toolbar = (Toolbar) findViewById(R.id.tool_bar);
setSupportActionBar(toolbar);
// Creating The ViewPagerAdapter and Passing Fragment Manager, Titles fot the Tabs and Number Of Tabs.
adapter = new ViewPagerAdapter(getSupportFragmentManager(),Titles,Numboftabs);
// Assigning ViewPager View and setting the adapter
pager = (ViewPager) findViewById(R.id.pager);
pager.setAdapter(adapter);
// Assiging the Sliding Tab Layout View
tabs = (SlidingTabLayout) findViewById(R.id.tabs);
tabs.setDistributeEvenly(true); // To make the Tabs Fixed set this true, This makes the tabs Space Evenly in Available width
// Setting Custom Color for the Scroll bar indicator of the Tab View
tabs.setCustomTabColorizer(new SlidingTabLayout.TabColorizer() {
#Override
public int getIndicatorColor(int position) {
//return ContextCompat.getColor(TabsActivity.this,R.color.tabsScrollColor);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
return getResources().getColor(R.color.tabsScrollColor,TabsActivity.this.getTheme());
}else {
return getResources().getColor(R.color.tabsScrollColor);
}
}
});
// Setting the ViewPager For the SlidingTabsLayout
tabs.setViewPager(pager);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}
If you'd like to keep things loosely coupled and structured, A fine rather alternative is to choose the EventBus . To see the usage see this Answer.
You can accomplish it using Interface.
YourInterface.java
public interface YourInterface{
void yourMethod(int data);
}
Use that Interface in your Dialog class:
public class CustomDialog extends Dialog implements
View.OnClickListener {
private YourInterface delegate;
....
public CustomDialog(Activity a) {
super(a);
// TODO Auto-generated constructor stub
this.c = a;
delegate = (YourInterface) a;
}
}
In your Activity that holds fragment implement interface:
public class YourActivity extends AppCompatActivity implements YourInterface {
....
#Override
public void yourMethod(int data) {
fragment.receiverMethod(data);
}
}
Tab1.java
public class Tab1 extends Fragment {
public void receiverMethod(int data) {
// do what you want with received data
}
}
Now to use that simply call delegate.yourMethod(data) to pass it to fragment
You can use Broadcast Receiver in your onDismiss like below in your Dialog
#Override
public void onDismiss(DialogInterface dialog) {
super.onDismiss(dialog);
if (onDismissListener != null) {
Intent intent = new Intent("DialogDismiss");
LocalBroadcastManager.getInstance(getActivity()).sendBroadcast(intent);
onDismissListener.onDismiss(dialog);
}
}
and in your Fragment you can receive the broadcast
// In your Fragment do below
BroadcastReceiver mReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
//Work Here
}
};
//In OnCreate
LocalBroadcastManager.getInstance(getActivity()).registerReceiver(mReceiver,
new IntentFilter("DialogDismiss"));
//onDestroy
LocalBroadcastManager.getInstance(getActivity()).unregisterReceiver(mReceiver);
If you get the view from the customDialog you can just access the fields normally with view.findViewById() from in your fragment class.
Put your data into budle as key-value pair and set bundle as an argument to fragment.
fragment.setArgument(bundle)
To get bundle in fragmen, call
Bundle bundle = getArgument() and get values from the bundle based on key.
You could return the String which was entered into the EditText by creating a setter and getter method within your Dialog class to return a String variable (e.g. editTextString) which you would assign a value to whenever the accept button is clicked.
Add your getter and setter methods to the Dialog class
private void setEditTextString() {
editTextString = eText.getText().toString()
}
public String getEditTextString() {
return editTextString;
}
Within your click listener for the accept button add the following line of code:
setEditTextString(eText.getText().toString());
Then all you need to do to return the value entered in the editText field in the Fragment class would be to call the public method within your Dialog class to return the string.
dialogClass.getEditTextValue()
Related
I have an app, where I have one Activity (main), and there in the layout, I have a ViewPager2. That ViewPager2's adapter is set with 2 fragments. Let's call one of these as Fragment A.
When Fragment A opens up, users have the option to open another fragment, Fragment B from within itself. (by transaction; I have an empty FrameLayout inside Fragment A). Fragment B provides a dialog box to edit the data shown with a RecyclerView in Fragment A. Fragment A itself also has a few options to change the data in its RecyclerView.
This data is populated from Shared preferences. Now, here's the problem - since the Fragments can be made to communicate only with the Activity with Interfaces, I can save the data in the Activity, but then I have no other option but to reload the entire RecyclerView in Fragment A since Fragment A doesn't know at which position it got the new data.
Please advice. Below are the Fragments and the Activity that I mentioned.
MainActivity.java:
package com.coffeetech.kittycatch;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.viewpager2.widget.ViewPager2;
import android.os.Bundle;
import com.google.android.material.tabs.TabLayout;
import com.google.android.material.tabs.TabLayoutMediator;
import java.util.ArrayList;
public class MainActivity extends AppCompatActivity implements FoodEditorFragment.SendFoodFromEditor{
ViewPager2 viewPager;
TabLayout tab_menu;
SwipeAdapter adapter;
ArrayList<Food> foods;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
viewPager=findViewById(R.id.viewpager);
adapter=new SwipeAdapter(this);
viewPager.setAdapter(adapter);
//SETTING TABS
tab_menu = findViewById(R.id.tab_menu);
new TabLayoutMediator(tab_menu, viewPager, true, new TabLayoutMediator.TabConfigurationStrategy() {
#Override
public void onConfigureTab(#NonNull TabLayout.Tab tab, int position) {
switch(position){
case 0:
tab.setText("INVENTORY");
break;
case 1:
tab.setText("SHOPPING LIST");
}
}
}).attach();
}
#Override
public void onBackPressed() {
super.onBackPressed(); //TODO: CONFIGURE THIS
}
#Override
public void sendFood(Food food, int position) { //TODO: CODE TO REPLACE DATA TO SPECIFIC POSITION
loadData();
saveData();
}
#Override
public void sendFood(Food food) { //TODO: CODE TO ADD DATA TO POSITION 0
loadData();
saveData();
}
public void loadData(){
//TODO: LOAD THE LIST HERE
}
public void saveData(){
//TODO: SAVE THE DATA HERE
}
}
The FragmentStateAdapter for the ViewPager2:
package com.coffeetech.kittycatch;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentActivity;
import androidx.viewpager2.adapter.FragmentStateAdapter;
public class SwipeAdapter extends FragmentStateAdapter {
Fragment fragment;
public SwipeAdapter(FragmentActivity fa){
super(fa);
}
#NonNull
#Override
public Fragment createFragment(int position) {
switch (position){
case 0: //START INVENTORY FRAGMENT
fragment = new InventoryFragment();
break;
case 1: //START SHOPPING LIST FRAGMENT
fragment = new ShoppingListFragment();
break;
}
return fragment;
}
#Override
public int getItemCount() {
return 2;
}
}
Fragment 'A':
package com.coffeetech.kittycatch;
import android.content.Context;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentTransaction;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.Toast;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import java.util.ArrayList;
public class InventoryFragment extends Fragment {
//GLOBAL VARIABLES
RecyclerView recyclerView;
FoodAdapter foodAdapter;
ArrayList<Food> foods = new ArrayList<Food>();
FloatingActionButton add_button;
FrameLayout frameLayout;
Food food;
int q; //for use in decrease and functions
public InventoryFragment() {
// Required empty public constructor
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public void onPause() { //TODO:CODE TO SAVE DATA
saveData();
super.onPause();
}
#Override
public void onResume() { //TODO:CODE TO LOAD DATA
loadData();
super.onResume();
//food constructor takes arguments -> (String name, int type, int quantity, int min_quantity)
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View v = inflater.inflate(R.layout.fragment_inventory, container, false);
foodAdapter = new FoodAdapter(foods);
recyclerView=v.findViewById(R.id.recycler_view);
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
recyclerView.setAdapter(foodAdapter);
//setting up the frameLayout
frameLayout = v.findViewById(R.id.food_editor_frame);
//setting up the Add button
add_button=v.findViewById(R.id.add_button);
add_button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) { //for new food addition to list
openFoodEditorFragment();
}
});
foodAdapter.setOnFoodcardClickListener(new FoodAdapter.OnFoodcardClickListener() {
#Override
public void deleteFood(int position) { //code that deletes current food
foods.remove(position);
foodAdapter.notifyItemRemoved(position);
}
#Override
public void onEdit(int position, int mode) { //code that runs the edit of each food, mode=1 for edit
openFoodEditorFragment(position,foods.get(position)); //TODO: SEE IF YOU NEED 'mode' AT ALL
}
#Override
public void decrease(int position) {
food = foods.get(position);
q=food.getQuantity();
food.setQuantity(q-1);
foodAdapter.notifyItemChanged(position);
}
#Override
public void increase(int position) {
food = foods.get(position);
q=food.getQuantity();
food.setQuantity(q+1);
foodAdapter.notifyItemChanged(position);
}
#Override
public void setSeekBar(int position,int progress) {
food = foods.get(position);
food.setQuantity(progress);
Toast.makeText(getContext(),"Quantity set to "+progress+"%",Toast.LENGTH_SHORT).show();
foodAdapter.notifyItemChanged(position);
}
});
return v;
}
public void openFoodEditorFragment(int position,Food food){ //code for Editor in Edit Old mode
//creating new Bundle and passing each member data of 'food'
Bundle bundle = new Bundle();
bundle.putString("name",food.getName());
bundle.putInt("type",food.getType());
bundle.putInt("quantity",food.getQuantity());
bundle.putInt("min_quantity",food.getMin_quantity());
bundle.putInt("mode",1);
bundle.putInt("position",position);
//setting up arguments for Fragment
FoodEditorFragment foodEditorFragment = new FoodEditorFragment();
foodEditorFragment.setArguments(bundle);
//creating the Fragment
FragmentTransaction transaction=getFragmentManager().beginTransaction();
transaction.replace(R.id.food_editor_frame,foodEditorFragment);
transaction.commit();
}
public void openFoodEditorFragment(){ //code for Editor in Add New mode
//creating new Bundle and passing each member data of 'food'
Bundle bundle = new Bundle();
bundle.putInt("position",0);
bundle.putInt("mode",0);
//setting up arguments for Fragment
FoodEditorFragment foodEditorFragment = new FoodEditorFragment();
foodEditorFragment.setArguments(bundle);
//creating the Fragment
FragmentTransaction transaction=getFragmentManager().beginTransaction();
transaction.replace(R.id.food_editor_frame,foodEditorFragment);
transaction.commit();
}
protected void setData(int position, Food food){
foods.remove(position);
foods.add(position,food);
foodAdapter.notifyItemChanged(position);
}
protected void setData(Food food){
foods.add(0,food);
foodAdapter.notifyItemInserted(0);
Toast.makeText(getContext(),"Added to the top",Toast.LENGTH_SHORT).show();
}
void loadData(){
//TODO: CODE TO LOAD DATA
}
void saveData(){
//TODO: CODE TO SAVE DATA
}
}
Fragment 'B':
package com.coffeetech.kittycatch;
import android.content.Context;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageButton;
import android.widget.RadioGroup;
import android.widget.TextView;
import android.widget.Toast;
public class FoodEditorFragment extends Fragment {
private TextView name,quantity,min_quantity;
private ImageButton save,cancel;
private RadioGroup radioGroup;
protected int mode,t,position;
protected Food food = new Food();
#Override
public void onAttach(#NonNull Context context) {
super.onAttach(context);
sffe = (SendFoodFromEditor)context;
}
public FoodEditorFragment() {
// Required empty public constructor
}
public interface SendFoodFromEditor{
void sendFood(Food food,int position); //FOR EDITING FOOD
void sendFood(Food food); //FOR NEW FOOD
}
SendFoodFromEditor sffe;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_food_editor, container, false);
name=view.findViewById(R.id.name_editor);
quantity=view.findViewById(R.id.quantity_editor);
min_quantity=view.findViewById(R.id.min_quantity_editor);
save=view.findViewById(R.id.save_button_editor);
cancel=view.findViewById(R.id.cancel_button_editor);
radioGroup=view.findViewById(R.id.radioGroup_editor);
mode=getArguments().getInt("mode");
position=getArguments().getInt("position");
if (mode==1){ //for editing Food
//CODE TO SETUP EDITOR ACCORDING TO INITIAL DETAILS
name.setText(getArguments().getString("name"));
quantity.setText(String.valueOf(getArguments().getInt("quantity")));
min_quantity.setText(String.valueOf(getArguments().getInt("min_quantity")));
t=getArguments().getInt("type");
if(t==0){//for discrete food
radioGroup.check(R.id.discrete_radioButton);
}else{//for cont food
radioGroup.check(R.id.cont_radioButton);
}
}
setButtons();
return view;
}
public void setButtons(){
save.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) { //USE BELOW 'food' TO PASS NEW DATA TO ACTIVITY
try {
if ((!name.getText().toString().isEmpty()) && ((radioGroup.getCheckedRadioButtonId() == R.id.discrete_radioButton) || (radioGroup.getCheckedRadioButtonId() == R.id.cont_radioButton))) {
food.setName(name.getText().toString());
food.setQuantity(Integer.parseInt(quantity.getText().toString()));
food.setMin_quantity(Integer.parseInt(min_quantity.getText().toString()));
if (radioGroup.getCheckedRadioButtonId() == R.id.discrete_radioButton) {
food.setType(0);
} else if (radioGroup.getCheckedRadioButtonId() == R.id.cont_radioButton) {
food.setType(1);
}
//CODE TO SEND THE FOOD TO ACTIVITY
if (mode == 1) {
sffe.sendFood(food, position);
} else {
sffe.sendFood(food);
}
//CLOSE THE FRAGMENT
getFragmentManager().beginTransaction().remove(FoodEditorFragment.this).commit();
} else {
throw new Exception();
}
}catch (Exception e){
Toast.makeText(getContext(),"Please set all details",Toast.LENGTH_SHORT).show();
}
}
});
cancel.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) { //CODE IF USER PRESSES ON CANCEL
//CLOSE THE FRAGMENT
getFragmentManager().beginTransaction().remove(FoodEditorFragment.this).commit();
}
});
}
}
You need to make following changes.
In Fragment A,
Replace
transaction.replace(R.id.food_editor_frame,foodEditorFragment);
With
transaction.add(R.id.food_editor_frame,foodEditorFragment);
Reason: using replace will remove the fragmentA and FragmentA will always be recreated.
In MainActivity
#Override
public void sendFood(Food food, int position){
//find fragment by Id
Fragment fragmentA = (Fragment)
getSupportFragmentManager().findFragmentById(R.id.fragmetnA);
fragment.setData(position,food)
//code for save data here
}
#Override
public void sendFood(Food food) {
Fragment fragmentA = (Fragment)
getSupportFragmentManager().findFragmentById(R.id.fragmetnA);
fragment.setData(food)
//code for save data here
}
First of all, I hope my question is clear. If it isn't please comment i will try to make it better!.
i have a question related to putting a item in a arraylist. I am using the master/detail flow (a standard project option in android studio) as a bases for my app. I already modified it but below is de code from the original template to simplify my question. For my problem i think there are three activities involved. Main activity, detail activity, mysavedbooks and the fragment activity.
My Problem
In the detail activity there is a fab button. WHat i want to do is to save the current displayed item in a new arraylist called Saveditems in the activity mysavedbooks.
How can i read the item (which is currently displayed by the detailactivity which extends the fragment) and put this in a saveditems arraylist.
Greetings,
Matthijs
below is the main activity
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.Toolbar;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.Snackbar;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import matthijs.bookshelf.dummy.DummyContent;
import java.util.List;
/**
* An activity representing a list of books. This activity
* has different presentations for handset and tablet-size devices. On
* handsets, the activity presents a list of items, which when touched,
* lead to a {#link bookDetailActivity} representing
* item details. On tablets, the activity presents the list of items and
* item details side-by-side using two vertical panes.
*/
public class bookListActivity extends AppCompatActivity {
/**
* Whether or not the activity is in two-pane mode, i.e. running on a tablet
* device.
*/
private boolean mTwoPane;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_book_list);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
toolbar.setTitle(getTitle());
FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
.setAction("Action", null).show();
}
});
View recyclerView = findViewById(R.id.book_list);
assert recyclerView != null;
setupRecyclerView((RecyclerView) recyclerView);
if (findViewById(R.id.book_detail_container) != null) {
// The detail container view will be present only in the
// large-screen layouts (res/values-w900dp).
// If this view is present, then the
// activity should be in two-pane mode.
mTwoPane = true;
}
}
private void setupRecyclerView(#NonNull RecyclerView recyclerView) {
recyclerView.setAdapter(new SimpleItemRecyclerViewAdapter(DummyContent.ITEMS));
}
public class SimpleItemRecyclerViewAdapter
extends RecyclerView.Adapter<SimpleItemRecyclerViewAdapter.ViewHolder> {
private final List<DummyContent.DummyItem> mValues;
public SimpleItemRecyclerViewAdapter(List<DummyContent.DummyItem> items) {
mValues = items;
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.book_list_content, parent, false);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(final ViewHolder holder, int position) {
holder.mItem = mValues.get(position);
holder.mIdView.setText(mValues.get(position).id);
holder.mContentView.setText(mValues.get(position).content);
holder.mView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (mTwoPane) {
Bundle arguments = new Bundle();
arguments.putString(bookDetailFragment.ARG_ITEM_ID, holder.mItem.id);
bookDetailFragment fragment = new bookDetailFragment();
fragment.setArguments(arguments);
getSupportFragmentManager().beginTransaction()
.replace(R.id.book_detail_container, fragment)
.commit();
} else {
Context context = v.getContext();
Intent intent = new Intent(context, bookDetailActivity.class);
intent.putExtra(bookDetailFragment.ARG_ITEM_ID, holder.mItem.id);
context.startActivity(intent);
}
}
});
}
#Override
public int getItemCount() {
return mValues.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
public final View mView;
public final TextView mIdView;
public final TextView mContentView;
public DummyContent.DummyItem mItem;
public ViewHolder(View view) {
super(view);
mView = view;
mIdView = (TextView) view.findViewById(R.id.id);
mContentView = (TextView) view.findViewById(R.id.content);
}
#Override
public String toString() {
return super.toString() + " '" + mContentView.getText() + "'";
}
}
}
}
below is the detail activity.
import android.content.Intent;
import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.Snackbar;
import android.support.v7.widget.Toolbar;
import android.view.View;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.app.ActionBar;
import android.support.v4.app.NavUtils;
import android.view.MenuItem;
/**
* An activity representing a single book detail screen. This
* activity is only used narrow width devices. On tablet-size devices,
* item details are presented side-by-side with a list of items
* in a {#link bookListActivity}.
*/
public class bookDetailActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_book_detail);
Toolbar toolbar = (Toolbar) findViewById(R.id.detail_toolbar);
setSupportActionBar(toolbar);
FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Snackbar.make(view, "saved book", Snackbar.LENGTH_LONG)
.setAction("Action", null).show();
}
});
// Show the Up button in the action bar.
ActionBar actionBar = getSupportActionBar();
if (actionBar != null) {
actionBar.setDisplayHomeAsUpEnabled(true);
}
// savedInstanceState is non-null when there is fragment state
// saved from previous configurations of this activity
// (e.g. when rotating the screen from portrait to landscape).
// In this case, the fragment will automatically be re-added
// to its container so we don't need to manually add it.
// For more information, see the Fragments API guide at:
//
// http://developer.android.com/guide/components/fragments.html
//
if (savedInstanceState == null) {
// Create the detail fragment and add it to the activity
// using a fragment transaction.
Bundle arguments = new Bundle();
arguments.putString(bookDetailFragment.ARG_ITEM_ID,
getIntent().getStringExtra(bookDetailFragment.ARG_ITEM_ID));
bookDetailFragment fragment = new bookDetailFragment();
fragment.setArguments(arguments);
getSupportFragmentManager().beginTransaction()
.add(R.id.book_detail_container, fragment)
.commit();
}
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == android.R.id.home) {
// This ID represents the Home or Up button. In the case of this
// activity, the Up button is shown. Use NavUtils to allow users
// to navigate up one level in the application structure. For
// more details, see the Navigation pattern on Android Design:
//
// http://developer.android.com/design/patterns/navigation.html#up-vs-back
//
NavUtils.navigateUpTo(this, new Intent(this, bookListActivity.class));
return true;
}
return super.onOptionsItemSelected(item);
}
}
below is the fragment
package matthijs.bookshelf;
import android.app.Activity;
import android.support.design.widget.CollapsingToolbarLayout;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import matthijs.bookshelf.dummy.DummyContent;
/**
* A fragment representing a single book detail screen.
* This fragment is either contained in a {#link bookListActivity}
* in two-pane mode (on tablets) or a {#link bookDetailActivity}
* on handsets.
*/
public class bookDetailFragment extends Fragment {
/**
* The fragment argument representing the item ID that this fragment
* represents.
*/
public static final String ARG_ITEM_ID = "item_id";
/**
* The dummy content this fragment is presenting.
*/
private DummyContent.DummyItem mItem;
/**
* Mandatory empty constructor for the fragment manager to instantiate the
* fragment (e.g. upon screen orientation changes).
*/
public bookDetailFragment() {
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments().containsKey(ARG_ITEM_ID)) {
// Load the dummy content specified by the fragment
// arguments. In a real-world scenario, use a Loader
// to load content from a content provider.
mItem = DummyContent.ITEM_MAP.get(getArguments().getString(ARG_ITEM_ID));
Activity activity = this.getActivity();
CollapsingToolbarLayout appBarLayout = (CollapsingToolbarLayout) activity.findViewById(R.id.toolbar_layout);
if (appBarLayout != null) {
appBarLayout.setTitle(mItem.content);
}
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.book_detail, container, false);
// Show the dummy content as text in a TextView.
if (mItem != null) {
((TextView) rootView.findViewById(R.id.book_detail)).setText(mItem.details);
}
return rootView;
}
}
Mysavedbooks activity
package matthijs.tuinierv2;
import java.util.ArrayList;
import java.util.List;
/**
* Created by Matthijs on 12-2-2016.
*/
public class Mysavedbooks {
public static final List<DummyContent.DummyItem> SavedItems= new ArrayList<DummyContent.DummyItem>();
}
I kind of solved to problem for now, except for the twopane mode. I need to look in the solution for the twopane mode further. I think it can be done in a better way but here is the solution.
Please comment if you have a better solution.
I added the String in ItemDetailActivity
public static String SAVED_ITEM_ID;
In the bookListActivity i added a line of code in this part:
` #Override
public void onBindViewHolder(final ViewHolder holder, int position) {
holder.mItem = mValues.get(position);
holder.mIdView.setText(mValues.get(position).id);
holder.mContentView.setText(mValues.get(position).content);
holder.mView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (mTwoPane) {
Bundle arguments = new Bundle();
arguments.putString(bookDetailFragment.ARG_ITEM_ID, holder.mItem.id);
bookDetailFragment fragment = new bookDetailFragment();
fragment.setArguments(arguments);
getSupportFragmentManager().beginTransaction()
.replace(R.id.book_detail_container, fragment)
.commit();
} else {
Context context = v.getContext();
Intent intent = new Intent(context, bookDetailActivity.class);
intent.putExtra(bookDetailFragment.ARG_ITEM_ID, holder.mItem.id);
//THE line of code I ADDED
itemDetailActivity.SAVED_ITEM_ID = holder.mItem.id;
context.startActivity(intent);
}
}
});
}`
Here is the code i added in the bookDetailActivity to retrieve the current book which is displayed in the itemdetailactivity en thereby the fragment.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_item_detail);
Toolbar toolbar = (Toolbar) findViewById(R.id.detail_toolbar);
setSupportActionBar(toolbar);
FloatingActionButton fab = (FloatingActionButton)findViewById(R.id.fabdetail);
fab.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
//code i added to retrieve the current item and save it in
int SAVED_ITEM_ID_INT = Integer.parseInt(SAVED_ITEM_ID);
ItemListActivity.PlantItem SAVED_ITEM = ItemListActivity.ITEMS.get(SAVED_ITEM_ID_INT);
Mysavedbooks.SavedItems.add(SAVED_ITEM);
Snackbar.make(view,"Book saved to My books", Snackbar.LENGTH_LONG).setAction("Action", null).show();
}
});
I want to pass dogruYanlis value which is an integer array to these fragments. If I try to handle this with bundle it it sends anything. The array that I received in fragment class is always null. I think that I can't handle with bundle but I don't know how I can solve this problem...
The Activity that I want to send data
package oztiryaki.my;
import android.content.Intent;
import android.os.Bundle;
import android.support.design.widget.TabLayout;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.view.ViewPager;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.Menu;
import android.widget.Toast;
import java.util.ArrayList;
import java.util.List;
public class result extends AppCompatActivity {
private Toolbar toolbar;
private TabLayout tabLayout;
private ViewPager viewPager;
private Bundle bundle;
int[] dogruYanlis;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_result);
toolbar = (Toolbar) findViewById(R.id.toolbarResult);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
viewPager = (ViewPager) findViewById(R.id.viewpager);
setupViewPager(viewPager);
tabLayout = (TabLayout) findViewById(R.id.tabs);
tabLayout.setupWithViewPager(viewPager);
Bundle list = getIntent().getExtras();
if(list == null){
return;
}
dogruYanlis = list.getIntArray("dogruYanlis");
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
private void setupViewPager(ViewPager viewPager) {
ViewPagerAdapter adapter = new ViewPagerAdapter(getSupportFragmentManager());
bundle = new Bundle();
bundle.putIntArray("dogruYanlis", dogruYanlis);
result2015Fragment f15 = new result2015Fragment();
f15.setArguments(bundle);
result2014Fragment f14 = new result2014Fragment();
f14.setArguments(bundle);
result2013Fragment f13 = new result2013Fragment();
f13.setArguments(bundle);
adapter.addFragment(f15, "2015");
adapter.addFragment(f14, "2014");
adapter.addFragment(f13, "2013");
viewPager.setAdapter(adapter);
}
class ViewPagerAdapter extends FragmentPagerAdapter {
private final List<Fragment> mFragmentList = new ArrayList<>();
private final List<String> mFragmentTitleList = new ArrayList<>();
public ViewPagerAdapter(FragmentManager manager) {
super(manager);
}
#Override
public Fragment getItem(int position) {
return mFragmentList.get(position);
}
#Override
public int getCount() {
return mFragmentList.size();
}
public void addFragment(Fragment fragment, String title) {
mFragmentList.add(fragment);
mFragmentTitleList.add(title);
}
#Override
public CharSequence getPageTitle(int position) {
return mFragmentTitleList.get(position);
}
}
}
The one of fragment activity
package oztiryaki.my;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import android.widget.Toast;
/**
* Created by oztir on 21.02.2016.
*/
public class result2015Fragment extends Fragment {
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.result2015,container,false);
int[] dogruYanlis = getArguments().getIntArray("dogruYanlis");
if(dogruYanlis == null){
Toast.makeText(getActivity(),"null sory:(", Toast.LENGTH_LONG).show();
}
TextView ygs1hp = (TextView) v.findViewById(R.id.ygs1hp);
return v;
}
public void getArray(int[] dogruYanlis){
Toast.makeText(getActivity(),Integer.toString(dogruYanlis[0]), Toast.LENGTH_LONG).show();
}
}
I had a similar struggle, maybe this will help. In case if your variables in the activity are not changing after it is created, there is one simple way to reach out to the activity's variables from the fragment it creates:
get the context in the fragment
then you can get the value of the variable from the fragment
Context context;
public void onViewCreated(View v, Bundle savedInstanceState) {
context = getActivity();
int i = ((result)context).dogruYanlis[0];
}
Try to create a Fragment using the wizard that Android studio provides, which gives you a dummy Fragment, with all the Fragment methods you need to pass data and such:
package FRAGMENTS;
import android.app.Fragment;
import android.content.Context;
import android.net.Uri;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import android.widget.Toast;
public class FragmentLifecycleDemo extends Fragment {
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
private static final String TEXT1 = "text1";
private static final String TEXT2 = "text2";
// the two strings are going to be used here
private TextView title;
private TextView subtitle;
private String text1;
private String text2;
private Context c;
private OnFragmentInteractionListener mListener;
public FragmentLifecycleDemo(Context c) {
// Required empty public constructor
this.c = c;
}
public static FragmentLifecycleDemo newInstance(String title, String subtitle, Context c) {
FragmentLifecycleDemo fragment = new FragmentLifecycleDemo(c);
Bundle args = new Bundle();
args.putString(TEXT1, title);
args.putString(TEXT2, subtitle);
fragment.setArguments(args);
return fragment;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Toast.makeText(c, "Hi! onCreate has just been called.", Toast.LENGTH_SHORT).show();
if (getArguments() != null) {
text1 = getArguments().getString(TEXT1);
text2 = getArguments().getString(TEXT2);
}
}
private void init(View v) {
title = (TextView) v.findViewById(R.id.txtTry);
title.setText(text1);
subtitle = (TextView) v.findViewById(R.id.txtReal);
subtitle.setText(text2);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_lifecycle_demo, container, false);
init(v);
Toast.makeText(c, "Greetings from onCreateView!", Toast.LENGTH_SHORT).show();
return v;
}
// TODO: Rename method, update argument and hook method into UI event
public void onButtonPressed(Uri uri) {
Toast.makeText(c, "Is it me, or a button has just been pressed?", Toast.LENGTH_SHORT).show();
if (mListener != null) {
mListener.onFragmentInteraction(uri);
}
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
Toast.makeText(c, "Howdy! I've just been attached to the activity.", Toast.LENGTH_SHORT).show();
if (context instanceof OnFragmentInteractionListener) {
mListener = (OnFragmentInteractionListener) context;
} else {
throw new RuntimeException(context.toString()
+ " must implement OnFragmentInteractionListener");
}
}
#Override
public void onDetach() {
super.onDetach();
Toast.makeText(c, "Oh no! I've been detached u.u", Toast.LENGTH_SHORT).show();
mListener = null;
}
/**
* This interface must be implemented by activities that contain this
* fragment to allow an interaction in this fragment to be communicated
* to the activity and potentially other fragments contained in that
* activity.
* <p/>
* See the Android Training lesson <a href=
* "http://developer.android.com/training/basics/fragments/communicating.html"
* >Communicating with Other Fragments</a> for more information.
*/
public interface OnFragmentInteractionListener {
// TODO: Update argument type and name
void onFragmentInteraction(Uri uri);
}
}
As you can see, the method where you should get the Bundle is the onCreate one, that receives the data you want to be available on the Fragment, which was send from the constructor named newInstance.
i am looking for a second opinion. I have a class that extends the Fragment class and contains a ViewPager and MaterialTabs. I need to find a workaround on a problem and I would like to remove tabs from ViewPager and add just one (fragment too) and so on.
For instance, i start with two tabs and on an action i want to remove those tabs and add a new one and on a different action to re-add those two tabs.
Is this plain stupid or it has a shot? Thank you.
Below is my class that i will work on:
import android.app.Fragment;
import android.app.FragmentManager;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.support.v13.app.FragmentStatePagerAdapter;
import android.support.v4.app.ActivityCompat;
import android.support.v4.view.ViewPager;
import android.support.v4.view.ViewPager.SimpleOnPageChangeListener;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import it.neokree.materialtabs.MaterialTab;
import it.neokree.materialtabs.MaterialTabHost;
import it.neokree.materialtabs.MaterialTabListener;
/**
*
*/
public class PuzzlesTabActivity extends Fragment implements MaterialTabListener {
public static int NUM_TABS = 2;
public static boolean currentlyRunning;
private MaterialTabHost tabHost;
private ViewPager pager;
private PuzzlesTabActivity.ViewPagerAdapter adapter;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(layout.puzzle_tab_layout, container, false);
if (Utils.isNetworkAvailable(this.getActivity())) {
this.tabHost = (MaterialTabHost) rootView.findViewById(id.myTabHost);
this.pager = (ViewPager) rootView.findViewById(id.myPager);
try {
this.pager.setPadding(0, 5, 0, 0);
// init view pager
this.adapter = new PuzzlesTabActivity.ViewPagerAdapter(this.getActivity().getFragmentManager());
this.pager.setAdapter(this.adapter);
this.pager.setOnPageChangeListener(new SimpleOnPageChangeListener() {
#Override
public void onPageSelected(int position) {
// when user do a swipe the selected tab change
PuzzlesTabActivity.this.tabHost.setSelectedNavigationItem(position);
}
});
this.pager.setCurrentItem(0);
// add tabs
for (int i = 0; i < this.adapter.getCount(); i++) {
this.tabHost.addTab(this.tabHost.newTab().setText(this.adapter.getPageTitle(i)).setTabListener(this));
}
} catch (Exception e) {
Log.e(Constants.TAG, e.getMessage());
}
} else {
ActivityCompat.startActivity(this.getActivity(), new Intent(this.getActivity(), MainActivity.class), null);
}
return rootView;
}
#Override
public void onTabSelected(MaterialTab tab) {
this.pager.setCurrentItem(tab.getPosition());
}
#Override
public void onTabReselected(MaterialTab tab) {
}
#Override
public void onTabUnselected(MaterialTab tab) {
}
private class ViewPagerAdapter extends FragmentStatePagerAdapter {
public ViewPagerAdapter(FragmentManager fm) {
super(fm);
}
public Fragment getItem(int num) {
switch (num) {
case 0:
PuzzlesFragment aFragment = new PuzzlesFragment();
return aFragment;
case 1:
FavFragment nFragment = new FavFragment();
return nFragment;
default:
return new PuzzlesFragment();
}
}
#Override
public int getCount() {
return PuzzlesTabActivity.NUM_TABS;
}
#Override
public CharSequence getPageTitle(int position) {
switch (position) {
case 0:
return PuzzlesTabActivity.this.getResources().getString(string.new_puzzles);
case 1:
return PuzzlesTabActivity.this.getResources().getString(string.fav_puzzles);
default:
return PuzzlesTabActivity.this.getResources().getString(string.new_puzzles);
}
}
}
public void onPause() {
super.onPause();
SharedPreferences prefs = this.getActivity().getSharedPreferences(Utils.PREFS_NAME, Context.MODE_PRIVATE);
SharedPreferences.Editor editor = prefs.edit();
editor.putString("lastActivity", this.getClass().getName());
editor.commit();
}
#Override
public void onStart() {
super.onStart();
PuzzlesTabActivity.currentlyRunning = true;
}
#Override
public void onStop() {
PuzzlesTabActivity.currentlyRunning = false;
super.onStop();
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
return super.onOptionsItemSelected(item);
}
}
Yes, this is fine. ViewPager already does something like this in a normal use case. It works by creating the fragment to the left, the current fragment, and the fragment to the right, as you swipe (so only three exist at a time).
As for adding and removing the tabs, that is fine to do as well. Just make sure to handle swapping for the new tab's fragment in the ViewPager.
I have two fragments, lets call them Fragment A and Fragment B, which are a part of a NavigationDrawer (this is the activity they a bound to). In Fragment A I have a button. When this button is pressed, I would like another item added to the ListView in Fragment B.
What is the best way to do this? Use Intents, SavedPreferences, making something public(?) or something else?
EDIT 5: 20/7/13 This is with srains latest code
This is the NavigationDrawer that I use to start the fragments:
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.support.v4.app.ActionBarDrawerToggle;
import android.support.v4.view.GravityCompat;
import android.support.v4.widget.DrawerLayout;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.WindowManager;
import android.view.inputmethod.InputMethodManager;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ListView;
public class Navigation_Drawer extends FragmentActivity {
public DrawerLayout mDrawerLayout; // Creates a DrawerLayout called_.
public ListView mDrawerList;
public ActionBarDrawerToggle mDrawerToggle;
private CharSequence mDrawerTitle;
private CharSequence mTitle;
private String[] mNoterActivities; // This creates a string array called _.
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
// Just setting up the navigation drawer
} // End of onCreate
// Removed the menu
#Override
public void onItemClick(AdapterView<?> parent, View view, int position,
long id) {
selectItem(position);
}
}
private void selectItem(int position) {
FragmentManager fragmentManager = getSupportFragmentManager();
if (position == 0) {
Fragment qnfragment = new QuickNoteFragment();
((FragmentBase) qnfragment).setContext(this);
Bundle args = new Bundle(); // Creates a bundle called args
args.putInt(QuickNoteFragment.ARG_nOTERACTIVITY_NUMBER, position);
qnfragment.setArguments(args);
fragmentManager.beginTransaction()
.replace(R.id.content_frame, qnfragment).commit();
} else if (position == 3) {
Fragment pendViewPager = new PendViewPager(); // This is a ViewPager that includes HistoryFragment
((FragmentBase) pendViewPager).setContext(this);
Bundle args = new Bundle();
pendViewPager.setArguments(args);
fragmentManager.beginTransaction()
.replace(R.id.content_frame, pendViewPager).commit();
}
// Update title etc
}
#Override
protected void onPostCreate(Bundle savedInstanceState) { // Used for the NavDrawer toggle
super.onPostCreate(savedInstanceState);
// Sync the toggle state after onRestoreInstanceState has occurred.
mDrawerToggle.syncState();
}
#Override
public void onConfigurationChanged(Configuration newConfig) { // Used for the NavDrawer toggle
super.onConfigurationChanged(newConfig);
// Pass any configuration change to the drawer toggles
mDrawerToggle.onConfigurationChanged(newConfig);
}
}
This is QuickNoteFragment:
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.net.Uri;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.support.v4.app.NotificationCompat;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
public class QuickNoteFragment extends FragmentBase implements OnClickListener {
public static final String ARG_nOTERACTIVITY_NUMBER = "noter_activity";
Button b_create;
// removed other defining stuff
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.quicknote, container, false);
int i = getArguments().getInt(ARG_nOTERACTIVITY_NUMBER);
String noter_activity = getResources().getStringArray(
R.array.noter_array)[i];
FragmentManager fm = getFragmentManager();
setRetainInstance(true);
b_create = (Button) rootView.findViewById(R.id.qn_b_create);
// Removed other stuff
getActivity().setTitle(noter_activity);
return rootView;
}
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
switch (v.getId()) {
case R.id.qn_b_create:
String data = "String data";
DataModel.getInstance().addItem(data);
break;
}
}
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
// TODO Auto-generated method stub
super.onCreateOptionsMenu(menu, inflater);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle item selection
}
}
public interface OnItemAddedHandler { // Srains code
public void onItemAdded(Object data);
}
}
This is HistoryFragment (Remember it is part of a ViewPager):
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.RiThBo.noter.QuickNoteFragment.OnItemAddedHandler;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.AdapterContextMenuInfo;
import android.widget.ListView;
import android.widget.SimpleAdapter;
import android.widget.TextView;
import android.widget.Toast;
public class HistoryFragment extends FragmentBase implements OnItemAddedHandler {
ListView lv;
List<Map<String, String>> planetsList = new ArrayList<Map<String, String>>();
SimpleAdapter simpleAdpt;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// TODO Auto-generated method stub
View view = inflater.inflate(R.layout.history, container, false);
initList();
ListView lv = (ListView) view.findViewById(R.id.listView);
simpleAdpt = new SimpleAdapter(getActivity(), planetsList,
android.R.layout.simple_list_item_1, new String[] { "planet" },
new int[] { android.R.id.text1 });
lv.setAdapter(simpleAdpt);
lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
public void onItemClick(AdapterView<?> parentAdapter, View view,
int position, long id) {
// We know the View is a TextView so we can cast it
TextView clickedView = (TextView) view;
Toast.makeText(
getActivity(),
"Item with id [" + id + "] - Position [" + position
+ "] - Planet [" + clickedView.getText() + "]",
Toast.LENGTH_SHORT).show();
}
});
registerForContextMenu(lv);
return view;
}
private void initList() {
// We populate the planets
planetsList.add(createPlanet("planet", "Mercury"));
planetsList.add(createPlanet("planet", "Venus"));
planetsList.add(createPlanet("planet", "Mars"));
planetsList.add(createPlanet("planet", "Jupiter"));
planetsList.add(createPlanet("planet", "Saturn"));
planetsList.add(createPlanet("planet", "Uranus"));
planetsList.add(createPlanet("planet", "Neptune"));
}
private HashMap<String, String> createPlanet(String key, String name) {
HashMap<String, String> planet = new HashMap<String, String>();
planet.put(key, name);
return planet;
}
// We want to create a context Menu when the user long click on an item
#Override
public void onCreateContextMenu(ContextMenu menu, View v,
ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, v, menuInfo);
AdapterContextMenuInfo aInfo = (AdapterContextMenuInfo) menuInfo;
// We know that each row in the adapter is a Map
HashMap map = (HashMap) simpleAdpt.getItem(aInfo.position);
menu.setHeaderTitle("Options for " + map.get("planet"));
menu.add(1, 1, 1, "Details");
menu.add(1, 2, 2, "Delete");
}
#Override
public void onItemAdded(Object data) {
// to add item
String string = String.valueOf(data);
Toast.makeText(getContext(), "Data: " + string, Toast.LENGTH_SHORT).show();
planetsList.add(createPlanet("planet", string));
}
#Override
public void onStart() {
super.onStart();
DataModel.getInstance().setOnItemAddedHandler(this);
}
}
This is FragmentBase:
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
public class FragmentBase extends Fragment {
private FragmentActivity mActivity; // I changed it to FragmentActivity because Activity was not working, and my `NavDrawer` is a FragmentActivity.
public void setContext(FragmentActivity activity) {
mActivity = mActivity;
}
public FragmentActivity getContext() {
return mActivity;
}
}
This is DataModel:
import android.util.Log;
import com.xxx.xxx.QuickNoteFragment.OnItemAddedHandler;
public class DataModel {
private static DataModel instance;
private static OnItemAddedHandler mOnItemAddHandler;
public static DataModel getInstance() {
if (null == instance) {
instance = new DataModel();
}
return instance;
}
public void setOnItemAddedHandler(OnItemAddedHandler handler) {
mOnItemAddHandler = handler;
}
public void addItem(Object data) {
if (null != mOnItemAddHandler)
mOnItemAddHandler.onItemAdded(data);
else {
Log.i("is context null?", "yes!");
}
}
}
Thank you
I suggest you to use interface and MVC, that will make your code much more maintainable.
First you need an interface:
public interface OnItemAddedHandler {
public void onItemAdded(Object data);
}
Then, you will need a data model:
public class DataModel {
private static DataModel instance;
private static OnItemAddedHandler mOnItemAddHandler;
public static DataModel getInstance() {
if (null == instance) {
instance = new DataModel();
}
return instance;
}
public void setOnItemAddedHandler(OnItemAddedHandler handler) {
mOnItemAddHandler = handler;
}
public void addItem(Object data) {
if (null != mOnItemAddHandler)
mOnItemAddHandler.onItemAdded(data);
}
}
When you click the button, you can add data into the datamodel:
Object data = null;
DataModel.getInstance().addItem(data);
Then, the FragmentB implements the interface OnItemAddedHandler to add item
public class FragmentB implements OnItemAddedHandler {
#Override
public void onItemAdded(Object data) {
// to add item
}
}
also, When the FragmentB start, you should register itself to DataModel:
public class FragmentB implements OnItemAddedHandler {
#Override
public void onItemAdded(Object data) {
// to add item
}
#Override
protected void onStart() {
super.onStart();
DataModel.getInstance().setOnItemAddedHandler(this);
}
}
You also can add DataModel.getInstance().setOnItemAddedHandler(this); to the onCreate method of FragmentB
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
DataModel.getInstance().setOnItemAddedHandler(this);
// do other things
}
update
you can send string simply:
String data = "some string";
DataModel.getInstance().addItem(data);
then on FragementB
public class FragmentB implements OnItemAddedHandler {
#Override
public void onItemAdded(Object data) {
// get what you send into method DataModel.getInstance().addItem(data);
String string = String.valueOf(data);
}
}
update
OK. You have add DataModel.getInstance().setOnItemAddedHandler(this) in onCreateView method, so there is no need to add it in onStart() method. You can remove the whole onStart method.
onStart will be called on the fragment start, we do not need to call it in onCreateView. And on onItemAdded will be call when call the method DataModel.getInstance().addItem(data), we do not need to call it in onCreateView neither.
so, you can remove the code below from onCreateView method:
DataModel.getInstance().setOnItemAddedHandler(this);
// remove the methods below
// onItemAdded(getView());
// onStart();
You have another fragment where there is a button, you can add the codes below in the clickhandler function:
String data = "some string";
DataModel.getInstance().addItem(data);
update3
I think the HistoryFragment has been detached after you when to QuickNoteFragment
You can add code to HistoryFragment to check:
#Override
public void onDetach() {
super.onDetach();
Log.i("test", String.format("onDetach! %s", getActivity() == null));
}
update4
I think HistoryFragment and QuickNoteFragment should has an parent class, named FragmentBase:
public class FragmentBase extends Fragment {
private Activity mActivity;
public void setContext(Activity activity) {
mActivity = mActivity;
}
public Activity getContext() {
return mActivity;
}
}
HistoryFragment and QuickNoteFragment extends FragmentBase. Then when you switch between them, you can call setContext to set a Activity, like:
private void selectItem(int position) {
FragmentManager fragmentManager = getSupportFragmentManager();
if (position == 0) {
Fragment qnfragment = new QuickNoteFragment();
qnfragment.setContext(this);
// ...
} else if (position == 1) {
Fragment pagerFragment = new RemViewPager();
pagerFragment.setContext(this);
// ...
}
}
now, we can get a non-null activity in HistoryFragment by calling getContext, so we can change onItemAdded method to:
#Override
public void onItemAdded(Object data) {
// to add item
String string = String.valueOf(data);
Toast.makeText(getContext(), "Data: " + string, Toast.LENGTH_SHORT).show();
planetsList.add(createPlanet("planet", string));
}
I hope this would work.
Some good design principals:
An activity can know everything pubic about any Fragment it contains.
A Fragment should not know anything about the specific Activities that contain it.
A Fragment should NEVER know about other fragments that may or may not be contained in the Parent activity.
A suggested approach (informal design pattern) based on these principles.
Each fragment should declare an interface to be implemented by its parent activity:
public class MyFragment extends Fragment
{
public interface Parent
{
void onMyFragmentSomeAction();
}
private Parent mParent;
public onAttach(Activity activity)
{
mParent = (Parent) activity;
}
// This would actually be in a listener. Simplifying to save typing.
void onSomeButtonClick(View button)
{
mParent.onMyFragmentSomeAction();
}
}
And the activity should implement the appropriate interfaces for all of its contained fragments.
public class MyActivity extends Activity
implements MyFragment.Parent,
YourFragment.Parent,
HisFragment.Parent
{
[usual Activity code]
void onMyFragmentSomeAction()
{
if yourFragment is showing
{
yourFragment.reactToSomeAction();
}
if hisFragment is showing
{
hisFragment.observeThatSomeActionHappened();
}
[etc]
}
The broadcast approach is good, too, but it's pretty heavyweight and it requires the target Fragment to know what broadcasts will be sent by the source Fragment.
Use Broadcast. Send a boradcast from A, and B will receive and handle it.
Add a public method to B, for example, public void addListItem(), which will add data to listview in B. Fragment A try to find the instance of Fragment B using FragmentMananger.findFragmentByTag() and invoke this method.