How to play android sounds NOT in activity class - java

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

Related

FLutter Android Plugin, onDestroy function is not attached to the plugin class

i am creating a plugin with the onAttachedToEngine function that i use to assign context and mediaPlayer session to variables, exactly like the docs say so nothing special is being done. The problem is that when my plugin throws an error and it's time for the onDestroy function to be called, the onDestroy function doesn't seem to see the variables i set during the usage of the current object.
so if i set a variable X to "hello" in the onAttachedToEngine, onDestroy will keep seeing it as null and creates nullPointer exceptions which crashes my plugin and app.
here is a sample code i am using :
public class flutterPlugin extends MediaBrowserService implements FlutterPlugin, MethodCallHandler {
private String randomString = "lowercase";
private void initInstance(BinaryMessenger binaryMessenger, Context context) {
this.channel = new MethodChannel(binaryMessenger, ID);
this.channel.setMethodCallHandler(this);
am = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
mContext=context;
mNotificationManager = (NotificationManager) mContext
.getSystemService(Context.NOTIFICATION_SERVICE);
setupBroadcastReceiver();
startSession(mContext);
this.randomStirng = "UPPERCASE";
}
#Override
public void onAttachedToEngine(#NonNull FlutterPluginBinding binding) {
this.initInstance(binding.getBinaryMessenger(), binding.getApplicationContext());
}
#Override
public void onDestroy() {
this.randomStirng // here the random string i initialized is equal to "lowercase"
// and the same goes for all the variables initialized in initInstance, they are alll treated an null
(...)
}
(...)
}
what could the issue be ? is onDestroy being called from a child process ? when getting the parent of super it returns the same class name as the plugin

android:singleton instance not garbage collected after application is closed

I have an android activity with a fragment.
In the fragment, I fetch data using retrofit and set a static flag, so that , when I again go to this fragment, I restrict fetching data again.
I also store the data in a singleton instance.
But even after I destroyed the activity/closed the application, the static flag and the instance is still available and the list is also present in the instance, which malfunctions my app.
But I want the instance to be created newly and fetch data at each run.
This is my singleton instance.
public class Utilities {
private static Utilities utils = null;
private List<Data> friendsList;
public List<Data> getDataList() {
return dataList;
}
public void setDataList(List<Data> dataList) {
this.dataList = dataList;
}
private List<Data> dataList;
public synchronized static Utilities getInstance(){
if(utils == null){
utils = new Utilities();
}
return utils;
}
}
This is my fragment:
public class DataFragment extends Fragment
{
private static boolean hasObtainedData;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
if(!hasObtainedData){
getData(v);
}else{
recyclerView.setAdapter(new Adapter(utils.getDataList()));
}
}
private void getData(View v) {
//get Data using Retrofit:
hasObtainedData = true;
utils.setDataList(dataListObtainedUsingRetrofit)
recyclerView.setAdapter(new Adapter(utils.getDataList()));
}
}
This is how, I call my fragment from MainActivity:
#Override
public void onTabSelected(TabLayout.Tab tab) {
getSupportFragmentManager().beginTransaction()
.replace(R.id.fragmentBox, new DataFragment()).commit();
}
I tried giving System.gc() at onDestroy() of MainActivity, but still, the singleton instance is alive.
I search many SOF posts based on this, but wasn't able to solve this issue.
Any help will be really useful.
The pointer to the Singleton is static in the Utilities-Class itself, so the Singelton can never be available for GC, unless you set utils = null on leaving MainAcitivity with something like
Utilities.reset();
Your singleton wont survive your app being terminated, and what's probably happening is that you aren't actually killing the app entirely during your tests. Run adb shell am force-stop <your-app-package> from your console and see whether that still results in the issue.
With that said, if you only want your data to run once per application launch, then I would recommend you move it into the onCreate() lifecycle callback of your Application
public class App extends Application {
#Override
public void onCreate() {
super.onCreate();
//Begin process to fetch data and cache it here
}
}
Don't forget to add the application name to your manifest too, <application android:name="your.packagename.App"
You then have no need to modify your data at all - it will only run once per application launch.
If, however, what you actually want is for your data to update every time the Activity is launched, then do the same process as before but inside onCreate() of you Activity. You can also clear it in onDestroy(), if you want it to updated when your Activity is recreated:
#Override
public void onDestry() {
super.onDestroy();
Utilities.getInstance().setDataList(null);
}
Also, if your data is bound to the lifecycle of your Activity, then you don't really need a singleton (which is bound to the lifecycle of the application).

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.

Call a class with AsyncTaks from a static class

I am trying to initialize a class that calls another class that uses AsyncTask. I am using GetDataFromDB gDataFromDB = new GetDataFromDB() but that does not initialize the class, it just gives me access to any static methods in the class. So what do I do to get the onCreate method to run? I have tried using intent but keep getting an error because this is a static class
public class FacadeDataFromDB extends Activity {
static ArrayList<HashMap<String, String>> visitorsList;
private static FacadeDataFromDB dataFromDB;
static boolean accessDB = false;
private FacadeDataFromDB() {
}
public static void initInstance() {
}
public static FacadeDataFromDB getInstance() {
if (dataFromDB == null) {
// Create the instance
dataFromDB = new FacadeDataFromDB();
}
return dataFromDB;
}
public static void setData() {
if (!accessDB) {
GetDataFromDB gDataFromDB = new GetDataFromDB();
accessDB = true;
}
// visitorsList = gDataFromDB.returnInfoFromDB();
}
public static ArrayList<HashMap<String, String>> getVisitorForDay() {
// TODO Auto-generated method stub
setData();
return visitorsList;
}
}
GetDataFromDB is the other class that I am calling. The current class is a static class and uses a singleton because I only want one initialization of the class the gets data from the db. If you have more questions or want me to post code let me know. Thanks
It seems to me that your two classes FacadeDataFromDB GetDataFromDB should not inherit Activity
Activities are made for GUI and user-interaction (I don't see any in your example) and their life-cycle is managed by the framework : you never create them manually with new.
See the android tutorial : https://developer.android.com/guide/components/activities.html and Activity javadoc : https://developer.android.com/reference/android/app/Activity.html.
I'm not sure that you completely understand the Android runtime. You should start Activities using Intent objects, not by creating them with the new keyword as you are. To ensure that your onCreate() method is called within your Activity, you could launch an explicit Intent from some other Activity/Context: Intent intent = new Intent(currentContext, FacadeDataFromDB.class);.
Also, when it comes to Activities, you shouldn't use private constructors. See this post for reasons why.

how to get context from PhoneStateListener class

i need to call method from several classes, but i don't know how to get the right context
the holding class:
public class SharedData {
......
......
public static void stop_ring(Context context){
Uri lcurUri = RingtoneManager.getActualDefaultRingtoneUri(context, RingtoneManager.TYPE_NOTIFICATION);
Ringtone ring = RingtoneManager.getRingtone(context, lcurUri);
ring.stop();
}
how can i call it from activity class, and how can i call it from PhoneStateListener class.
Activity extends Context so you can call it like so:
SharedData.stop_ring(this);
For a listener you will have to put Context in the constructor and save it as a property. Then call:
SharedData.stop_ring(saved_context);
the major solution is
1.
public class MyPhoneStateListener extends PhoneStateListener
{
public MyPhoneStateListener(Context ctx) {
super();
}
2.
When istance the listener
TelephonyManager telephonyManager = (TelephonyManager) this.getSystemService(Context.TELEPHONY_SERVICE);telephonyManager.listen(
new MyPhoneStateListener(Context),
PhoneStateListener.LISTEN_CALL_STATE);
3.
finish
by
Try to use getApplicationContext(). Mostly it works.

Categories