I have navigation drawer used to navigate through my application.
When I switch to fragment with ViewPagers containing three ListViews, everything is displayed normally.
The problem appears when I switch to another fragment, and then go back to my ListViews. Everything is empty.
Video with a problem:
https://youtu.be/hsZAGaAG_vs
Code of my Fragment containing ViewPagers:
public class PlayerListFragment extends Fragment {
private class RolePagerAdapter extends FragmentPagerAdapter {
public RolePagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
switch (position) {
case 0:
return new SniperFragment();
case 1:
return new RiflerFragment();
case 2:
return new IglFragment();
}
return null;
}
#Override
public int getCount() { // 3 pages
return 3;
}
#Nullable
#Override
public CharSequence getPageTitle(int position) {
switch (position) {
case 0:
return getActivity().getResources().getText(R.string.sniper_tab);
case 1:
return getActivity().getResources().getText(R.string.riflers_tab);
case 2:
return getActivity().getResources().getText(R.string.igls_tab);
}
return null;
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_player_list, container, false);
}
#Override
public void onStart() {
super.onStart();
// setup viewpager
RolePagerAdapter adapter = new RolePagerAdapter(getActivity().getSupportFragmentManager());
ViewPager pager = getActivity().findViewById(R.id.pager);
pager.setAdapter(adapter);
// setup tablayout
TabLayout tabLayout = getActivity().findViewById(R.id.tabs);
tabLayout.setupWithViewPager(pager);
// hide default toolbar and set new
((AppCompatActivity)getActivity()).getSupportActionBar().hide();
Toolbar listToolbar = getActivity().findViewById(R.id.player_list_toolbar);
((AppCompatActivity) getActivity()).setSupportActionBar(listToolbar);
DrawerLayout drawerLayout = getActivity().findViewById(R.id.drawer_layout);
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
getActivity(),
drawerLayout,
listToolbar,
R.string.nav_open_drawer,
R.string.nav_close_drawer);
drawerLayout.addDrawerListener(toggle);
toggle.syncState();
}
Code of my fragment containing listview:
public class SniperFragment extends AbstractRoleListFragment {
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
return super.onCreateView(inflater, container, savedInstanceState);
}
#Override
public void onResume() {
super.onResume();
new SetupAdapterTask().execute(Role.Sniper);
}
}
Code of parent class of that fragment:
public abstract class AbstractRoleListFragment extends ListFragment {
SQLiteDatabase db;
Cursor cursor;
protected class SetupAdapterTask extends AsyncTask<Role, Void, SimpleCursorAdapter> {
#Override
protected SimpleCursorAdapter doInBackground(Role... role) {
SQLiteOpenHelper helper = new MyDatabaseHelper(getActivity());
try {
db = helper.getReadableDatabase();
cursor = db.query("PLAYERS",
new String[]{"_id", "NAME"}, "ROLE = ?",
new String[]{role[0].toString()},
null, null, null);
return new SimpleCursorAdapter(getActivity(),
android.R.layout.simple_list_item_1,
cursor,
new String[]{"NAME"},
new int[] {android.R.id.text1},
0);
} catch (SQLiteException e) {
Log.e("ERR", "Error while setting up adapter in SniperFragment", e);
return null;
}
}
#Override
protected void onPostExecute(SimpleCursorAdapter adapter) {
if (adapter != null) {
setListAdapter(adapter);
} else {
Toast.makeText(getActivity(), "Database unavailable", Toast.LENGTH_SHORT)
.show();
}
}
}
#Override
public void onDestroy() {
super.onDestroy();
cursor.close();
db.close();
}
}
I tried to change code filling my listview with data to another method like onResume, onStart but none worked
Related
I am calling ViewPager(Fragment C) from a ListView(Fragment A). But this only works once. If I move back to my list and select another item , it doesnot move into the listview. It just shows a blank layout of fragment c.
Below is the code for Fragment A:
public class FragmentA extends Fragment implements AdapterView.OnItemClickListener{
ListView list;
Communicator communicator;
ArrayList<Book> book_a;
ArrayList<String> book_titles;
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View view= inflater.inflate(R.layout.fragment_a,container,false);
savedInstanceState = getArguments();
if (getArguments() != null) {
// savedInstanceState = getArguments();
book_a = (ArrayList<Book>) getArguments().getSerializable("bookarray");
book_titles = getList(book_a);
//Log.d("Frag_a:Title",book_a.get(5).getTitle());
list= (ListView) view.findViewById(R.id.listview);
ArrayAdapter<String> adapter = new ArrayAdapter<String>(getActivity(),android.R.layout.simple_list_item_1,book_titles);
list.setAdapter(adapter);
list.setOnItemClickListener(this);
}
return view;
}
public ArrayList<String> getList(ArrayList<Book> book2){
ArrayList<String> list_titles = new ArrayList<String>();
int size = book2.size();
for(int i=0;i<size;i++){
Book object;
object = book2.get(i);
list_titles.add(object.title);
}
return list_titles;
}
public void setCommunicator(Communicator communicator)
{
this.communicator = communicator;
}
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
communicator.respond(position);
}
public interface Communicator{
public void respond(int index);
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
if(context instanceof Communicator){
communicator = (Communicator) context;
} else {
throw new RuntimeException(context.toString()+"must implement Communicator");
}
}
#Override
public void onDetach() {
super.onDetach();
communicator = null;
}
}
Below is the code for MainActivity:
public class MainActivity extends AppCompatActivity implements FragmentA.Communicator{
FragmentB f2;
ArrayList<Book> b = new ArrayList<Book>();
FragmentManager manager;
static int flag = 0;
static String search="great";
SearchView sv ;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
sv = (SearchView) findViewById(R.id.searchView);
sv.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
#Override
public boolean onQueryTextSubmit(String query) {
flag = 1;
search = query;
getBooks();
return false;
}
#Override
public boolean onQueryTextChange(String newText) {
getBooks();
return false;
}
});
getBooks();
/*
manager = getSupportFragmentManager();
f1 = (FragmentA) manager.findFragmentById(R.id.fragment);
f1.setCommunicator(this);*/
}
#Override
public void respond(int index) {
f2 = (FragmentB) manager.findFragmentById(R.id.fragment2);
if(f2!=null && f2.isVisible())
{
f2.changeData(index);
}
else
{
Bundle bundle = new Bundle();
bundle.putInt("index", index);
bundle.putSerializable("bookarray",(ArrayList<Book>)b);
Fragment newFragment = new FragmentC();
newFragment.setArguments(bundle);
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.fragment, newFragment);
transaction.addToBackStack(null);
transaction.commit();
}
}
public void afterGetBooks(ArrayList<Book> bks) {
for (Book h : bks) {
b.add(h);
}
manager = getSupportFragmentManager();
Bundle args = new Bundle();
args.putSerializable("bookarray",(ArrayList<Book>)bks);
FragmentA f1 = new FragmentA();
f1.setArguments(args);
FragmentTransaction transaction = manager.beginTransaction();
transaction.replace(R.id.fragment,f1);
transaction.addToBackStack(null);
transaction.commit();
f1.setCommunicator(this);
}
private void getBooks(){
String url;
if(flag==0){
url = "https://kamorris.com/lab/audlib/booksearch.php/";}
else{
url = "https://kamorris.com/lab/audlib/booksearch.php?search=" + search;
flag=0;
}
//ArrayList<Book> boo;
Retrofit retrofit = new Retrofit.Builder().baseUrl("https://kamorris.com/lab/audlib/booksearch.php/").addConverterFactory(GsonConverterFactory.create()).build();
Book.API api = retrofit.create(Book.API.class);
Call<ArrayList<Book>> call = api.getBooks(url);
call.enqueue(new Callback<ArrayList<Book>>() {
#Override
public void onResponse(Call<ArrayList<Book>> call, Response<ArrayList<Book>> response) {
ArrayList<Book> Books = response.body();
for(Book h: Books){
Log.d("Retro-Title",h.getTitle());
//b.add(h);
}
afterGetBooks(Books);
}
#Override
public void onFailure(Call<ArrayList<Book>> call, Throwable t) {
Toast.makeText(getApplicationContext(),t.getMessage(),Toast.LENGTH_SHORT).show();
}
});
}
Below is the code for Fragment C:
public class FragmentC extends Fragment {
ViewPager vp;
static int list_pos;
FragmentPagerAdapter adapterViewPager;
public static ArrayList<Book> book_c;
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_c,container,false);
if(getArguments()!= null){
book_c = (ArrayList<Book>) getArguments().getSerializable("bookarray");
list_pos = getArguments().getInt("index");
}
vp = (ViewPager) view.findViewById(R.id.viewpager);
adapterViewPager = new MyPagerAdapter(getFragmentManager());
vp.setAdapter(adapterViewPager);
return view;
}
public static class MyPagerAdapter extends FragmentPagerAdapter {
private static int NUM_ITEMS = 11;
public MyPagerAdapter(FragmentManager fragmentManager) {
super(fragmentManager);
}
// Returns total number of pages
#Override
public int getCount() {
return NUM_ITEMS;
}
// Returns the fragment to display for that page
#Override
public Fragment getItem(int position) {
switch (list_pos) {
case 0: // Fragment # 0 - This will show FirstFragment
list_pos = position;
return FragmentB.newInstance(book_c,0);
case 1: // Fragment # 0 - This will show FirstFragment different title
list_pos = position;
return FragmentB.newInstance(book_c,1);
case 2: // Fragment # 1 - This will show SecondFragment
list_pos = position;
return FragmentB.newInstance(book_c,2);
case 3: list_pos = position;
return FragmentB.newInstance(book_c,3);
case 4:list_pos = position;
return FragmentB.newInstance(book_c,4);
case 5:list_pos = position;
return FragmentB.newInstance(book_c,5);
case 6:list_pos = position;
return FragmentB.newInstance(book_c,6);
case 7:list_pos = position;
return FragmentB.newInstance(book_c,7);
case 8:list_pos = position;
return FragmentB.newInstance(book_c,8);
case 9:list_pos = position;
return FragmentB.newInstance(book_c,9);
default:
return null;
}
}
// Returns the page title for the top indicator
#Override
public CharSequence getPageTitle(int position) {
return "Page " + position;
}
}
}
Also is there a way, where I can start my viewpager from the description of the listitem which I selected.
Also Fragment B is just a text view holder.
I tried to see the control flow with the debugger. But when I try it that way these lines in Fragment C are not working ..
{
book_c = (ArrayList<Book>) getArguments().getSerializable("bookarray");
list_pos = getArguments().getInt("index");
}
vp = (ViewPager) view.findViewById(R.id.viewpager);
adapterViewPager = new MyPagerAdapter(getFragmentManager());
vp.setAdapter(adapterViewPager);
Your fragment has not been destroyed and therefore when it is brought back, onCreateView is not being called. Instead override setUserVisibleHint.
#Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
if (isVisibleToUser) {
// This is true when your fragment is visible, write code to populate view here
} else {
// This is true when your fragment is hidden.
}
}
The solution i found is to change the Fragment Manager
adapterViewPager = new MyPagerAdapter(getFragmentManager());
to
adapterViewPager = new MyPagerAdapter(getChildFragmentManager());
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.
I have a App with a Slidingmenu where i can pick different Fragment, which displays different kind of ListFragments.
The ListFragments will be filled by JSON from my Database Server.
If you Click on one of the Listitems, a new Fragment is shown which contains more Details about the selected Listitem.
public void updateList(final Activity a, final ListFragment L) {
adapter = new SimpleAdapter(a, mCommentList,
R.layout.single_comment, new String[] {TAG_PIC_ID,TAG_CATEGORY, TAG_ACTIVITY, TAG_DATUM, TAG_AKTUSR, TAG_MAXUSR, TAG_GENDER, /*TAG_POST_ID,*/ TAG_TITLE, TAG_MESSAGE,
TAG_USERNAME }, new int[] { R.id.imgrow, R.id.category, R.id.activity/*R.id.id*/ , R.id.datum, R.id.aktusr, R.id.maxusr, R.id.gender, /*R.id.category,*/ R.id.title, R.id.message,
R.id.username });
L.setListAdapter(adapter);
ListView lv = L.getListView();
lv.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
int intid = (int)id;
Details nextFrag= new Details();
L.getFragmentManager().beginTransaction()
.replace(R.id.frame_container, nextFrag, "Test")
.addToBackStack(null)
.commit();
}
});
}
When i call the function from a "single" fragment its no problem and the DetailPage is shown.
The Problem is when i call the function from a TabbedActivity with a SectionsPagerAdapter.
The TabbedActivity
package info.androidhive.slidingmenu;
public class TabbedActivity extends Fragment {
SectionsPagerAdapter mSectionsPagerAdapter;
public static final String TAG = TabbedActivity.class.getSimpleName();
ViewPager mViewPager;
public static TabbedActivity newInstance() {
return new TabbedActivity();
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.activity_item_one, container, false);
mSectionsPagerAdapter = new SectionsPagerAdapter(
getChildFragmentManager());
mViewPager = (ViewPager) v.findViewById(R.id.pager);
mViewPager.setAdapter(mSectionsPagerAdapter);
return v;
}
public class SectionsPagerAdapter extends FragmentPagerAdapter {
public SectionsPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
Fragment fragment = new newEntrys();
switch (position) {
case 0:
fragment = new newEntrys();
break;
case 1:
fragment = new oldEntrys();
break;
default:
break;
}
return fragment;
}
#Override
public int getCount() {
return 2;
}
#Override
public CharSequence getPageTitle(int position) {
Locale l = Locale.getDefault();
switch (position) {
case 0:
return "Aktuelle Einträge";
case 1:
return "Vergangene Einträge";
}
return null;
}
}}
The TabbedActivity contains the 2 Fragments newEntry and oldEntry which are nearly equal.
package info.androidhive.slidingmenu.fragments;
public class RegisterdEvents_new extends ListFragment{
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.read, container, false);
return rootView;
}
public void startTask(){
Read SO = new Read();
Load LEvt = SO.new Load(getActivity(), this, "NEW");
LEvt.execute();
}
public void onResume() {
startTask();
super.onResume();
}
}
So the function updateList above is called in
Load LEvt = SO.new Load(getActivity(), this, "NEW");
But the problem is that i always get the Error
No view found for id 0x7f0a000f (package:id/frame_container) for fragment Details{e3992e2 #0 id=0x7f0a000f Test}
Someone of you can help me to solve this problem?
This tutorial refers to the communicating between fragments but doesn't do it for tabs. I want to send data between from my "Daycare" fragment which is a tab to my "You" fragment which is also a tab. I've been stuck for a week on this. I don't really know how to combine the concept of interfaces with android tabbed fragments and data from asynctasks.
I have created an interface in my Daycare fragment. I want to send the String "daycarename" to the "you" fragment with the help of the "passparam" method. From what I understood it needs to somehow pass through the MainActivity which implements my TabClickedListener interface. How do I pass it from the MainActivity back to the other fragment?
public class MainActivity extends Activity implements ActionBar.TabListener, DaycareFragment.TabClickedListener {
SectionsPagerAdapter mSectionsPagerAdapter;
ViewPager mViewPager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final ActionBar actionBar = getActionBar();
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
mSectionsPagerAdapter = new SectionsPagerAdapter(getFragmentManager(), this);
mViewPager = (ViewPager) findViewById(R.id.pager);
mViewPager.setAdapter(mSectionsPagerAdapter);
mViewPager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
#Override
public void onPageSelected(int position) {
actionBar.setSelectedNavigationItem(position);
}
});
for (int i = 0; i < mSectionsPagerAdapter.getCount(); i++) {
actionBar.addTab(
actionBar.newTab()
.setText(mSectionsPagerAdapter.getPageTitle(i))
.setTabListener(this));
}
}
#Override
public void onTabSelected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
mViewPager.setCurrentItem(tab.getPosition());
}
public class SectionsPagerAdapter extends FragmentPagerAdapter {
public SectionsPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
switch (position) {
case 0:
return new YouFragment();
case 1:
return new DaycareFragment();
case 2:
return new ThirdFragment();
}
return null;
}
#Override
public int getCount() {
// Show 3 total pages.
return 3;
}
#Override
public CharSequence getPageTitle(int position) {
Locale l = Locale.getDefault();
switch (position) {
case 0:
return getString(R.string.title_section3).toUpperCase(l);
case 1:
return getString(R.string.title_section1).toUpperCase(l);
case 2:
return getString(R.string.title_section2).toUpperCase(l);
}
return null;
}
}
public class MainFragment extends Fragment {
private static final String ARG_SECTION_TYPE = "section type";
public MainFragment(){}
public MainFragment(int sectionNumber) {
Bundle args = new Bundle();
args.putInt(ARG_SECTION_TYPE, sectionNumber);
setArguments(args);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_main, container, false);
//setup the view
switch(getArguments().getInt(ARG_SECTION_TYPE)) {
//hide or show fields based on page number.
}
return rootView;
}
}
#Override
public void passParam(String var) {
Toast.makeText(this, "Clicked " + var, Toast.LENGTH_LONG).show();
}
}
I am implementing an interface in my ListFragment:
public class DaycareFragment extends ListFragment {
TabClickedListener listener;
public interface TabClickedListener {
public void passParam(String var);
}
String email;
UserFunctions userFunctions;
Boolean owner;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_daycare, container, false);
movies = new ArrayList<HashMap<String, String>>();
userFunctions = new UserFunctions();
HashMap map = new HashMap();
map = userFunctions.getdauser(getActivity());
email = (String) map.get("email");
new GetDaDaycares().execute();
return rootView;
}
class GetDaDaycares extends AsyncTask<String, String, String>{
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected String doInBackground(String... args) {
String city = "london";
try {
List<NameValuePair> params = new ArrayList<NameValuePair> ();
params.add(new BasicNameValuePair("city", city));
#SuppressWarnings("unused")
JSONObject json = parser.makeHttpRequest(getdaycare, params);
jArray = json.getJSONArray("lTable");
for (int i =0; i<jArray.length();i++){
JSONObject c = jArray.getJSONObject(i);
String daycarename = c.getString("daycarename");
HashMap<String, String> map = new HashMap<String, String>();
map.put("daycarename", daycarename);
movies.add(map);
}
} catch(JSONException e) {
e.printStackTrace();
}
return null;
}
protected void onPostExecute(String zoom){
pDialog.dismiss();
getActivity().runOnUiThread(new Runnable() {
public void run() {
ListAdapter adapter = new SimpleAdapter(getActivity(), movies,
R.layout.list, new String[] {"daycarename"},
new int[]{R.id.textView1});
setListAdapter(adapter);
ListView lv = getListView();
lv.setOnItemClickListener(new OnItemClickListener(){
#Override
public void onItemClick(AdapterView<?> parent, View view, int position,
long id) {
String daycarename =movies.get(position).get("daycarename");
}
});
}
});
}
}
}
If this was my problem (which it has been) I would have a central object that is in charge of 'sharing' data between the fragments.
The implementation usually seems to follow 1 of 2 paths: One, create a singleton that any object can get an instance of, or two, the activity initializes the single instance of an object and passes it to each fragment upon their initialization.
Fragments (or an AsyncTask) would then update and pull data from that central object via the Observer Pattern or on display, however you'd want.
p.s.
If you are going to have an AsyncTask in a fragment, you will want to implement a strategy for insuring your UI is not dead when it finishes. Otherwise you can throw an exception.
p.p.s
onPostExecute runs on the UI thread by default.
In your Activity:
public void passStrToYou(String daycarename)
{
FragmentManager fm = getFragmentManager();
Fragment youFrag = (YouFragment)fm.FragmentManager fm.findFragmentById(R.id.youFragment);
//call mathod 'setDayCareName' in 'you' fragment
youFrag.setDayCareName(daycarename);
}
Hope this help!
This is my page:
package[...]
import [...]
public class Home extends FragmentActivity {
ViewPager mViewPager;
ListView list;
row_video_Adapter adapter;
public Home CustomListView = null;
public ArrayList<ModelloLista> CustomListViewValuesArr = new ArrayList<ModelloLista>();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home);
// Create the adapter that will return a fragment for each of the three
// primary sections of the app.
mSectionsPagerAdapter = new SectionsPagerAdapter(
getSupportFragmentManager());
// Set up the ViewPager with the sections adapter.
mViewPager = (ViewPager) findViewById(R.id.pager);
mViewPager.setAdapter(mSectionsPagerAdapter);
// ListView
CustomListView = this;
/******** Take some data in Arraylist ( CustomListViewValuesArr ) ***********/
setListData();
Resources res =getResources();
list= (ListView)findViewById(R.id.section_label); // List defined in XML ( See Below )
/**************** Create Custom Adapter *********/
adapter=new row_video_Adapter(CustomListView, CustomListViewValuesArr,res);
list.setAdapter(adapter);
}
/****** Function to set data in ArrayList *************/
public void setListData(){
final ModelloLista sched = new ModelloLista();
sched.setTitolo("Video 1");
sched.setImmagine("video_preview");
sched.setUrl("http:\\www.com");
CustomListViewValuesArr.add(sched);
}
/***************** This function used by adapter ****************/
public void onItemClick(int mPosition){
ModelloLista tempValues = ( ModelloLista ) CustomListViewValuesArr.get(mPosition);
// SHOW ALERT
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.home, menu);
return true;
}
public class SectionsPagerAdapter extends FragmentPagerAdapter {
public SectionsPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
Fragment fragment = new DummySectionFragment();
Bundle args = new Bundle();
args.putInt(DummySectionFragment.ARG_SECTION_NUMBER, position + 1);
fragment.setArguments(args);
return fragment;
}
#Override
public int getCount() {
// Show 5 total pages.
return 5;
}
#Override
public CharSequence getPageTitle(int position) {
Locale l = Locale.getDefault();
switch (position) {
case 0:
return getString(R.string.title_section1).toUpperCase(l);
case 1:
[...]
}
return null;
}
}
public static class DummySectionFragment extends Fragment {
public static final String ARG_SECTION_NUMBER = "section_number";
public DummySectionFragment() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_home_dummy,
container, false);
//TextView dummyTextView = (TextView) rootView.findViewById(R.id.section_label);
switch(getArguments().getInt(ARG_SECTION_NUMBER)){
case 1:
//dummyTextView.setText("text 1");
break;
case 2:
[...]
}
return rootView;
}
}
}
How can I put my Custom ListView in a fragment?
I tried to move the code in the switch(getArguments().getInt(ARG_SECTION_NUMBER)){ but there were many errors.
What should I do?