Android - Java - Access private variable in Main-Activity from another instanced class - java

I've been thinking for hours about this problem now without finding a solution. Still I think I'm just overlooking some very simple things.
My program is (mainly) supposed to record and playback audio, so I got one Main-Activity which contains all the functions with interactivity to the user and I got one class I called 'AudioHandler' to manage all the audio stuff in the background.
The Main-Activity uses an instance of AudioHandler.
Within the AudioHandler-class I got an OnCompletionListener, to notice when playback of the recorded audio-file has finished.
The problem is: When playback has finished - and the OnCompletionListener gets called, I want to change an ImageView (Turn the pause-button into a play-button) in the Main-Activity.
How can I access the ImageView in the Main-Activity from the AudioHandler-Instance?
...without making the ImageView-Variable public.
Method that calls play from the AudioHandler in the Main-Activity:
public State playRecording() {
//change play-button to stop-button
iPlay.setImageResource(R.drawable.stop_button_active);
//start or resume playback of the recorded Audio
ah.play();
//Return that the program is in playing-mode
return State.PLAYING;
}
play-function in AudioHandler
public void play() {
try {
mPlayer.start();
} catch (IllegalArgumentException e) {
Log.d("MEDIA_PLAYER", e.getMessage());
e.printStackTrace();
} catch (IllegalStateException e) {
Log.d("MEDIA_PLAYER", e.getMessage());
e.printStackTrace();
}
//add listener to notice when the end of the audio record has been reached
mPlayer.setOnCompletionListener(new OnCompletionListener() {
#Override
public void onCompletion(MediaPlayer mp) {
//should somehow change the ImageView 'iPlay' in the Main-Activity when reaching this point.
}
});
}
Any help is appreciated :)
Marco

If you need to gain access to a variable, that variable should be either package-accessible or public. Or, even better, you should have an encapsulating method. Something like:
// On the main class:
public ImageView getIPlay(){
return iPlay;
}
private static MainActivity instance;
public MainActivity getInstance(){
return instance;
}
/** Either on the constructor or the 'OnCreate' method, you should add: */
instance = this;
Now you can access the ImageView from any Activity or class with:
MainActivity.getInstance().getIPlay();
It's that simple, really. You can go through a lot of other solutions, from using reflection through AOP or any kind of things. But it's just making the issue more complex. Try creating the setter method.

Your question is about object encapsulation.
When you define an instance variable as private, you are saying that only that object and members of that class can access the variable. This is a good thing because it protects you from accidentally changing data you did not want to. This is also why we have getters and setters.
So in your class you have something I imagine looks like this
public class Main {
... some code here
private ImageView myView;
... more code here
what you need to do is add the following methods to your Main class
public ImageView getView() {
return myView;
}
and
public void setView(ImageView a) {
myView = a;
}
so now when you want to access the ImageView from another class, you just call something like Main.getView() and you'll have it.
Now if this doesn't answer your question, it's because you didn't design your app too thoughtfully (so it seems) but luckily I won't be the kind of responder who tells you to uproot everything you have done and start over.
It sounds like you're working with an Android app and your issue is to communicate between activities.
This is why Android has something called Intents. You can send an Intent from one activity to another to carry data. So in this case you would send an Intent from one activity to the main class that would tell the main class to change the picture in the imageview. I won't lie, I suck at using intents but there are many wonderful tutorials online that will show you how to do this.
Another option would be to create a RemoteView of your layout that has the play/pause button and access it from the other activity, RemoteView has a built in function to change the bitmap of a remote imageview (again, see the Android Developer Documentation for RemoteView for more on this)
I'm sorry I couldn't give you some actual code, I'm not confident enough in my abilities on these topics but I'm 100% confident that one of the three methods I just listed will answer your question.

You could create a public wrapper method within your main Activity that toggles the ImageView between Pause and Play.
Or, you could pass the the ImageView to the AudioHandler (via the constructor?) and just manipulate it there.

Related

Clear Difference Between 'application' and 'activity' [duplicate]

An extended Application class can declare global variables. Are there other reasons?
Introduction:
If we consider an apk file in our mobile, it is comprised of
multiple useful blocks such as, Activitys, Services and
others.
These components do not communicate with each other regularly and
not forget they have their own life cycle. which indicate that
they may be active at one time and inactive the other moment.
Requirements:
Sometimes we may require a scenario where we need to access a
variable and its states across the entire Application regardless of
the Activity the user is using,
An example is that a user might need to access a variable that holds his
personnel information (e.g. name) that has to be accessed across the
Application,
We can use SQLite but creating a Cursor and closing it again and
again is not good on performance,
We could use Intents to pass the data but it's clumsy and activity
itself may not exist at a certain scenario depending on the memory-availability.
Uses of Application Class:
Access to variables across the Application,
You can use the Application to start certain things like analytics
etc. since the application class is started before Activitys or
Servicess are being run,
There is an overridden method called onConfigurationChanged() that is
triggered when the application configuration is changed (horizontal
to vertical & vice-versa),
There is also an event called onLowMemory() that is triggered when
the Android device is low on memory.
Application class is the object that has the full lifecycle of your application. It is your highest layer as an application. example possible usages:
You can add what you need when the application is started by overriding onCreate in the Application class.
store global variables that jump from Activity to Activity. Like Asynctask.
etc
Sometimes you want to store data, like global variables which need to be accessed from multiple Activities - sometimes everywhere within the application. In this case, the Application object will help you.
For example, if you want to get the basic authentication data for each http request, you can implement the methods for authentication data in the application object.
After this,you can get the username and password in any of the activities like this:
MyApplication mApplication = (MyApplication)getApplicationContext();
String username = mApplication.getUsername();
String password = mApplication.getPassword();
And finally, do remember to use the Application object as a singleton object:
public class MyApplication extends Application {
private static MyApplication singleton;
public MyApplication getInstance(){
return singleton;
}
#Override
public void onCreate() {
super.onCreate();
singleton = this;
}
}
For more information, please Click Application Class
Offhand, I can't think of a real scenario in which extending Application is either preferable to another approach or necessary to accomplish something. If you have an expensive, frequently used object you can initialize it in an IntentService when you detect that the object isn't currently present. Application itself runs on the UI thread, while IntentService runs on its own thread.
I prefer to pass data from Activity to Activity with explicit Intents, or use SharedPreferences. There are also ways to pass data from a Fragment to its parent Activity using interfaces.
The Application class is a singleton that you can access from any activity or anywhere else you have a Context object.
You also get a little bit of lifecycle.
You could use the Application's onCreate method to instantiate expensive, but frequently used objects like an analytics helper. Then you can access and use those objects everywhere.
Best use of application class.
Example: Suppose you need to restart your alarm manager on boot completed.
public class BaseJuiceApplication extends Application implements BootListener {
public static BaseJuiceApplication instance = null;
public static Context getInstance() {
if (null == instance) {
instance = new BaseJuiceApplication();
}
return instance;
}
#Override
public void onCreate() {
super.onCreate();
}
#Override
public void onBootCompleted(Context context, Intent intent) {
new PushService().scheduleService(getInstance());
//startToNotify(context);
}
Not an answer but an observation: keep in mind that the data in the extended application object should not be tied to an instance of an activity, as it is possible that you have two instances of the same activity running at the same time (one in the foreground and one not being visible).
For example, you start your activity normally through the launcher, then "minimize" it. You then start another app (ie Tasker) which starts another instance of your activitiy, for example in order to create a shortcut, because your app supports android.intent.action.CREATE_SHORTCUT. If the shortcut is then created and this shortcut-creating invocation of the activity modified the data the application object, then the activity running in the background will start to use this modified application object once it is brought back to the foreground.
I see that this question is missing an answer. I extend Application because I use Bill Pugh Singleton implementation (see reference) and some of my singletons need context. The Application class looks like this:
public class MyApplication extends Application {
private static final String TAG = MyApplication.class.getSimpleName();
private static MyApplication sInstance;
#Contract(pure = true)
#Nullable
public static Context getAppContext() {
return sInstance;
}
#Override
public void onCreate() {
super.onCreate();
Log.d(TAG, "onCreate() called");
sInstance = this;
}
}
And the singletons look like this:
public class DataManager {
private static final String TAG = DataManager.class.getSimpleName();
#Contract(pure = true)
public static DataManager getInstance() {
return InstanceHolder.INSTANCE;
}
private DataManager() {
doStuffRequiringContext(MyApplication.getAppContext());
}
private static final class InstanceHolder {
#SuppressLint("StaticFieldLeak")
private static final DataManager INSTANCE = new DataManager();
}
}
This way I don't need to have a context every time I'm using a singleton and get lazy synchronized initialization with minimal amount of code.
Tip: updating Android Studio singleton template saves a lot of time.
I think you can use the Application class for many things, but they are all tied to your need to do some stuff BEFORE any of your Activities or Services are started.
For instance, in my application I use custom fonts. Instead of calling
Typeface.createFromAsset()
from every Activity to get references for my fonts from the Assets folder (this is bad because it will result in memory leak as you are keeping a reference to assets every time you call that method), I do this from the onCreate() method in my Application class:
private App appInstance;
Typeface quickSandRegular;
...
public void onCreate() {
super.onCreate();
appInstance = this;
quicksandRegular = Typeface.createFromAsset(getApplicationContext().getAssets(),
"fonts/Quicksand-Regular.otf");
...
}
Now, I also have a method defined like this:
public static App getAppInstance() {
return appInstance;
}
and this:
public Typeface getQuickSandRegular() {
return quicksandRegular;
}
So, from anywhere in my application, all I have to do is:
App.getAppInstance().getQuickSandRegular()
Another use for the Application class for me is to check if the device is connected to the Internet BEFORE activities and services that require a connection actually start and take necessary action.
Source: https://github.com/codepath/android_guides/wiki/Understanding-the-Android-Application-Class
In many apps, there's no need to work with an application class directly. However, there are a few acceptable uses of a custom application class:
Specialized tasks that need to run before the creation of your first activity
Global initialization that needs to be shared across all components (crash reporting, persistence)
Static methods for easy access to static immutable data such as a shared network client object
You should never store mutable instance data inside the Application object because if you assume that your data will stay there, your application will inevitably crash at some point with a NullPointerException. The application object is not guaranteed to stay in memory forever, it will get killed. Contrary to popular belief, the app won’t be restarted from scratch. Android will create a new Application object and start the activity where the user was before to give the illusion that the application was never killed in the first place.
To add onto the other answers that state that you might wish store variables in the application scope, for any long-running threads or other objects that need binding to your application where you are NOT using an activity (application is not an activity).. such as not being able to request a binded service.. then binding to the application instance is preferred. The only obvious warning with this approach is that the objects live for as long as the application is alive, so more implicit control over memory is required else you'll encounter memory-related problems like leaks.
Something else you may find useful is that in the order of operations, the application starts first before any activities. In this timeframe, you can prepare any necessary housekeeping that would occur before your first activity if you so desired.
2018-10-19 11:31:55.246 8643-8643/: application created
2018-10-19 11:31:55.630 8643-8643/: activity created
You can access variables to any class without creating objects, if its extended by Application. They can be called globally and their state is maintained till application is not killed.
The use of extending application just make your application sure for any kind of operation that you want throughout your application running period. Now it may be any kind of variables and suppose if you want to fetch some data from server then you can put your asynctask in application so it will fetch each time and continuously, so that you will get a updated data automatically.. Use this link for more knowledge....
http://www.intridea.com/blog/2011/5/24/how-to-use-application-object-of-android

In Android how do you get a reference to a global variable that is a subclass of another global variable?

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.

Is there a way to delegate the implementation of an interface to a different class?

I've been working on Xamarin for the past couple of years along with Android studio and I decided to create an application for a friend (full source code here https://github.com/nekrull/waiter don't be too harsh please :) )
The idea is that there is a base activity which exchanges fragments when a new screen should appear.
Fragments have everything that has to do with user interaction and the activity they are attached to handles the business logic.
To do this I have a base class CoreActivity/DataActivity which has some methods most Fragments use (like blocking the back button) and some helper methods (like calling a method on an attached fragment of a specific class) , a CoreInteraction that responds to this activity and
CoreFragment/AttachedFragment which is used as the base of all view fragments
so for example the view fragment would look like this:
public class GroupsFragment extends AttachedFragment<GroupsFragment.GroupsInteraction> {
//this is what we expect to be able to call in the parent
public interface GroupsInteraction extends CoreInteraction {
Group get_shown_group();
void new_group();
void select_parent();
}
}
which is basically a fragment that expects its attached activity to be able to respond to the interaction methods.
the activity fragment would look like this:
public class MainActivity extends DataActivity<MainData> implements
GroupsFragment.GroupsInteraction, (other interactions here) {
}
The problem is that since the application I'm working on has only one Activity with many small screens, the code inside the base activity will get big, that does not cause a problem with the application or compiling or anything else. But it makes it really hard to find what I'm looking for easily.
What I used to do in Xamarin is something like this:
public partial class MainActivity : DataActivity<MainData> {
}
for the initialization activity and then each interaction would get its own file like this:
public partial class MainActivity : GroupsInteraction {
}
It had the same effect (since the class is compiled as a single class) but the code would be tidy and easy to read.
Obviously there are no partial classes in Java, but is there a way to delegate the implementation of an interface to another class?
Something along the lines of saying "when you're invoking a method from interface a, invoke it from that class" without actually writing stuff like :
public Group get_shown_group() {
return new GroupHandler(this).get_shown_group();
}
public void new_group() {
new GroupHandler(this).new_group();
}
public void select_parent() {
new GroupHandler(this).select_parent();
}
Thanks in advance for any help you can provide
Something along the lines of saying "when you're invoking a method from interface a, invoke it from that class"
Taking you literally what you describe is plain delegation, a class does not implement some or any functionality itself, instead it wraps a class implementing the desired functionality, calling the methods of said wrapped class. You could even switch implementation at runtime, just changing the wrapped class as you go (assuming the classes share a common interface, of course). Of course that does not "spare" you from writing the delegations yourself.
class Wrapper implements GroupsInteraction {
private final GroupInteraction gi;
public Wrapper(GroupsInteraction gi) {
this.gi = gi;
}
Group get_shown_group() {
return this.gi.get_shown_group();
}
// ... other interface impls
}
Additionally, you should keep the GroupHandler as a member instead of creating a new Object each time, so
public Group get_shown_group() {
return new GroupHandler(this).get_shown_group();
}
becomes
public Group get_shown_group() {
return this.groupHandler.get_shown_group();
}
You can try Delegation Pattern
BaseActivity {
MyDelegateClass delegate;
void example() {
delegate.example();
}
}
P.S. both activity and delegate implements same interface
Details here

Sending information from one fragment to another Android

I am having this issue where I have nested fragments. I need one to be able to send information to the other.
For example, if I press a button in the inner fragment I want the outer fragment to perform an action.
Any help would be great!
Edit: I forgot to mention that both of these are live fragments. As far as I know using bundles only allows me to set arguments when creating a fragment but not after it has been created.
Well there are plenty of ways to manage this. It really depends on the architecture you want to go with.
You could go lazy and use a Bus library that uses sub/pub modeling and reflection for notifying generic objects that registered and have matching signature methods of changes, However, this is frowned upon to use reflection for regular coding practices that could be implemented without it.
I would say you can either create an interface that represents the calls that would go back and forth like IMainActivityCallbacks with methods like dataChange(myObject obj)
.
Then in your onAttach of fragment you cast the context as IMainActivityCallbacks. Make sure the MainActivity implements the interface.
Then simply call the mIMainActivityCallbacks.dataChange(someObject);
This will call the method in the parent activity and allow him to pass it to the child fragment that needs it with mMyOtherFragment.publicMethod(newDataJustReceived).
You could also get crazier if you want and pass an interface into the child fragment that references the outer fragment so when MainActivity news up the children fragment, the outer one could implement an interface of doStuff and then be passed as an interface to the inner child fragment. So the child fragment can easily say if "mParentInterface" is not null then mParentInterface.doStuff.
There are millions of ways to skin a cat, but prefer to use interfaces rather then Reflection based libraries typically. Hope that helps.
Use interface in this case. 1) Define interface in you first fragment(in which you click something and waiting something to happen in a second fragment) and use callback method you define in your interface. For example:
OnButtonClickListener mCallback;
......your code
public interface OnButtonClickListener {
void onButtonSelected(int position);
}
......your code
then you call your callback method
.....
gridView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> adapterView, View view, int position, long l) {
mCallback.onButtonSelected(position);
}
});
2) Then implement this interface in host activity you have for nested fragments.
For example:
public class MainActivity extends AppCompatActivity implements YourFragment.OnButtonClickListener{....
3) Define callback method of your interface in this activity. For example:
public void onButtonSelected(int position) {
...Here just change something in your second fragment.....
Hope this will be helpful.
I use greenrobot EventBus in that cases.
You need to add this library to your build gradle:
compile 'org.greenrobot:eventbus:3.0.0'
That you can send message like this:
EventBus.getDefault().post(new ActionEvent("test action"));
And another fragment can catch it this way:
#Subscribe(threadMode = ThreadMode.MAIN)
public void onActionEvent(ActionEvent event) {
//do something
}
You can sending different actions, if you want, same way.
Don`t forget to according to fragment lifecycle:
#Override
public void onStart() {
super.onStart();
EventBus.getDefault().register(this);
}
#Override
public void onStop() {
EventBus.getDefault().unregister(this);
super.onStop();
}

Google Play Game Services - Listener null pointer exception

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.

Categories