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();
}
}
Related
I'm trying to implement Global variables in and Android Studio Application that uses BLE gatt services.
I need to save a number received from BLE in a global variable.
So I have created this class:
public class Globals extends Application {
private List<Float> current = new ArrayList<>();
public float getCurrent() {
return current.get(current.size()-1);
}
public void setCurrent(float someVariable) {
this.current.add(someVariable);
}
}
I have also modified the manifest with android:name. I can use correctly these functions in both the main activity and in some fragment. But I want to implement it in other extends different from Application or Activity.
In another java file I have this class:
class SerialSocket extends BluetoothGattCallback {
// Here how can i get the function declared in Globals??
Globals globalClass = (Globals) getApplicationContext();
Obviousy I can't use getApplicationContext() inside the BluetoothGattCallback extend, but what code can I use?
You can create a static instance of Globals and access.
public class Globals extends Application {
private static Globals instance;
private List<Float> current = new ArrayList<>();
#Override
public void onCreate() {
instance = this;
super.onCreate();
}
public float getCurrent() {
return current.get(current.size()-1);
}
public void setCurrent(float someVariable) {
this.current.add(someVariable);
}
public static Globals getInstance() {
return instance;
}
public static Context getContext(){
return instance;
// or return instance.getApplicationContext();
}
}
Now anywhere in app you can access the current variable or change the value by
Globals.getInstance().getCurrent();
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;
}
In my Android app I'm trying to get a DatabaseHelper object injected into ArticleView but Dagger complains with the following error message:
Error:(11, 7) error: android.content.Context cannot be provided without an #Provides-annotated method.
dk.jener.paperflip.ArticleActivity.database
[injected field of type: dk.jener.paperflip.model.retriever.DatabaseHelper database]
dk.jener.paperflip.model.retriever.DatabaseHelper.<init>(android.content.Context context)
[parameter: android.content.Context context]
How do I fix it?
My code is as follows:
#Singleton
#Module
public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
#Inject
public DatabaseHelper(Context context) {
super(context, "foobar", null, 1);
}
...
}
#Module
public class ApplicationContextModule {
private final Context context;
public ApplicationContextModule(Context context) {
this.context = context;
}
#Provides
#Singleton
public Context provideApplicationContext() {
return context;
}
}
#Singleton
#Component(modules = { DatabaseHelper.class })
public interface RetrieverComponent {
void inject(ArticleActivity activity);
}
public class ArticleActivity extends AppCompatActivity {
#Inject
DatabaseHelper database;
#Override
protected void onCreate(Bundle savedInstanceState) {
...
RetrieverComponent component = DaggerRetrieverComponent.builder()
.applicationContextModule(new ApplicationContextModule(getApplicationContext()))
.build();
component.inject(this);
}
...
}
As far as I can figure Context is already provided by ApplicationContextModule#provideApplicationContext .
In the provided code seems that you missed to include the ApplicationContextModule module in your component. It should be like:
#Component(modules = { ApplicationContextModule.class })
Also DatabaseHelper does not need to have #Module annotation (it is not a module but just a normal class).
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.
is there any way to use in my adapter class.
public class ImageAdapter extends BaseAdapter {
int mGalleryItemBackground;
private Context mContext;
if(!flag){
////
}
// Here i want to set if else condition but i am not able to do this.*/
}
You can use if-else syntax only in methods or constructors. I assume you want to initialize fields of ImageAdapter looking at some parameters. If so, you can do it at the constructor:
public class ImageAdapter extends BaseAdapter {
int mGalleryItemBackground;
private Context mContext;
public String myField;
public ImageAdapter(int mGalleryItemBackground, Context mContext, boolean flag) {
this.mGalleryItemBackground = mGalleryItemBackground;
this.mContext = mContext;
if(!flag){
myField = "abc";
} else {
myField = "cba";
}
}
}
You can do this by following code.
String field = flag?"success":"fail";