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.
Related
I created a global variable called GlobalVariables in my app:
public class GlobalVariables extends Notifications {
private boolean purchased = false;
public boolean getPurchaseState() {
return this.purchased;
}
public void setPurchaseState(boolean result) {
purchased = result;
}
}
As you may have noticed it extends a class called Notifications instead of extending Application. This is because I already had a class called Notifications which itself extends Application, and I read that it's not possible for two classes to extend Application since only one class can be added in the <application tag in Manifest, and in my case that class is Notifications. I read that the solution was simply to have one class subclass other, so I had GlobalVariables subclassing Notifications.
So I then wrote this in my activity
GlobalVariables globalVariables = (GlobalVariables) getApplication();
which causes a crash that says getApplication() cannot be cast to GlobalVariables.
How do I get globalVariables?
You can't, if Notifications is your application class you can't cast it to a subclass as Android still considers it a Notifications class. You could set GlobalVariables as the Application class though (inheriting Notifications).
I don't know what exactly you want to achieve but SharedPreferences might help to access variables across the app and also keep their state when the app gets closed.
Otherwise ViewModels (MVVM) help you access variables across Fragments or different parts of the App, same as Repositories.
there is Class Named "Configs.java" contains :
public Contect context;
public Activity currentActivity;
On Global Class Named "App.java" :
public static Configs configs = new Configs();
On Main Activity Java Class Oncreate :
App.configs.context = getApplicationContext();
App.configs.currentActivity = this;
On Products Activity Java Class Oncreate (Main Activity Not Finished And Must Work In Background):
App.configs.currentActivity = this;
After Long Time Minimized , it shows An Error On Bellow Line From Products Activity Java Class :
App.configs.currentActivity = this;
NullPointerException
Unable To Use "Bundle savedInstanceState" Because It's Activity Valiable
Try moving this code to onResume() instead of onCreate() and see if the error still exists.
Using static variables on Android is no good. This post explains that Android is very likely to kill your app (kills your Application instance, hence the static variable becomes null when your app is recreated and the class loader reinstantiates your vars) to save memory. The post also refers to Saving Activity state in Android which offers an alternative to save stuff with Bundles.
Anyway, if you need a quick solution, make your Configs class a singleton, and use getters and setters instead of making it public. Make the getter check if your singleton is null, and in this case, instantiate a new and return it. You won't get NPEs but it is very risky since it won't restore the previous state.
I'm implementing GCM for the first time and the sample app on google provides DemoActivity which deals with GCM functionality. (http://developer.android.com/google/gcm/client.html)
I can copy those gcm related codes over to my MainActivity, but I 'd like to keep things separate, ie. create a separate file for gcm and let MainActivity use it.
In python world, mixin would be great fit here.
But I'm not sure if mixin exists for java and if its the right tool here.
How would one implement the GCM functionality in a separate class in java?
I'm thinking something like the following.
Create GcmHelper.java
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
-->
public void onCreate(Bundle savedInstanceState, Activity activity) {
context = getApplicationContext();
this.mActivity = activity;
MainActivity::onCreate creates GcmHelper() and calls GcmHelper.onCreate(bundle, this)
do make similar changes for onResume() and activity related code to use the handed-over activity.
Create a Seperate Class eg. GcmHelper
Make GcmHelper constructor using Context parameter
Copy Every GCM related functions to GcmHelper
Create object of GcmHelper by passing the context in MainActivity->OnCreate
Finally call the required methods...
In the application i'm making I want to start an intent in one activity
Intent toonService = new Intent(Login.this, ToonService.class);
toonService.putExtra("toonName", result.getName());
Login.this.startService(toonService);
Will the following code close the intent i just opened? If not how can i get it to?
Intent toonService = new Intent(MainActivity.this,ToonService.class);
MainActivity.this.stopService(toonService);
the second piece of code would be called at a time completly unrelated to the first piece of code.
Well, assuming you only want one instance of this service running at once you could hold a static variable in the service class and access it from anywhere. Example;
public class ToonService extends Service{
public static ToonService toonService;
public ToonService(){
toonService = this;
}
...
}
The constructor for ToonService now stores the created instance in the static variable toonService. Now you can access that service from anywhere from the class. Example below;
ToonService.toonService.stopSelf();
You could also handle multiple instances by having the class store a static List of running instances, rather than just the single instance. It is worth noting, that when you tell a service to stop, you are only requesting that it is stopped. Ultimately the Android OS will determine when it is closed.
Definitely you can close the service from another activity.
Method-1: Do the following steps
1. Write a method in Activity 1 that returns that activity reference.
2. Write a method in Activity 1 that closes the service.
3. In Activity2 call the first method and get the reference. Using that reference call the second method
1. private static Context context=this;
public static Context getContext(){
return context;
}
2. public void stop(){
//stop the service here
}
3. In activity 2
Activity context=Activity1.getContext();
context.stop();
Method 2: follow the following steps.
Write a BroadcastReceiver as an inner class in Activity1 . In onReceive() stop the service.
Broadcast the intent from the second Activity.
I am still fairly new to Android and I am trying to implement Achievements inside my app. I basically want to replicate the achievements implemented in the "Type-a-Number Challenge" sample app given on the Google play developer site here.
I have a first activity that contains the methods and classes to handle the achievements, and a second activity where I have the variables that would be forwarded to the first activity for "processing". I copied the code that I believed was necessary for doing this, but I am always getting a null pointer exception when calling the listener inside the second class.
Here is my listener in the second activity:
public interface Listener {
public void onEnteredScore(int score);
}
Listener mListener = null;
public void setListener(Listener l) {
mListener = l;
}
The null pointer exception is flagged here when I call the listener as such (where mRequestedScore is different to 0):
mListener.onEnteredScore(mRequestedScore);
The first activity's class implements the second activity listener like this:
public class FirstActivity extends BaseGameActivity
implements SecondActivity.Listener
And includes the onEnteredScore method as such
#Override
public void onEnteredScore(int requestedScore) {
checkForAchievements(requestedScore);
pushAccomplishments();
}
I am not entirely sure if the error appears because the listener is expecting a click or some action by the user, or the "linkage" is not being established properly between both activities.
I looked around for similar issues but haven't found anything yet.
Apologies if the mistake is obvious.
Thanks in advance for any help provided.
Your "linkage" isn't established, hence the null.
If you want to pass data between Activities (not fragments), you'll need to use the Intent framework - see How do I pass data between Activities in Android application?
The Interface method that you are following in the Type a Number Challenge is useful for passing data between Fragments and the parent Activity. That is what it is being used for in that example. You don't appear to be using Fragments.
For achievements, you are probably better served using a class attached to your FirstActivity. That class can then implement your Listener interface (if the interface is even useful at that point). Using a separate activity is far more heavyweight than is required.