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!
Related
I have a main activity which shows 3 fragments inside View Pagers with tabs.
mainActivity.java
public class mainActivity extends AppCompatActivity {
globalVariableActivity variable = new globalVariableActivity();
private APIService mAPIService;
private TextView mResponseTv;
private RecyclerView recyclerView;
private Token token = new Token("","","");
private Gson gson = new Gson();
private Context context=mainActivity.this;
private Toolbar toolbar;
private TabLayout tabLayout;
private ViewPager viewPager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//check if token is still active
String current_token=token.getToken(context);
MyFirebaseInstanceIDService Fcm= new MyFirebaseInstanceIDService();
Fcm.onTokenRefresh(context,current_token);
toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(false);
viewPager = (ViewPager) findViewById(R.id.viewpager);
setupViewPager(viewPager);
tabLayout = (TabLayout) findViewById(R.id.tabs);
tabLayout.setupWithViewPager(viewPager);
}
private void setupViewPager(ViewPager viewPager) {
ViewPagerAdapter adapter = new ViewPagerAdapter(getSupportFragmentManager());
adapter.addFragment(new BeritaFragment(), "Berita");
adapter.addFragment(new DiskusiFragment(), "Diskusi");
adapter.addFragment(new PesanFragment(), "Pesan");
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) {
//Toast.makeText(context,"Item " + position + " shown.", Toast.LENGTH_SHORT).show();
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) {
Toast.makeText(context,"Position : " + position + " Title : "+ mFragmentTitleList.get(position) + " shown.", Toast.LENGTH_SHORT).show();
return mFragmentTitleList.get(position);
}
}
interface LyfecycleListener {
void onCreatedView();
}
here's the first fragment code
beritaFragment.java
public class BeritaFragment extends Fragment {
// TODO: Rename parameter arguments, choose names that match
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
private APIService mAPIService = APIUtils.getAPIService();;
private Gson gson = new Gson();
private TextView createdAtText;
private TextView judulText;
private ImageView imageView;
private RecyclerView mRecyclerView;
private ListAdapter mListadapter;
private ArrayList<DataBerita> list_berita= new ArrayList<>();
private OnFragmentInteractionListener mListener;
public BeritaFragment() {
}
// TODO: Rename and change types and number of parameters
public static BeritaFragment newInstance(String param1, String param2) {
BeritaFragment fragment = new BeritaFragment();
return fragment;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getBeritaTask getBerita= new getBeritaTask();
try {
Log.d("berita :", "On create 1");
getBerita.execute().get(10000, TimeUnit.MILLISECONDS);
Log.d("berita :", "On create 2");
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_berita, container, false);
Log.d("Berita","On create view");
Toast.makeText(getActivity() ,"Berita Fragment onCreateView", Toast.LENGTH_SHORT).show();
ArrayList<DataBerita> data_berita;
mRecyclerView = (RecyclerView) view.findViewById(R.id.recycler_view);
judulText = (TextView)view.findViewById(R.id.summary_judul);
createdAtText = (TextView)view.findViewById(R.id.created_at);
//imageView = (ImageView)view.findViewById(R.id.gambar);
final LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity());
layoutManager.setOrientation(LinearLayoutManager.VERTICAL);
mRecyclerView.setLayoutManager(layoutManager);
//data_berita=getBeritaList();
Log.d("Berita","1");
Log.d("Berita List : ", list_berita.toString());
Log.d("Berita","3");
mListadapter = new ListAdapter(list_berita);
mRecyclerView.setAdapter(mListadapter);
//Log.d("Berita view :", view.toString());
return view;
}
public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
}
// TODO: Rename method, update argument and hook method into UI event
public void onButtonPressed(Uri uri) {
if (mListener != null) {
mListener.onFragmentInteraction(uri);
}
}
public interface OnFragmentInteractionListener {
// TODO: Update argument type and name
void onFragmentInteraction(Uri uri);
}
public class ListAdapter extends RecyclerView.Adapter<ListAdapter.ViewHolder>
{
private ArrayList<DataBerita> dataList;
public ListAdapter(ArrayList<DataBerita> data)
{
this.dataList = data;
}
public class ViewHolder extends RecyclerView.ViewHolder
{
TextView judulText;
TextView waktuText;
ImageView gambarView;
public ViewHolder(View itemView)
{
super(itemView);
this.judulText = (TextView) itemView.findViewById(R.id.summary_judul);
this.waktuText = (TextView) itemView.findViewById(R.id.created_at);
//this.gambarView = (ImageView) itemView.findViewById(R.id.gambar);
}
}
#Override
public ListAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType)
{
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.berita_list_layout, parent, false);
ViewHolder viewHolder = new ViewHolder(view);
return viewHolder;
}
#Override
public void onBindViewHolder(ListAdapter.ViewHolder holder, final int position)
{
Uri ImageURI=Uri.parse(dataList.get(position).getGambar_utama());
holder.judulText.setText(dataList.get(position).getSummary_judul());
holder.waktuText.setText(dataList.get(position).getCreated_at());
//holder.gambarView.setImageURI(ImageURI);
holder.itemView.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View v)
{
Toast.makeText(getActivity(), "Item " + position + " is clicked.", Toast.LENGTH_SHORT).show();
}
});
}
#Override
public int getItemCount()
{
return dataList.size();
}
}
private class getBeritaTask extends AsyncTask<Void, Void, Void> {
protected void onPreExecute() {
Log.d("Berita","2.1");
}
protected Void doInBackground(Void... voids) {
mAPIService.getBeritaList().enqueue(new Callback<Berita>() {
#Override
public void onResponse(Call<Berita> call, Response<Berita> response) {
list_berita = new ArrayList<>();
DataBerita data_berita = new DataBerita("","","","");
String id_berita;
String judul;
String gambar_utama;
String created_at;
Log.d("Berita","2.2");
if(response.isSuccessful()) {
Berita body = gson.fromJson(response.body().toString(),Berita.class);
for (int i = 0; i < body.getList_berita().getData().size(); i ++) {
id_berita=body.getList_berita().getData().get(i).getId_berita();
judul=body.getList_berita().getData().get(i).getSummary_judul();
gambar_utama=body.getList_berita().getData().get(i).getGambar_utama();
created_at=body.getList_berita().getData().get(i).getCreated_at();
data_berita = new DataBerita(id_berita,judul,gambar_utama,created_at);
list_berita.add(data_berita);
}
Log.d("Berita List",list_berita.toString());
}else{
Log.d("Berita", "Fail");
}
}
#Override
public void onFailure(Call<Berita> call, Throwable t) {
Log.d("Berita Fail", t.getMessage());
}
});
return null;
}
}
here's the 2nd and 3rd fragment (these 2 fragments are still mostly empty, with code for toast and log only for now)
DiskusiFragment.java
public class DiskusiFragment extends Fragment {
// TODO: Rename parameter arguments, choose names that match
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
private static final String ARG_PARAM1 = "param1";
private static final String ARG_PARAM2 = "param2";
// TODO: Rename and change types of parameters
private String mParam1;
private String mParam2;
private OnFragmentInteractionListener mListener;
public DiskusiFragment() {
// Required empty public constructor
}
// TODO: Rename and change types and number of parameters
public static DiskusiFragment newInstance(String param1, String param2) {
DiskusiFragment fragment = new DiskusiFragment();
return fragment;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
Toast.makeText(getActivity() ,"Diskusi Fragment onCreateView", Toast.LENGTH_SHORT).show();
return inflater.inflate(R.layout.fragment_diskusi, container, false);
}
// TODO: Rename method, update argument and hook method into UI event
public void onButtonPressed(Uri uri) {
if (mListener != null) {
mListener.onFragmentInteraction(uri);
}
}
public interface OnFragmentInteractionListener {
// TODO: Update argument type and name
void onFragmentInteraction(Uri uri);
}
}
here's the problem,
fragment onCreateView function seems to be called on / in the wrong fragment.
when I start the app here's what happened :
Item position 0 , 1, and 2 is called
1st fragment on create view is called, and 2nd fragment on create view is called immediately
what happens next, depends on what I do :
when I change from 1st fragment => 2nd fragment, 3rd fragment on create view is called
when I change from 1st fragment => 3rd fragment, 3rd fragment on create view is called
when I switch from 2nd fragment => 1st fragment, no fragment on create view called
when I switch from 2nd fragment => 3rd fragment, no fragment on create view called
when I switch from 3rd fragment => 2nd fragment, no fragment on create view called (or sometimes 1st fragment on create view is called)
when I change from 3rd fragment => 1st fragment, 1st fragment on create view called
is this what suppose (in regard to onCreateView function is called on the wrong fragment) to happen?
if not, where did I code wrong?
Thank you very much
*EDIT : this behaviour is normal, I'm really new to android. Very sorry for the inconvenience guys
The FragmentPagerAdapter keeps additional fragments, besides the one shown, in the resumed state.
If you want to initialize stuff in the fragment you should do it when
OnCreate is called.
Anything that is related to the UI been loaded properly should happen on
onViewCreated
In addition, if you want to receive more information about how to handle fragments inside a ViewPager
#Shreyas Shetty answered it really well on this thread
What do you mean by "wrong" fragment? View pager creates next fragment prior to navigating to it to make the transition smooth and quick. And when the fragment is created its lifecycle methods are called accordingly, there's nothing wrong with this behaviour. If you want to perform some action when the user swipes to specific fragment in your view pager, you can use OnPageChangeListener.
This question already has answers here:
Passing Data Between Fragments to Activity
(7 answers)
Closed 5 years ago.
I am new to Java. The activity is to receive an ID and reuse that ID to get the detail of the recipe with a Recipe API. I am using three tabs to show different content. The problem that I could not figure out is that the first (description tab) and the third (step tab) can receive the string from main activity, but the second tab (ingredient tab) always receives null value from the main activity. Also, The string does not show on the first tab immediately when I run the activity. It only shows after I click on the third tab and come back to the first one.
Activity
public class SearchHomeResultActivity extends AppCompatActivity {
private SectionsPagerAdapter mSectionsPagerAdapter;
private ViewPager mViewPager;
public String RecipeId = "479101";
public String SInstruction;
public String SIngredients;
public String STitle;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_search_result);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager());
// Set up the ViewPager with the sections adapter.
mViewPager = (ViewPager) findViewById(R.id.container);
mViewPager.setAdapter(mSectionsPagerAdapter);
TabLayout tabLayout = (TabLayout) findViewById(R.id.tabs);
mViewPager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(tabLayout));
tabLayout.addOnTabSelectedListener(new TabLayout.ViewPagerOnTabSelectedListener(mViewPager));
new CallMashapeAsync().execute(RecipeId);
}
public class CallMashapeAsync extends AsyncTask<String, Integer, HttpResponse<JsonNode>> {
protected HttpResponse<JsonNode> doInBackground(String... msg) {
HttpResponse<JsonNode> request = null;
try {
request = Unirest.get("https://spoonacular-recipe-food-nutrition-v1.p.mashape.com/recipes/" + msg[0] + "/information")
.header("X-Mashape-Key", "EulyPgSat2mshhTi8JJxY40UEWzdp1mMmEGjsnrbQq1AB0vuOY")
.header("X-Mashape-Host", "spoonacular-recipe-food-nutrition-v1.p.mashape.com")
.asJson();
} catch (UnirestException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return request;
}
protected void onProgressUpdate(Integer... integers) {
}
protected void onPostExecute(HttpResponse<JsonNode> response) {
String answer = response.getBody().toString();
try {//get all response
JSONObject obj = new JSONObject(answer);
//get ingredients
String Ringredient = obj.getString("extendedIngredients");
List<String> terms1 = new ArrayList<String>();
JSONArray ing = new JSONArray(Ringredient);
for (int i = 0; i < ing.length(); i++) {
JSONObject ING1 = ing.getJSONObject(i);
String Ostr = ING1.getString("originalString");
terms1.add(Ostr);
}
String listString = "";
for (String s : terms1) {
listString += s + "\n";
}
//get instructions
String Rid1 = obj.getString("instructions");
//get title
String Rid2 = obj.getString("title");
SInstruction = Rid1;
SIngredients = listString;
STitle = Rid2;
} catch (JSONException e) {
throw new RuntimeException(e);
}
}
}
public String getIns() {
//
return SInstruction;
}
public String getIngredients() {
//
return SIngredients;
}
public String getRTitle() {
//
return STitle;
}
public class SectionsPagerAdapter extends FragmentPagerAdapter {
public SectionsPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
switch (position) {
case 0:
descriptionTab tab1 = new descriptionTab();
return tab1;
case 1:
IngredientsTabActivity tab2 = new IngredientsTabActivity();
return tab2;
case 2:
StepTabActivity tab3 = new StepTabActivity();
return tab3;
}
return null;
}
#Override
public int getCount() {
// Show 3 total pages.
return 3;
}
}
}
Fragment
public class StepTabActivity extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState){
View rootView = inflater.inflate(R.layout.step_layout, container, false);
SearchHomeResultActivity getData = (SearchHomeResultActivity) getActivity();
String Rid = getData.getIngredients();
TextView txt = rootView.findViewById(R.id.name);
txt.setText(Rid);
return rootView;
}
This is the code of the Step (the third) fragment. Other two are the same, but just calling different methods to get different strings for the TextView.
Please help me. Thank you so much!
You can create a constructor like method called newInstance in your fragment as below,
public static FragmentName newInstance(String str) {
Bundle args = new Bundle();
FragmentName fragment = new FragmentName();
fragment.setArguments(args);
resID = str;
return fragment;
}
define your "resID" as global variable and use it in fragment's onCreate method.
and from activity when u are adding fragment to viewPager adapter do like this
adapter.addFrag(FragmentName.newInstance(resID), "fragment_name");
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 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?