android get context of fragment in activity - java

I want to get the context or instance of fragment in a activity.I tried following codeļ¼š
In fragment:
public static XXFragment instance;
In the onCreate():
instance = this;
In activity:
Context context = XXFrangment.instance;
But it has NullPointerException error.Because I haven't invoked onCreate() of fragment.So how can I do to get the context or instance of Fragment?Hope somebody could help me!

I think there is some error in your way of thinking about Context :-)
First of all, Fragment does not have a Context until added to an Activity. After it is added, the Activity itself is it's Context, so there is no need to extract it from the Fragment. Just use this in Activity code :-)
As a side note, avoid static fields holding complex objects such as Fragments and Activities. In a real, production environment you will never do this, as it leads to so called memory leaks, a big problem in software.

It's good practice to use static method for fragment initializing. Implement this method in your fragment class:
public static YourFragment newInstance() {
Bundle args = new Bundle();
YourFragment fragment = new YourFragment();
fragment.setArguments(args);
return fragment;
}
As you can see, you are able to add parameters in a newInstance() method. These parameters are usually used for adding them as arguments of the fragment.

Related

Android - Hold Activity reference in application-level non-Activity class

I have an application class and it holds a reference of MyAdapter class:
public class MyApplication extends Application {
......
private static MyAdapter sMyAdapter;
public static MyAdapter getMyAdapter() {
if (sMyAdapter == null) {
sMyAdapter = new MyAdapter(this);
MyApplication.setMyAdapter(sMyAdapter);
}
return sMyAdapter;
}
public static void setMyAdapter(MyAdapter myAdapter) {
sMyAdapter = myAdapter;
}
......
}
MyAdapter class is a customized android adapter class, and the application Context is passed to the Adapter. The application holds a reference of it because it may be used anytime till the application is still running.
The problem is that now I need an Activity Context in the Adapter to start another Activity when some button is clicked because if I use application Context I need to add a Intent flag FLAG_ACTIVITY_NEW_TASK which I don't want to because that way the new Activity being started will be running in a new task. I tried a lot with changing launch mode and taskAffinity but either new issues came up or the Activity will be running in a new task.
So I am thinking to hold an Activity reference which shows the button in the Adapter class, and to avoid memory leak, I came up with the following:
public class MyActivity extends Activity {
......
#override
public void onResume() {
......
MyApplication.getMyAdapter().setActivity(this);
......
}
......
#override
public void onDestroy() {
......
MyApplication.getMyAdapter().setActivity(null);
......
}
}
Then in the Adapter class I will use the Activity reference to start another Activity. I tested and this worked fine but the question is would this avoid memory leak and is this a proper way to hold the Activity reference when onResume and release it when onDestroy? Is there any other decent way to achieve my purpose? Thanks.
would this avoid memory leak
Not really. You MyApplication object will still keep a reference to your adapter with all it's 'contents' (further references).
Yes, you've got rid of keeping the destroyed Activity around, and you might feel it's okay to keep the adapter because you're 'going to need it again anyways', still this whole construct is a horrible code smell and will with certainty introduce new memory leaks and other problems as you develop this further.
Logically, this adapter is part of an Activity, and as the Activity 'dies', so should the adapter.
I'm sure there's a reason why you felt you needed that adapter on your application, so I'd post another question asking 'how can I achieve soandso without my application knowing of my adapter'.

How can I use my global variable inside an Adapter class? Android

Hi i'm trying to pass a value by using Global Variable. I have created a class file where it is extended to Application and then add it on my Manifest.
public class MyApplication extends Application {}
After that I had created an Adapter Class which is extended to BaseExpandableListAdapter, I've search on how to set and get the global variable i've created and found this
((MyApplication) getActivity().getApplication()).setMy_id(my_id);
and to be able to get the value I use this
Integer my_id = ((MyApplication) getActivity().getApplication()).getMy_id();
In my Fragments, I can use my getMy_id() method but when putting it inside the BaseExpandableListAdapter, I'm having an error in getActivity(). I already tried using this but still it says Cannot resolve method getApplication(), is there any other way to get the value of my global variable.
I'm doing this because I'm trying to use Cursor for my ListView. I wanted to create a Expandable ListView where the data is from my database and my Cursor have a parameter for it's WHERE condition where my data in my global variable will be used.
The reason why I'm using it as a global variable because I use this data in different Fragments where it is not static it changes its value depends on the selected item.
Thank you in advance.
You need to have a constructor in your class that extends BaseExpandableListAdapter. The defined constructor should receive a parameters of Context type. Here is the example -
private Context mContext;
public YourExpandableListAdapter(Context context) {
mContext = context;
Integer my_id = ((MyApplication) context.getApplicationContext()()).getMy_id();
}
Now create an instance like this in your activity -
YourExpandableListAdapter ob = new YourExpandableListAdapter(this);
This should work.
I'm not really sure what you're trying to achieve but whatever it is you're doing seems hacky to me! As per answering your question, getApplication() needs a context, so when you do
((MyApplication) getActivity().getApplication())
You are essentially using the activitiy's(getActivity()) context. And you cannot call getActivity() in an Adapter class. Try passing the context of your activity from the activity to the adapter in your constructor, something like.
MyAdapter myAdapter = new MyAdapter(this); //This line will be in your activity, and this will be the instance of your activity
And your adapter constructor would look something like
public MyAdapter(Context context){
//Use this context to get the application instance, something like
Integer my_id = ((MyApplication) context.getApplication()).getMy_id();
}
For Me, all above didn't work. try this:
((MyApplication) context.getApplicationContext()).getMy_id();

Passing a query to a loader manager in a fragment from an activity

I am using a LoaderManager in a fragment that populates a ListView with data from an SQLLite database using a SimpleCursorAdapter..
public class TimelineFragment extends ListFragment implements LoaderCallbacks { }
This fragment is "displayed" because it is referenced in the xml of the main activity.
Everything is working well, with the notifyChange in the ContentProvider CRUD actions reflecting any additions or deletions (actual CHANGES to the database).
I wish to implement a user based query function, but am having a great deal of trouble working out how to access the LoaderManager from within the MainActivity.
I need to send an sql selection string to the LoaderManager to requery the database. How do i do this from within the MainActivity?
Any help would be greatly appreciated...
I made a workaround. I brought the fragment code to the main activity code. This avoided the referencing issue I had as the loader was local to the class.
Probably not best practice but as a hack it worked...
You could send a query from a loader callback onCreateLoader(int id, final Bundle args).
You can see onCreateLoader takes a Bundle arg.
In an activity you initialise a loader with
getSupportLoaderManager().initLoader(ID_LOADER,bundle,this);
You pass into a bundle arguments you need to query sqllitedatabase
Bundle bundle=new Bundle();
bundle.putInt("pathToUri","someData")
Then in a Loader callback onCreateLoader(int id, final Bundle args)
you can access that "someData"
String uriPath=bundle.getInt("pathToUri")+"";
Then you create URI :
Uri selectQueryUri=CONTENT_URI.buildUpon().appendPath(uriPath).build();
and create a query:
getContentResolver().query(selectQueryUri,........)
dataProvider implements the query.
Don't forget to add a Bundle arg in a restartLoader as well.
If instead you pass in null the app will crash.
getSupportLoaderManager().restartLoader(ID_LOADER, bundle, this);

Static Context from Activity.onStart()

I am trying to generate a notification from a class, Utilities.java, outside of the subclass of Context. I've thought about providing a SingletonContext class and have looked at posts ike this. I'd like to be able to return != null Context object since the notification can be generated at any given time because it is generated from a messageReceived() callback.
What are there downsides to doing something like this:
public static Context c;
public class MainActivity extends Activity{
#Override
public void onStart()
super.onStart()
c = this.getApplicationContext();
}
//other method somewhere outside this class
public Context getContext(){
return MainActivity.c
}
I don't think it would be any different than putting this on the onCreate(), however, it guarantees that the context is up to date when the activity starts.
The Context keeps a reference to this activity in memory, which you might not want. Perhaps use
this.getApplicationContext();
instead. This will still let you do file IO and most other things a context requires. Without a specific reference to this activity.
Maybe you should overwrite the onResume Method.
If you open a new activity, and switch back, the onStart method will not getting invoked.
Android Lifecycle: doc
BTW: I read about problems with ApplicationContext using a dialog or toast, so if you use the context to create on of these you should use your Activity as context.

Android: how can fragment take a global variable of Activity

I have an activity with a global variable int x, how can a fragment get the current value of variable x of its activity ?
Either set the var as public static, or use
((MyActivity)getActivity()).getX()
Using a public static variable isn't the best way to communicate between an activity and a fragment. Check out this answer for other ways:
The Android documentation recommends using an interface when the Fragment wants communicate with the Activity. And when the Activity wants to communicate with the Fragment, the Activity should get a reference to the Fragment (with findFragmentById) and then call the Fragment's public method.
The reason for this is so that fragments are decoupled from the activity they are in. They can be reused in any activity. If you directly access a parent Activity or one of its global variables from within a fragment, you are no longer able to use that fragment in a different Activity.
Kotlin version:
(activity as MyActivity).x
***In your Activity
==================
Bundle args = new Bundle();
args.putInt("something", Whatever you want to pass);
fragA.setArguments(args);
In your Fragment
==================
Bundle args = getArguments();
//whatever you want to get ,get it here.
//for example integer given
int index = args.getInt("index", 0);

Categories

Resources