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";
Related
I am sort of new to Dagger and still learning it. According to the tutorials and blogs I read, currently Android does not have a way of injecting dependencies into ViewModels hence we need to use a custom ViewModelProvider.Factory, that said, I managed to get my hands on this one
public class ViewModelProviderFactory implements ViewModelProvider.Factory {
private static final String TAG = ViewModelProviderFactory.class.getSimpleName();
private final Map<Class<? extends ViewModel>, Provider<ViewModel>> creators;
#Inject
public ViewModelProviderFactory(Map<Class<? extends ViewModel>, Provider<ViewModel>> creators) {
this.creators = creators;
}
#Override
public <T extends ViewModel> T create(Class<T> modelClass) {
Provider<? extends ViewModel> creator = creators.get(modelClass);
if (creator == null) {
for (Map.Entry<Class<? extends ViewModel>, Provider<ViewModel>> entry : creators.entrySet()) {
if (modelClass.isAssignableFrom(entry.getKey())) {
creator = entry.getValue();
break;
}
}
}
if (creator == null) {
throw new IllegalArgumentException("unknown model class " + modelClass);
}
try {
return (T) creator.get();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
It works, it has worked for many of my use cases until now. Originally I had to an instance of a ViewModel with something like this
public AFragment extends BaseFragment{
#Inject
ViewModelProviderFactory providerFactory;
private MyViewModel viewModel;
MyViewModel getViewModel(){
return ViewModelProviders.of(this, providerFactory).get(MyViewModel.class);
}
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
viewModel = getViewModel();
tokenAuthenticator.setAuthenticatorListener(this);
}
}
But as the project grew I realized this was not neat, I had to do this in all my fragments so I opted for a different approach, I wanted to instantiate my ViewModel in my BaseFragment instead and I did this
public abstract class BaseFragment<T extends BaseViewModel, E extends ViewDataBinding> extends DaggerFragment implements TokenAuthenticator.AuthenticatorListener {
private static final String TAG = BaseFragment.class.getSimpleName();
public E binding;
public final CompositeDisposable disposables = new CompositeDisposable();
public T viewModel;
#Inject
ViewModelProviderFactory providerFactory;
private int layoutId;
/**
* #return view model instance
*/
public T getViewModel() {
final Type[] types = ((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments();
return ViewModelProviders.of(this, providerFactory).get((Class<T>)types[0]);
}
}
This gives me compile error
A binding with matching key exists in component: xxx.xxx.core.base.dagger.builders.FragmentBuilderModule_ContributeDeliveryPlanFragment.DeliveryPlanFragmentSubcomponent
.
.
.
A binding with matching key exists in component: xxx.xxx.core.base.dagger.builders.FragmentBuilderModule_ContributePayWithMtmMobileMoneyFragment.PayWithMtmMobileMoneyFragmentSubcomponent
java.util.Map<java.lang.Class<? extends androidx.lifecycle.ViewModel>,javax.inject.Provider<androidx.lifecycle.ViewModel>> is injected at
xxx.xxx.core.base.ViewModelProviderFactory(creators)
xxx.xxx.core.base.ViewModelProviderFactory is injected at
mika.e.mikaexpressstore.core.base.BaseFragment.providerFactory
xxx.xxx.xxx.xxx.cashondelivery.CashOnDeliveryFragment is injected at
dagger.android.AndroidInjector.inject(T) [xxx.xxx.core.base.dagger.component.AppComponent → xxx.xxx.core.base.dagger.builders.FragmentBuilderModule_ContributeCashOnDeliveryFragment.CashOnDeliveryFragmentSubcomponent]
2 errors
From the error message I can tell Dagger is complaining the ViewModelProviderFactory is being injected in the base but used in the child, I need help, is there a way to make this work? surely I want to reduce on boilerplate and repetitive code.
I finally fixed it, not how I wanted but better than having to instantiate each viewmodel from the child class. After reading this answer I came to a realization that this was not possible, so instead I removed #Inject annotation from ViewModelProviderFactory in my BaseFragment and it looked like
public abstract class BaseFragment<T extends BaseViewModel, E extends ViewDataBinding> extends DaggerFragment implements TokenAuthenticator.AuthenticatorListener {
private static final String TAG = BaseFragment.class.getSimpleName();
public E binding;
public final CompositeDisposable disposables = new CompositeDisposable();
public T viewModel;
#Inject
private ViewModelProviderFactory providerFactory;
private int layoutId;
/**
* #return view model instance
*/
public T getViewModel() {
final Type[] types = ((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments();
return ViewModelProviders.of(this, providerFactory).get((Class<T>)types[0]);
}
#MainThread
protected final void setProviderFactory(ViewModelProviderFactory providerFactory) {
this.providerFactory = providerFactory;
}
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
viewModel = getViewModel();
}
}
And injected the provider from the child fragments instead then called the setter from the BaseFragment
public AFragment extends BaseFragment{
#Inject
ViewModelProviderFactory providerFactory;
private MyViewModel viewModel;
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
setLayoutId(R.layout.layout_layout);
setProviderFactory(providerFactory);
super.onCreate(savedInstanceState);
}
}
Key here is to call setProviderFactory(provider) before super.onCreate(savedInstanceState) because when super onCreate is called the provider should not be null, it should be set and ready to create the ViewModel
here is my class, I want to call a method from DatabaseAccess class:
public class CardAdapter extends RecyclerView.Adapter<CardAdapter.ViewHolder> {
List<Person> mItems;
public Context context;
private static SQLiteDatabase database;
private SQLiteOpenHelper openHelper;
public CardAdapter() {
super();
DatabaseAccess databaseAccess = DatabaseAccess.getInstance(this);
databaseAccess.open();
List<String> kandidatet = DatabaseAccess.getKandidatet();
database.close();
Person p;
mItems = new ArrayList<>();
for (int i = 0; i < kandidatet.size(); i++) {
p = new Person();
p.setName(kandidatet.get(i));
mItems.add(p);
}
.....
....
...
}
the error is in this row:
DatabaseAccess databaseAccess = DatabaseAccess.getInstance(this);
here is the method in the class DatabaseAccess:
private DatabaseAccess(Context context) {
this.openHelper = new DatabaseOpenHelper(context);
}
It doesn't accept "this" as a context
how to fix this?
It's because this must refer to object being of Context class or its child. Activity is subclass of Context your other classes are not. To work around this you can pass context to the adapter object upon its creation:
public CardAdapter(Context context) {
...
DatabaseAccess databaseAccess = DatabaseAccess.getInstance(context);
this refers to the class you're currently in. You must call this from an activity if you want it to be a valid context since activity implements Context interface.
Since you're calling it from a class which does not extend Activity, surely you get an error since this is not a Context in that case. You can fix this by calling the method with the field context you've declared above:
DatabaseAccess databaseAccess = DatabaseAccess.getInstance(context);
Before you do that, you'll need to initialize this field with a proper context, which you can do by changing the constructor to accept the Context :
public CardAdapter(Context ctx){
context = ctx;
//the rest of the code.
Be aware that now you also need to change the call of the constructor to new CardAdapter(this) if you're calling it from the activity (or getActivity if you're calling it from a Fragment).
I have some public variables define in my activity class:
public class RentListingFeed extends ActionBarActivity {
private ParseQueryAdapter<ParseObject> mainAdapter;
private CustomAdapter rexovoAdapter;
private ListView listView;
public String typeQuery;
public String bedQuery;
public String toiletQuery;
public String condQuery;
public String availQuery;
public String intentionQuery;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_rent_listing_feed);
typeQuery=getIntent().getStringExtra("Type");
bedQuery=getIntent().getStringExtra("Beds");
toiletQuery=getIntent().getStringExtra("Toilets");
condQuery=getIntent().getStringExtra("Condition");
availQuery=getIntent().getStringExtra("Availability");
intentionQuery=getIntent().getStringExtra("Intention");
As you can see, these variable are getting their values from some activity.
How can I access these variable in a separate class?
My separate class:
public class CustomAdapter extends ParseQueryAdapter<ParseObject> {
public CustomAdapter(Context context) {
// Use the QueryFactory to construct a PQA that will only show
// Todos marked as high-pri
super(context, new QueryFactory<ParseObject>() {
public ParseQuery create() {
ParseQuery query = new ParseQuery("PropertyDetails");
query.whereEqualTo("Tag", "Property");
query.whereEqualTo("Type","");
return query;
}
});
}
In this class, I have to assign these variables to :
query.whereEqualTo("Type","");
How can I do that?
Thanks and Regards
Declare them as static
public static String typeQuery;
Now you can use them in your other class
RentListingFeed.typeQuery
You should not declare class variables as public. The right way to do is, is to make them private and get / set them via their respective methods. For the type it should be like this:
public void setTypeQuery(String typeQuery) {
this.typeQuery = typeQuery;
}
public String getTypeQuery() {
return this.typeQuery;
}
Now you can create an object of your class in your CustomAdapter and set / get these variables as you like:
RentListingFeed rentListingFeed = new RentListingFeed();
rentListingFeed.getTypeQuery();
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.
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();
}
}