I have this class here which calls the method setPoint
public class PointsList extends Fragment {
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.listpoints, container, false);
public static class PointCreation extends Fragment {
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.point_creation, container, false);
setPoint(view, CREATE);
return view;
}
}
static final void setPoint(View view, int goal) {
final EditText SerialField = (EditText) view.findViewById(R.id.Serial);
if(goal == CREATE) {
Button buttonGuardar = (Button) view.findViewById(R.id.buttonGuardar);
buttonGuardar.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
String Serial = SerialField.getText().toString();
pointsList.add(new Serial);
//go back to R.layout.listpoints
}
});
}
}
My goal is after I click the button to add the new Serial to the List, I can go back to the previous menu from
R.layout.point_creation to R.layout.listpoints
To move around fragments I generally use something like this:
Fragment fragment = new PointsList();
FragmentManager fragmentManager = getActivity().getSupportFragmentManager();
fragmentManager.beginTransaction()
.replace(R.id.container, fragment)
.commit();
But inside:
static final void setPoint(View view, int goal)
getActivity().getSupportFragmentManager();
cannot be referenced from a static context, and I don't know how to go around it with making the static class non-static? I've some global flags which I use in the static Classes (have 2 of them) that would be a bit painfull to export since
public class PointCreation(int something) extends Fragment
is something I can't do.
You can get the activity from view:
Activity activity = (Activity)view.getContext()
If you use FragmentActivity (it seems to be so), then cast Context to FragmentActivity (instead of regular Activity) and further you will able to call getSupportFragmentManager()
FragmentActivity activity = (FragmentActivity)view.getContext();
FragmentManager manager = activity.getSupportFragmentManager();
You can use by below code;
private static FragmentActivity myContext;
#Override
public void onAttach(Activity activity) {
myContext = (FragmentActivity) activity;
super.onAttach(activity);
}
You can use myContext as Context
You can't reference from a static to non-static objects. First thing, that comes to mind is to use singleton pattern for your fragment. In other words add to you fragment singleton snippet:
static PointsList instance;
public PointsList getInstace(){
if(instance == null){
instance = new PointsList ();
}
return instance;
}
and in your fragment onCreate method assign it to the instance:
instance = this;
after that you can remove static modifier from setPoint method. And call it from any part of your project like PointsList.getInstance().setPoint();
p.s. what goals from static you have to use? You should use static very carefully, many things can be done through singleton instead of using statics.
Related
I have a ListView in a Fragment that is populated when the app starts.
I put a ParcelableArrayList in a Bundle in my newInstance method, and I get it back in my OnCreateView after passing the ArrayList in the newInstance method in my Activity (which is the data read from the SQLite database).
This part works, as I display my data in my Fragment correctly.
I implemented a button that removes all data from the table, and I would now like to update my view after I cleaned the table.
The remove all button is handled in my main activity where I call my database handler to empty the table.
What is the best way to do that ? Here are the parts of the code that seem relevant to me :
My Fragment class :
public class MainFragment extends Fragment {
public static final String RECETTES_KEY = "recettes_key";
private List<Recette> mRecettes;
private ListView mListView;
public MainFragment() {
// Required empty public constructor
}
public static MainFragment newInstance(List<Recette> r) {
MainFragment fragment = new MainFragment();
Bundle bundle = new Bundle();
bundle.putParcelableArrayList(RECETTES_KEY, (ArrayList<? extends Parcelable>) r);
fragment.setArguments(bundle);
return fragment;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
mRecettes = getArguments().getParcelableArrayList(RECETTES_KEY);
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_main, container, false);
}
#Override
public void onViewCreated(#NonNull View view, #Nullable Bundle savedInstanceState) {
configureListView();
}
// Configure ListView
private void configureListView(){
this.mListView = getView().findViewById(R.id.activity_main_list_view);
RecetteAdapter adapter = new RecetteAdapter(getContext(), mRecettes);
mListView.setAdapter(adapter);
}
}
Relevant parts from my Main acivity :
This is in my OnCreate method :
mDatabaseHandler = new DatabaseHandler(this);
mRecettes = mDatabaseHandler.readRecettes();
mDatabaseHandler.close();
This is in the method I use to show a fragment :
if (this.mMainFragment == null) this.mMainFragment = MainFragment.newInstance(mRecettes);
this.startTransactionFragment(this.mMainFragment);
Let me know if I should add more of my code, this is my first time posting :)
Lucile
In your R.layout.fragment_main, you can add an id to the root view, say with android:id#+id/fragment_root
And whenever you want to change the fragment view:
In activity:
MainFragment fragment = (MainFragment) getSupportFragmentManager().getFragmentById(R.id.fragment_root);
fragment.updateList(mRecettes);
And then create the new method updateList() in your MainFragment
public void updateList(List<Recette> recettes) {
mRecettes.clear();
mRecettes.addAll(recettes);
configureListView();
}
Also you can tag your fragment when you add it to your transaction instead of using its id, and then use getSupportFragmentManager().getFragmentByTag()
I want to set the text of textview in activity from a fragment. This is how I do it.
MainActivity.java
public class MainActivity extends AppCompatActivity implements NavigationView.OnNavigationItemSelectedListener {
public TextView textViewNotification;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
NavigationView navigationView = findViewById(R.id.nav_view);
navigationView.setNavigationItemSelectedListener(this);
textViewNotification = (TextView) MenuItemCompat.getActionView(navigationView.getMenu().findItem(R.id.nav_notification));
}
}
HomeFragment.java
public class HomeFragment extends Fragment {
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
((MainActivity)getActivity()).getSupportActionBar().setTitle("PIT IAI & FIP Regional");
ViewGroup root = (ViewGroup) inflater.inflate(R.layout.fragment_home, container, false);
MainActivity activity = (MainActivity) getActivity();
activity.notification.setText("This is a test"); // => got error here.
return root;
}
}
But it didin't work. This is the error that I got:
android.content.res.Resources$NotFoundException: String resource ID #0x1
at android.content.res.Resources.getText(Resources.java:348)
at android.widget.TextView.setText(TextView.java:5846)
How is it exactly to get and set public attributes of activity from fragments? is it not possible? Please help.
Supposed you want to send the text to the activity based on some action.
You can use an interface, first create a public interface in your fragment and add one method inside it which takes one string parameter
public interface CommunicateWithActivity{
void onCommunicate(String s)
}
, declare a global variable mListener of type CommunicateWithActivity,
private CommunicateWithActivity mListener;
then override onAttach and inside try/catch block
#Override
public void onAttach(#NonNull Context context) {
super.onAttach(context);
try {
mListener = (CommunicateWithActivity) context;
} catch (ClassCastException e) {
throw new ClassCastException(context.toString() + "CommunicateWithActivity implementation in Activity is required");
}
}
then in the activity implement the interface an override "onComunicate(String s)" method in the activity and you will get your string inside the methd.
#Override
public void onCommunicate(String s) {
//do whatever you want
}
Henry Gunawan your MainActivity does not have any public field called notification you actually named it textViewNotification.
Moreover i am seeing some bad practices in your code
Avoid declaring public fields instead use getters and setters to access them
Your fragment assuming that it's host is always a MainActivity instance and it has a field called notification , which is not a good practice , fragments are meant to be a standalone unit, fragments should not depends on specifics of their host activity as they may be host by any activity hence this is a misuse of fragments, use should instead use callbacks if you want your host activity to do something for you as explained by Amr Sakr.
This should be an easy question, but for some reason I am having trouble with it. Let's say I have a FragmentOne and FragmentTwo. FragmentOne looks like this:
private static final String PATH_KEY = "path_key";
private Asset asset;
public FragmentOne() {
// Required empty public constructor
}
public static FragmentOne newInstance(Asset asset) {
FragmentOne fragment = new FragmentOne();
Bundle args = new Bundle();
args.putSerializable(PATH_KEY, asset);
fragment.setArguments(args);
return fragment;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
asset = (Asset) getArguments().getSerializable(PATH_KEY);
}
}
#Override
public View onCreateView(final LayoutInflater inflater, final ViewGroup container,
final Bundle savedInstanceState) {
final FragmentOneBinding binding = DataBindingUtil
.inflate(inflater, R.layout.fragment_video, container, false);
bindAsset(binding, asset);
return binding.getRoot();
}
public void bindAsset(FragmentOneBinding binding, Asset asset) {
binding.textView.setText("FragOne displays asset like this " + asset.text);
//this is the only method which differs from FragmentTwo
}
while FragmentTwo looks like this:
private static final String PATH_KEY = "path_key";
private Asset asset;
public FragmentTwo() {
// Required empty public constructor
}
public static FragmentTwo newInstance(Asset asset) {
FragmentTwo fragment = new FragmentTwo();
Bundle args = new Bundle();
args.putSerializable(PATH_KEY, asset);
fragment.setArguments(args);
return fragment;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
asset = (Asset) getArguments().getSerializable(PATH_KEY);
}
}
#Override
public View onCreateView(final LayoutInflater inflater, final ViewGroup container,
final Bundle savedInstanceState) {
final FragmentTwoBinding binding = DataBindingUtil
.inflate(inflater, R.layout.fragment_video, container, false);
bindAsset(binding, asset);
return binding.getRoot();
}
public void bindAsset(FragmentOneBinding binding, Asset asset) {
binding.textView.setText("But FragTwo, which is very different, displays asset like this " + asset.image.getName());
//this is the only method which differs from FragmentOne
}
As you can see, in both fragments, the newInstance, onCreate, and onCreateView methods are structurally the same. The only real difference is that the bindView method called from inside the onCreateView of both fragments is not the same.
Using generics, abstract classes, interfaces, or some combination, can I simplify things down to a template design pattern? So that the next time I want to make a fragment with the exact same structure I can do something a little like this?
class FragmentThree extends TemplateFragment {
#Override
public void bindAsset(FragmentThreeBinding binding, Asset asset){
binding.textView.setText(asset.name);
}
}
I tried making an abstract class already, but you can't have a static method in an abstract class, so newInstance() stops me here. I've tried a few ways of implementing interfaces as well, but am not having any luck.
I think the abstract class you attempted is the right way to go. You will need to still put newInstance() in each concrete subclass, not only because it is static, but also because it needs to know the concrete type to instantiate.
abstract method cann't use static 。
Factory Mode in order to create class instantiate.
Fragment use Factory Mode ,itself add static Method .
I am having trouble figuring out how to share data between my two fragments which are hosted on the same activity.
The objective:
I want to transfer string from the the selected position of a spinner and an image url string from a selected list view position from fragment A to fragment B.
The Attempt:
I read the fragments doc on this problem here http://developer.android.com/guide/components/fragments.html#CommunicatingWithActivity
And went ahead an created the following Interface to use betweeen the Fragments and the Host Activity.
public interface OnSelectionListener {
public void OnSelectionListener(String img, String comments );
}
Then I proceeded to implement it in my fragment A's onCreateView method like so:
postList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
ListData link = data.get(position);
String permalink = link.getComments();
String largeImg = link.getImageUrl();
Fragment newFragment = new DetailsView();
FragmentTransaction transaction = getFragmentManager().beginTransaction();
// Replace whatever is in the fragment_container view with this fragment,
// and add the transaction to the back stack
transaction.replace(R.id.fragment_container, newFragment);
transaction.addToBackStack(null);
// Commit the transaction
transaction.commit();
//pass data to host activity
selectionListener.OnSelectionListener(permalink,largeImg);
}
});
And also in the onAttach method
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
selectionListener = (OnSelectionListener)getActivity();
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString() + " must implement onSelectionListener");
}
}
In the Host activity I implemented the interface I wrote and overrided the method like so:
#Override
public void OnSelectionListener(String img, String comments) {
DetailsView detailsView = new DetailsView();
DetailsView dView = (DetailsView)getSupportFragmentManager().findFragmentByTag(detailsView.getCustomTag());
dView.setInformation(img, comments);
}
In Fragment B I set a "tag" the following way
private String tag;
public void setCustomTag(String tag)
{
this.tag = tag;
}
public String getCustomTag()
{
return tag;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setCustomTag("DETAILS_VIEW");
And my thinking is that that the information can be passed to Fragment B by calling this method from the host activity
void setInformation (String info, String img){
RedditDetailsTask detailsTask = new RedditDetailsTask(null,DetailsView.this);
detailsTask.execute(info);
setDrawable(img);
}
What I need:
I want to know how to properly use tags to get this to work, I dont have any fragment id's declared in my xml and rather opted to exchange fragments in a fragment_container.
I also am not sure if this is a good way to pass multiple strings between fragments. I am a newbie programmer so I know my logic probably looks pretty embarrassing but I am trying to do my best learn to do this right. I would appreciate it if you more senior developers can point me in the right direction for doing this.
You don't need to use tags. Take a look at this example. The Activity implements an interface that allows you to talk from Fragment1 back to the Activity, the Activity then relays the information into Fragment2.
I've left out all the android stuff about FragmentManager etc.
interface FragmentListener {
void onTalk(String s1);
}
public class MyActivity extends Activity implements FragmentListener {
Fragment2 fragment2;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_my);
// Find fragment2 and init
}
#Override
public void onTalk(String s1) {
fragment2.onListen(s1);
}
private static class Fragment1 extends Fragment {
private FragmentListener communication;
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
communication = (FragmentListener) activity;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_one, container, false);
}
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
// or in an onClick listener
communication.onTalk("blah blah");
}
}
private static class Fragment2 extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_two, container, false);
}
public void onListen(String s1) {
Log.d("TADA", s1);
}
}
}
My approach would be, when you get the callback in activity through the OnSelectionListener interface, I would create the Fragment B object and set arguments to it as follows:
#Override
public void OnSelectionListener(String img, String comments) {
DetailsView detailsView = new DetailsView();
Bundle args=new Bundle();
args.putString("img",img);
args.putString("comments",comments);
detailsView.setArguments(args);
//code here to replace the fragment A with fragment B
}
Then in Fragment B's onCreate method you can retrieve the values as follows:
#Override
public void onCreate(Bundle savedInstanceState) {
Bundle args=getArguments();
String img=args.getString("img");
String comments=args.getString("comments");
//do whatever you want to do with the varaibles
}
You could try to make two public static String's in your B fragment.
it Would look like something like this
public static String img;
public static String comment;
The you set the variables before making the transaction to fragment B
FragmentTransaction transaction = getFragmentManager().beginTransaction();
// Replace whatever is in the fragment_container view with this fragment,
// and add the transaction to the back stack
transaction.replace(R.id.fragment_container, newFragment);
transaction.addToBackStack(null);
SecondFragment.img = new String("imgString"); //Making a new string so incase you change the string in bfragment, the values wont change in here
SecondFragment.comment = new String("comment");
// Commit the transaction
transaction.commit();
Then in the onStop(), or onDestroy() - depending on when you want the variables to be null, check this - you set the the static variables to null, so they dont take memory space
public void onDestroy(){
super.onDestroy();
img = null;
comment = null;
}
I am trying to use the method
public Fragment getItem(int position) {
// getItem is called to instantiate the fragment for the given page.
// Return a DummySectionFragment (defined as a static inner class
// below) with the page number as its lone argument.
Fragment fragment = new MappingPage();
Bundle args = new Bundle();
args.putInt(DummySectionFragment.ARG_SECTION_NUMBER, position + 1);
fragment.setArguments(args);
return fragment;
}
I have written a class called MappingPage(), if I try to use the above method, the fragment I create is of type MappingPage because has been extended and hence throw an error as the function returns a fragment (not a MappingPage Object)
EDIT:I am getting an error when I do
Fragment fragment = new MappingPage();
Eclipse tell me that I need to change fragment to type MappingPage, which means i have to change the return type of the function
two Questions
1) How are you supposed to put your custom fragments into this?
2) Why does the dummySectionFrament return a Fragment Object and not a DummySectionFragment object?
thanks in advance
public static class DummySectionFragment extends Fragment {
/**
* The fragment argument representing the section number for this
* 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_main_dummy,
container, false);
TextView dummyTextView = (TextView) rootView
.findViewById(R.id.section_label);
dummyTextView.setText(Integer.toString(getArguments().getInt(
ARG_SECTION_NUMBER)));
return rootView;
}
}
here is my class
public class MappingPage extends Fragment
{
private MapView map;
private MapController myMapController;
public static final String ARG_SECTION_NUMBER = "1";
public MappingPage() {
}
public View onCreateView (LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//Context context = new ContextThemeWrapper(getActivity(), R.style.fragment_theme);
//LayoutInflater Inflater = inflater.cloneInContext(context);
View view=inflater.inflate(R.layout.fragment_main_dummy, container, false);
return view;
}
#Override
public void onResume() {
map = (MapView)getActivity().findViewById(R.id.openmapview);
map.setBuiltInZoomControls(true);
myMapController = map.getController();
myMapController.setZoom(15);
super.onResume();
}
}
Regarding your first question, this should work. MappingPage is an indirect instance of the Fragment class, and you can therefore return it.
About question two, the method that you call always returns a specific type, like Fragment in the case of getItem(). However, this can be a subclass of that as well, and if you are sure it is, you can safely cast it to that subclass.