What I am trying to do is to sent a Notification to Wear with a PendingIntent to open a simple Activity of which TextView is set by an Intents Extra (String). The problem is, that the Extras seems to be empty.
Here is my Code for the MainActivity:
public class MainActivity extends ActionBarActivity {
public static final String KEY = "eu.paliga.creatinganotification.Key";
public static final String MSG = "welcome back";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button button = (Button) findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent viewIntent = new Intent(MainActivity.this, ViewEventActivity.class);
viewIntent.putExtra(KEY, MSG);
PendingIntent viewPendingIntent = PendingIntent.getActivity(MainActivity.this, 0, viewIntent, 0);
NotificationCompat.Builder notificationBuilder =
new NotificationCompat.Builder(MainActivity.this)
.setSmallIcon(R.drawable.ic_launcher)
.setContentTitle("trying")
.setContentText("to figure it out")
.setContentIntent(viewPendingIntent);
NotificationManagerCompat notificationManager =
NotificationManagerCompat.from(MainActivity.this);
notificationManager.notify(0, notificationBuilder.build());
}
});
}
....
}
and for the Activity that is started by the Intent:
public class ViewEventActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_viewintent);
Intent intent = getIntent();
if (intent.hasExtra(MainActivity.KEY)) {
String msg = intent.getStringExtra(MainActivity.KEY);
Log.d("MyTag", msg);
((TextView)findViewById(R.id.textView2)).setText(msg);
}
}
}
When you use PendingIntent.getActivity(MainActivity.this, 0, viewIntent, 0) (specifically, the 0 as the last parameter), extras do not get replaced per the PendingIntent overview:
Because of this behavior, it is important to know when two Intents are considered to be the same for purposes of retrieving a PendingIntent. A common mistake people make is to create multiple PendingIntent objects with Intents that only vary in their "extra" contents, expecting to get a different PendingIntent each time. This does not happen. The parts of the Intent that are used for matching are the same ones defined by Intent.filterEquals. If you use two Intent objects that are equivalent as per Intent.filterEquals, then you will get the same PendingIntent for both of them.
They go into details on how to deal with them, although the most common solution is to replace your call with:
PendingIntent.getActivity(MainActivity.this, 0, viewIntent,
PendingIntent.FLAG_UPDATE_CURRENT)
Where FLAG_UPDATE_CURRENT denotes that the system should update the extras in the PendingIntent.
Related
I have MainActivity and UserAcitivity, I have passed some values to UserActivity through intent.
from the UserActivity, I call Notification then notification appeared, I made notification tap to
start the UserActivity by Pending Intent. When the Notification tap the App crashes because the values passed from MainAcitvity become null.
I can't Use SharedPreferences because the Value conflict for another UserAcitivity(the passed value was unique for every user)
example code is here:-
This is MainAcitvity
public void buttonClick(View view){
Intent intent = new Intent(this,SecondActivity.class);
intent.putExtra("myname","ashiqueHira");
startActivity(intent);
}
This is SecondAcivity Oncreate method;
String heading= "";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
Intent intent = getIntent();
heading = intent.getStringExtra("myname");
Toast.makeText(this, heading, Toast.LENGTH_SHORT).show();
}
This is my Notification method
public void notificationPops(){
Intent intent = new Intent(this, SecondActivity.class);
createNotificationChannel();
TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
stackBuilder.addNextIntentWithParentStack(intent);
Vibrator vibrator = (Vibrator) getApplicationContext().getSystemService(Context.VIBRATOR_SERVICE);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, 0);
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_ID)
.setSmallIcon(R.drawable.ic_vibration_black_24dp)
.setContentTitle("Token Reminder")
.setContentText("Dismiss the Alarm by Clicking this")
.setPriority(NotificationCompat.PRIORITY_MAX)
.setVibrate(new long[] { 100, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000 })
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
// Set the intent that will fire when the user taps the notification
.setContentIntent(pendingIntent)
.setAutoCancel(true);
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this);
notificationManager.notify(0, builder.build());
}
private void createNotificationChannel() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel serviceChannel = new NotificationChannel(
CHANNEL_ID,
"myChannel",
NotificationManager.IMPORTANCE_HIGH
);
serviceChannel.enableVibration(true);
NotificationManager manager = getSystemService(NotificationManager.class);
manager.createNotificationChannel(serviceChannel);
}
}
This is a similar condition that I have. The difference is I have many usages for the getIntent value
and that value is unique for every Activity.
Thanks in Advance
So, basically you get NullPointerException. For reducing this problem change youe SecondActivity code like this:
String heading= "";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
Intent intent = getIntent();
if(intent.getStringExtra("myname")!= null){
heading = intent.getStringExtra("myname");
Toast.makeText(this, heading, Toast.LENGTH_SHORT).show();
}
}
This will reduce your nullException error and your app cannot crash.
Another thing If you always need heading value pass through intent. Then pass the value also from notification pendingIntent and get it from SecondActivity
I found a way to solve this problem by adding and replacing the following code
in the notificationPops() method
Intent intent = new Intent(this, SecondActivity.class);
intent.putExtra("yourName",heading);
PendingIntent pendingIntent = PendingIntent.getActivity(getApplicationContext(), 0,
intent, PendingIntent.FLAG_UPDATE_CURRENT);
this will get you the value to the activity when the activity stats by notification taps.
Please post if other best practices to solve the problem above
My app repeatedly loads data from a server. Among those data are messages.
Whenever new messages are loaded, the MainActivity is called on an Interface's callback method onMessagesReceived(int numOfMessages).
The app has only one Activity and every screen is implemented as a Fragment. Switching of Fragments is managed by a dedicated Navigator class.
My problem is the handling of the user tapping on the Notification. When the user taps on the Notification, the message list should be shown.
public class MainActivity extends AppCompatActivity implements MessageListener {
private static final int MESSAGE_NOTIFICATION_ID = 101010;
private static final String EXTRA_SHOW_MESSAGES = "SHOW_MESSAGES";
private Navigator mNavigator;
#Override
onMessagesReceived(int numOfMessages) {
Intent intent = new Intent(this, MainActivity.class);
testIntent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
testIntent.putExtra(EXTRA_SHOW_MESSAGES, true);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, 0);
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, "testChannel")
.setSmallIcon(R.drawable.ic_message_notification)
.setContentTitle("New messages!")
.setContentText("You got " + numOfMessages + " new messages")
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
.setContentIntent(pendingIntent);
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this);
notificationManager.notify(MESSAGE_NOTIFICATION_ID, builder.build());
}
#Override
protected void onResume() {
super.onResume();
Bundle extras = getIntent().getExtras();
if (extras != null && extras.containsKey(EXTRA_SHOW_MESSAGES)) {
if (extras.getBoolean(EXTRA_SHOW_MESSAGES)) {
mNavigator.openMessageList();
}
}
}
}
At the moment, the MainActivity shows up, when the app is in background, but in onResume, the Bundle returns as null.
When the app is in the foreground, nothing happens at all.
I want to achieve on a click on the Notification:
- When the user is inside the app, the MessageList Fragment should be opened
- When the user is not inside the app, it should be started before opening the MessageList Fragment
Can someone give me a hint, how to proceed from here? Maybe using Intents isn't the right solution here?
You can use intents just put some boolean extras in intent an just check the value in main activity if that extra value is true then call your method.
After some more digging on Intents and Notifications, I finally came up with a solution.
public class MainActivity extends AppCompatActivity implements MessageListener {
private static final int MESSAGE_NOTIFICATION_ID = 101010;
private static final String EXTRA_SHOW_MESSAGES = "SHOW_MESSAGES";
private Navigator mNavigator;
#Override
onMessagesReceived(int numOfMessages) {
Intent intent = new Intent(this, MainActivity.class);
testIntent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
testIntent.putExtra(EXTRA_SHOW_MESSAGES, true);
PendingIntent pendingIntent = PendingIntent.getActivity(
this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, "testChannel")
.setSmallIcon(R.drawable.ic_message_notification)
.setContentTitle("New messages!")
.setContentText("You got " + numOfMessages + " new messages")
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
.setContentIntent(pendingIntent);
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this);
notificationManager.notify(MESSAGE_NOTIFICATION_ID, builder.build());
}
#Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
this.setIntent(intetnt)
Bundle extras = intent.getExtras();
if (extras != null && extras.containsKey(EXTRA_SHOW_MESSAGES)) {
if (extras.getBoolean(EXTRA_SHOW_MESSAGES)) {
mNavigator.openMessageList();
}
}
}
}
I moved my code, reading the new Intent, to onNewIntent. This method gets called, when an Activity gets a new Intent and before onResume. This triggers regardless of the Activity being in the foreground or not. I also set this new Intent to be the Activities Intent with setIntent, otherwise the Intent that initialy started my Activity, is called by getIntent().
I have been searching a lot of questions and answers in stackoverflow. I am still not able to solve my problem.
I set broadcast for a particular time.
I receive the broadcast perfectly in another class 'AlarmReceiver.java' which creates notification on receiving broadcast.
But I pass a string through an intent that calls a class 'AlarmResponder.java' on pressing the notification.
The class is getting called.
I receive the String data i passed through the intent only for the first time.
Next time I dont get anything. getextras() gives me null .
If i change the ID of the notification in NotificationManager.notify(1, mBuilder.build()); as
NotificationManager.notify(2, mBuilder.build()); it works .
But always it works only once
Please help me
public class AlarmReceiver extends BroadcastReceiver{
#Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
CharSequence reminderText = intent.getCharSequenceExtra("reminderText");
if (reminderText != null && reminderText != "") {
Uri notification = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
Ringtone r = RingtoneManager.getRingtone(context, notification);
r.play();
//Toast.makeText(context, intent.getCharSequenceExtra("reminderText"), Toast.LENGTH_LONG).show();
NotificationCompat.Builder mBuilder =
new NotificationCompat.Builder(context)
.setSmallIcon(R.drawable.ic_launcher)
.setContentTitle(reminderText)
.setContentText("its time buddy");
// Creates an explicit intent for an Activity in your app
Intent resultIntent = new Intent(context, AlarmResponder.class);
resultIntent.putExtra("reminderText", reminderText);
resultIntent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP);
// The stack builder object will contain an artificial back stack for the
// started Activity.
// This ensures that navigating backward from the Activity leads out of
// your application to the Home screen.
TaskStackBuilder stackBuilder = TaskStackBuilder.create(context);
// Adds the back stack for the Intent (but not the Intent itself)
stackBuilder.addParentStack(AlarmResponder.class);
// Adds the Intent that starts the Activity to the top of the stack
stackBuilder.addNextIntent(resultIntent);
PendingIntent resultPendingIntent =
stackBuilder.getPendingIntent(
0,
PendingIntent.FLAG_UPDATE_CURRENT
);
mBuilder.setContentIntent(resultPendingIntent);
NotificationManager mNotificationManager =
(NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
// mId allows you to update the notification later on.
mNotificationManager.notify(1, mBuilder.build());
}
}
}
and the AlarmResponder class is
public class AlarmResponder extends Activity{
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
onNewIntent(getIntent());
}
#Override
public void onNewIntent(Intent intent){
Bundle extras = intent.getExtras();
if(extras != null){
if(extras.containsKey("reminderText"))
{
setContentView(R.layout.alarm_responder);
TextView reminderText = (TextView) findViewById(R.id.reminderText);
// extract the extra-data in the Notification
String msg = extras.getString("reminderText");
reminderText.setText(msg);
}
}
}
}
Problem
When the user presses Send "Button 1"(scroll down to see the construction of the app) a new Notification is created from the RefreshService. If the user presses this notification a MainActivity instance gets started and receives a String with the value Button 1 over the Intent.
This value gets displayed.
When the user presses now the Send "Button 2" a new Notification is created from the RefreshService. If the user presses this notification a MainActivity instance gets started and receives a String ALSO with the value Button 1 over the Intent.
So as you can guess, normally there should be the value Button 2.
When the first Button the user pressed was Send "Button 2" then there would allways Button 2 be sent.
The only sollution to get the value of the second button is to restart the phone and pressing the second button first. Even force close doesn't work.
I know that I also can change the UI in another way. But I need this approach in a app where I need to restart the 'MainActivity' with another Intent so the approach should be the same.
Construction
A Activity called MainActivity
A IntentService called RefreshService
MainActivity
public class MainActivity extends Activity implements View.OnClickListener {
public static final String RECEIVED = "received";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
((TextView)findViewById(R.id.textView_received)).setText(getIntent().getStringExtra(RECEIVED));
findViewById(R.id.button_1).setOnClickListener(this);
findViewById(R.id.button_2).setOnClickListener(this);
}
#Override
public void onClick(View v) {
Intent intent = new Intent(this, RefreshService.class);
if(v.getId() == R.id.button_1){
intent.putExtra(RECEIVED, "Button 1");
Toast.makeText(this,"Sent \"Button 1\"",Toast.LENGTH_LONG).show();
}
else if(v.getId() == R.id.button_2){
intent.putExtra(RECEIVED, "Button 2");
Toast.makeText(this,"Sent \"Button 2\"",Toast.LENGTH_LONG).show();
}
startService(intent);
}
}
RefreshService
public class RefreshService extends IntentService {
public RefreshService() {
super("RefreshService");
}
#Override
protected void onHandleIntent(Intent intent) {
String received = intent.getStringExtra(MainActivity.RECEIVED);
Intent notificationIntent = new Intent(this, MainActivity.class);
notificationIntent.putExtra(MainActivity.RECEIVED, received);
notificationIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
NotificationCompat.Builder builder = new NotificationCompat.Builder(this).setContentTitle("IntentServiceRefresh").setContentText(received).setSmallIcon(R.drawable.ic_notification_small).setContentIntent(pendingIntent);
Notification notification = builder.build();
// Hide the notification after it's selected
notification.flags |= Notification.FLAG_AUTO_CANCEL;
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(0, notification);
}
}
App Layout
My suspicion is that, since the only thing changing in the Intent is the extras, the PendingIntent.getActivity(...) factory method is simply re-using the old intent as an optimization.
In RefreshService, try:
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, PendingIntent.FLAG_CANCEL_CURRENT);
See:
http://developer.android.com/reference/android/app/PendingIntent.html#FLAG_CANCEL_CURRENT
I'm trying to run an activity through a notification and event onCreate I would like to "redirect". To this add a thought on information in the Intent class. An important feature is that the class that generates the notification is performed through a service. I retrieve the context from getApplicationContext method provided by the class android.app.Application. Whenever I call method getExtras() is returning null. What am I doing wrong?
public class OXAppUpdateHandler {
private void addNotification(Context context, int iconID,
CharSequence tickerText, CharSequence title, CharSequence content) {
CharSequence notificationTicket = tickerText;
CharSequence notificationTitle = title;
CharSequence notificationContent = content;
long when = System.currentTimeMillis();
Intent intent = new Intent(context, MainActivity_.class);
intent.setFlags(
Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
intent.putExtra(OPEN_UPDATE_ACTIVITY_KEY, 1);
PendingIntent pendingIntent =
PendingIntent.getActivity(context, 0, intent, 0);
NotificationManager notificationManager =
(NotificationManager) context.getSystemService(
Context.NOTIFICATION_SERVICE);
Notification notification =
new Notification(iconID, notificationTicket, when);
notification.setLatestEventInfo(context, notificationTitle,
notificationContent, pendingIntent);
notificationManager.notify(NOTIFICATION_ID, notification);
}
public static boolean isUpdateStart(Intent intent) {
Bundle bundle = intent.getExtras();
boolean result = bundle != null &&
bundle.containsKey(OPEN_UPDATE_ACTIVITY_KEY);
if (result) {
bundle.remove(OPEN_UPDATE_ACTIVITY_KEY);
}
return result;
}
}
#EActivity(R.layout.activity_main)
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (OXAppUpdateHandler.isUpdateStart(getIntent())) {
startActivity(new Intent(this, UpdateActivity_.class));
}
}
}
I'm going to lean out the window and guess that your problem is here:
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0);
You are passing intent to getActivity() and expecting that you will get back a PendingIntent that matches your Intent and includes your extras. Unfortunately, if there is already a PendingIntent floating around in the system that matches your Intent (without taking into consideration your Intent extras) then getActivity() will return you that PendingIntent instead.
To see if this is the problem, try this:
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent,
PendingIntent.FLAG_UPDATE_CURRENT);
This says that if there is already a PendingIntent that matches your Intent somewhere in the system that it should replace the extras with the ones in your intent parameter.
(1) Check here to make sure you are using the put/get extras correctly as I don't see the code where you are adding data the intent.
(2) It looks like you are not calling get intent and get extra and, as a result, not actually getting anything from the bundle (assuming that information extists). If you are checking for a boolean value you should get the data you place in the bundle as follows:
Bundle bundle = getIntent().getExtras();
if (bundle.getBooleanExtra("WHATEVER"){
//whatever you want to do in here
}