Fragment "overwrites" another fragment when first selected - java

I have Bottom Navigation with which I switch between 3 fragments: "ConnectFragment", "DashboardFragment" and "ChatFragment".
Switching from Connect to Chat and vice versa works OK, but when I select Dashboard it causes a bug that makes Dashboard appear when selecting Chat in navigation, what is causing this?
All 3 fragments have identical functionality and layout, so i assume the problem lays in MainActivity.
MainActivity:
public class MainActivity extends AppCompatActivity implements DashboardFragment.FragmentDashListener, ChatFragment.FragmentChatListener, ConnectFragment.FragmentConnListener {
FragmentManager fm = getSupportFragmentManager();
Fragment active;
Fragment FragmentConnect = new ConnectFragment();
Fragment FragmentDashboard = new DashboardFragment();
Fragment FragmentChat = new ChatFragment();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
BottomNavigationView bottomNav = findViewById(R.id.bottom_navigation);
bottomNav.setOnNavigationItemSelectedListener(navListener);
fm.beginTransaction().add(R.id.fragment_container, FragmentChat).hide(FragmentChat).commit(); //Ustvari vse 3 fragmente, skrije 2 da se nena vedno znova kreirajo
fm.beginTransaction().add(R.id.fragment_container, FragmentDashboard).hide(FragmentDashboard).commit();
fm.beginTransaction().add(R.id.fragment_container, FragmentConnect).commit();
}
private BottomNavigationView.OnNavigationItemSelectedListener navListener = new BottomNavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem menuItem) {
active = FragmentConnect;
switch (menuItem.getItemId()) {
case R.id.nav_connect:
fm.beginTransaction().hide(active).show(FragmentConnect).commit();
active = FragmentConnect;
return true;
case R.id.nav_dashboard:
fm.beginTransaction().hide(active).show(FragmentDashboard).commit();
active = FragmentDashboard;
return true;
case R.id.nav_send:
fm.beginTransaction().hide(active).show(FragmentChat).commit();
active = FragmentChat;
return true;
}
return false;
}
};
#Override
public void onInputChatSent(CharSequence input) {
ConnectFragment.updateEditText(input);
}
#Override
public void onInputConnSent(CharSequence input) {
DashboardFragment.updateEditText(input);
}
#Override
public void onInputDashSent(CharSequence input) {
ChatFragment.updateEditText(input);
}
}
Fragments:
All 3 fragments have identical code, below are Dashboard and Chat.
public class DashboardFragment extends Fragment {
private FragmentDashListener listener;
private static EditText editText;
private Button ButtonOk;
public interface FragmentDashListener{
void onInputDashSent (CharSequence input);
}
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_dashboard, container, false);
editText = v.findViewById(R.id.edit_text);
ButtonOk = v.findViewById(R.id.Button_Ok);
ButtonOk.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
CharSequence input = editText.getText();
listener.onInputDashSent(input);
}
});
return v;
}
public static void updateEditText(CharSequence newText){
editText.setText(newText);
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
if(context instanceof FragmentDashListener){
listener = (FragmentDashListener) context;
} else {
throw new RuntimeException(context.toString()+"must implement FragmentDashListener");
}
}
}
public class ChatFragment extends Fragment {
private FragmentChatListener listener;
private static EditText editText;
private Button ButtonOk;
public interface FragmentChatListener{
void onInputChatSent (CharSequence input);
}
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_chat, container, false);
editText = v.findViewById(R.id.edit_text);
ButtonOk = v.findViewById(R.id.Button_Ok);
ButtonOk.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
CharSequence input = editText.getText();
listener.onInputChatSent(input);
}
});
return v;
}
public static void updateEditText(CharSequence newText){
editText.setText(newText);
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
if(context instanceof FragmentChatListener){
listener = (FragmentChatListener) context;
} else {
throw new RuntimeException(context.toString()+"must implement FragmentChatListener");
}
}
}

Remove the first line
active = FragmentConnect;
from onNavigationItemSelected method. This will fix the issue
or modify it as below
if(active == null) {
active = FragmentConnect;
}

Related

How to update listview in Fragment with custom adapter

I am giving product id with barcode scanner. I can add product to listView but when i try to increase or decrease amount of the product. It doesn't update UI. I used Toast message to see weather list is updated, it updates list but doesn't update UI
I have tried to use runOnUiThread() but i couldn't find any solution. How to update UI can you please help me
custom_lisView_row
BaseActivity which keeps MainFragment on it
public class BaseActivity extends AppCompatActivity {
public static final String MAIN_FRAGMENT = "mainFragment";
public static final String PRODUCTS = "products";
FragmentManager fragmentManager;
Dialog dialog ;
public static ArrayList<MyProduct> myProductList = new ArrayList<>();
public static MyTablet myTablet = new MyTablet();
Activity mActivity;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_base);
//Initialize fragment manager
fragmentManager = getSupportFragmentManager();
fragmentManager.beginTransaction().replace(R.id.fl_BaseActivity, new MainFragment()).commit();
//Create database
mDatabase = FirebaseDatabase.getInstance().getReference();
dialog = new Dialog(this);
//Runs when i enter product id
initScanner();
}
public void updateMyProductList(MyProduct myProduct){
for(int i= 0 ; i< myProductList.size() ; i++ ){
MyProduct temp = myProductList.get(i);
if (temp.getId().equals(myProduct.getId())) {
temp.setAmount(temp.getAmount() + myProduct.getAmount());
myProductList.set(i, temp);
return;
}
}
myProductList.add(myProduct);
updateMainFragment();
}
private void initScanner() {
mDatabase.child(PRODUCTS).child(finalData).get().addOnCompleteListener(new OnCompleteListener<DataSnapshot>() {
#Override
public void onComplete(#NonNull Task<DataSnapshot> task) {
MyProduct myProduct = task.getResult().getValue(MyProduct.class);
myProduct.setAmount(1);
dialog.setContentView(R.layout.custom_product_dialog);
dialog.getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
dialog.setCancelable(false);
TextView tv_addBasket_product_dialog = dialog.findViewById(R.id.tv_addBasket_product_dialog);
tv_addBasket_product_dialog.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
updateMyProductList(myProduct);
dialog.dismiss();
}
});
dialog.show();
}
};
}
public void updateMainFragment() {
if (isExist(MAIN_FRAGMENT)) {
Fragment fragment = findFragment(MAIN_FRAGMENT);
((MainFragment) fragment).updateMyList();
}
}
//Add fragments to BaseActivity
public void addFragments(Fragment fragment, String tag) {
fragmentManager.beginTransaction().add(R.id.fl_BaseActivity, fragment, tag).commit();
}
//Replace fragments to BaseActivity
public void replaceFragments(Fragment fragment, String tag) {
fragmentManager.beginTransaction().replace(R.id.fl_BaseActivity, fragment, tag).commit();
}
//Remove fragment from BaseActivity
public void removeFragment(String tag) {
Fragment fragmentB = fragmentManager.findFragmentByTag(tag);
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
if (fragmentB != null) {
fragmentTransaction.remove(fragmentB);
fragmentTransaction.commit();
}
}
// finds fragment and returns it
// It may return null first check fragment is exist. use isExist() method
public Fragment findFragment(String tag) {
Fragment fragment = fragmentManager.findFragmentByTag(tag);
return fragment;
}
//Check fragment exist in BaseActivity
public boolean isExist(String tag) {
Fragment fragmentB = fragmentManager.findFragmentByTag(tag);
if (fragmentB != null) {
return true;
}
return false;
}
}
MainFragment
public class MainFragment extends Fragment {
ListView lv_MainFragment;
public MyProductListAdapter myListAdapter;
public static ArrayList<MyProduct> myProductList;
Activity mActivity;
#Override
public void onAttach(Context context) {
super.onAttach(context);
mActivity = getActivity();
}
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
myProductList = BaseActivity.myProductList;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_main, container, false);
lv_MainFragment = view.findViewById(R.id.lv_MainFragment);
myListAdapter = new MyProductListAdapter(mActivity.getApplicationContext(), R.layout.custom_product_list_row, myProductList);
lv_MainFragment.setAdapter(myListAdapter);
return view;
}
public void updateMyList() {
myProductList = BaseActivity.myProductList;
myListAdapter.notifyDataSetChanged();
}
}
MyProductListAdapter
public class MyProductListAdapter extends ArrayAdapter<MyProduct> {
private Context mContext;
private ArrayList<MyProduct> list;
AppCompatButton acb_DecreaseAmount_productListRow, acb_IncreaseAmount_productListRow;
public MyProductListAdapter(Context context, int resource, ArrayList<MyProduct> objects) {
super(context, resource, objects);
this.mContext = context;
this.list = objects;
}
#Override
public View getView(int position, #Nullable View convertView, #NonNull ViewGroup parent) {
View view = convertView;
if (view == null) {
LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view = inflater.inflate(R.layout.custom_product_list_row, parent, false);
tv_ProductAmount_productListRow = view.findViewById(R.id.tv_ProductAmount_productListRow);
acb_DecreaseAmount_productListRow = view.findViewById(R.id.acb_DecreaseAmount_productListRow);
acb_IncreaseAmount_productListRow = view.findViewById(R.id.acb_IncreaseAmount_productListRow);
tv_ProductAmount_productListRow.setText(String.valueOf(list.get(position).getAmount()));
acb_IncreaseAmount_productListRow.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
double productPrice = list.get(position).getPrice();
int productAmount = list.get(position).getAmount();
productAmount++;
list.get(position).setAmount(productAmount);
Toast.makeText(mContext, String.valueOf(productAmount), Toast.LENGTH_SHORT).show();
tv_ProductAmount_productListRow.setText(String.valueOf(list.get(position).getAmount()));
}
});
acb_DecreaseAmount_productListRow.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
int productAmount = list.get(position).getAmount();
if (productAmount > 1) {
double productPrice = list.get(position).getPrice();
productAmount--;
list.get(position).setAmount(productAmount);
Toast.makeText(mContext, String.valueOf(productAmount), Toast.LENGTH_SHORT).show();
tv_ProductAmount_productListRow.setText(String.valueOf(list.get(position).getAmount()));
}
}
});
}
return view;
}
}
Hej Metehan,
your use case sounds perfect for a RecyclerView with a ListAdapter. You just submit a new list of products to the adapter and it will handle the updating and notifying for you.

Where to define Async class in a multi tab android project

I am working on an android project with three tabs (3 tabs are created using Fragment class).
I created one Async inner class in Mainactivity and calling that class from onCreate(), but nothing is happening in the Logcat. Can anyone suggest me Where to define Async class which is getting resource in JSON format. Any better way of doing this thing is also welcome.
package com.utb.iftekhar.cityweatherappsnapshot1;
public class Tab2Fragment extends Fragment {
private static final String TAG="Tab2Fragment";
private Button button;
private static final String CITY_NAME_SEARCHED="cityNameSearched";
private List<String> historyList;
private ListView historyListView;
private ArrayAdapter<String> arrayAdapter;
String cityNameSearched="";
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View view=inflater.inflate(R.layout.tab2_frag, container, false);
historyListView=view.findViewById(R.id.historyList);
historyList=new ArrayList<>();
if(getArguments()!=null){
cityNameSearched=getArguments().getString(CITY_NAME_SEARCHED);//Not able to set values to the ctiNameSearched variable.
}else
{
Log.i("No","Arguments");//
}
if(!(cityNameSearched==null) || !cityNameSearched.equals("")){
historyList.add(cityNameSearched);
Log.i("before", cityNameSearched);
Log.i("Value in tab2frag",cityNameSearched);
}
return view;
}
//This method is returning the searched city name searched int the edit text from fragment(Tab1Fragment) but not able to access this value in cityNameSearched variable.
public void updateEditText(String newText){
Log.i("received from 1 in 2",newText);
this.cityNameSearched=newText;
}
/*
#Override
public void onAttach(Context context) {
super.onAttach(context);
if(context instanceof Tab2FragmentListener){
tab2FragmentListener=(Tab2FragmentListener)context;
}else{
throw new RuntimeException(context.toString()+
" must implement Tab2FragmentListener"
);
}
}
#Override
public void onDetach() {
super.onDetach();
tab2FragmentListener=null;
}*/
}
public class Tab1Fragment extends Fragment{
private String weatherResults;
private Tab1FragmentListener tab1FragmentListener;
private String cityNameSearched;
public interface Tab1FragmentListener{
void onInput1Set(String input);
}
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container,
#Nullable Bundle savedInstanceState) {
View view=inflater.inflate(R.layout.tab1_frag, container, false);
getWeatherButton=(Button)view.findViewById(R.id.getWeatherButton);
searchCityByName=(EditText)view.findViewById(R.id.searchCityByName);
weatherResultTextView=(TextView)view.findViewById(R.id.weatherResult);
mainActivity=new MainActivity();
getWeatherButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
downloadTask=new DownloadTask(new DownloadTask.AsyncResponse() {
#Override
public void processFinish(String output) {
if(!output.equals("")){
weatherResultTextView.setText(output);
}else{
weatherResultTextView.setText("");
}
}
});
cityNameSearched=searchCityByName.getText().toString().trim();
tab1FragmentListener.onInput1Set(cityNameSearched);
Log.i("CityNameSearched", cityNameSearched);
try {
String encodedCityName= URLEncoder.encode(cityNameSearched,"UTF-8" );
} catch (Exception e) {
e.printStackTrace();
}
downloadTask.execute("https://openweathermap.org/data/2.5/weather?q="+cityNameSearched+"&appid=b6907d289e10d714a6e88b30761fae22");
Log.i("Button Cliked","Clicked");
InputMethodManager mgr=(InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
mgr.hideSoftInputFromWindow(searchCityByName.getWindowToken(), 0);
}
});
return view;
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
if(context instanceof Tab1FragmentListener){
tab1FragmentListener=(Tab1FragmentListener)context;
}else{
throw new RuntimeException(context.toString()+
" must implement Tab1FragmentListener"
);
}
}
#Override
public void onDetach() {
super.onDetach();
tab1FragmentListener=null;
}
public void updateEditText(String newText){
searchCityByName.setText(newText);
}
}
public class MainActivity extends AppCompatActivity implements Tab1Fragment.Tab1FragmentListener {
private static final String TAG="MainActivity";
private SectionsPageAdapter mySectionPageAdapter;
private ViewPager viewPager;
private DataForTabs dataForTabs;
private Tab1Fragment tab1Fragment;
private Tab2Fragment tab2Fragment;
String input="";
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.d(TAG,"onCreate: Starting.");
tab1Fragment=new Tab1Fragment();
Log.i(" From 1 to main ", input);//No Log appears for this input variable
mySectionPageAdapter=new SectionsPageAdapter(getSupportFragmentManager());
//set up the ViewPager with the sections adaptor
viewPager=(ViewPager)findViewById(R.id.container);
setupViewPager(viewPager);
TabLayout tabLayout=(TabLayout)findViewById(R.id.tabs);
tabLayout.setupWithViewPager(viewPager);
}
public void setupViewPager(ViewPager viewPager){
SectionsPageAdapter adapter=new
SectionsPageAdapter(getSupportFragmentManager());
adapter.addFragment(new Tab1Fragment(),"Home");
adapter.addFragment(new Tab2Fragment(),"History");
adapter.addFragment(new Tab3Fragment(),"About");
viewPager.setAdapter(adapter);
}
#Override
public void onInput1Set(String input) {
tab2Fragment.updateEditText(input);
this.input=input;
}
}

Where to place EventBus.getDefault().unregister in BaseAdapter

Friends, I've spent enough time to find an answer to my question(here and on android's site) But no luck.
Here is the logic:
From DialogFragment upon finishing putting user's data he clicks OK button:
import de.greenrobot.event.EventBus;
...
public class AddDialogFragment extends DialogFragment implements
DialogInterface.OnClickListener {
...
public void onClick(DialogInterface dialog, int which) {
StringBuilder date = new StringBuilder(today.getText().subSequence(0,
today.getText().length()));
date = (date.toString().equals(getString(R.string.today))) ? new StringBuilder("20150104") : date;
int weight = 89;
String[] bsi = rb.getSelectedItems();
String[] gsi = rg.getSelectedItems();
DatabaseManipulation dm = new DatabaseManipulation(getActivity());
dm.run(date, weight, bsi, gsi);
dm.destroy();
DialogDataModel toSend = new DialogDataModel(weight, date.toString(), bsi, gsi);
/*
Context activity = getActivity();
if (activity instanceof WDActivity)
((WDActivity) activity).updateListItemFragment();
*/
EventBus.getDefault().post(new UpdateItemEvent(toSend));
Log.d(LOG_TAG, "send event");
Toast.makeText(getActivity(), R.string.saved_data, Toast.LENGTH_LONG).show();
}
...
Event is successfully sent to Adapter class which is registered for receiving this event:
...
import de.greenrobot.event.EventBus;
public class ItemsAdapter extends BaseAdapter implements ListAdapter {
private static final String LOG_TAG = "Logs";
private ArrayList<DialogDataModel> list = new ArrayList<DialogDataModel>();
private Context activity;
public ItemsAdapter (ArrayList<DialogDataModel> list, Context context) {
this.list = list;
this.activity = context;
registerEventBus();
}
#Override
public int getCount() {
return list.size();
}
#Override
public Object getItem(int pos) {
return list.get(pos);
}
#Override
public long getItemId(int pos) {
return pos;
//just return 0 if your list items do not have an Id variable.
}
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
View view = convertView;
if (view == null) {
LayoutInflater inflater = (LayoutInflater) activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view = inflater.inflate(R.layout.row_item, null);
}
DialogDataModel curData = list.get(position);
TextView itemDate = (TextView)view.findViewById(R.id.item_date);
itemDate.setText(curData.getDate());
TextView itemWeight = (TextView)view.findViewById(R.id.item_weight);
itemWeight.setText( Integer.toString(curData.getWeight()) );
TextView itemEvents = (TextView)view.findViewById(R.id.item_events);
itemEvents.setText(curData.getEventsShort());
//Handle buttons and add onClickListeners
ImageButton editBtn = (ImageButton)view.findViewById(R.id.item_edit_btn);
editBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (activity instanceof WDActivity)
((WDActivity) activity).AddNewData(v, list.get(position));
notifyDataSetChanged();
}
});
ImageButton deleteBtn = (ImageButton) view.findViewById(R.id.item_delete_btn);
deleteBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String date = list.get(position).getDate();
DatabaseManipulation dm = new DatabaseManipulation(activity);
dm.deleteItem(date);
dm.destroy();
list.remove(position);
notifyDataSetChanged();
}
});
return view;
}
public void registerEventBus(){
if (!EventBus.getDefault().isRegistered(this)) EventBus.getDefault().register(this);
Log.d(LOG_TAG, "Registred from adapter");
}
public void unregisterEventBus(){
EventBus.getDefault().unregister(this);
}
public void onEventMainThread(UpdateItemEvent event) {
Log.d(LOG_TAG, "Event fired!");
list = DialogDataModel.replaceFieldsInArray(list,event.getModel());
notifyDataSetChanged();
}
}
After clicking OK in dialog window the user sees the list of items and the item he's updated is up to date. Without this logic he sees the old version of this item item in the list and to refresh the list he needs to relaunch the app.
Yes, it's working with EventBus.
But as you can see here in the class there is no place for unregistering it from listening for UpdateItemEvent. Since there are no destructors in java(I don't believe that garbage collector should do this for me) I should handle this. Moreover the class registeres as listener in constructor (it happens several times, that's why you see this ugly if statement(if (!EventBus.getDefault().isRegistered(this))) You may ask me why not getting this adapter through Activity (there is the only one in the app) I tried building a chain AddDialogFragment -> WDActivity -> PlaceholderFragment -> ItemsAdapter
//AddDialogFragment
Context activity = getActivity();
if (activity instanceof WDActivity)
((WDActivity) activity).updateListItemFragment();
//WDActivity --beginTransaction().replace does not work here
...
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_wd);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
// Create the adapter that will return a fragment for each of the three
// primary sections of the activity.
mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager());
// Set up the ViewPager with the sections adapter.
mViewPager = (ViewPager) findViewById(R.id.container);
mViewPager.setAdapter(mSectionsPagerAdapter);
}
...
public void updateListItemFragment() {
android.support.v4.app.FragmentManager fragmentManager = getSupportFragmentManager();
android.support.v4.app.Fragment currentFragment = fragmentManager.findFragmentById(R.id.container);
if (currentFragment instanceof PlaceholderFragment && currentFragment != null) {
fragmentManager.beginTransaction().remove(currentFragment).commit();
fragmentManager.beginTransaction().add(R.id.container, currentFragment).commit();
((PlaceholderFragment)currentFragment).fillList();
}
//PlaceholderFragment
public class PlaceholderFragment extends Fragment {
private static final String LOG_TAG = "Logs";
private static final String ARG_SECTION_NUMBER = "section_number";
private ListView listViewItem;
public static PlaceholderFragment newInstance(int sectionNumber) {
PlaceholderFragment fragment = new PlaceholderFragment();
Bundle args = new Bundle();
args.putInt(ARG_SECTION_NUMBER, sectionNumber);
fragment.setArguments(args);
return fragment;
}
public PlaceholderFragment() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
if(getArguments().getInt(ARG_SECTION_NUMBER)==1)
return onCreateViewInputChart(inflater, container, savedInstanceState);
if(getArguments().getInt(ARG_SECTION_NUMBER)==2)
return onCreateViewManual(inflater, container, savedInstanceState);
return onCreateViewInputData(inflater, container, savedInstanceState);
}
private View onCreateViewManual(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_howto, container, false);
return rootView;
}
private View onCreateViewInputData(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_list_data, container, false);
findViewsByIdListItem(rootView);
fillList();
return rootView;
}
private View onCreateViewInputChart(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_chart, container, false);
return rootView;
}
//listViewItems
private void findViewsByIdListItem(View v) {
listViewItem = (ListView) v.findViewById(R.id.listViewItems);
}
public void fillList(){
Context activity = getActivity();
DatabaseManipulation dm = new DatabaseManipulation(activity);
ArrayList<DialogDataModel> aldm = dm.getItemsList();
dm.destroy();
ItemsAdapter innerAdapter = new ItemsAdapter(aldm, activity);
listViewItem.setAdapter(innerAdapter);
( (BaseAdapter) listViewItem.getAdapter() ).notifyDataSetChanged();
}
#Override
public void onAttach(Context activity) {
super.onAttach(activity);
}
#Override
public void onDetach(){
super.onDetach();
}
}
//SectionsPagerAdapter - just for your information
public class SectionsPagerAdapter extends FragmentPagerAdapter {
public SectionsPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
// getItem is called to instantiate the fragment for the given page.
return PlaceholderFragment.newInstance(position);
}
#Override
public int getCount() {
return 3;
}
#Override
public CharSequence getPageTitle(int position) {
switch (position) {
case 0:
return "Enter your data";
case 1:
return "Chart";
case 2:
return "How to use it";
}
return null;
}
}
//ItemsAdapter is placed higher
This did not work. Finally I found out that the bottleneck is in linking PlaceholderFragment and ListAdapter: listViewItem is null everywhere except onCreateViewInputData. I could not figure out why. Google didn't give me the answer and I took it as a magic. Btw due to this feature I cannot use PlaceholderFragment's onAttach and onDetach for saying ItemsAdapter to register/unregister for receiving the event. This:
#Override
public void onAttach(Context activity) {
super.onAttach(activity);
( (ItemsAdapter) listViewItem.getAdapter() ).registerEventBus();
}
doesn't work for the same reason listViewItem is null. Maybe there is some way to manage with this more accurately?
Finally I cope with this: the bottleneck is in linking PlaceholderFragment and ListAdapter: listViewItem is null everywhere except onCreateViewInputData . Below is rewised SectionsPagerAdapter:
public class SectionsPagerAdapter extends FragmentPagerAdapter {
Context activity;
SparseArray<Fragment> registeredFragments = new SparseArray<Fragment>();
public SectionsPagerAdapter(FragmentManager fm, Context activity) {
super(fm);
this.activity = activity;
}
#Override
public Fragment getItem(int position) {
// getItem is called to instantiate the fragment for the given page.
return PlaceholderFragment.newInstance(position);
}
#Override
public int getCount() {
return 3;
}
#Override
public CharSequence getPageTitle(int position) {
switch (position) {
case 0:
return activity.getString(R.string.chart);
case 1:
return activity.getString(R.string.weight_diary);
case 2:
return activity.getString(R.string.how_to);
}
return null;
}
#Override
public Object instantiateItem(ViewGroup container, int position) {
Fragment fragment = (Fragment) super.instantiateItem(container, position);
registeredFragments.put(position, fragment);
return fragment;
}
#Override
public void destroyItem(ViewGroup container, int position, Object object) {
registeredFragments.remove(position);
super.destroyItem(container, position, object);
}
public Fragment getRegisteredFragment(int position) {
return registeredFragments.get(position);
//maybe use adapater.getRegisteredFragment(viewPager.getCurrentItem());
}
}
and here is my call to the widget in the one of 3 fragments:
public void updateListItemFragment() {
android.support.v4.app.Fragment inputData = mSectionsPagerAdapter.getRegisteredFragment(1);
ListView lv = ((PlaceholderFragment)inputData).listViewItem;
//for test purposes I refill listview with no items - here you need to hand filled BaseAdapter instance: CustomAdapter innerAdapter = new CustomAdapter(ArrayList<yourDataModel>, getContext());
lv.setAdapter(null);
}
And as you've may already wondered there is no need for event bus anymore. Btw if the fragment is not crated yet you need to check it: details are here. Thanks to CommonsWare for quik reply and advice.

View Pager Android

I'm trying to implement a View Pager from : http://developer.android.com/training/animation/screen-slide.html
But I seem to have a problem when it comes to creating the page number. When debugging the downloaded zip from the previous mentioned website, first method called is create(int pageNumber) and afterwards onCreate() where you're getting the page number. In my case, it's the other way around, therefore I get a null pointer exception.
Here is my current implementation of the View Pager:
public class SingleCheckInDisplay extends android.support.v4.app.Fragment {
private Checkin data;
private FragmentManager fragmentManager;
private List<CheckinUser> enlooped;
private TextView checkInLocation;
private TextView checkInDescription;
private TextView checkInTime;
private Button cancelBtn;
private ImageButton singleCheckInEnloopBtn;
private ImageButton singleCheckInCancelBtn;
private HorizontalListView enloopedFriends;
public static final String ARG_PAGE = "page";
private int mPageNumber;
public static SingleCheckInDisplay create(int pageNumber) {
SingleCheckInDisplay fragment = new SingleCheckInDisplay();
Bundle args = new Bundle();
args.putInt(ARG_PAGE, pageNumber);
fragment.setArguments(args);
return fragment;
}
public SingleCheckInDisplay(Checkin data) {
this.data = data;
}
public SingleCheckInDisplay() {
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mPageNumber = 2;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_single_check_in_display, container, false);
enlooped = data.getCheckinUsers();
fragmentManager = getActivity().getSupportFragmentManager();
ImageView main_pic = (ImageView) v.findViewById(R.id.main_pic);
checkInLocation = (TextView) v.findViewById(R.id.single_check_in_location);
checkInDescription = (TextView) v.findViewById(R.id.single_check_in_desc);
checkInTime = (TextView) v.findViewById(R.id.single_check_in_time_text);
checkInTime.setText(data.getCheckinDate().toString());
enloopedFriends = (HorizontalListView) v.findViewById(R.id.sinlge_check_in_enlooped_list);
DisplayImageOptions options = new DisplayImageOptions.Builder()
.showImageOnLoading(R.drawable.sm_profile)
.showImageForEmptyUri(R.drawable.sm_profile)
.showImageOnFail(R.drawable.sm_profile)
.cacheOnDisk(true)
.cacheInMemory(true)
.imageScaleType(ImageScaleType.EXACTLY)
.considerExifParams(true)
.displayer(new SimpleBitmapDisplayer())
.build();
ImageLoader.getInstance().displayImage(data.getImages(), main_pic, options);
checkInDescription.setText(data.getDescription());
checkInLocation.setText(data.getPlaceAddressAndName());
checkInLocation.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// Set a bundle with place ID, the rest will be obtained by calling Graph API
Bundle args = new Bundle();
args.putString("placeID", data.getPlaceId());
SingleCheckInPlace scp = new SingleCheckInPlace();
scp.setArguments(args);
FragmentManager fm = getActivity().getSupportFragmentManager();
fm.beginTransaction().replace(R.id.container, scp).addToBackStack(null).commit();
}
});
SingleCheckInAdapter adapter = new SingleCheckInAdapter(getActivity(), enlooped);
enloopedFriends.setAdapter(adapter);
cancelBtn = (Button) v.findViewById(R.id.single_ck_display_cancel_button);
cancelBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
MapsFilterFragment firstFragment = new MapsFilterFragment();
fragmentManager.beginTransaction().add(R.id.container, firstFragment).commit();
}
});
singleCheckInEnloopBtn = (ImageButton) v.findViewById(R.id.single_check_in_enloop_btn);
singleCheckInEnloopBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(getActivity(), "Enlooped !", Toast.LENGTH_SHORT).show();
fragmentManager.popBackStack();
}
});
singleCheckInCancelBtn = (ImageButton) v.findViewById(R.id.single_check_in_no_btn);
singleCheckInCancelBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(getActivity(), "Maybe next time", Toast.LENGTH_SHORT).show();
goBack();
}
});
return v;
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
}
#Override
public void onDetach() {
super.onDetach();
}
private void goBack() {
fragmentManager.popBackStack();
}
public int getPageNumber() {
return mPageNumber;
}
}
And here is the miplementation of the Pager itself:
public class ScreenSlideFragment extends android.support.v4.app.Fragment {
private ViewPager mPager;
private PagerAdapter mPagerAdapter;
private static final int NUM_PAGES = 11;
public ScreenSlideFragment() {
// Required empty public constructor
}
#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_screen_slide, container, false);
mPager = (ViewPager) view.findViewById(R.id.pager);
mPagerAdapter = new ScreenSlidePagerAdapter(getFragmentManager());
mPager.setAdapter(mPagerAdapter);
return view;
}
private class ScreenSlidePagerAdapter extends FragmentStatePagerAdapter {
public ScreenSlidePagerAdapter(android.support.v4.app.FragmentManager fm) {
super(fm);
}
#Override
public android.support.v4.app.Fragment getItem(int position) {
return SingleCheckInDisplay.create(position);
}
#Override
public int getCount() {
return NUM_PAGES;
}
}
}
DO like this
ViewPager mviewPager=(ViewPage)findViewById(R.id.urcontainer);
mviewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
#Override
public void OnPageSelected(int position) {
int page_number=position; //this will give u the current page number
}
});
`

FragmentTabHost with own fragment stack for each tab

I have MainActivity which has FragmentTabHost with several tabs. Each fragment in tab can be replaced with another fragment, so if we navigate back, we will see first displayed fragment for this tab (own stack for each tab). I have a quite working solution.
The below example demonstrates TabHost with 2 tabs and fragment classes for the first tab.
Is there any simpler, better or more elegant way to achieve this result?
AbstractPrimaryFragment.java. This class is a root fragment class that replaces fragments inside it. Other tab fragment classes can extend this superclass.
public abstract class AbstractPrimaryFragment extends Fragment {
// Simple framelayout.
private static final int RES_ID = R.layout.primary_fragment_layout;
protected static final int CONTENT_LAYOUT_ID = R.id.primary_fragment_layout;
protected Fragment mActiveFragment;
public AbstractPrimaryFragment()
{
setRetainInstance(true);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
return inflater.inflate(RES_ID, container, false);
}
#Override
public void onActivityCreated(Bundle savedInstanceState)
{
super.onActivityCreated(savedInstanceState);
// Check if active fragment is in layout, if not, make default fragment for this tab.
mActiveFragment = getChildFragmentManager().findFragmentById(CONTENT_LAYOUT_ID);
if (mActiveFragment == null)
{
mActiveFragment = makeDefaultActiveFragment();
String tag = getDefaultFragmentTag();
getChildFragmentManager().beginTransaction().add(CONTENT_LAYOUT_ID, mActiveFragment, tag).commit();
}
}
public boolean onBackPressed()
{
boolean backPressed = false;
final FragmentManager fragmentManager = getChildFragmentManager();
if (fragmentManager.getBackStackEntryCount() > 0)
{
fragmentManager.addOnBackStackChangedListener(new OnBackStackChangedListener()
{
#Override
public void onBackStackChanged()
{
mActiveFragment = fragmentManager.findFragmentById(CONTENT_LAYOUT_ID);
fragmentManager.removeOnBackStackChangedListener(this);
}
});
fragmentManager.popBackStack();
backPressed = true;
}
return backPressed;
}
protected abstract Fragment makeDefaultActiveFragment();
protected abstract String getDefaultFragmentTag(); }
Tab1PrimaryFragment.java
public class Tab1PrimaryFragment extends AbstractPrimaryFragment implements OnTab1Fragment1Listener {
private static final String FRAGMENT1_TAG = "tab1_fragment1";
private static final String FRAGMENT2_TAG = "tab2_fragment2";
#Override
protected Fragment makeDefaultActiveFragment()
{
return new Tab1Fragment1();
}
#Override
protected String getDefaultFragmentTag()
{
return FRAGMENT1_TAG;
}
#Override
public void onTab1Fragment1ButtonClick(Tab1Fragment1 tab1Fragment1)
{
Tab1Fragment2 tab1Fragment2 = new Tab1Fragment2();
getChildFragmentManager().beginTransaction().replace(CONTENT_LAYOUT_ID, tab1Fragment2, FRAGMENT2_TAG).addToBackStack(tab1Fragment1.getTag()).commit();
mActiveFragment = tab1Fragment2;
}}
Tab1Fragment1.class (default active fragment)
public class Tab1Fragment1 extends Fragment {
public interface OnTab1Fragment1Listener
{
public void onTab1Fragment1ButtonClick(Tab1Fragment1 tab1Fragment1);
}
private OnTab1Fragment1Listener mOnTab1Fragment1Listener;
public void setOnTab1Fragment1Listener(OnTab1Fragment1Listener onTab1Fragment1Listener)
{
mOnTab1Fragment1Listener = onTab1Fragment1Listener;
}
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
Fragment parentFragment = getParentFragment();
if (parentFragment != null && parentFragment instanceof OnTab1Fragment1Listener)
{
mOnTab1Fragment1Listener = (OnTab1Fragment1Listener) parentFragment;
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
Button button = new Button(getActivity());
button.setOnClickListener(new OnClickListener()
{
#Override
public void onClick(View v)
{
if(mOnTab1Fragment1Listener != null)
{
mOnTab1Fragment1Listener.onTab1Fragment1ButtonClick(Tab1Fragment1.this);
}
}
});
return button; }}
Tab1Fragment2.java. Dummy fragment. This fragment is displayed when onTab1Fragment1ButtonClick is called.
public class Tab1Fragment2 extends Fragment {}
And MainActivity.java
public class MainActivity extends FragmentActivity {
private static final int RES_ID = R.layout.main_activity;
private static final int TAB_CONTENT_ID = android.R.id.tabcontent;
private static final int TABHOST_ID = android.R.id.tabhost;
private static final String TAB1_PRIMARY_FRAGMENT_TAG = "tab1_primary_fragment";
private static final String TAB2_PRIMARY_FRAGMENT_TAG = "tab2_primary_fragment"
private FragmentTabHost mTabHost;
#Override
protected void onCreate(Bundle bundle)
{
super.onCreate(bundle);
setContentView(RES_ID);
initializeTabHost();
}
private void initializeTabHost()
{
mTabHost = (FragmentTabHost) findViewById(TABHOST_ID);
mTabHost.setup(this, getSupportFragmentManager(), TAB_CONTENT_ID);
LayoutInflater inflater = LayoutInflater.from(this);
mTabHost.addTab(mTabHost.newTabSpec(TAB1_PRIMARY_FRAGMENT_TAG).setIndicator(inflater.inflate(R.layout.smth1, null)), Tab1PrimaryFragment.class, null);
mTabHost.addTab(mTabHost.newTabSpec(TAB2_PRIMARY_FRAGMENT_TAG).setIndicator(inflater.inflate(R.layout.smth2, null)), Tab2PrimaryFragment.class, null);
}
#Override
public void onBackPressed()
{
Fragment fragment = getSupportFragmentManager().findFragmentById(TAB_CONTENT_ID);
if (fragment != null && fragment instanceof AbstractPrimaryFragment)
{
if (((AbstractPrimaryFragment) fragment).onBackPressed())
{
return;
}
}
super.onBackPressed();
}}

Categories

Resources