How to implement Fragment and AppCompatActivity in a single activity in android - android

I have implemented swipe in tablayout of my activity call Performance_Medicine
public class Performance_Medicine extends Fragment{
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
//Returning the layout file after inflating
//Change R.layout.tab1 in you classes
return inflater.inflate(R.layout.performance_medicine, container, false);
}
}
Now, I am trying to implement cardview in same activity. But getting error
like below image

You are getting the error because you are trying to pass an instance of Performance_Medicine which extends Fragment. You need to pass in a context which you can do via this.getActivity() or this.getContext(). If you can pass the application context via a singleton or this.getActivity().getApplicationContext() then you may be better off memory wise.

Remember that a Fragment has its own lifecycle, but it runs in the context of its host Activity, that means you can not use 'this' for getting the Context, instead you need to use getActivity(). Also, as sam_c says, in your onCreate() method, the last line of code must be the 'return...' since this method has the return type 'View', and if you call the return statement, the method won't execute anything after this. Hope this helps to clarify.

Related

How do I communicate between fragments as if they were all on one activity?

I am using the android studio fragments sample. My goal is to set the value of EditText et1 in fragment1 by using code in fragment2. Also I want to update the ListView lv, that is in fragment1 by using code in fragment2.
The example does some back and forth sending of ARG_SECTION_NUMBER, but that is just text and won't work for a listview. What does not work is this
private View rvza, rvl, rvea;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
rvza = inflater.inflate(R.layout.fragment_zeit_und_aktion, container, false);
rvl = inflater.inflate(R.layout.fragment_liste, container, false);
rvea = inflater.inflate(R.layout.fragment_eintragen_und_aendern, container, false);
....
}
...
Button btnNeu = (Button) rvea.findViewById(R.id.btnNeu); //this line is somewhere...
What also doesn't work is this
new MainActivity().myfunction((ListView)rvl.findViewById(R.id.listView));
it gives an Attempt to invoke interface method 'int
android.widget.ListAdapter.getCount()' on a null object reference at
public void myfunction(ListView lv)
{
int count = lv.getAdapter().getCount();
So how do I communicate between fragments having one parent activity? Is there a helper class?
If you want to access any method or variable, that has an use by more than one child, make parent activity singleton and access the desired method or variable in child fragment. Also if you want to access anything within fragment from anther, don't forgot to make and init an object of that fragment in parent activity and use that object further to add or replace fragment in fragment manager. By this you have access to every child through the parent activity
How to make singleton? See below example.
public class SingletonExample {
// Static member holds only one instance of the
// SingletonExample class
private static SingletonExample singletonInstance;
// SingletonExample prevents any other class from instantiating
private SingletonExample() {
}
// Providing Global point of access
public static SingletonExample getSingletonInstance() {
if (null == singletonInstance) {
singletonInstance = new SingletonExample();
}
return singletonInstance;
}
public void printSingleton(){
System.out.println("Inside print Singleton");
}
}
There is an official guide on Android developers on how to communicate between fragments:
https://developer.android.com/training/basics/fragments/communicating.html
Basically, your fragment A will talk to the activity via an interface and the activity will look up fragment B and call some method on the fragment.
If you want to decouple things more, however, you could use something like otto event bus:
http://square.github.io/otto/
It can be used to communicate between different parts of your application without having to deal with the underlying details.

Android app programming- not sure why findViewByID does the following:

This code works:
public static class PlaceholderFragment extends Fragment {
public PlaceholderFragment() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_detail, container, false);
Intent intent = getActivity().getIntent();
String weather = intent.getStringExtra(Intent.EXTRA_TEXT);
if(weather != null) {
TextView textViewWeather=(TextView)rootView.findViewById(R.id.weatherText);
textViewWeather.setText(weather);
BUT if you replace, in the line
(TextView)rootView.findViewById(R.id.weatherText);
rootView by findView() or getActivity, it returns null so the next line creates a run time fatal error which halts the program.
I don't understand why. I thought that the context is the activity?! I'm confused,and can't find a good answer via android developer,so here I am...
Thanks in advance to whoever helps!!
when you call :
View rootView = inflater.inflate(R.layout.fragment_detail, container, false);
TextView textViewWeather=(TextView)rootView.findViewById(R.id.weatherText);
the rootView now contains the views that are defined in fargment_detail.xml .
and weatherText is one of them.
but when you call getActivity().findViewById() or findViewById() you want to find the weatherText inside xml file of activity and there is no weatherText there so it will retun null
This line gets the element with id weatherText from its rootView. Which is nothing but your fragment xml file
TextView textViewWeather=(TextView)rootView.findViewById(R.id.weatherText);
Now if you are replacing above code with below
TextView textViewWeather=(TextView)getActivity().findViewById(R.id.weatherText);
now the parent Activity in which this fragment is hosted which has TextView and id weatherText will be searched by framework. Which is obvious is not present at all.
If you remove the rootView you are calling it directly on the activity so those two suggestions are equal (and activity is indeed the context).
But the activity doesn't know about the layout yet, you just inflated it from xml but it has not been given to the activity yet, and therefore can't be found. You do that by returning it from the onCreateView call you are in in your example code.

Android fragment: how to pass values in XML

I have a simple fragment with 2 TextView objects. The fragment has the corresponding Java class. How do I pass values from the activity layout XML to the fragment? I want to instantiate the same fragment multiple times with the TextView objects having different values.
So, the activity XML would be something like:
*
Thank you.
Everybody seems to ignore it but you can actually pass static arguments like a label through XML.
It's a bit complicated. First you need to declare the custom attributes you want to use in a file like attrs.xml, then you need to override Fragment.onInflate() to retrieve the value of these attributes.
The official Android documentation provides a simple example on how to retrieve a label from the XML layout to use it in a Fragment.
I guess that you are expecting some way of data binding in xml (for example like in wpf).
There is no data binding like that in android (at least not without third party libraries).
What you do have is your onCreateView () method of fragment.
There you catch reference to those TextView objects, like this:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment, container,
false);
TextView myTextView1 = (TextView)view.findViewById ("textView1");
TextView myTextView2 = (TextView)view.findViewById ("textView2");
return view;
}
There you can also set value of those textViews, or you can set it latter in code like this:
myTextView1.setText ("this is my textview1 test");
So, to conclude - there is no typical inside xml data binding in android, you have to find those views in fragment code and then manipulate with them.
EDIT:
if you have data somewhere in activity, and you want to pass it to your fragment when you create it, you can use fragment setArgument() function (and corresponding getArguments() ).
You have example here: Setting Fragment arguments from Activity - in the accepted answer.
EDIT 2:
According to new Data Binding Library it's possible to do binding like this:
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable name="user" type="com.example.User"/>
</data>
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#{user.firstName}"/>
<TextView android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#{user.lastName}"/>
</LinearLayout>
</layout>
link: https://developer.android.com/tools/data-binding/guide.html
But note that it's still beta release.
It seems like you are going about using fragment wrong.
But nonetheless you can just use textview.setText in each fragments java class...
you want to pass data to the fragment and let the fragment use it. The following article describes the whole 9 yard:
http://developer.android.com/training/basics/fragments/communicating.html
In short:
sender to setArguments:
Bundle args = new Bundle();
args.putString("myText", aText);
f.setArguments(args);
the receiving Fragment to retrieve argument:
String text = getArguments().getInt("myText"); // myTextView.setText(...)
The following is an example of a Fragment. Notice the way you interact with the TextView. You just have to create as many fragments as you want and put them into an ArrayList so that you will be able to get information from all fragments.
public class Yourfragment extends Fragment {
private TextView mTextView;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.your_fragment, container, false);
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
View _view = getView();
if(_view != null){
mTextView = (EditText) _view.findViewById(R.id.your_textView);
}
}
}
To answer your question,
you need to have a mainclass extending Activity class from which you will instantiate the fragmnet. And you need a fragment class with those two TextView objects ad the class variables with a parameterized constructor . So you need to maintain a Map which has key as the name of your fragment and textviewvalue1"+"textviewvalue2. So now while creating an instance of a fragment, you can send the value yiu have in the map as parameters to that fragment constructor.
Like this:
public class Yourfragment extends Fragment {
private TextView mTextView1;
private TextView mTextView2;
public Yourfragment(String txt1,String txt2){
super();
this.mTextView1.setText(txt1);
this.mTextView2.setText(txt2);
}
#Override public View
onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
//ur logic
}
#Override public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
//ur logic
}
} }
And in the place where you instantiate, use map.get( fragmentname).split("+")[0] and map.get( fragmentname).split("+")[1] as parameters to conatructor and set the title of fragment to fragmentname

Android: How to get a view given an activity inside a normal class?

I have a normal class (not an activity). Inside that class, I have a reference to an activity.
Now I want to access a view (to add a child) contained in the layout xml of that activity.
I don't know the name of the layout file of that activity. I only know the ID of the view, which I want to access (for example: R.id.my_view).
How can I do that?
Regarding the NullPointerException (which you should add to the question), always make sure you've called setContentView() in your Activity before trying to access a View defined in XML. Example usage:
public class MainActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
...
}
...
}
Then, somewhere,
ViewGroup group = (ViewGroup) context.findViewById(R.id.group); // In your example, R.id.my_view
The reason you need to have called setContentView() is that before it's called, your View(Group) doesn't exist. Because findViewById() is unable to find something that doesn't exist, it returns null.
As simple as that!
View view = activity.findViewById(R.id.my_view);
In case of the Layout:
LinearLayout layout = (LinearLayout) activity.findViewById(R.id.my_layoutId);
And to add the Views:
layout.addView(view);
You could make your method accept an Activity parameter and then use it to find the view by id.
Ex:
public class MyClass{
public void doSomething(Activity context){
TextView text=(TextView)context.findViewById(R.id.my_textview);
}
}
Then in your activity:
obj.doSomething(YourActivity.this);

getView returning null when fragment has been created from an activity

I have a working tablet application which I am now trying to make work on phones too.
On a table there is two fragments on the screen a list fragment and a details fragment.
When on a phone the list fragment appears and creates a new activity when a list item is pressed.
This activity simply creates the fragment in the onCreate() method and commits it to the screen as follows.
// Place an DeallDetailsFragment as our content pane
DealDetailsFragment f = new DealDetailsFragment();
getFragmentManager().beginTransaction().add(android.R.id.content, f).commit();
getFragmentManager().executePendingTransactions();
This is working as expected however from within this activity I need to tell the fragment what details to load and display. In my DealDetailsFragment class I have a updateDeal() method which updates the content as follows.
if (deal==null) { // could be null if user presses the loading deals list item before it loads
return;
}
this.deal=deal;
if (dealTitle==null) { // get the view objects only once
holder = new ViewHolder();
holder.dealHeat=(TextView) getView().findViewById(R.id.dealDetails_heat_textView);
holder.dealPrice=(TextView) getView().findViewById(R.id.dealDetails_price_textView);
holder.dealRetailer=(TextView) getView().findViewById(R.id.dealDetails_retailer_textView);
holder.dealTitle=(TextView) getView().findViewById(R.id.dealDetails_title_textView);
holder.dealDesc=(TextView) getView().findViewById(R.id.dealDetails_desc_textView);
holder.goToButton= (LinearLayout) getView().findViewById(R.id.dealDetails_goToDeal);
holder.dealImage=(ImageView) getView().findViewById(R.id.dealDetails_imageView);
holder.postedBy=(TextView) getView().findViewById(R.id.dealDetails_poster_textView);
holder.datePosted=(TextView) getView().findViewById(R.id.dealDetails_date_textView);
getView() is returning null when the application is ran on a phone where there is only a single fragment shown.
Any ideas? Unfortunately, there is not many fragment examples available online.
Move your method call to be executed during onCreateView, and use the view you are inflating for reference instead of getView(). See the fragment lifecycle for more information: https://developer.android.com/guide/components/fragments.html#Creating
and the documentation of getView() that explains why it returns null before onCreateView(LayoutInflater, ViewGroup, Bundle) returns:
getView()
Get the root view for the fragment's layout (the one returned by onCreateView(LayoutInflater, ViewGroup, Bundle)), if provided.
https://developer.android.com/reference/android/app/Fragment.html#getView()
Moving the method to onCreateView() did not help me.so... Create a global variable mView
protected View mView;
and in onCreateView()
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
Log.d(TAG, "oncreateView");
super.onCreateView(inflater, container, savedInstanceState);
View view = inflater.inflate(R.layout.activity_secure_cloud_drive_folder, container, false);
this.mView = view;
return view;
}
and the replace all your getView() with mView
You can fix that by putting your code inside the onViewCreated()-method, which you should override. Don't forget to call super() on it.
You must check the Android Lifecycle to understand WHY is it null on
onAttach(...) function.
The first function called when fragment is created is added is onAttach(), but actually no view has been created. That's why null is returned when you try to access within this call.
Next function is onCreate()... but there is no view created yet!!!!
The third function called is onCreateView(), and it's here where you have to indicate which is the view attached to this fragment.... And it's only from this call where a view object exists and can be accessed.
Read and learn the full lifecycle here.
Greetings
Because onCreate() is called before onCreateView() , whether you inflate a view in onCreateView() or not, you'll get nothing through getView() in onCreate(), because in that time , onCreate() has not been called yet .
it becomes null basically because you call getview() before the view being inflated. Create a View object and fill using inflaterand then find your UI element see code below
View view = inflater.inflate(R.layout.fragment_albumslist, container, false);
TextView t= (TextView)view.findViewById(R.id.txtTest);
t.setText(strtext);
return view;

Categories

Resources