I have followed this tutorial to use SQLite db in my android app.
Since I am a beginner I'm having problems understanding "context" parameter used in the example.
I want to call adapter and insert/update/delete records from a class that does not extend activity which in this example stands for context.
Now I don't know what to pass in the adapter as context, since I'm not calling adapter from activity.
Can someone please explain this?
Pass the ActivityName.this as class context as argument to the adapter class's constructor
the ActivityName is the name of the Activityclass in which you are calling the adapter
you could imagine that the context defines WHERE/WHEN the sqlite database exists. sqlite databases do not exist on their own, they exist within the confines of your activity, thus in your activity's context.
for the next steps you must understand that the context is a dynamic "thing" (in reallife you could imagine it as someone's HERE and NOW). the context is individual to the activity and its moment, just as your here and now are yours and yours only and change over time.
if you are calling a class from within your activity, then this does the trick (passing the activity's context from within the activity itself is OK - sorta like you saying to your buddy: this is how i am feeling NOW).
public class MyActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Context contextNew = this;
myClass(contextNew);
an easy all around solution (panacea) would be to create a static Context variable (contextVariable) inside MyActivity and access it directly from without via: MyActivity.contextVariable. but that does not work, because you get an error when you try to declare/use a static Context variable.
So, if you plan on using sqlite inside a service that is NOT called from within the main activity, like, for example, a service triggered by a broadcast receiver (neither a service nor a receiver have a context per se), then you must access the original application's context from within said receiver.
accessing the original activity's context is simple, but far from obvious.
this works for me (thanx #ZiGi and #Cristian):
import android.app.Service;
import android.content.Context;
public class BatchUploadGpsData extends Service {
public Context contextNew;
#Override
public void onCreate() {
contextNew = getApplicationContext();
this is an example from working code that uploads navigation data to a database on the web every time the android device connects to a WIFI network. i have a receiver listening to connectivity changes (existing as a separate class called directly "from" Manifest file).
i hope that this makes sense, if you want more detail on this, check out this post of mine where i have the complete (barebones) code for said receiver.
As you see in the example, there is a context passed to the ToDoAdapter. You can pass activity as a context or activity.getApplicationContext(). Read about context here.
Related
How do I call the functions provided by Activity class from a class that does not extend Activity? Theoretically, yes, if I don't extend Activity I cannot directly use the functions provided by it. But is there a workaround provided for this? If not, are there replacements or alternative ways for these functions?
For example,
If my class extends Activity, I can call setContentView() to instantiate my layout xml file. But if my class extends some other class and doesn't extend Activity, then I can use the LayoutInflater to do the task. But what about other functions like registerReceiver() ? How do I get the functionality of 'registerReceiver()' from any other class , obviously I wouldn't want every such class to extend Activity. Static access by "Activity.function_name" is also not possible as these functions are not static.
Certain services can be accessed from anywhere. For example 'println()' or Log.e(),System functions can be called from anywhere, whenever needed. Is there a similar way for other critical functions?
Conclusion:
Pass Context to destination class. For accessing some functions however, type-casting the passed Context to Activity is required.
Both Changdeo's and BT's answers are correct.
Thanks.
Although I have not found any documentation explicitly stating why, in every case where I have ever needed to do this, simply passing the Activity's Context is sufficient.
For a Context called contextActivity passed into any function, the following will allow access to these member functions you require:
((Activity) contextActivity).<anyMemberFunction>
Or if you need these functions in multiple cases it might be simplest just to do the following:
Activity myActivity = (Activity) contextActivity;
From there you can access these Activity member functions whenever you like by using:
myActivity.<desiredFunction>;
As I mentioned, I have never found any case where this hasn't worked, but also no solid documentation saying this will always work. This is the trick I have seen consistently used though. If anyone has more to add, please do.
For Ex
Class XYZActivity extends Activity
{
......
......
MyClass myClass = new MyClass(this);
// OR you can pass just context
// MyClass myClass = new MyClass(getContext());
}
Class MyClass
{
Context context;
Myclass(Context context)
{
this.context = context;
context.registe....//Or any function
}
}
The setup: custom adapter that feeds data into ListView. Data is based on some numbers calculated by external service. I am using AIDL to bind the service and get the data I need.
Problem: How do I know when to unbind the service? Connection is private to adapter itself and the only way to detect that whole application is shutting down is overriding unregisterDataSetObserver. Or at least I didn't find another way and this one worked well with same adapter using content provider+content observer. Does not work with AIDL though - I'm getting the ServiceConnectionLeaked error.
I know I can add a "unbindFromService" method to my adapter and call it from onDestroy() of my activity but that isn't elegant enough for me. I'd prefer some "honest" trigger if possible.
Implement ActivityLifecycleCallbacks in your CustomAdapter and then from your activity call
mAdapter.setActivity(this);
Adapter class
public class CustomAdapter extends ArrayAdapter<String> implements ActivityLifecycleCallbacks{
Activity mActivity;
public void setActivity(Activity activity) {
/* or you could remove setactivity and do below operation in Constructor */
mActivity = activity;
mActivity.getApplication().registerActivityLifecycleCallbacks(this);
}
#Override
public void onActivityDestroyed(Activity activity) {
/*unregister so that you do not get callbacks after activity is destroyed*/
if(activity instanceof MainActivity)
mActivity.getApplication().unregisterActivityLifecycleCallbacks(this);
/*unregister your activity or in any other callbacks*/
}
/* skipped other dummy functions*/
}
Connection is private to adapter is wrong. Adapter is Context-less and so a service should not be private to the adapter.
Your adapter will never be able to bind to the service without a Context. Inherently, you have a function that provides a Context for your adapter to bind to the service. Therefore, the bound connection is not private to your Adapter: It is the Context passed that allowed its creation.
The real problem is that AFAIK there is no way to listen to the context. Meaning, say that you held the context instance inside your adapter: There is no way to allow the adapter to listen to this context and somehow know that the Activity is done. This leads you to accept the not-elegant-enough-for-you solution: Your activity should notify the adapter which is using its context! Otherwise, you will end up with a more hacked-up solution.
Please notice that the whole debate in the comments deals with your "service is private to the adapter" thingy. In reality, the elegant way to do this would be to have a ServiceProvider interface that provides the connection and this would be implemented by your activity. You adapter should be initialized with a ServiceProvider passed. Some functions would be getConnection and isRunning. In this way, your Activity will take care of the connection while the Adapter uses it. (Synchronization)
I would use a Service to insert fresh data into a SQLite table or to refresh a ContentProvider, then use a SimpleCursorAdapter (android.support.v4.widget.SimpleCursorAdapter which is backward compatible) and the LoaderManager, SQLiteCursorLoader/CursorLoader, Loader pattern to show the data on a List or ListFragment.
The SQLiteCursorLoader is not given by the Android SDK, but Mark Murphy have one on in GitHub, so you could take a look at it if you want to persist the fresh data in a local SQLite DB.
Since the Service can be independent from the underlying data in SQLite and the Adapter for the list you can unbind it when is finished inserting new data or refreshing the provider so you can procede with the recommended patterns to unbind Services (See this question: Android: How to safely unbind a service) and take a look at http://developer.android.com/reference/android/app/Service.html#ProcessLifecycle.
I really hope this gives you a hint. Good luck!
In some places we were giving like "DatabaseUtil db=new DatabaseUtil(DailyPlanView.this);" where DatabaseUtil is the class with the constructor argument is context. But if we create the object for the DatabaseUtil class in the DailyPlanVIew class we are using the above code. My doubt is what is the use of the context and instead of passing the context object as argument why we are passing "this".
Whenever you are dealing with Context, its important to understand its used in everything. From using a database to obtaining system services. This is required by the way android works with Context. Specifically when you are passing this you are basically passing the class that encapsulates this statement.
class MyActivity extends Activity
{
onCreate(Bundle bundle)
{
View v = new View(this);
}
}
passing this refers to the object that encapsulates it. This is a Object oriented concept... Where this is reffering to MyActivity. One thing to keep in mind when passing context is ensure that you are passing the correct kind. Some Context objects have a longer lifespan than others and if not managed properly can lead to Context leaking. Specifically in this example, this works because Activity extends Context.
The differences occur in the View class.
getApplicationContext()
getBaseContext()
this, which in the Context of an activity has the life span of an Activity (Example above)
One thing to add about Context is that it is basically a reference to the current Application and it's specific data.
Some more information about context can be found in this thread:
What is 'Context' on Android?
I have a singleton that holds a lot of information on my App (ACCU.class).
I'm using the application context to do a single initialization and single finishing.
One of the key features is another singleton called IMCDefinition that reads from a raw resource named imc.xml. If I call the line IMCDefinition.getInstance(getResources().openRawResource(R.raw.imc)); from an Activity Context it works. From an Application context it doesn't...
Following goes the code:
public class App extends Application
{
public App()
{
IMCDefinition.getInstance(getResources().openRawResource(R.raw.imc));
ACCU.getInstance(this);
System.out.println("Global ACCU Object Initialized");
}
}
Done! You don't get to mess with the Constructor in this class. onCreate() is the way to go. Put your code there. Forget about the question. Should i put this in a separate answer?
I have to use context in many places of my code such as database operations, preference operations, etc. I don't want to pass in context for every method.
Is it a good practice to create a reference to application context at the main Activity and use it anywhere such as database operations? So, I don't need some many context in method parameters, and the code can avoid position memory leak due to use of Activity Context.
public class MainActivity extends Activity {
public static Context s_appContext;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
s_appContext = this.getApplicationContext();
To me it smells like a hack although I do agree it can be a pain having to pass all those contexts around. At least one problem I see with that approach is when trying to unit test any of your code needing a context - now everything depends on your main activity's onCreate method having been called.