Knotty problem with MP3 stream MediaPlayer in Android. I've done yet some app with it, but now I refactor the code cause of some reasons.
There is a call of a Service in the activity of Player:
mp3Service.playSong(getBaseContext(),url);
The playSong method consists of this:
public void playSong(Context c, String url) {
if (this.currenturl.equals(""))
{
this.mplayer = MediaPlayer.create(c, Uri.parse(url));
this.currenturl=url;
this.mplayer.start();
}
else
{
if (!this.currenturl.equals(url))
{
this.mplayer.stop();
//this.mplayer=null;
this.mplayer = MediaPlayer.create(c, Uri.parse(url));
this.mplayer.start();
this.currenturl=url;
} else
{
if (this.on==false)
this.mplayer.start();
};
};
this.on=true;
}
The call to playSong method worked normally when it was on the ImageView click listener! The music started to play.
But, when calling simply from player activity onCreate - it stops the app.
Not sure why, but it's totally hard to understand what context parameter to use here.
I've read some similar articles and documentation, but there is much fog.
How to determine what should I use for the first Context parameter here?
Does it depend on from where I call the .playSong(Context, Uri)? If yes, how?
Context is very abstract for new in Android, the class documentation by itself don't shed light to it.
There are many choices which I tried but I need logical reason why to use this and how to determine why app stops.
getApplicationContext()
getBaseContext()
this
PlayerActivity.this
and others. But without understanding it's not right. Maybe the error is in the other place.
But without the service call all was working.
I agree that Context and when to use which kind can be a hard idea to grasp. From what I have learned, it normally seems best to use your Activity's Context in most situations. These are my thoughts on it and somebody please correct me if I'm wrong with examples/facts.
How to determine what should I use for the first Context parameter here? Does it depend on from where I call the .playSong(Context, Uri)? If yes, how?
Yes and not necessarily. From what I have read, you want to use the Context that is closest to the Object that needs it...use the most minimal Context needed.
If you call if from an Activity and the Object will be destroyed when that Activity is destroyed then use the Activity Context (here Player.this).
If you are calling a service, which has its own Context then use the Service's Context.
If it needs access to things like System services then use getApplicationContext()
You said you've already read articles about using Context and since I don't know which ones I won't post a bunch of links. However,
Here is a good SO answer about using getApplicationContext()
Maybe the error is in the other place.
If you post what error you are getting then maybe we can help better to find the error
Related
I have been receiving some crash reports in the Play Store which initially seemed crazy to me.
Some activities (in 1 case, it's a broadcast receiver) are crashing in onCreate()/onResume() due to NullPointerException.
These activities are using static methods which in turn use the Application singleton [for context], but the object returned is null like if the application object didn't exist at all. From my understanding, the application should always have an instance.
My code is ordinary, the application sets a static field in its onCreate(), and the classes that the activities call use MyApplication.getInstance() which returns the application object.
How can MyApplication.getInstance() return null when called from activities? I have no idea how that could happen.
Of course, I have been unable to replicate this crash.
This mainly happens in Android 6, but I have some reports from Android 8 and 9.
I guess you are doing what the most voted answer says in this question.
However, you should see what many people warn in the comments:
The downside is that there is no guarantee that the non-static
onCreate() will have been called before some static initialization
code tries to fetch your Context object. That means your calling code
will need to be ready to deal with null values which sort of defeats
the whole point of this question. – Melinda Green
.
It's upsetting to see how many upvotes this answer has. You should never hold a static instance to context - for proofs sake, try using Leak Canary (github.com/square/leakcanary) and find the memory leak caused because of this. #people-with-enouhg-rep-and-Android-knowledge, please re-review this answer and act accordingly. This is guaranteed to be used by beginners and it's plain simple wrong. – Crearo Rotar
You should either:
User your Activity context whenever possible and pass it to any other class that needs it.
Or, what I really recommend, set up dependency injection using Dagger2. It is a little difficult to learn at the beginning, but there is a lot of information and tutorials to help you get started. Once you setup Dagger properly, all you need to access you Application context in a null-safe way is Inject it in the corresponding class like this:
public class MyClass {
#Inject
Context context;
...
}
As an alternative to the other answer about dagger dependency injection I just wanted to give an example of getting context from an activity the old fashioned way. If you declare context as a member variable it will be available all over your activity and can be passed to other classes as needed:
public class ExampleActivity extends AppCompatActivity {
private Context mContext;
#Override protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_example);
mContext = this;
}
I think I found the cause. In Android 6 auto restore not initializing app, the problem is the same and they identified the cause as being the auto backup feature that was introduced in Android 6. Basically, after a restore from the backup, the app is restarted in a weird way where the Application object is not created before the Activity. We now can reproduce the problem and disabling backup fixes the problem.
I just learned that I can use either:
Toast.makeText(MainActivity.this, R.string.some_string,Toast.LENGTH_SHORT).show();
or,
Toast.makeText(getApplicationContext(), R.string.some_string,Toast.LENGTH_SHORT).show();
To display a Toast in Android.
Earlier I thought context was actually a sort of handle to the parent window where it should be display but the documentation is unclear about this.
Then I came across this table:
It also doesn't seem to mention what context exactly to use for a Toast?
Edit:
Is context like a "handle to parent window" for the sub-window like Toast? or does it actually allow the Toast.makeText to get access to resources or something?
Why is it being used at all if the context doesn't matter?
Looking at Toast.java, I can see the Context is used only for:
obtaining Resources
obtaining Package Name
getText which is actually same as #1
So apparently there's no difference whether it's Activity or ApplicationContext, unless those resources depend on theme (which is not the case as far as I can tell).
And no, the context passed to Toast is not a handle to parent window in any sense.
I'd recommend to use the activity in your case. Since you're calling from the activity itself. The activity is a Context and you're using the method on the activity to get another context (the application). It is a little unnecessary.
However in the case you're calling a toast from somewhere else it might be a better idea to use the application, since the application will always be there while your app is active.
You can show Toast only from UI (main thread) context. If you want show this from Service (but this is contradicts Google guidelines), you can do this way: Show toast at current Activity from service
For toasts, which are short-lived, you can usually use whatever context you want. Typically, you would use the activity context, but application context is fine as well.
I have a simple flashlight application and I would like to have the light switch on-off functionality by simply clicking on the widget also.
Now when I click on the widget my program starts, it is ok but it would be better to reach the functionality of my app directly from the widget.
I think now the appwidgetprowider just starts my activity:
Intent intent = new Intent(context, MainActivity.class);
In my flashlight`s main activity I switch on the led of the phone by the
switchOnTheFlash()
method.
Does anyone have an idea, how could I start this method from the widget?
Thank you and best regards!
Intent is not needed to turn on the flashlight as it will always take you somewhere in activities or actions. The simplest thing to do is make your switchOnTheFlash() function static like this -
public static void switchOnTheFlash() {
// Your Function
}
and Now you can call this function from any activity just like -
YourACtivity.switchOnTheFlash();
If Errors Occur --
Make sure that all the variables you use in switchOnTheFlash() should be static too or you will be getting error like cannot use non-static variables in static function (or may be somewhat written a bit different).
Another error, if you use functions like getResources() you can get errors. To get rid, Just make a static Context mContext; globally and initialize it like mContext = this; in OnCreate. Then simply replace mContext.getResources()... everywhere in your function switchOnTheFlash().
Cheers!
I'm trying to create my own class for reading lines from a file, but that seems to be the problem.
From what I've been able to determine standard (Java) ways don't work under Android. I need to getResources() and so on.
public myInput(Context context) throws FileNotFoundException{
super();
br = new BufferedReader(new InputStreamReader(context.getResources().
openRawResource(R.raw.file)));
}
That's the constructor. I'm trying to create it like this.
public void choosePassword(Context context){
try{
myInput fromFile = new myInput(context);
} catch(Exception e){
}
}
The metod choosePassoword() is being called form my Activity class and to be honest don't know what he wants for Context. I want to give the method choosePassword() the file from which he should choose that password, that's what I want... can someone help me do just that?
An Activity is an indirect sub-class of Context so you can simply use choosePassword(this) when calling it from your Activity.
... to be honest don't know what he wants for Context
OK. This is an important thing to understand in Android. Contexts are the basis by which almost all apps interact or even have an identity. A Context essentially identifies where a Component's run instruction originated (this is an oversimplification). For an Android Component to run, it must have a Context to run in. Luckily, in most circumstances, the Context is provided for you. There are two specific types of Contexts that you will almost always have access to:
Every Activity is a Context. This one is subject to Lifecycle method calls.
Every Application is a Context. This one is outside of the Lifecycle and is initialized before any other Component of the Application is even created.
Both of these may be used whereever you may need a Context. If you need the Application Context, you may get it from nearly any component with the getApplication() method.
For Your Purposes
This makes your calls quite easy. If all of the calls are made from your Activity, then you may supply this as your argument. Even better, if the methods themselves are part of your Activity, you need not necessarily pass the Context as an argument and again, simply use this.
Of Important Note
You will learn that sometimes, it is easier to get one Context or another. You will also learn that sometimes while it may be more difficult, it is safer to use one Context over the other. For this, I would recommend reading up on the Lifecycle of an Activity. Not using the right one can result in memory leaks and unsafe execution. In general, if you need a Context for data or execution that only survives the Lifecycle, you can use an Activity. If you need a Context for data or execution that occurs outside the Lifecycle, use the Application.
Anyhow, didn't mean to write a book. There is a wealth of information on Contexts, how to use them and which to use. Certainly read up on it. It will make your life a ton easier.
Hope this helps,
FuzzicalLogic
I'm trying to create an android project that contains shared code which will be used by others.
In this project I only have POJO and no android specific classes.
Some of the functionality requires calling some activities and is depended on the result.
My POJO classes get reference to the calling activity when used, but that's happening at run time and I have no control over the implementation of those activities.
My problem is that with the reference of the calling activity I can startActivityForResult but I have no way of adding the onActivityResult, which might exists in the calling activity but is not aware of the requestCode I used.
My question then is how do I know, from within a regular java object when the activity has returned? since, as far as I understand I can only implement onActivityResult on Activity classes.
thanks!
You will have quite a few problems with this setup, but this is how you might want to get started:
You will have to include an activity in your project which does nothing else than starting the activity you want to get the result from and stores it in a globally accessible storage (e.g. a singleton or a static field).
class Pojo {
static final ConditionVariable gate = new ConditionVariable();
static int result;
int m(Context context) {
context.startActivity(new Intent(context, ForwarderActivity.class));
gate.block();
return result;
}
}
class ForwarderActivity extends Activity {
private boolean started = false;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (!started) {
started = true;
startActivityForResult(new Intent("ContactsProvider"), 1);
}
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
Pojo.result = resultCode;
Pojo.gate.open();
}
}
There are a couple of problems, though. Like your POJO's method can't be called from the main (UI) thread, because you need to convert an asynchronous call (startActivityForResult()) to a synchronous one (Pojo.m()) and the activity you want to receive info from will be started on the main thread, so you can't block it in Pojo.m()...
Anyway, the code does not work, but you can see which way to go if you really have to stick with this setup. But you should really try to come up with some other means of fetching the data, like a content provider.
i have the same problem while i play with UNITY3D,the unity have it's own Activity(the unity player),i don't wanna edit it for some reason. but the player activity do nothing inside the "onActivityResult" function. And i have something to do when access image picker,i can call "unityPlayer.startActivityForResult" to open image picker,but NO WAY TO CODE MY OWN "onActivityResult".
i think what we hope is something like this:
OtherActivityClass.onActivityResultListener=function(){My Own CODE}..........OR
OtherActivityClass.onActivityResultListener.add(myResultListener)..................
My question then is how do I know, from within a regular java object when the activity has returned?
Have the activity call the POJO, supplying the result.
My POJO classes get reference to the calling activity when used, but that's happening at run time and I have no control over the implementation of those activities.
Then whoever is in "control over the implementation of those activities" will need to have the activity call the POJO, supplying the result. This is no different than any other callback/listener mechanism.
Maybe PendingIntent http://developer.android.com/reference/android/app/PendingIntent.html can help you with that. I'm still looking around for a solution to my problem and for me, this class looks quite promising.
Another way might be to make your own class abstract and have a method onActivityResult that is required to be overridden. Of course, you would have to rely on JavaDoc and "please call super.onActivityResult" to be able to process the result in your code. But if the users of your class want to have some success with your code they should follow your JavaDoc instructions.
Similar to what Szabolcs Berecz suggests, it is possible. There is no beautiful solution, but following is possible:
create a simple no view activity that starts the intent for you
distribute the result through a global listener manager where interested classes can register and unregister theirself (the POJO e.g.)
this is non blocking but startActivityForResult and waiting for its result is non blocking in general
I've set this up in a library for app settings and some settings do start a system intent (e.g. select an image) and need to wait for their result and this works even after screen rotation without the need of any code adjustments by the libraries user.