Is an Activity equal to a Context? - java

I've been wondering about something in android development.
I have a class for requesting permissions to the device in an easier way for me, this class name is PermissionRequester
public class PermissionRequester{
int sdk;
Context context;
public PermissionRequester(Context context) {
this.context = context;
sdk = Build.VERSION.SDK_INT;
}
}
In a beginning, I was requesting a Context in my constructor for checking if the permission was allowed or denied by the user. Using Context didn't work, so I change "Context" to "Activity" and it worked.
public class PermissionRequester {
int sdk;
Activity activity;
public PermissionRequester(Activity activity) {
this.activity = activity;
sdk = Build.VERSION.SDK_INT;
}
}
In my MainActivity, I instanciate like this
PermissionRequester requester = new PermissionRequester(MainActivity.this);
So my question is the next:
Why didn't I get a compile error in both cases using Context and Activity?

Context is the Base Object. To be more precise an Activity is a specialization of Context. That's why you Activity works in your case.
Take a look at this architecture of an Activity:
java.lang.Object
↳ android.content.Context
↳ android.content.ContextWrapper
↳ android.view.ContextThemeWrapper
↳ android.app.Activity

Add to DEX7RA's answer.
Another important Context is Appication, which is base class for those who need to maintain global application state. You can provide your own implementation by specifying its name in your AndroidManifest.xml's tag, which will cause that class to be instantiated for you when the process for your application/package is created.
I usually do application wide initialization in Application's OnCreate event, like creating database, log file, etc.

Related

Communication Between Two Android Activities via Reference to Caller or Callee

I have two activities Activity A and Activity B inside of the same application and they need to be able to call methods on each other. A needs to communicate to B at the start (possibly see "code" below).
B will call a lot of methods on A (this means that I cannot use the startActivityForResult method for communication because this would close B (Activity B is a Bluetooth Client and Server because it is a Peer to Peer app)). I do use startActivityForResult to start B for more of a kill signal than anything as the result.
Activity A uses a SupportMapFragment and Activity B cannot be a fragment because I want to be able to switch from B to A and then never use B again.
Originally, I started with one activity and tried switching between views using a ViewFlipper and just a call to setContentView(R.layout.my_layout_A) or setContentView(R.layout.my_layout_B). The fragment of course caused a lot of problems for both.
Using Fragments were confusing. The SupportMapFragment is the code for a Google Map which is a Fragment.
When I click a menu option inside of the MapsActivity (Activity A), I would like to be able to start myBluetoothActivity (Activity B) with a reference to the MapsActivity (Activity A) OR start myBluetoothActivity and then be able to set a reference to the caller inside of myBluetoothActivity (but this option would require having a reference to the BluetoothActivity inside of the MapsActivity or having some way to obtain the started activity from the intent).
//the following code is in Kotlin, but this can easily be converted over to java:
//option A: (pass it inside of the constructor)
var mbta:myBluetoothActivity = myBluetoothActivity(this)
//line for intent that I am unsure of
//intent so that I can start the activity with the pointer to the caller already passed into the new activity
startActivity(mbta)
//option B: (set this reference after obtaining a reference from intent):
var mintent:Intent = Intent(this.applicationContext, myBluetoothActivity::class.java)
startActivity(mintent)
//obtain the reference to the BluetoothActivity from the intent (NOT SURE HOW TO DO THIS???)
mbta.setCallerReference(this)
How can I accomplish this communication between the two activities via reference between the two activities? Should I use an interface for communication? If I should use it, (which I did try) how should I?
In other words, I am trying to access the caller activity (Activity A) from (Activity B) directly via a reference to Activity A inside of B OR trying to get the reference to B from the intent that started it inside of Activity A. I am trying to get a reference to that, so I can use it for communication/method calling/member variable and UI modification purposes.
NOTES: 1. The BluetoothActivity and the MapsActivity are NOT SERIALIZABLE. I tried serializing it and then adding it to the extras Bundle in the Intent and it just crashed saying that that was impossible to serialize due to BroadCastReciever. As this also deals with WIFI. Which I am highly considering separating out to be put with the BluetoothActivity in a future release.
I am also ASSUMING that Activity B will never just be started up by anything other than my MapsActivity class.
I am also new to Kotlin, but I know Java.
When I tried using an interface, I caused a StackOverflow error and I have no idea why.
I have read the documentation for Intents on the website.
I have done some research on here which gave me those ideas above. I am not sure how to implement them.
You are using the wrong approach. The solution requires a bit more work than you would think. The correct approach is to:
First, realize that these activities Activity A and Activity B (and any other activities) are activities that are specific to your application and you want to establish direct communication between them.
Second, realize that you are trying to get the current (or a previous) activity's context. The context will help serve the reference.
Third, you can create your own Activity and Application classes by extending the desired classes. The Application class is a low-level class used for the activities.
From here, you will be able to make use of the getApplicationContext() which will return your custom Application class.
Design: It is inside of your CustomApplication class that you must track the references to the activities that you want. From there all that you have to do is cast the getApplicationContext() to your CustomApplication class and then call your methods that access the Activity(ies). You must of course cast your Activities if you want to access certain instances of a specific activity that you created to its "type." For example:
MapsActivity mact = (MapsActivity)(((MyApplication)(this.getApplicationContext())).getCurrentActivity())
You must of course note that this activity must be already created (the onCreate method was already called) for this to return the current activity. The same of course goes for the other life-cycle methods for the activity as you will make a baseActivity which will deal with these as well as you will also have an Application life-cycle that will help deal with this too.
To answer the question: "How to get the current foreground activity context in android?" I turned to StackOverflow and found user: gezdy 's answer to be exactly what I needed at: How to get current foreground activity context in android?.
(BEGIN QUOTATION FROM: GEZDY)
You should manage activities references. Add the name of the
application in the manifest file :
<application
android:name=".MyApp"
....
</application>
Your application class :
public class MyApp extends Application {
public void onCreate() {
super.onCreate();
}
private Activity mCurrentActivity = null;
public Activity getCurrentActivity(){
return mCurrentActivity;
}
public void setCurrentActivity(Activity mCurrentActivity){
this.mCurrentActivity = mCurrentActivity;
}
}
Create a new Activity :
public class MyBaseActivity extends Activity {
protected MyApp mMyApp;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mMyApp = (MyApp)this.getApplicationContext();
}
protected void onResume() {
super.onResume();
mMyApp.setCurrentActivity(this);
}
protected void onPause() {
clearReferences();
super.onPause();
}
protected void onDestroy() {
clearReferences();
super.onDestroy();
}
private void clearReferences(){
Activity currActivity = mMyApp.getCurrentActivity();
if (this.equals(currActivity))
mMyApp.setCurrentActivity(null);
}
}
So, now instead of extending Activity class for your activities, just
extend MyBaseActivity. Now, you can get your current activity from
application or Activity context like that :
Activity currentActivity = ((MyApp)context.getApplicationContext()).getCurrentActivity();
(END OF QUOTATION FROM: GEZDY)
Note: All code is written in java for this answer.

Passing Activity's context (prevent memory leak)

I have a non-activity class which creates a number of views like ImageView and TextView in my activity class.
To do this, I need to pass my activity context from activity class to non-activity class. Here is the code of my non-activity class -
public class Create {
Activity activity;
Create(Activity act){
activity = act;
}
}
Is this a good practise? Should I use getApplicationContext() instead like this? What's the difference between the two methods? -
public class Create {
Context context;
public Create(Context context){
this.context = context.getApplicationContext();
}
}
Will there be a memory leak if I use the above methods? Which method is better? How to destroy the context after use to prevent memory leak?
Is there any advantage of declaring the Activity/Context as final or protected like this -
protected Context context;
or
final Context context;
It depends on how you're using your Create object. If you're using it like:
public class MyActivity extends Activity {
public void someMethod() {
Create mCreate = new Create(this);
mCreate.doSomething();
}
}
It'll be fine. If you do something like use an inner class that does some stuff in the background, and the activity is closed, you might end up leaking context if the inner class hasn't finished processing yet.
In the case of use of context.getapplicationcontext vs passing the activity (which is a context), the latter is better in this situation, because I'm assuming your create class is only creating views for the activity it's associated with; once the activity is finished, the lifecycle for those views is presumably over.
Android Activity extends ContextThemeWrapper.
ContextThemeWrapper ultimatley extends Context.
So think of Context as the superclass and Activity as a subclass. For example, Context has 10 methods and Activity has the same 10 methods plus 20 other methods.
In terms of memory leaks, that all depends on how you're using it. Make sure you destroy all unused objects in onDestroy() to prevent memory leaks. See http://www.raizlabs.com/dev/2014/04/hunting-your-leaks-memory-management-in-android-part-2-of-2/
I prefer the first method. That way you still get access to the other methods that Activity provides which Context might not have.
You can do this:
public class Create extends SomethingThatRequiresASuper {
Activity activity;
Create(Activity act){
this.activity = act;
super (act.getApplicationContext())
}
}
You can declare Context protected if you want. That just means that the scope of that object is limited.
Don't declare it final. If you do that, you won't be able to change Context later.
i think it would be fine to past the context through. And if you develop in android framework you could directly use attribute 'mContext' in View, but this is not work in SDK.

android.app.Application cannot be cast to android.app.Activity

I'm trying to change a LinearLayout from another class, but when i run this code:
public class IRC extends PircBot {
ArrayList<String> channels;
ArrayList<Integer> userCount;
ArrayList<String> topics;
LinearLayout channelLayout;
Context context;
public IRC(Context ctx) {
this.setName("xxxx");
channels = new ArrayList<String>();
userCount = new ArrayList<Integer>();
topics = new ArrayList<String>();
context = ctx;
channelLayout = (LinearLayout) ((Activity) context).findViewById(R.id.channels);
}
i get a ClassCastException
context is the Main activity that extends Activity passed with a getApplicationContext();
LOGCAT
05-08 17:53:55.102 3736-3799/g.d.allinonechat E/AndroidRuntime﹕ FATAL EXCEPTION: Thread-5357
java.lang.ClassCastException: android.app.Application cannot be cast to android.app.Activity
at g.d.xxx.IRC.<init>(IRC.java:34)
at g.d.xxx.MainActivity$1.run(MainActivity.java:49)
at java.lang.Thread.run(Thread.java:856)
You are passing the Application Context not the Activity Context with
getApplicationContext();
Wherever you are passing it pass this or ActivityName.this instead.
Since you are trying to cast the Context you pass (Application not Activity as you thought) to an Activity with
(Activity)
you get this exception because you can't cast the Application to Activity since Application is not a sub-class of Activity.
in case your project use dagger, and then this error show up
you can add this at android manifest
<application
...
android: name = ".BaseApplication"
...> ...
In my case, when I'm in an activity that extends from AppCompatActivity, it did not work(Activity) getApplicationContext (), I just putthis in its place.
You are getting this error because the parameter required is Activity and you are passing it the Application.
So, either you cast application to the Activity like: (Activity)getApplicationContext();
Or you can just type the Activity like: MyActivity.this
In my case I just put android:name=".CustomBaseClass" inside the activity tag instead of the application tag inside the manifest, hope it helps someone.
You can also try this one.
override fun registerWith( registry: PluginRegistry) {
GeneratedPluginRegistrant.registerWith(registry as FlutterEngine)
//registry.registrarFor("io.flutter.plugins.firebasemessaging.FirebaseMessagingPlugin")
}
I think this one is far better solution than creating a new class.
I had a similar problem when checking for internet connection in my viewmodel.
The error in my logcat:
java.lang.ClassCastException: android.app.Application cannot be cast to com.example.newsapplication.util.AppApplication in viewmodel
I added this line in the manifest and my application worked just fine.
android:name="com.example.newsapplication.util.AppApplication"
In my case, I just put add name property inside the application tag in the Manifest file
<application
android:name=".TodoApplication"
...
In my case I removed the line android:name ="<some_name>" and it worked. Looks like it was looking for a class with the name that was provided earlier whereas my Project does not have the class.
In my case, I deleted the android:name=".TodoApplication" from application and added it inside the activity tag.
<activity android:name=".BaseApplication"/>
Ensure you delete from the Application tag

How to retrieve a context from a non-activity class?

I have found one answer that appears to say I should create a separate class and make a static MyApplication object and make a get method. Then any class can call MyApplication.get() to retrieve the context.
Is there any other cleaner way? This is my situation:
I have a class A and a class B. Class A contains an object from class B (let's call the object b). In class A I call, "b.play()". However, I get a null pointer exception because class B needs to pass a context to the MediaPlayer.create() method.
Until now I threw together a hack and from class A I called.... "b.play(this)" and simply passed the context to B. However that is pretty ugly and looks like a bad use of OOP.
Any thoughts?
This problem seem to arise a lot in Android development. One solution to obtaining a reference to a specific Context is subclassing the Application and grab a reference to the Context which you want.
public class MyApplication extends Application {
private Context context;
#Override
public onCreate() {
super.onCreate();
this.context = getApplicationContext() // Grab the Context you want.
}
public static Context getApplicationContext() { return this.context; }
}
This solution however requires that you specify the name of your subclass in your manifest.
<application
android:name=".MyApplication"
</application>
You can then use this anywhere in your application like this in non-activity classes.
MyApplication.getContext(); // Do something with the context! :)
If class B requires a Context to operate, then I don't see any problem having class A provide that to it (through a parameter on the play method, a parameter in a constructor, etc).
I don't think you are doing any poor OOP by providing class B the dependencies that it needs to do it's job.
Passing this around is a viable way of doing things, especially if this is the activity that creates the object in need of a Context. Sometimes, I'll put the Context into the constructor (like public MyObject(Context context){this.context = context;}), so that you don't need to send it every time. However, if your object is shared across multiple Activities, you should probably update the context it is looking at with the new Activity, though I haven't tested what happens if you use the old activity.
I've answered also here.
You can do that using ContextWrapper, as described here.
For example:
public class MyContextWrapper extends ContextWrapper {
public MyContextWrapper(Context base) {
super(base);
}
public void someMethod() {
// MediaPlayer.create(this, ...)
}
}

Accessing Resources without a Context

I'm trying to put configuration, such as URLs/etc, into a resource folder for a utility class to use. However, I don't want to pass the Context from the activities everywhere. I would like to be able to access a resource via a path name (seems like assets/ was designed for this use), without using a context to access the resource.
In this particular case, I want a singleton to use something in configuration when it's instantiated. It has no need for anything from resources besides that one time during instantiation. Therefore, having to pass in a Context every time getInstance() is called would be a complete waste.
Also, this is specific to the App's configuration, and should not be in stored in a shared system file or anything like that.
Use
Resources.getSystem().getString(android.R.string.someuniversalstuff)
You can use it ABSOLUTELY EVERYWHERE in your application, even in static constants declaration! But for system resources only.
For local resources use that solution.
You could extend the main application class and provide universal helpers there to access resources. This relieves the need for context as the application would provide the context instead of the caller. The application class is singleton style and should always be available while any portion of your application is running (including services).
public class MyApplication extends Application {
protected static MyApplication instance;
#Override
public void onCreate() {
super.onCreate();
instance = this;
}
public static Resources getResources() {
return instance.getResources();
}
}
This provides you access to:
MyApplication.getResources()....
Be sure to declare your custom application in your manifest to gain access to this. Assuming your custom application is in the root of your application's namespace:
<application
android:name=".MyApplication"
... >
I would recommend doing the following:
Rather than passing context everywhere make your activity class a singleton class with a public function that returns the context:
private static ActivityMain instance;
Initialize inside onCreate() before super.onCreate():
instance = this;
Then add these public functions to your activity:
/** Get singleton instance of activity **/
public static ActivityMain getInstance() {
return instance;
}
/** Returns context of this activity **/
public static Context getContext(){
return instance.getApplicationContext();
}
Now you can use the following anywhere in any class:
Context context = AntiMorphActivity.getContext();
String packageName = context.getPackageName();
int id = context.getResources().getIdentifier("web_page", "raw", packageName);
Unfortunately I don't think there is a real way around this. I lay mine out something like this, and also pass in the getApplicationContext() instead of the activity context.
public static AppController getAppController(Context context){
if(self == null) {
//Create instance
self = new AppController();
}
return self;
}
And then:
appController = AppController.getAppController(getApplicationContext());
The stackoverflow answer to the question below shows how to use POJO to obtain a stream to a resource, if you supply its path. This might be useful in cases you need to select a specific resource from one of many.
Is it possible to read a raw text file without Context reference in an Android library project

Categories