Android context choice - java

I don't understand which context I should use in
(mApplicationContext or context parameter from onRecieve method). Please, could you give me some explanation what context parameter I should use and why (I read about memory leaks, documentation for this methods)
final PendingIntent pendingIntent = PendingIntent.getActivity(**mApplicationContext**, <smth>);
Notification.Builder notificationBuilder = new Notification.Builder( **mApplicationContext**).<smth>;
NotificationManager notificationManager = (NotificationManager) **mApplicationContext**.getSystemService(Context.NOTIFICATION_SERVICE);
// Constructor
public DownloaderTask(MainActivity parentActivity) {
super();
mParentActivity = parentActivity;
mApplicationContext = parentActivity.getApplicationContext();
}
mApplicationContext.sendOrderedBroadcast(new Intent(
MainActivity.DATA_REFRESHED_ACTION), null,
new BroadcastReceiver() {
final String failMsg = "Download has failed. Please retry Later.";
final String successMsg = "Download completed successfully.";
#Override
public void onReceive(Context context, Intent intent) {
if (getResultCode() != Activity.RESULT_OK) {
final PendingIntent pendingIntent = PendingIntent
.getActivity(mApplicationContext, <smth>);
RemoteViews mContentView = new RemoteViews(
mApplicationContext.getPackageName(),
R.layout.custom_notification);
if(success){
mContentView.setTextViewText(R.id.text,
successMsg);
} else {
mContentView.setTextViewText(R.id.text, failMsg);
}
Notification.Builder notificationBuilder = new Notification.Builder(
mApplicationContext).<smth>;
notificationBuilder.setContentIntent(pendingIntent);
NotificationManager notificationManager = (NotificationManager) mApplicationContext.getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(MY_NOTIFICATION_ID, notificationBuilder.build());
log("Notification Area Notification sent");
}
}
}, null, 0, null, null);
}

Always use the most specific context that you have. Use "this" in activities, and the context that is provided to you through methods.
Leave the application context to those cases where you can't have access to an activity context.

speaking generally, if you are in an activity, 'this' is your context ( remember to import android.content.Context; ), you can also pass the context to your fragments.
There are other times when it's a good idea to getApplicationContext, like in services launching alarms and such, but you'd do well to think of the activity you are working with as the context and you'll find out about the other exceptions as you go along.
keeping to this pattern, it is always informative when you think you have access to a context but you realize you don't; consider what exactly you are trying to do with that object, and what part of the program it "belongs" to.
So, inferring what constructed this object, another activity did DownloaderTask(this) or DownloaderTask(this.context) or DownloaderTask(getApplicationContext); I'd do it the first of those ways and just form the constructor here with public void DownloaderTask(Context context) =]

Related

mediaplayer.stop causes android app to crash

In our andorid broadcaster receiver class, we are trying to stop the ringtone that's initiated from mainactivity.class. We used mediaplayer.stop to stop the ringtone, which it successfully does, but it crashes the app. We have used .stop (), .pause (), .release (), but none of them is working unfortunately. The codes of broadcastreceiver is as given hereunder
Firebase class (summarized code) where media player is initialized and pending broadcast intent to buttonreceiver class is fired where mediaplayer is stopped.
public class Firebase extends FirebaseMessagingService {
public static Ringtone ringtone;
public static MediaPlayer mp;
Intent buttonIntent = new Intent(this, ButtonReceiver.class);
buttonIntent.putExtra("notificationId",notification_id);
PendingIntent btsPendingIntent = PendingIntent.getBroadcast(this, requestID, buttonIntent,PendingIntent.FLAG_UPDATE_CURRENT);
NotificationCompat.Action action1 = new NotificationCompat.Action.Builder(R.mipmap.ic_launcher, "Dismiss", btsPendingIntent).build();
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this, MainActivity.asw_fcm_channel)
.setSmallIcon(R.mipmap.ic_launcher)
.setContentTitle(title)
.setContentText(message)
.setDefaults(Notification.DEFAULT_ALL)
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setTimeoutAfter(60000)
.setCategory(NotificationCompat.CATEGORY_CALL)
.setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION))
.setAutoCancel(false)
.setContentIntent(pendingIntent)
.addAction(action1)
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
.setFullScreenIntent(pendingIntent2, true)
.setVibrate(new long[]{100, 200, 300, 400, 500, 400, 300, 200, 400});
mp = MediaPlayer.create(this, Settings.System.DEFAULT_RINGTONE_URI);
mp.start();
}
Button Receiver Class (where media player is stopped)
public class ButtonReceiver extends BroadcastReceiver {
public MediaPlayer mp;
#Override
public void onReceive(Context context, Intent intent) {
int notificationId = intent.getIntExtra("notificationId", 0);
mp.stop ();
mp.seekTo(0);
NotificationManager manager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
manager.cancel(notificationId);
}
}
Please help us out on this issue.
Your code doesn't show MediaPlayer being initialized, so it would definitely crash as soon as you try to reference the mp instance.
I'm pretty sure that you misunderstood how MediaPlayer works. It's not a global service -- you have to manage each instance yourself. Based on your code, you're instantiating it twice in different places, and expecting them to somehow control the same instance. You're declaring and creating the MediaPlayer, and starting playback in your FirebaseMessagingService class, but you're trying to stop it in your BroadcastReceiver class. But there, you're trying to use a totally different instance of MediaPlayer, which has never been initialized, and that's why it's crashing.
You'll need to keep a global reference to your mp object (either in a singleton, or in your Application object), and change the rest of your code to use it properly. For example:
public class App extends Application {
public static MediaPlayer mp;
}
public class Firebase extends FirebaseMessagingService {
...
if(App.mp == null){
App.mp = MediaPlayer.create(this, Settings.System.DEFAULT_RINGTONE_URI);
}
App.mp.start();
....
}
and in your Broadcast Receiver:
if(App.mp != null){
App.mp.stop ();
App.mp = null
}

How to replace firebase notification with your own on Android?

My Android application gets firebase notifications. And I need to localize this notifications depends on application language on the client side, not on server side.
If application is in foreground I use onMessageReceived() from FirebaseMessagingService and push my own localized notification. But if application is in background onMessageReceived() doesn't called.
In this case I use my own class extended BroadcastReceiver. onReceive(Context context, Intent intent) method catches notification, I localize it and push. Everything goes good, but in the end I get 2 push notifications: my own localized and firebase.
How can I get rid of this firebase notification and get only my own?
public class FirebaseDataReceiver extends BroadcastReceiver {
Context context;
PendingIntent pendingIntent;
public void onReceive(Context context, Intent intent) {
this.context = context;
Bundle dataBundle = intent.getExtras();
String title = "";
String body = "";
String type = "";
String objectId = "";
if (dataBundle != null) {
type = dataBundle.getString("type");
objectId = dataBundle.getString("objectId");
title = NotificationUtils.getNotificationTitle(context, dataBundle);
body = NotificationUtils.getNotificationBody(context, dataBundle);
}
Intent newIntent = new Intent(context, TutorialActivity_.class);
newIntent.putExtra("target", "notification");
newIntent.putExtra("type", type);
newIntent.putExtra("objectId", objectId);
newIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP
| Intent.FLAG_ACTIVITY_SINGLE_TOP);
pendingIntent = PendingIntent.getActivity(context,
0,
newIntent,
PendingIntent.FLAG_UPDATE_CURRENT);
Notification notification = new Notification.Builder(context)
.setContentTitle(title)
.setContentText(body)
.setPriority(Notification.PRIORITY_HIGH)
.setDefaults(Notification.DEFAULT_ALL)
.setContentIntent(pendingIntent)
.setAutoCancel(true)
.setSmallIcon(R.drawable.splash_mini)
.build();
deleteLastNotification();
NotificationManagerCompat.from(context).notify(0, notification);
}
}
You should really use Data notifications from the server. Normal message notifications can't achieve this behaviour you're looking for. Check out the docs here:https://firebase.google.com/docs/cloud-messaging/concept-options
So your request to Firebase from the server should look something like this:
{
"message":{
"token":"bk3RNwTe3H0:CI2k_HHwgIpoDKCIZvvDMExUdFQ3P1...",
"data":{
"Nick" : "Mario",
"body" : "great match!",
"Room" : "PortugalVSDenmark"
}
}
}
Instead of:
{
"message":{
"token":"bk3RNwTe3H0:CI2k_HHwgIpoDKCIZvvDMExUdFQ3P1...",
"notification":{
"title":"Portugal vs. Denmark",
"body":"great match!"
}
}
}

EditText in BroadcastReceiver Android

I am trying to create custom notifications. I have two EditText attributes in my XML file. I'm unable to understand how to pass the value of EditText from ReminderFragment.java to AlertReceiver.java or rather, can I declare EditText in AlertReceiver itself?
ReminderFragment.java
Declaration
eText = (EditText) findViewById(R.id.edittext);
findViewById(R.id.btnSetReminder).setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
String str = eText.getText().toString();
//how to return the string to createNotification method in AlertReceiver.java
setAlarm();
}
});
Method called when Button Set Reminder is clicked
public void setAlarm() {
calcal = new GregorianCalendar();
calcal.set(pYear, pMonth, pDay, pHour, pMinute);
Intent alertIntent = new Intent(ReminderFragment.this, AlertReceiver.class);
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
alarmManager.set(AlarmManager.RTC_WAKEUP, calcal.getTimeInMillis(),
PendingIntent.getBroadcast(ReminderFragment.this, 1, alertIntent, PendingIntent.FLAG_UPDATE_CURRENT));
}
and AlertReceiver.java
public class AlertReceiver extends BroadcastReceiver {
public AlertReceiver() {
}
#Override
public void onReceive(Context context, Intent intent) {
createNotification(context, "Good morning",
"You have a meeting with Mr. C today!", "Alert");
//this is where the custom text must appear
}
public void createNotification(Context context, String s, String s1, String alert) {
PendingIntent notificIntent = PendingIntent.getActivity(context, 0,
new Intent(context, ReminderFragment.class), 0);
NotificationCompat.Builder nBuilder = (NotificationCompat.Builder) new NotificationCompat.Builder(context)
.setSmallIcon(R.drawable.icon)
.setContentTitle(s)
.setTicker(alert)
.setContentText(s1);
nBuilder.setContentIntent(notificIntent);
nBuilder.setDefaults(NotificationCompat.DEFAULT_SOUND);
nBuilder.setAutoCancel(true);
NotificationManager mNotificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
mNotificationManager.notify(1, nBuilder.build());
}
}
I will tell you how a broadcast receiver works.
Assuming you have registered it properly in manifest, you send a 'broadcast' message (duh), much like a cellular tower.
And your receiver is supposed to 'catch' that broadcast message. The way you pass data in that broadcast message is by passing extras.
The general way to put an additional message is by putting 'extras'
you can do that by adding:
alertIntent.putExtra("key", "value");
there are many different data types to choose from for key and value, like strings, arrays , booleans , etc
You can put an extra (or multiple) in your Intent:
in setAlarm() simply add
alertIntent.putExtra(<key>, <string>);
replace <key> with any string you like, e.g. "text" or just "key" and <string> with the string you want to send to the AlarmReceiver.
In AlarmReceiver you can then get the string in onReceive using
String text = intent.getExtras().getString(<key>);
<key> of course has to be the exact same you used in putExtra(), otherwise it won't work.
You can even put multiple Extras with multiple different keys if you like.

Instantiate non-activity class on pending intent in android

i have a notification in android, and i want to do something like
MyStaticClass.start() when i click in the notification, this class is not an activity, its only to instantiate a needed class.
How can i do it it?
This is my actually code:
String notificationContent = "Hay una nueva version disponible";
String notificationTitle = "Firext";
Bitmap largeIcon = BitmapFactory.decodeResource(FirextApplication.getInstance().getResources(), R.drawable.ic_launcher);
int smalIcon = R.drawable.ic_launcher;
Intent intent = new Intent(FirextApplication.getInstance(), UpdateProcess.class);
intent.setData(Uri.parse("content://" + Calendar.getInstance().getTimeInMillis()));
PendingIntent pendingIntent = PendingIntent.getActivity(FirextApplication.getInstance(), 0, intent, Intent.FLAG_ACTIVITY_NEW_TASK);
NotificationManager notificationManager = (NotificationManager) FirextApplication.getInstance().getSystemService(Context.NOTIFICATION_SERVICE);
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(
FirextApplication.getInstance())
.setWhen(Calendar.getInstance().getTimeInMillis())
.setContentText(notificationContent)
.setContentTitle(notificationTitle)
.setSmallIcon(smalIcon)
.setAutoCancel(true)
.setTicker(notificationTitle)
.setLargeIcon(largeIcon)
.setDefaults(Notification.DEFAULT_LIGHTS | Notification.DEFAULT_VIBRATE | Notification.DEFAULT_SOUND)
.setContentIntent(pendingIntent);
Notification notification = notificationBuilder.build();
notificationManager.notify((int) Calendar.getInstance().getTimeInMillis(), notification);
And the class i need to call
public class UpdateProcess {
private static final String APPLICATION_VND_ANDROID_PACKAGE_ARCHIVE = "application/vnd.android.package-archive";
private static final String NEWVERSION = "NewVersion.apk";
private static final File EX = Environment.getExternalStorageDirectory();
private static volatile UpdateProcess instance = null;
private Activity activity;
private UpdateProcess(Activity activity) {
this.activity = activity;
checkForNewUpdates();
}
public static void startUpdate(Activity activity) {
if (instance == null) {
synchronized (UpdateProcess.class) {
if (instance == null) {
instance = new UpdateProcess(activity);
}
}
} else {
UpdateProcess.instance.activity = activity;
}
}
I only need do a UpdateProcess.startUpdate();
Edit:
This is my new code:
private void showNot() {
String notificationContent = "Hay una nueva version disponible";
String notificationTitle = "Firext";
Bitmap largeIcon = BitmapFactory.decodeResource(FirextApplication.getInstance().getResources(), R.drawable.ic_launcher);
int smalIcon = R.drawable.ic_launcher;
Intent intent = new Intent(FirextApplication.getInstance(), UpdateProcess.class);
PendingIntent pendingIntent = PendingIntent.getService(context, 0, intent, 0);
Notification notificationBuilder = new NotificationCompat.Builder(context)
.setWhen(Calendar.getInstance().getTimeInMillis())
.setContentText(notificationContent)
.setContentTitle(notificationTitle)
.setSmallIcon(smalIcon)
.setTicker(notificationTitle)
.setLargeIcon(largeIcon)
.setDefaults(Notification.DEFAULT_LIGHTS | Notification.DEFAULT_VIBRATE | Notification.DEFAULT_SOUND)
//.setContentIntent(pendingIntent)
.addAction(android.R.drawable.arrow_up_float, "Call", pendingIntent).build();
NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(0, notificationBuilder);
}
public class UpdateProcess extends IntentService {
private static final String APPLICATION_VND_ANDROID_PACKAGE_ARCHIVE = "application/vnd.android.package-archive";
private static final String NEWVERSION = "NewVersion.apk";
private static final File EX = Environment.getExternalStorageDirectory();
private static volatile UpdateProcess instance = null;
private Context context;
private UpdateProcess(Context context) {
super("UpdateProcess");
this.context = context;
checkForNewUpdates();
}
#Override
protected void onHandleIntent(Intent intent) {
startUpdate(getApplicationContext());
}
But when i do click in action nothing happens..i get thi error:
05-10 17:15:22.955 753-7617/? W/ActivityManager﹕ Unable to start service Intent { flg=0x10000000 cmp=com.firext.android/.util.UpdateProcess bnds=[192,346][1080,490] } U=0: not found
Edit 2. Now works, i forget include service in manifest
I need to show a toast message in a method inside UpdateProcess, what i should use?
Your Notification can trigger an Activity, a Service, or a BroadcastReceiver via its PendingIntent. Activity is a Context. Service is a Context. BroadcastReceiver receives a Context as a parameter to onReceive(). Hence, from all three locations, you already have a Context, so use that one.
You might also consider getting rid of the Toast entirely. A Toast is only good for a message that the user does not need, as the user might not see it.
I only need do a UpdateProcess.startUpdate();
It would appear that checkForNewUpdates() will do some significant work.
If that work will take less than ~15 seconds, convert UpdateProcess to UpdateIntentService, extending IntentService, and do your checkForNewUpdates() work in onHandleIntent(). You can use a getService() PendingIntent to trigger the UpdateIntentService to do its work.
If the work is likely to take longer than that, you should consider using the WakefulBroadcastReceiver pattern (or perhaps my WakefulIntentService), to ensure that the device stays awake long enough for your work to complete.
Instead to use getActivity() use getService() in you pending intent. Create an ad-hoc intent service to call UpdateProcess.startUpdate() in onHandleIntent(). In this case you can't use an activity as parameter of course, but maybe you can change the parameter in a Context.

Multiple notification on same intent

I am writing an application and in this application I need to set multiple notification with same intent just like open my application whenever user tap on any notification.
All the notification comes on different time and date without having any data but the problem is, if I set two notification for 03:27 PM and 03:28 PM then the first notification (03:27 PM) is canceled (Overwritten by second) and second is working correctly.
I am currently using this code for achieving this goal:
this method is used to set notification from Activity:
public static void setNotificationOnDateTime(Context context, long fireTime)
{
int requestID = (int) System.currentTimeMillis();
AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
Intent i = new Intent(context, NotificationReceiver.class);
PendingIntent pi = PendingIntent.getBroadcast(context, requestID, i, 0);
am.set(AlarmManager.RTC_WAKEUP, fireTime, pi);
}
and my NotificationReceiver class look like this:
NotificationManager nm;
#Override
public void onReceive(Context context, Intent intent) {
Log.w("TAG", "Notification fired...");
nm = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
PendingIntent contentIntent;
Bundle bundle = intent.getExtras().getBundle("NotificationBundle");
if(bundle == null)
{
contentIntent = PendingIntent.getActivity(context, 0,
new Intent(context, SplashScreen.class), 0);
}
else
{
contentIntent = PendingIntent.getActivity(context, 0,
new Intent(context, MenuScreen.class)
.putExtra("NotificationBundle", bundle), 0);
}
Notification notif = new Notification(R.drawable.ic_launcher,
"Crazy About Android...", System.currentTimeMillis());
notif.setLatestEventInfo(context, "Me", "Message test", contentIntent);
notif.flags |= Notification.FLAG_AUTO_CANCEL;
nm.notify(1, notif);
}
I alerady spend a lot time on googling and found some solutions but they didn't work for me here is the link of some of them:
android pending intent notification problem
Multiple notifications to the same activity
If any one knows how to do this please help me.
Quote:
Post a notification to be shown in the status bar. If a notification with the same id has already been posted by your application and has not yet been canceled, it will be replaced by the updated information.
But you're always using 1 for the id parameter. Use a unique ID when you post several notifications.
Update If that doesn't help, you can still create Intents which do not compare as being equal, while having an equal effect.
this may be helpful
notif.flags |= Notification.FLAG_ONGOING_EVENT;
the notification will never close...
Try to set as below :
contentIntent=PendingIntent.getActivity(p_context, i, new Intent(context, MenuScreen.class),PendingIntent.FLAG_CANCEL_CURRENT);
It might help you.

Categories

Resources