Can't get the Context where is define in the super class - java

I have a super class:
public abstract class AsyncRequest {
private Context context;
public AsyncRequest(Context context) {
this.context = context;
}
public Context getContext() {
return this.context;
}
protected abstract String getHost();
}
And two sub class:
public abstract class IRequest extends AsyncRequest{
IRequest(Context context) {
super(context);
}
#Override
public String getHost() {
return getHostFromSharedPreferences();
}
private String getHostFromSharedPreferences(){
SharedPreferences preferences = ((Activity) getContext()).getPreferences(Context.MODE_PRIVATE);
return preferences.getString(IPresenter.SP_HOST,"");
}
}
public class LoginRequest extends IRequest{
public LoginRequest(Context context, String name, String password) {
super(context);
}
}
when I init a LoginRequest, and I use getContext() to get the context in IRequest,I get NullPointerException.
I don't know why,do someoneelse know?

Make it sure when you instantiate LoginRequest you are sending non null Context as argument
LoginRequest(Context context, String name, String password)

Class A
{
int x;
A(int x)
{
this.x=x;
}
X getX()
{
return this.x;
}
}
What value are you passing to variable "x" here ?
In your case it is context.
To get the context of a class in android, there is always an inbuilt getApplicationContext() method.
My suggestion is,
Class A
{
Context context;
onCreate Method Block
{
....................
....................
context=getApplicationContext();
}
}
Now use this context variable wherever inside your class, it wouldn't throw null pointer exception.

I just know the casue to problem right now.
As you see,I have init a LoginRequest with the constructor with context,of course the context is null,and the method getContext() in the AsyncRequest I try to invoke using loginRequest.getContex() will get an object which is not null.But the issue is that where I try to invoke the method getContext() is in the IRequest,which means that iRequest.getContext(),but I did't init the iRequest,So this is the cause!.
The problem teachs me that you should know the really object which invokes the method.I simply think that because the LoginRequest extends IRequest,when I init LoginRequest,I init IRequest,which is a bad idea you need to give up.
Because I need to invoke the same code in the Object which extends IRequest,so I invoke the code in IRequest,but I can't get the context in IRequest.There is one of the ways to solve the problem:
I create a class named App and let it extends Application,in this class it has one attribute public static Context context,and in the onCreate method I init the context.Because App is alive in the whole android lifecycle,so I can get it anywhere.Just use App.context.
Finally,Thanks everybody try to solve my problem.

Change this:
public AsyncRequest(Context context) {
this.context = context;
}
...to this:
public AsyncRequest(#NonNull Context context) {
// noinspection ConstantConditions - public API
if(context == null) {
throw new NullPointerException();
}
this.context = context;
}
You'll likely find that you're calling the constructor with a null Context. The constructor is responsible for ensuring that the object's fields are valid, so it's important to check for invalid arguments.

Related

How to inject Context in non-activity class?

I am trying to inject Context in non-activity class. In my case, I am trying to inject in Model class (from MVP pattern). I need Context to get string from resources. The method result() returns Observable which returns ViewModel which is modified API model. ViewModel is used to show in MainActivity. I tried this code, but Context is null, I think that it is not injected.
public class MainActivityModel implements MainActivityMVP.Model {
#Inject
Context context;
private Repository repository;
public MainActivityModel(Repository repository) {
((App) getApplication()).getComponent().inject(this); //Cannot resolve getApplication() method :(
this.repository = repository;
}
#Override
public Observable<List<ViewModel>> result(String username) {
return repository.getRepositories(username).map(new Func1<List<Repository>, List<ViewModel>>() {
#Override
public List<ViewModel> call(List<Repository> repositories) {
List<ViewModel> viewModelList = new ArrayList<ViewModel>();
for (Repository repository : repositories) {
// here Context is null
viewModelList.add(new ViewModel(context.getString(R.string.repository) + repository.getName()));
}
return viewModelList;
}
});
}
}
This is Component class, where there is inject(MainActivityModel target) method which I am not able to use inject MainActivityModel because getApplication is not available from non-Activity class:
#Singleton
#Component(modules = {ApplicationModule.class, MainActivityModule.class, GithubApiModule.class})
public interface ApplicationComponent {
void inject(MainActivity target);
void inject(MainActivityModel target);
}
I think that Context can be sent via result(String username, Context context) method. But what is the meaning of Dependency Injection if I passing Context as method parameter? Maybe I misunderstood fundamental concept of DI.
So my question: is it possible to inject Context in non-activity class? Or it should be passed as method parameter?
For injecting a Context you will need to write a module with a provides method:
#Module (injects = {MainActivityModel.class})
public class RootModule {
private Context context;
public RootModule(App application) {
this.context = application.getApplicationContext();
}
#Provides
#Singleton
Context provideContext() {
return context;
}
}
In your custom App class:
public class App extends Application {
public ObjectGraph objectGraph;
#Override
public void onCreate() {
super.onCreate();
objectGraph = ObjectGraph.create(getInjectionModule());
}
protected Object getInjectionModule() {
return new RootModule(this);
}
}
And inject in model's constructor:
public MainActivityModel(Repository repository) {
((App) getApplication()).objectGraph.inject(this);
this.repository = repository;
}

Implementing a class of only one instance

Good day everybody! Here's my question:
I need to make a Tutorial for my app. For doing this, I've created a class called TutorialClass which contains some methods that I need to call from several other classes. The working flow is quite like this:
Class 1:
//...
if(Tutorial.tutorialStep==Tutorial.TUTORIAL_STEP1){
Tutorial.TutorialStep1();
Tutorial.tutorialStep=Tutorial.TUTORIAL_STEP2;
}
Class 2:
//...
if(Tutorial.tutorialStep==Tutorial.TUTORIAL_STEP2){
Tutorial.TutorialStep2();
Tutorial.tutorialStep=Tutorial.TUTORIAL_STEP3;
}
And so on...
All the classes I use, have not to extend Activity necessarily
You can find this piece of code in several class I use.
So, first of all I need to create an instance of TutorialClass
TutorialClass Tutorial = null;
So here is the question: how can I use this instance from all the classes in which I have to show my tutorial? As you can see, the value of tutorialStep has to be visible from all classes, and all classes have to see that value or change it, in order to let the tutorial go on.
Here is the code of my tutorial class:
public class TutorialClass{
Context context;
public static int tutorialStep;
final int TUTORIAL_STEP1=1;
final int TUTORIAL_STEP2=2;
final int TUTORIAL_STEP3=3;
//...
TutorialClass(Context context){
this.context = context;
}
public void Tutorial1() { ... }
public void Tutorial2() { ... }
public void Tutorial3() { ... }
//...
}
I've read that exist a Singleton class that allows to reach my objective, but I've noticed that it's not the best solution. Do you have any solution? Thanks to all!
you need to create another class that return instance of the TutorialClass
public class TutorielInstance {
private static TutorialClass instance;
private static Context context;
public static synchronized TutorialClass getInstance(){
if(instance==null){
instance=new TutorialClass(context);
}
return instance;
}
public static void setContext(Context c){
context=c;
}
}
and then in the activity you can use
TutorielInstance.setContext(this);
TutorialClass tutorialClass=TutorielInstance.getInstance();

how to mock private static inner class?

I have a class like
public class Enclosing {
public String methodA() {
Inner.getContext();
......
}
private static class Inner{
// some context init
public static Context getContext() {
.....
}
}
}
Now I want to test methodA without invoking the real Inner.getContext(). I have been searching all over but cannot find a working solution. I am using Java 8. Can I have some help please? Many thanks
You can apply the extend and override technique, here's how it works.
Given this code:
public class Enclosing {
public String methodA() {
Inner.getContext();
......
}
You can move the Inner.getContext() call to a protected method:
public class Enclosing {
public String methodA() {
getContext();
......
}
protected void getContext() {
Inner.getContext();
......
}
And then in your test case, you can extend the enclosing class, and override the protected method to do whatever you want with it:
#Test
public void test_something() {
Enclosing enclosing = new Enclosing() {
#Override
protected void getContext() {
// do what you need here
}
};
// your test code on enclosing where you control getContext
}
As an alternative to #janos' answer, you can inject a strategy (basically, the "prefer composition over inheritance" approach):
interface ContextStrategy {
void getContext();
}
and then inject an instance of this into the constructor of Enclosing:
class Enclosing {
private final ContextStrategy ctxStrategy;
Enclosing(ContextStrategy ctxStrategy) {
this.ctxStrategy = ctxStrategy;
}
String methodA() {
ctxStrategy.getContext();
// ...
}
}
and then implement this interface for the production case, as a nested class in Enclosing:
static class ContextStrategyImpl implements ContextStrategy {
#Override public void getContext() {
Inner.getContext();
}
}
and implement an alternative version for your mock case.
You should not mock a private class (whether it is a nested class like the one here or an actual inner class).
Instead, mock only the Context type if it's really needed (otherwise, use a real Context object). For example, such a test is shown below, using the JMockit library:
#Test
public void mockingTheContext(#Mocked Context anyContext) {
new Expectations() {{
// record any method call results expected from "anyContext"
}};
new Enclosing().methodA();
new Verifications() {{
// verify calls to "anyContext", if applicable
}};
}
In the test above, the fact that Context is created inside a nested class is irrelevant. In general, mocking private methods or classes should always be avoided, since they are only implementation details.

How we can pass data?

How we can pass data of a methods MainAntivity to another class type SQLiteOpenHelper.
For example we have :(MainActivity.java)
public class MainActivity extends ActionBarActivity {
public static String PACKAGE_NAME;
public String xxx(){
PACKAGE_NAME = getApplicationContext().getPackageName();
return PACKAGE_NAME;
}
}
And another class is :(DB.java)
public class DB extends SQLiteOpenHelper{
MainActivity cc = new MainActivity();
Log.d("test",(String) cc.xxx());
}
But above code not work.
You shouldn't instantiate activity classes this way. Use a separate class instead, where you can define methods which you'd like to use somewhere else. In your case, receiving package name, I'd do something like this
public class PackageNameHelper
{
private Context mContext;
public PackageNameHelper(Context context)
{
mContext = context;
}
public String GetPackageName(){
return mContext.getPackageName();
}
}
Then in your activity / SQLite helper you'd do:
PackageNameHelper helper = new PackageNameHelper(getApplicationContext());
String packageName = helper.getPackageName()
Or you can make the helper class static, that way Context must be passed directly int the getPackageName() method, like
public class PackageNameHelper
{
public static String GetPackageName(Context context){
return context.getPackageName();
}
}
and use it like
//Where context is an instance of a context
String packageName = PackageNameHelper.getPackageName(context);
You should not instantiate your Activities, In your case in my opinion a good way can be defining a constructor for your DB class that takes an argument as context for this application. Than you can save it in a member variable and use it whenever you need.
public class DB extends SQLiteOpenHelper {
Context mContext;
/* Constructor */
public DB(Context context) {
mContext = context;
}
}
If you need to package name within your DB class codes, you can use mContext.getPackageName() to retrieve package name.

Get application context from non activity singleton class

In my android project, I have ImageAdapter class in which I pass app context for some further needs.
public class ImageAdapter extends BaseAdapter {
private Context c;
public ImageAdapter(Context c) {
this.c = c;
}
...
}
The problem is that I wanna make ImageAdapter as a singleton to have an easy access to the instance of this class from all of my activities. But I have no idea how to pass app context from getApplicationContext() method from one of my activities to ImageAdapter. So is there any "magic" to do that as follows?
public class ImageAdapter extends BaseAdapter {
private Context c;
private static class Holder {
public static final ImageAdapter IA = new ImageAdapter();
}
private ImageAdapter() {
this.c = /* some magic here */.getApplicationContext();
}
public static ImageAdapter getInstance() {
return Holder.IA;
}
...
}
Maybe you have some other ideas for sharing ImageAdapter for any of my activities.
I'm a newbie to android and I'm a little bit confused with the ways of passing data among activities.
I will be grateful for any help.
Update: 06-Mar-18
Use MyApplication instance instead of Context instance. Application instance is a singleton context instance itself.
public class MyApplication extends Application {
private static MyApplication mContext;
#Override
public void onCreate() {
super.onCreate();
mContext = this;
}
public static MyApplication getContext() {
return mContext;
}
}
Previous Answer
You can get the the application context like this:
public class MyApplication extends Application {
private static Context mContext;
#Override
public void onCreate() {
super.onCreate();
mContext = getApplicationContext();
}
public static Context getContext() {
return mContext;
}
}
Then, you can call the application context from the method MyApplication.getContext()
Don't forget to declare the application in your manifest file:
<application
android:name=".MyApplication"
android:icon="#drawable/icon"
android:label="#string/app_name" >
I'd rather pass a context instance as a parameter to every method in singleton which really needs it
APPROACH #1:
Since you specify that ImageAdapter is a singleton, one simple answer is to create that singleton from a class that has access to app context:
public class MyApplication extends Application {
#Override
public void onCreate() {
super.onCreate();
ImageAdapter.createIt(this);
}
}
public class ImageAdapter extends BaseAdapter {
private static ImageAdapter it;
// Get the singleton.
public static ImageAdapter getIt() {
return it;
}
// Call this once, to create the singleton.
public static void createIt(Context context) {
it = new ImageAdapter(context);
}
private final Context c;
private ImageAdapter(Context context) {
c = context;
}
}
APPROACH #2:
If it were not a singleton, then I would use the accepted answer. In that case, remove the local variable from ImageAdapter, because context can always be obtained from MyApplication. Expanding on the accepted answer, if you want a local method as a convenience, define ImageAdapter.getContext(). Complete solution:
public class MyApplication extends Application {
private static Context appContext;
public static Context getContext() {
return appContext;
}
#Override
public void onCreate() {
super.onCreate();
appContext = this;
}
}
public class ImageAdapter extends BaseAdapter {
public ImageAdapter() {
}
// [Optional] Call this whenever you want the app context.
private Context getContext() {
return MyApplication.getContext();
}
}

Categories