I am currently trying to call a method from a utility class that will reference a new cursor created for this utility method. Unfortunately, my new class will not let me create the cursor without context. I have tried numerous ways of passing context from the calling activity, but get null pointer exceptions in most cases.
Here is the portion of my code:
findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Tools.pickRandomItem();
}
});
and in the Tools Class:
public static void pickRandomItem() {
Cursor cur = getContentResolver().query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, null,
null, null,MediaColumns.TITLE + " ASC");
}
Using the above code it throws an error on getContentResolver(), and all attempts I've made to pass context have failed.
I am fairly new to programming for Android, and don't fully understand the concept of contexts. Any help you could provide would be greatly appreciated!
Create a class that extends Application for your project (you have to declare it in the Manifest too), in the Application make a
private static MyApplication app
in the onCreate() of it assign it to the field
app = this;
and make a
public static MyApplication get()
in it. When you need a Context you can use a
MyApplication.get()
A few hints on Context:
Get Context in you View via getContext() and pass it to getContentResolver(context).
Use application-context approach as described here by #apps.
Don't store context inside Activity or Views. This leads to memory leaks.
Related
Hi I am kind of new to android, still learning. And my problem is that, for example I have a method which was created in the MainActivity and I need to call it from another class.
Is it a good practice to get the instance of the MainActivity so that I may be able to call the method in the MainActivity from another class?
This is an example:
public class MainActivity extends AppCompatActivity {
private static MainActivity inst;
public static MainActivity instances()
{
return inst;
}
#Override
public void onStart() {
super.onStart();
inst = this;
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void showToast (String text){
Toast.makeText(inst, text, Toast.LENGTH_SHORT).show();
}
Then this is the other class:
public class broadcastReceiver extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
MainActivity instance = new MainActivity();
instance.showToast(AnyText);
}
}
I saw this type of coding while looking at tutorials and wondered if it's a good practice or maybe there might be a better way? Since I get the warning of Do not place Android Context Classes in static classes
Thanks in advance for any insight or help! :D
I guess You want to make A singleton of Activity Class
but as Mention in All Pattern Design
using Singleton
If and Only If its only way to Make A Global Variable
Singleton is based on Lazing Initialing and Load On Memory
so I guess If you cant to Interact With Activiy You can Use
BroadCast Or Intents
You can call method from another class like this:
MainActivity instance = new MainActivity();
String data = instance.data();
and create data method in that class:
public String data() {
return mangaId;
}
Is it a good practice to get the instance of the MainActivity so that
I may be able to call the method in the MainActivity from another
class?
You totally can do this but you don't need to make it static and use a constructor. Just create a new instance like follows and you'll access the public methods
MainActivity mainActivity = new MainActivity();
mainActivity.showToast(text);
About the warning
It suggests avoiding having context fields defined as static. The warning itself explains why: It's a memory leak. If you make it static it will be accessible anywhere in your app and some methods can hold the reference to this context for a really long time and it won't be garbage collected. It will lead to a outofmemory exception and the app could crash. But here you're trying to invoke showToast() from broadcastreceiver so you can just get rid of static references. And it you need them in the future you safe ways to inject context
You cannot create instances of an Activity using the new operator.
You have to use an Intent to let an Activity to be created.
So you cannot get a reference to an instance of your activity.
The only methods you can use of your activity class are static ones.
THE PROBLEM
I have two Android classes that I want to test:
CommentContentProvider, which extends ContentProvider and is backed by a SQLiteDatabase.
CommentActivity, which extends Activity and accesses CommentContentProvider indirectly through a ContentResolver.
I currently have two test classes:
CommentContentProviderTest, which extends ProviderTestCase2<CommentContentProvider> and uses a MockContentResolver. This works fine.
CommentActivityTest, which extends ActivityInstrumentationTestCase2<CommentActivity>. This works fine, except for the parts of CommentActivity that access CommentContentProvider.
The problem is that, when CommentActivity accesses CommentContentProvider, it does so through the standard ContentResolver:
ContentResolver resolver = getContentResolver();
Cursor cursor = resolver().query(...);
Thus, when CommentActivityTest is run, it launches CommentActivity, which accesses (read and write) the production database, as shown in the above two lines.
My question is how to make CommentActivity use the standard ContentResolver in production but MockContentResolver during test.
RELATED QUESTIONS
This differs from Android unit testing with ContentProviders and other questions I've found about testing ContentProviders because those can extend android.test classes designed for testing ContentProviders while I need to extend a class for testing an Activity.
This is similar to How to inject a dependency when testing an Android activity without a third-party framework?, which was also posted by me but is unanswered. I am now willing to use a third-party framework if it will help.
Query using MockContentResolver leads to NullPointerException is related and leads to the solution in Option 1 below, but I do not know if it is the best solution in my case.
POSSIBLE SOLUTIONS
It would be nice if I could inject a ContentResolver (possibly a MockContentResolver or RenamingDelegatingContext) through the Intent that starts CommentActivity, but I can't do that, since Contexts are not Parcelable.
Which of the following options are best, or is there a better option?
OPTION 1
Add a debug flag to the Intent that starts CommentActivity:
public class CommentActivity extends Activity {
public static final String DEBUG_MODE = "DEBUG MODE";
private ContentResolver mResolver;
#Override
protected void onCreate(Bundle savedInstanceState) {
:
// If the flag is not present, debugMode will be set to false.
boolean debugMode = getIntent().getBooleanExtra(DEBUG_MODE, false);
if (debugMode) {
// Set up MockContentResolver or DelegatingContextResolver...
} else {
mResolver = getContentResolver();
}
:
}
I don't like this option because I don't like to put test-related code in my non-test classes.
OPTION 2
Use the abstract factory pattern to pass a Parcelable class that either provides the real ContentProvider or a MockContentProvider:
public class CommentActivity extends Activity {
public static final String FACTORY = "CONTENT RESOLVER FACTORY";
private ContentResolver mResolver;
#Override
protected void onCreate(Bundle savedInstanceState) {
:
ContentResolverFactory factory = getIntent().getParcelableExtra(FACTORY);
mResolver = factory.getContentResolver(this);
:
}
where I also have:
public abstract class ContentResolverFactory implements Parcelable {
public abstract ContentResolver getContentResolver(Context context);
}
public abstract class RealContentResolverFactory extends ContentResolverFactory
public ContentResolver getContentResolver(Context context) {
return context.getContextResolver();
}
}
public abstract class MockContentResolverFactory extends ContentResolverFactory
public ContentResolver getContentResolver(Context context) {
MockContentResolver resolver = new MockContentResolver();
// Set up MockContentResolver...
return resolver;
}
}
In production, I pass in (via an intent) an instance of RealContentResolverFactory, and in test I pass in an instance of MockContentResolverFactory. Since neither has any state, they're easily Parcelable/Serializable.
My concern about this approach is that I don't want to be "that guy" who overuses design patterns when simpler approaches exist.
OPTION 3
Add the following method to CommentActivity:
public void static setContentResolver(ContentResolver) {
:
}
This is cleaner than Option 1, since it puts the creation of the ContentResolver outside of CommentActivity, but, like Option 1, it requires modifying the class under test.
OPTION 4
Have CommentActivityTest extend ActivityUnitTestCase<CommentActivity> instead of ActivityInstrumentationTestCase2<CommentActivity>. This lets me set CommentActivity's context through setActivityContext(). The context I pass overrides the usual getContentResolver() to use a MockContentResolver (which I initialize elsewhere).
private class MyContext extends RenamingDelegatingContext {
MyContext(Context context) {
super(context, FILE_PREFIX);
}
#Override
public ContentResolver getContentResolver() {
return mResolver;
}
}
This works and does not require modifying the class under test but adds more complexity, since ActivityUnitTestCase<CommentActivity>.startActivity() cannot be called in the setUp() method, per the API.
Another inconvenience is that the activity must be tested in touch mode, and setActivityInitialTouchMode(boolean) is defined in ActivityInstrumentationTestCase2<T> but not ActivityUnitTestCase<T>.
FWIW, I am being a little obsessive about getting this right because I will be presenting it in an Android development class I am teaching.
Option 2 seems best to me. I'm not bothered about the use of a factory; I'm more bothered by the intent causing a change in behavior at a distance. But the other solutions put non-production code in the production code, so what you are testing isn't much like how things work in production. Hope that helps.
I (having mediocre developing skills) actually try to use Sugar as a database wrapper for my android project.
Therefore, I was following along the "Getting-Started-Guide" (http://satyan.github.io/sugar/getting-started.html) to get ready as soon as possible.
I created a class for my entities, called DataSet.java :
import com.orm.SugarRecord;
public class DataSet extends SugarRecord{
int someData;
double evenMoreData;
public DataSet(Context ctx){
super(ctx);
}
public DataSet(Context ctx,
int someData,
long evenMoreData) {
super(ctx);
this.someData = someData;
this.evenMoreData = evenMoreData;
}
}
I call the class in the following way:
someGreatClass something;
someMoreGreatCode somemore;
DataSet dataSet = new DataSet(
ctx, // Here Eclipse throws the error
something.method(),
somemore.anothermethod());
DataSet.save();
When I try to build this and to push it onto my device, Eclipse refuses to compile and throws this error:
ctx cannot be resolved to a variable
Considering the fact that I'm relatively new to Android development, the error may be obvious and I hope to get a tip how to solve this.
P.S.: Furthermore, I don't fully get the developer's statement in the getting-started-Note:
Please retain one constructor with Context argument. (This constraint will be removed in subsequent release.)
Thank you very much!
// Edit: Did edit the class name from LocationDataSet to Data set for clarification
First of all, the getting-started-note tells you that you need a constructor with only a context parameter, you did this here so that's ok
public DataSet(Context ctx){
super(ctx);
}
about
ctx cannot be resolved to a variable
I think you don't have a variable called ctx, I don't know if you're familiar with android context? (basically a context is a service or an activity), if you're using this code in an activity or a service, just use the 'this' keyword and not the ctx variable
The code you provide doesn't really show what you're doing, but you showed us the code from 'DataSet', but the error happens with a LocationDataSet? And you're calling save on DataSet?
The save method must be called on an object, not a class.
Also don't forget that sugar needs the special application class in the manifest
UPDATE with example:
Your dataset class (the sugarrecord) should look like this, that's ok in your code as far as I can see
public class DataSet extends SugarRecord<DataSet>{
private String someData;
public DataSet(Context c){
super(c);
}
public DataSet(Context c, String someData){
super(c);
this.someData = someData;
}
}
An activity that uses the record should look like this
public class SomeActivity extends Activity {
public void someMethodThatUsesDataSet(){
// Create a dataset object with some data you want the save and a context
// The context we use here is 'this', this is the current instance of SomeActivity,
// you absolutely need this, I think this is what you're doing wrong,
// you can't use ctx here because that's not a known variable at this point
DataSet example = new DataSet(this, "data you want to save");
// Tell Sugar to save this record in the database
example.save();
}
}
I'm writing a library class to encapsulate some of my logic in my first Android app. One of the functions which I want to encapsulate is a function which queries the address book. As such, it needs a ContentResolver. I'm trying to figure out how to keep the library functions black-boxed... that is, to avoid having each Activity pass in its own context to get a ContentResolver.
Problem is I cannot for the life of me figure out how to get a ContentResolver from within my library function. I can't find an import that contains getContentResolver. Googling said to use getContext to get a Context on which to call getContentResolver, but I can't find an import containing getContext either. Next posts said to use getSystemService to get an object to call getContext. BUT - I can't find any import containing getSystemService either!
So I'm stuck wondering, how can I get a ContentResolver within an encapsulated library function, or am I pretty much stuck having every calling Activity pass in a reference to its own context?
My code is something basically like this:
public final class MyLibrary {
private MyLibrary() { }
// take MyGroupItem as a class representing a projection
// containing information from the address book groups
public static ArrayList<MyGroupItem> getGroups() {
// do work here that would access the contacts
// thus requiring the ContentResolver
}
}
getGroups is the method where I was looking to avoid having to pass in a Context or ContentResolver if I could, as I was hoping to have it cleanly black-boxed.
You can use like this:
getApplicationContext().getContentResolver() with the proper context.
getActivity().getContentResolver() with the proper context.
Have each library function call pass in a ContentResolver... Or extend Application to keep hold of a context and access it statically.
Here is how I wound up doing this, for any who may find this thread in the future:
I used sugarynugs' method of creating a class that extends Application, and then added the appropriate registration in the application manifest file. The code for my application class is then:
import android.app.Application;
import android.content.ContentResolver;
import android.content.Context;
public class CoreLib extends Application {
private static CoreLib me;
public CoreLib() {
me = this;
}
public static Context Context() {
return me;
}
public static ContentResolver ContentResolver() {
return me.getContentResolver();
}
}
Then, to get a ContentResolver in my library class, my function code is such:
public static ArrayList<Group> getGroups(){
ArrayList<Group> rv = new ArrayList<Group>();
ContentResolver cr = CoreLib.ContentResolver();
Cursor c = cr.query(
Groups.CONTENT_SUMMARY_URI,
myProjection,
null,
null,
Groups.TITLE + " ASC"
);
while(c.moveToNext()) {
rv.add(new Group(
c.getInt(0),
c.getString(1),
c.getInt(2),
c.getInt(3),
c.getInt(4))
);
}
return rv;
}
A bit hard without seeing more of how you are coding your library, but I don't see another option then to use the context, and so pass that when calling that class.
A 'random' class does not have the environment to get a contentresolver: you need a context.
Now it's not too strange to actually pass your (activity) context to your class. From http://android-developers.blogspot.com/2009/01/avoiding-memory-leaks.html
On Android, a Context is used for many operations but mostly to load and
access resources. This is why all the
widgets receive a Context parameter in
their constructor. In a regular
Android application, you usually have
two kinds of Context, Activity and
Application. It's usually the first
one that the developer passes to
classes and methods that need a
Context
(emphasis mine)
I want to use a singleton pattern to hold a database and some other data/methods for my Android application.
I realize there are many reasons against singletons, but for this case I'd like to use it.
I've sub-classed UIApplication and made a data class within it called MyAppData.
MyAppData needs to have access to the SQLite database.
When I create the databse, I need to pass a context. I could pass the application context, but it will not directly relate to MyAppData.
I don't know if this wlll cause problems with my code.
So my thought is to have MyAppdata extend android.content.ContextWrapper. I don't think I should extend Activity because it's really not an activity, its a data class with methods to access the database.
I'm wondering if I extend ContextWrapper will there be something deep in the code I'm missing that will cause big problems down the road (memory leaks, etc).
This may not be the ideal approach to this (and I've considered other options), but my goal is to:
Have a singleton class in UIApplication that can encapsulate the database and be retrieved easily from any activity in my app.
Thanks in advance for your suggestions/warnings/advice.
Subclass android.database.sqlite.SQLiteOpenHelper and android.app.Application (with the latter being properly declared in AndroidManifest.xml).
Now,
public class MyApplication extends Application {
private static SQLiteOpenHelper openHelper;
#Override
public void onCreate() {
super.onCreate();
openHelper = new DbManager(this);
//
}
public static SQLiteDatabase getDB() {
return openHelper.getWritableDatabase();
}
}
Then have helper DAO classes that will perform instertions/updates/etc.
That's what I'm using in all of my apps.
I've used this approach:
Create a class responsible for managing the db, let's call it DBUtil. This class will extend android.database.sqlite.SQLiteOpenHelper. You can pass a reference to the application context to the constructor of this class. This class will contain methods for creating the db, adding, removing and retrieving items.
Create another class, let's call it AppCore, create a static instance of the DBUtil and a static init() method that accepts an ApplicationContext object
public class AppCore
{
public static var dbUtil:DBUtil;
public static void init( ApplicationContext context )
{
dbUtil = new DBUtil( context );
}
}
Then in the onCreate() method of our your application's main Activity, initialize the AppCore class.
#Override
protected void onCreate(Bundle savedInstanceState)
{
AppCore.init( getApplicationContext() );
}
So, it's not really a Singleton. Instead, the DBUtil instance is maintained as a static property, yet still accessible throughout your application, such as this:
AppCore.dbUtil.createNewRecord( params );
Also, I found this tutorial to be very helpful when getting started with this topic: http://developer.android.com/guide/tutorials/notepad/index.html