Have been creating a custom notification, so far implemented it successfully getting the notification, however when i am trying to call a function/method from MainActivity using the button on the notification i created i get the below error :
System services not available to Activities before onCreate()
Below is the method defined by me inside the MainActivity that updates the notification UI and also stops the mediaplayer.
public void attachMediaActivity()
{
//INITIALIZE THE CONTEXT
context =this;
notificationManager=(NotificationManager) getSystemService(NOTIFICATION_SERVICE);
remoteViews=new RemoteViews(this.getPackageName(),R.layout.custom_notification);
remoteViews.setImageViewResource(R.id.notif_icon,R.drawable.stream_icon);
remoteViews.setTextViewText(R.id.notif_title,"stopped");
Intent button_intent= new Intent("button_clicked");
button_intent.putExtra("id",notification_id);
Intent notification_intent=new Intent(context,MainActivity.class);
PendingIntent pendingIntent=PendingIntent.getActivity(context,0,notification_intent,PendingIntent.FLAG_UPDATE_CURRENT);
builder =new NotificationCompat.Builder(context);
builder.setSmallIcon(R.mipmap.ic_launcher)
.setCustomBigContentView(remoteViews)
.setContentIntent(pendingIntent)
.setOngoing(true);
notificationManager.notify(notification_id,builder.build());
if (mediaPlayer.isPlaying())
{
mediaPlayer.stop();
}
}
Broadcast listener attached to the button of notification that calls the above method from main activity.
public class Button_listener extends BroadcastReceiver{
#Override
public void onReceive(Context context, Intent intent)
{
NotificationManager manager =(NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE);
manager.cancel(intent.getExtras().getInt("id"));
Toast.makeText(context, "GENERATED BY NOTIFICATION", Toast.LENGTH_SHORT).show();
new MainActivity().attachMediaActivity();
}
}
LOGCAT:
01-24 11:52:29.010 13062-13062/com.amplitude.tron.samplemediaplayer E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.amplitude.tron.samplemediaplayer, PID: 13062
java.lang.RuntimeException: Unable to start receiver com.amplitude.tron.samplemediaplayer.Button_listener: java.lang.IllegalStateException: System services not available to Activities before onCreate()
at android.app.ActivityThread.handleReceiver(ActivityThread.java:2750)
at android.app.ActivityThread.access$1800(ActivityThread.java:157)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1433)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5525)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:730)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:620)
Caused by: java.lang.IllegalStateException: System services not available to Activities before onCreate()
at android.app.Activity.getSystemService(Activity.java:5288)
at com.amplitude.tron.samplemediaplayer.MainActivity.attachMediaActivity(MainActivity.java:159)
at com.amplitude.tron.samplemediaplayer.Button_listener.onReceive(Button_listener.java:21)
at android.app.ActivityThread.handleReceiver(ActivityThread.java:2743)
at android.app.ActivityThread.access$1800(ActivityThread.java:157)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1433)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5525)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:730)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:620)
What i have implemeted so far :
where am i going wrong .. also prior to calling notification manager i have been getting getPackageName() as NULL
Please help! Thanks in advance
new MainActivity().attachMediaActivity();
Problem lies here. Contrary of normal way, creating an instance of Activity with a new tag won't let you go through with its lifecycle that it supposed to.
You can launch your Activity by setting up a bundle, pass it with Intent, initiate a startActivity and finally check the bundle value in Activity and invoke the attachMediaActivity method. Or else, if you want, you can get a hold of your current Activity instance in these ways and call the method.
The error that you got clearly says, System services not available to Activities before onCreate().
That is, You can not use NotificationManager from an Activity without calling startActivity(Intent).
What you can do is, start the activity with intent+ extras to call the method inside the MainActivity. OR you can use the CallBack method using Interfaces.
Update
Declare Intent as:
Intent intent = new Intent(context, MainActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtra("attachMedia",true); // Extra info
context.startActivity(intent);
And now, inside the MainActivity onCreate(), (after all initialization)
boolean attachMedia = getIntent().getBooleanExtra("attachMedia",false);
if (attachMedia) {
attachMediaActivity();
}
Related
It's mine BroadcastReciever class. The class working on Boot phone status.
Code ;
public class BroadCastRecieverBoot extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent ıntent) {
if(Intent.ACTION_BOOT_COMPLETED.equals(ıntent.getAction()))
{
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
context.startForegroundService(new Intent(context, MyService.class));
context.startForegroundService(new Intent(context, GPSTracker.class));
} else {
context.startService(new Intent(context, MyService.class));
context.startService(new Intent(context, GPSTracker.class));
}
}
}
}
I get This Error ;
android.app.RemoteServiceException: Context.startForegroundService() did not then call Service.startForeground()
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1792)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6523)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:857)
It doesn't work on Android Oreo now. I don't know what is the mistake of that.
According to official document of Android 8.0 Background Execution Limits
Android 8.0 introduces the new method
startForegroundService() to start a new service in the foreground.
After the system has created the service, the app has five seconds to
call the service's startForeground() method to show the new service's
user-visible notification. If the app does not call startForeground()
within the time limit, the system stops the service and declares the
app to be ANR.
So, make sure you have started ongoing notification by calling startForeground (int id, Notification notification) in the onCreate() method of your service.
Note: Apps targeting API Build.VERSION_CODES.P or later must request the permission Manifest.permission.FOREGROUND_SERVICE in order to use this API.
I have a reminder app that will notify me at a given time when the next reminder from an array of objects it due.
I am trying to make it set the notification again on boot.
I have my boot receiver all set in the Manifest, but how do I access any information from MainActivity once the phone has booted, given that the app hasn't been opened yet?
I was hoping to use this -
public class BootReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Log.i("RegularReminders","onReceive");
new MainActivity().setNotifications();
}
}
But it returns a null error from within that notification once it tries to run the method in MainActivity, the app crashes as the emulator boots up and I see this in the logcat -
java.lang.RuntimeException: Unable to start receiver com.androidandyuk.regularreminders.BootReceiver: java.lang.NullPointerException: Attempt to invoke virtual method 'int java.util.ArrayList.size()' on a null object reference
This points to a line -
if (reminders.size() >= 0) {
I did wonder if I could save the notification message to SharedPrefs and call it back in the receiver, but I got errors of null object reference doing that too.
I tried sending back another broadcast adding extra info, but I guess the receiver set up in MainActivity isn't listening as the app hasn't been run?
I know Google is protecting us from Malware, not letting them do much after book, but is there any way round this so I can set my notification after a reboot?
Thanks.
Although you can't access variables from the MainActivity, you can access SharedPreferences and the SQLite Database used in the app, so in this case I made a new array and read the database into it and worked on that.
The problem is that your activity is not created when you receive ACTION_BOOT_COMPLETED.
What you could do is to start your activity after the boot is completed and pass it arguments to tell it do some work.
public class BootReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Log.i("RegularReminders","onReceive");
if (intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED)) {
Intent i = new Intent(context, YourActivity.class);
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
Bundle args = new Bundle();
//put some args inside the bundle
//attach the bundle
i.putExtras(args);
//start the activity
context.startActivity(i);
}
}
}
If you don't what to start and show your activity. You can use Android Services.
From my mobile I am starting a foreground service in my android watch. I am able to do that correctly. But when I try to stop the service as well as the activity in watch , I am getting an error message( watch app is crashing). I am using message listener service to receive the message from mobile.
I also have a stop button in watch app which is running perfectly(if I try to stop the service from watch itself) and it has the same lines of code. I am not sure where I am wrong when I receive message from mobile app to stop the foreground service.
#Override public void onMessageReceived(MessageEvent messageEvent) {
Log.i(INFOTAG, "Stop msg received");
if(messageEvent.getPath().equals(STOP_MESSAGE_PATH_2)){
started = false;
Intent stopIntent = new Intent(
MainActivity.this, ForegroundService.class);
stopService(stopIntent);
this.finish();
}
}
Below is the error log I am getting:
java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String android.content.Context.getPackageName()' on a null object reference
at android.content.ContextWrapper.getPackageName(ContextWrapper.java:132)
at android.content.ComponentName.(ComponentName.java:77)
at android.content.Intent.(Intent.java:4160)
at com.magi.magidemo.MainActivity.onMessageReceived(MainActivity.java:464)
at com.google.android.gms.wearable.internal.zzcf$5.zza(Unknown Source)
at com.google.android.gms.wearable.internal.zzcf$5.zzs(Unknown Source)
at com.google.android.gms.internal.zzmn.zzb(Unknown Source)
at com.google.android.gms.internal.zzmn$zza.handleMessage(Unknown Source)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5254)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698)
You need to get the Activity's instance from the override method.
Like this:
public MainActivity activity;
// in the override method
this.activity = activity;
Then use it:
Intent stopIntent = new Intent(
activity, ForegroundService.class);
Have a look: android.content.Context.getPackageName()' on a null object reference
i am getting a lot of reports from users about my app crashing. The constant error appears to be associated with my parse.com initialisation, however, i have set it up as outlined in the parse tutorial.
here is the Stack Trace:
java.lang.RuntimeException: Unable to start receiver com.parse.ParseBroadcastReceiver: java.lang.RuntimeException: applicationContext is null. You must call Parse.initialize(context, applicationId, clientKey) before using the Parse library.
at android.app.ActivityThread.handleReceiver(ActivityThread.java:2580)
at android.app.ActivityThread.access$1700(ActivityThread.java:151)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1397)
at android.os.Handler.dispatchMessage(Handler.java:110)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:5292)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:824)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:640)
at dalvik.system.NativeStart.main(Native Method)
Caused by: java.lang.RuntimeException: applicationContext is null. You must call Parse.initialize(context, applicationId, clientKey) before using the Parse library.
at com.parse.Parse.checkContext(Parse.java:606)
at com.parse.Parse.getApplicationContext(Parse.java:214)
at com.parse.ManifestInfo.getContext(ManifestInfo.java:322)
at com.parse.ManifestInfo.getPackageManager(ManifestInfo.java:330)
at com.parse.ManifestInfo.getPackageInfo(ManifestInfo.java:356)
at com.parse.ManifestInfo.deviceSupportsGcm(ManifestInfo.java:441)
at com.parse.ManifestInfo.getPushType(ManifestInfo.java:210)
at com.parse.PushService.startServiceIfRequired(PushService.java:168)
at com.parse.ParseBroadcastReceiver.onReceive(ParseBroadcastReceiver.java:19)
at android.app.ActivityThread.handleReceiver(ActivityThread.java:2573)
... 10 more
and here is my initialisation code:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home_screen);
Parse.initialize(this, "hGG5RdgNVdI7eCeZynV32lWYXywQRHkpp5zLdY7Q", "TwmNbpBYEt4u3euE3lzNIgwyroSl8RPGF2dJFsPv");
ParseInstallation.getCurrentInstallation().saveInBackground();
Can anybody see what is causing this error, and how to fix it?
below is my receiver code:
public static class Receiver extends ParsePushBroadcastReceiver {
private String notificationText;
private Boolean notificationreceived = false;
public Receiver(){
}
private static final String TAG = "MyNotificationsReceiver";
#Override
public void onPushOpen(Context context, Intent intent) {
Log.e("Push", "Clicked");
Intent i = new Intent(context, HomeScreen.class);
notificationreceived = true;
i.putExtra("alert",notificationText);
i.putExtra("alertreceived", notificationreceived);
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(i);
Scb998.scb988b=true;
try {
JSONObject json = new JSONObject(intent.getExtras().getString("com.parse.Data"));
Scb998.msg = json.getString("alert");
} catch (JSONException e) {
Log.d(TAG, "JSONException: " + e.getMessage());
}
}
}
Move you Parse initialization into your App class (extended from Application)
public class App extends Application {
#Override
public void onCreate() {
super.onCreate();
Parse.initialize(this, "hGG5RdgNVdI7eCeZynV32lWYXywQRHkpp5zLdY7Q", "TwmNbpBYEt4u3euE3lzNIgwyroSl8RPGF2dJFsPv");
ParseInstallation.getCurrentInstallation().saveInBackground();
}
}
And of course refer to it your AndroidManifest.xml
<application
android:name=".app.App"
....
</application>
Reason of crash is next. When your app is at background, it can be killed by system. From Google guide
A process holding an activity that's not currently visible to the user (the activity's onStop() method has been called). These processes have no direct impact on the user experience, and the system can kill them at any time to reclaim memory for a foreground, visible, or service process. Usually there are many background processes running, so they are kept in an LRU (least recently used) list to ensure that the process with the activity that was most recently seen by the user is the last to be killed. If an activity implements its lifecycle methods correctly, and saves its current state, killing its process will not have a visible effect on the user experience, because when the user navigates back to the activity, the activity restores all of its visible state. See the Activities document for information about saving and restoring state.
When you app receives push notification, then parse will not be initialized, because you initialize it at activity onCreate method, which won't be called.
I have an application with two buttons. One button that "closes" the application and one that begins the algorithm. When I click "begin" it "hides" the application and displays a notification in the notification bar. I need to be able to execute/call a method when the notification is clicked/pressed. There are a few answers for this sort of question, but they are incredibly vague and one only points to a link to the doc on BroadcastReceiver.
If you are going to leave a url to the BroadcastReceiver doc and say "read this page," please don't reply to this question. If you are going to explain how I could use BroadcastReceiver to execute a method (from within the same class that displayed the notification), please show me some code for how this could be done.
My algorithm: press a button, display notification, click notification, call a method (don't display activity). That's it.
If it's not possible, just let me know. If it is, please show me what you would do to make it possible. Something this simple shouldn't have been overlooked by the developers of the android sdk.
After several iterations of trial and error, I finally found a fairly straightforward and clean way to run an arbitrary method when a notification's action is clicked. In my solution, there is one class (I'll call it NotificationUtils) that creates the notification and also contains an IntentService static inner class that will run when actions on the notification are clicked. Here is my NotificationUtils class, followed by the necessary changes to AndroidManifest.xml:
public class NotificationUtils {
public static final int NOTIFICATION_ID = 1;
public static final String ACTION_1 = "action_1";
public static void displayNotification(Context context) {
Intent action1Intent = new Intent(context, NotificationActionService.class)
.setAction(ACTION_1);
PendingIntent action1PendingIntent = PendingIntent.getService(context, 0,
action1Intent, PendingIntent.FLAG_ONE_SHOT);
NotificationCompat.Builder notificationBuilder =
new NotificationCompat.Builder(context)
.setSmallIcon(R.drawable.ic_launcher)
.setContentTitle("Sample Notification")
.setContentText("Notification text goes here")
.addAction(new NotificationCompat.Action(R.drawable.ic_launcher,
"Action 1", action1PendingIntent));
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(context);
notificationManager.notify(NOTIFICATION_ID, notificationBuilder.build());
}
public static class NotificationActionService extends IntentService {
public NotificationActionService() {
super(NotificationActionService.class.getSimpleName());
}
#Override
protected void onHandleIntent(Intent intent) {
String action = intent.getAction();
DebugUtils.log("Received notification action: " + action);
if (ACTION_1.equals(action)) {
// TODO: handle action 1.
// If you want to cancel the notification: NotificationManagerCompat.from(this).cancel(NOTIFICATION_ID);
}
}
}
Now just implement your actions in onHandleIntent and add the NotificationActionService to your manifest within the <application> tags:
<service android:name=".NotificationUtils$NotificationActionService" />
Summary:
Create a class that will create the notification.
Inside that class, add a IntentService inner classes (make sure it is static or you will get a cryptic error!) that can run any method based on the action that was clicked.
Declare the IntentService class in your manifest.
On Notification click we can't get any fire event or any click listener. When we add notification in notification bar, we can set a pending intent, which fires an intent (activity/service/broadcast) upon notification click.
I have a workound solution for you, if you really don't want to display your activity then the activity which is going to start with pending intent send a broad cast from there to your parent activity and just finish the pending activity and then once broadcast receiver receives in parent activity call whatever method you want inside the receiver. For your reference..
// This is what you are going to set a pending intent which will start once
// notification is clicked. Hopes you know how to add notification bar.
Intent notificationIntent = new Intent(this, dummy_activity.class);
notificationIntent.setAction("android.intent.action.MAIN");
notificationIntent.addCategory("android.intent.category.LAUNCHER");
PendingIntent contentIntent = PendingIntent.getActivity(this, 0,
notificationIntent,
PendingIntent.FLAG_UPDATE_CURRENT |
Notification.FLAG_AUTO_CANCEL);
// Now, once this dummy activity starts send a broad cast to your parent activity and finish the pending activity
//(remember you need to register your broadcast action here to receive).
BroadcastReceiver call_method = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String action_name = intent.getAction();
if (action_name.equals("call_method")) {
// call your method here and do what ever you want.
}
};
};
registerReceiver(call_method, new IntentFilter("call_method"));
}
}