I need to use PackageManager pm = context.getPackageManager(); inside a PagerAdapter but I don't know how to get a context.
public class MyPagerAdapter extends PagerAdapter {
...
}
How can context inside PagerAdapter?
The answer of #DeeV means you must provide a context to your PageAdapter by yourself, either via the constructor or via a setter. Then store it inside the PageAdapter as a field and retrieve it whenever you need it.
private ViewGroup _container;
public override Java.Lang.Object InstantiateItem(ViewGroup container, int position)
{
_container = container;
}
private Context GetContext()
{
return (Activity)_container.Context;
}
It's not recommended provide Context, this may cause memory leaks,
if you need the context to access resources, you can provide the resources through the constructor.
MyPagerAdapter(val resources: Resources){
}
....
val adapter = MyPagerAdapter(context.resources)
Related
I have been trying to use getResources in a non-activity class. I found some advice on how to do so here. To use one of the suggested ways, by Lilzilala, (there are multiple, but mostly suggest the same thing), I have created a special class, used this to specify the resources as "res", and then instantiated this class using "new" in a line which invokes "getResources".
However, I'm getting a "cannot resolve method getResources" error on "getResources". I'm a bit of a noob, but don't know why this is happening. From what I can tell, this error happens when there simply isn't a resource with that name available. Which makes me think maybe Resources doesn't contain getResources() by default?
class executeTrimmer<Resdefine> {
public class ResDefine {
private Resources res;
public ResDefine(Resources res)
{
this.res = res;
}}
Bitmap img1 = BitmapFactory.decodeResource(new ResDefine(getResources()),
R.drawable.bmpname);
}
EDIT - following suggestions that I add context, I have tried this:
class executeTrimmer<Resdefine> {
private static Context context;
public executeTrimmer(Context context){
this.context = context;
}
public class ResDefine {
private Resources res;
public ResDefine(Resources res)
{
this.res = res;
}}
Bitmap img1 = BitmapFactory.decodeResource(new ResDefine(executeTrimmer.context.getResources),
R.drawable.bmpname);
But this still brings up error "cannot resolve symbol getResources". I've tried multiple different ways to pass context to it, and consistently faced the same error.
As you can see in the official documentation, "getResources" is Context's method, therefore you can't call it out from nowhere, neither statically. This method requires a context instance.
In your case you must at least pass a context to your class to be able to invoke it as next:
context.getResources()
I think you got confused from seen it being directly called inside Activities without a prefixed context, but as all Activities are actually a context, this is why there is no prefix.
To clarify. When called inside an activity, this:
getResources()
is the same as this:
this.getResources()
where the prefix "this." refers to the activity, which in turn is a context by itself.
On the other hand your code should be like next, without the ResDefine class. And notice that the decodeResource call is required to be inside a method and not at class level scope (this is not allowed in Java). And in fact you don't even need to use a context, so pass instead the Resources instance from the caller's class which is supposed to hold the context:
public class executeTrimmer {
private final Resources res;
public executeTrimmer(final Resources res) {
this.res= res;
}
public void loadBitmap()
Bitmap img1 = BitmapFactory.decodeResource(this.res, R.drawable.bmpname);
........
}
}
And for the caller, next a very naive example, so may get an idea:
public class MainActivity extends Activity {
#Override
protected void onCreate(#Nullable final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
new executeTrimmer(this.getResources()).loadBitmap();
}
}
In my app I have a TabLayout and each of the tabs is represented by a fragment. I have several tables in a database. And for each table I want to have a tab that would display a list of table's contents. To access a database I need to pass in a context but it's only available from the MainActivity. How to access a database instance from each fragment?
Here's some code:
ElectronicsDatabase.java
#Database(entities = {Smartphone.class, Tablet.class,
Laptop.class, VideoGameConsole.class}, version = 1)
public abstract class ElectronicsDatabase extends RoomDatabase {
public abstract SmartphoneDao getSmartphoneDao();
public abstract TabletDao getTabletDao();
public abstract LaptopDao getLaptopDao();
public abstract VideoGameConsoleDao getVideoGameConsoleDao();
private static final String DB_NAME = "products.db";
private static ElectronicsDatabase db;
public static ElectronicsDatabase getInstance(Context context)
{
if (db == null)
{
db =buildDatabaseInstance(context);
}
return db;
}
private static ElectronicsDatabase buildDatabaseInstance(Context context)
{
return Room.databaseBuilder(context, ElectronicsDatabase.class,
DB_NAME).allowMainThreadQueries().build();
}
}
And in the main activity I access it like this:
db = ElectronicsDatabase
.getInstance(getApplicationContext());
In your fragments you can use getActivity() to acccess context of your parent activity.
but i suggest you to use viewModel for accessing to your database.
Try to use ViewModel to access database in any activity or Fragment
ViewModel is a class that is responsible for preparing and managing the data for a UI component (activity or Fragment)
In your case which is needing a Context for DB access via Room, it is better to pass a non-UI Context as to avoid unnecessary information being passed around for no reason leading to possible memory leaks.
You can get access to a non-UI Context which will be called ApplicationContext from your base activity, or your main activity. Simply like this:
Context appContext= getApplicationContext();
Then store it in a Repo class, so you can simply use it anytime you need it again anywhere without worrying about it.
However, if you need a context for something related to drawing on the screen, like inflating an XML for example, then in that case you will need a UI Context as not to lose UI details like your theme for example. In that case you can get the context from inside your fragment using:
getContext() Or getActivity().
I won't go to further details about contexts but,
if you want to learn more about what Context really is you can start from here:
https://medium.freecodecamp.org/mastering-android-context-7055c8478a22
That might be a very late answer, but I believe it might help some in the future:
If you are using multiple fragments and DI, you can create a viewModel for your activity, then inject the desired value into it
#HiltViewModel
class MainActivityViewModel #Inject constructor(
private val repository: PlantsRepository
): ViewModel() {
private val mutableLiveData = MutableLiveData<List<Plant>>()
val liveData: LiveData<List<Plant>> = mutableLiveData // object to observe
init {
viewModelScope.launch {
mutableLiveData.postValue(repository.getAllPlants())
fillExampleData()
}
}
}
(sample for reference)
then you simply use it in your fragments:
class FragmentExampleScreen : Fragment() {
private val sharedViewModel: MainActivityViewModel by activityViewModels()
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
...
sharedViewModel.liveData.observe(viewLifecycleOwner) { idk ->
Log.i("hello", idk.toString())
}
...
}
}
I have a static function in which I need to access my color resources. In order access color resources I need context variable which is static. I am confused if I can make context static. Is there any side effects to it? or, is there any other way I can access my resources without using context
Here is the function
private static SpannableStringBuilder setTextColor(
SpannableStringBuilder Text, int spanLength, boolean isSuggestion) {
addressText.setSpan(
new ForegroundColorSpan(
context
.getResources()
.getColor(
isSuggestion ? R.color.blur: R.color.red)),
addressText.length() - 1 - spanLength,
addressText.length(),
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
return Text;
}
I am confused if I can make context static. Is there any side effects
to it?
You can declare a context as static but it is not recommended in Android, because it might lead to a memory leak in your app.
is there any other way I can access my resources without using
context?
No, you need a context instance to access resources in your app.
Back to your case, the easiest way is passing a context as param of the method.
private static SpannableStringBuilder setTextColor(Context context, SpannableStringBuilder Text, int spanLength, boolean isSuggestion) {
int color = context.getResources().getColor(isSuggestion ? R.color.blur : R.color.red);
addressText.setSpan(new ForegroundColorSpan(color),
addressText.length() - 1 - spanLength,
addressText.length(),
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
return Text;
}
Inside your activity, pass this as context when calling setTextColor, for example.
setTextColor(this, new SpannableStringBuilder(), 0, false);
In Kotlin, you can achieve this by creating a class that extends Application and storing the application context in the companion object.
Usually it will look similar to this:
class App : Application() {
override fun onCreate() {
super.onCreate()
instance = this
}
companion object {
private var instance: App? = null
val context: Context?
get() = instance?.applicationContext
}
}
And you can access the context anywhere via App.context
In regards to your concerns about storing a static context, if you were storing an activity or fragment context then you risk creating memory leaks, but since we're storing the application context which is tied to the lifecycle of the entire application, there won't be any issues with memory leaks.
You may run into issues if you want to write testable code that depends on a static context, in which case I would recommend you pass the context into the function rather than access it directly.
1) Create your App class which extend Application
private static Context context;
#Override
public void onCreate() {
super.onCreate();
context = getApplicationContext();
2) Create getApplicationContext() method which return context
public static Context getApplicationContext() {
return context;
}
3) Now you can get context anywhere in your class like
Context context = App.getContext().getApplicationContext();
To be able to get app context anywhere in my app, I created App class like this:
public class App extends Application
{
private static Context mContext;
public static Context getContext()
{
return mContext;
}
#Override
public void onCreate()
{
super.onCreate();
mContext = this
}
}
It works and also it's used in many places in my app where I need to use context (for example, to load resources) and I am not able to inject any other context to use.
However, Android Studio throws warning this approach (static context fields) causes memory leak.
Do you have any idea how to avoid static context field, but get similar functionality?
Never place static Context in your application since it will cause unexcepted memory leaks, however if you still want to use static Context in your application you can wrap the context in a WeakReference so change
private static Context mContext;
to
private static WeakReference<Context> mContext;
and on create change it to
mContext = new WeakReference<>(Context);
and finally get the Context using
public static Context getContext() {
return mContext.get();
}
if you want to research more about WeakRef use the link below,
https://developer.android.com/reference/java/lang/ref/WeakReference
Its not necessary use static for access context ,you can use get context ,get application context or get activity any where.
as far as possible you should avoid from passing context.
like this in fragments :DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(getContext(), layoutManager.getOrientation());
and in this (if the OP wanted to use Context in where the class does not host a Context method) case you can pass context without define it as a static.
for example :
public class DashboardWalletSpinnerAdapter extends ArrayAdapter<Wallet> {
private LayoutInflater mLayoutInflater;
private static final int CLOSE = 0;
private static final int OPEN = 1;
public DashboardWalletSpinnerAdapter(Context mContext, List<Wallet> walletList) {
super(mContext, R.layout.spinneritemclose_dashbaord, walletList);
mLayoutInflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
How can I play sound from a class that DOES NOT extend activity? I've been searching for a while and in every tutorial or answers from stackoverflow I've seen that sounds are always implemented in an activity class.
But in this case I have a class thas has the logic of my game, in which I have a gameUpdate() function; and in that function I want to make a specific sound play if something happens (for example a collision). How can I possibly access the activity that is currently running, from this class? Is there any way to do that?
Thanks.
If you need to get the current Activity instance or context you need to pass it to your other classes so that you can use it. For example:
class ABC extends Activity
{
public void onCreate(Bundle b)
{
XYZ xyz=new XYZ(this); // Sending the current Activity instance
}
}
class XYZ
{
ABC activity;
public XYZ(ABC activity)
{
this.activity = activity; //Now you can use it in this class
}
}
getActivity() or if is inside a fragment getFragment().getActivity()
Or alternativelly you can make add a Context to your class and get the activity reference from the constructor of the class.
Ex:
public class MyClass {
Context mContext();
public MyClass(Context context){
this.context = context;
}
}
and in your Activity class when you call MyClass:
MyClass myClass = new MyClass(this);
Inside your custom lass you can reference activity methods using its context.
So you actually just need a Context, not specifically an Activity (which is a Context). I would recommend that the class that should play sounds has a constructor which requires a Context. Keep a reference, not directly to the Context that you receive, but to the Application context using getApplicationContext() to get a Context that is safe to retain without the risk of memory leaks.
public class MySoundPlayingClass {
private final Context mContext;
public MySoundPlayingClass(Context ctx) {
// Since ctx could be an Activity, and this class
// could exist outside of the lifecycle of the Activity,
// grab the Application context to get a safe reference.
mContext = ctx.getApplicationContext();
}
}
Have a Util class and do something similar to below one. You can pass the context (it can be Activity instance) and the resource id to play it
Usage:
Util.play(context, R.raw.soundFile);
Sample Util class:
public class Util {
public static void play(final Context context, int resource) {
MediaPlayer mp = MediaPlayer.create(context, resource);
if (null != mp) {
mp.setOnCompletionListener(new OnCompletionListener() {
#Override
public void onCompletion(MediaPlayer mp) {
mp.release();
}
});
mp.start();
}
}
}