Static context in App class - memory leak - java

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);
}

Related

Can an Android Context inside an activity be static?

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();

Is it good idea use static class AppContext?

I found in one of github project class:
public class AppContext {
private static Context sContext;
private static Application sApplication;
public static Application getApplication() {
if (sApplication == null) {
throw new IllegalStateException("AppContext.setApplication was not called in Application.onCreate() method. " +
"Please inherit your application from the com.blandware.android.atleap.BaseApplication class.");
}
return sApplication;
}
public static void setApplication(Application application) {
sApplication = application;
}
public static Context getContext() {
if (sContext == null) {
throw new IllegalStateException("AppContext.setContext was not called in Application.onCreate() method. " +
"Please inherit your application from the com.blandware.android.atleap.BaseApplication class.");
}
return sContext;
}
public static void setContext(Context context) {
sContext = context;
}
}
It seams create, don't need more pass context to static function etc. But I'm worried about memory leaks. Can AppContext make it? When i shoud use Aplication context when activity context or view?
The Application object can not leak. There is always exactly one Application object for every app. It looks like the author is just using this class to make it easy to access in places where another Context is not available to be used to call getApplicationContext() to get the Application object.
Context, on the other hand, could be an Activity or a Service, and those really should not be stored beyond their lifetime. You will have to look at exactly which Context objects are being stored here to find out if there is a leak.

Android application creation of internal file that isn't in an activity

I am trying to create an internal file in an android application. I have generated the code that works fine with java, but in order to create the internal file I believe I must have the context to do so.
Example: File file = new File(Context.getFilesDir(), "somefile.txt");
The problem I am running into is that the file creation and checks if it is made are maintained in a singleton class that I have created. When using the following
Example: File file = new File("somefile.txt");
everything seems to compile and work, but after closing the application it seems the file wasn't created. This leads me to believe that I need the application directory using the 1st example given. The problem is how do I get the applications context within a single class?
The problem is how do I get the applications context within a single class?
From Android Docs:
There is normally no need to subclass Application. In most situation, static singletons can provide the same functionality in a more modular way. If your singleton needs a global context (for example to register broadcast receivers), the function to retrieve it can be given a Context which internally uses Context.getApplicationContext() when first constructing the singleton.
Create your singleton like this:
// ...
private Context mAppContext = null;
private static MySingleton mSingleton = null;
// ...
private MySingleton(Context context) {
mAppContext = context;
// ... other initialization
}
public static MySingleton get(Context context) {
if (mSingleton == null) {
/*
* Get the global application context since this is an
* application-wide singleton
*/
mSingleton = new MySingleton(
context.getApplicationContext());
}
return mSingleton;
}
The each time you obtain your singleton from any activity, you have access to the global application context.
You can use it for your creation of files within your singleton like:
public void createFile(String filename) {
File file = new File(mAppContext.getFilesDir(), filename);
}
Or you can use the other ways mentioned here
Or you could extend Application class thats already a Singleton. It can be rather usefull :)
package com.example.myapp;
import android.app.Application;
import android.content.Context;
public class MyApp extends Application {
private static Context context;
private static MyApp my_instance;
#Override
public void onCreate() {
// TODO Auto-generated method stub
super.onCreate();
my_instance = this;
context = this;
}
public static synchronized MyApp getInstance() {
return my_instance;
}
public static synchronized Context getContext() {
return context;
}
}
The mehod:
new File("filename")
does not create a file on disk.
You need to open the file and write to it for the file to be created, or use
File.createNewFile

How to play android sounds NOT in activity class

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();
}
}
}

Get context directly in PagerAdapter?

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)

Categories