I want to have a background service, which will stay alive after the app is closed and which I can bind to again when the app is started.
For testing I made it that a counter will increase every time I bind to the service.
So theoretically the app should start, I will create the service, then bind to it -> the counter should move up.
Then I close the app and press the Bind button again and It should log a "1" and move the counter up again.
But it doesn't ...
It will display a 0 every time I restart the app and bind to it ...
This is my current Test - Service - class:
package com.programm.testapp;
import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.util.Log;
public class TestService extends Service {
/*
* Service Binder
*/
private final IBinder iBinder = new TestService.LocalConnectionService();
public class LocalConnectionService extends Binder {
public TestService getService(){
return TestService.this;
}
}
/*
* Test var
* It should increase every time the app is started.
*/
private int test;
#Override
public IBinder onBind(Intent intent) {
Log.d("mDEBUG", "Test: " + test);
test++;
return iBinder;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d("mDEBUG", "Service: Start Command");
return START_STICKY;
}
}
This is my current Test - Activity:
package com.programm.testapp;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
public class MainActivity extends AppCompatActivity {
private TestService service;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button createButton = findViewById(R.id.button_create_service);
createButton.setOnClickListener(this::createService);
Button destroyButton = findViewById(R.id.button_destroy_service);
destroyButton.setOnClickListener(this::destroyService);
Button bindButton = findViewById(R.id.button_bind_service);
bindButton.setOnClickListener(this::bindService);
Button unbindButton = findViewById(R.id.button_unbind_service);
unbindButton.setOnClickListener(this::unbindService);
}
private void createService(View v){
Intent intent = new Intent(this.getBaseContext(), TestService.class);
startService(intent);
}
private void destroyService(View v){
Intent intent = new Intent(this.getBaseContext(), TestService.class);
stopService(intent);
}
private void bindService(View v){
Intent intent = new Intent(this.getBaseContext(), TestService.class);
bindService(intent, serviceConnection, BIND_AUTO_CREATE);
}
private void unbindService(View v){
unbindService(serviceConnection);
}
private ServiceConnection serviceConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.d("mDEBUG", "Connection: on service connected");
MainActivity.this.service = ((TestService.LocalConnectionService) service).getService();
}
#Override
public void onServiceDisconnected(ComponentName name) {
Log.d("mDEBUG", "Connection: on service disconnected");
}
};
}
This is my AndroidManifest.xml - file:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.programm.testapp">
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service
android:name=".TestService"
android:enabled="true"
android:exported="false"></service>
</application>
</manifest>
This is my output after I ...
Pressed Create Service - Button
Pressed Bind Service - Button
Pressed Unbind Service - Button
Close App and Restart it
Pressed Bind Service - Button
:
.../com.programm.testapp D/mDEBUG: Service: Start Command
.../com.programm.testapp D/mDEBUG: Test: 0
.../com.programm.testapp D/mDEBUG: Connection: on service connected
.../com.programm.testapp D/mDEBUG: Service: Start Command
.../com.programm.testapp D/mDEBUG: Test: 0
.../com.programm.testapp D/mDEBUG: Connection: on service connected
By the way the second "Service: Start Command" is called as I CLOSE the app ... after a few new Logs I noticed, that also the Constructer and the "onCreate" method of the Service - class will be called with it.
Is this normal?
Edit:
When I only minimize the App and not close it via Activity - Menu the behavior is exactly the one I want!!!
Edit 2:
A Foreground service does the job for now ...
I couldn't find any other solution for this
If you actively close the app (by closing it from the Android activity list), Android will most likely kill your service. You can see that in your apps Logcat. The only real way around that is a foreground service.
Furthermore, onBind will not be called every time you bind to the service. From the Android documentation:
You can connect multiple clients to a service simultaneously. However, the system caches the IBinder service communication channel. In other words, the system calls the service's onBind() method to generate the IBinder only when the first client binds. The system then delivers that same IBinder to all additional clients that bind to that same service, without calling onBind() again.
Secondly, just that onStartCommand is called does not mean the service is recreated. It can be called multiple times during the service life cycle. For instance, each time startService is called, onStartCommand is executed, but the service is not necessarily recreated.
Also, it looks like you do not un-bind the service when closing the activity. That makes your activity leak the ServiceConnection and your app crash. It would explain why you see the service re-created every time you close and re-start the app.
Try adding an unbind in your activity's onPause method:
#Override
void onPause() {
super.onPause()
unbindService(this.serviceConnectino)
}
A working configuration could look like below. It implements incrementing the counter using a dedicated service function, rather than onBind:
MyBoundService.kt
package com.test
import android.app.Service
import android.content.Intent
import android.os.Binder
import android.os.IBinder
import android.util.Log
class MyBoundService : Service() {
abstract class MyBinder: Binder() {
abstract fun getService(): MyBoundService
}
val iBinder: MyBinder = object: MyBinder() {
override fun getService(): MyBoundService {
return this#MyBoundService
}
}
private var counter = 0
fun increment() {
counter ++
Log.i("MyBoundService", "Counter: ${counter}")
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
Log.i("MyBoundService", "startCommand");
return super.onStartCommand(intent, flags, startId)
}
override fun onBind(p0: Intent?): IBinder? {
counter++
Log.i("MyBoundService", "Bound: ${counter}")
return iBinder
}
override fun onUnbind(intent: Intent?): Boolean {
Log.i("MyBoundService", "Unbound")
return super.onUnbind(intent)
}
}
MainActivity.kt
package com.test
import android.content.Intent
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import kotlinx.android.synthetic.main.activity_main.*
import android.content.ComponentName
import android.content.Context
import android.content.ServiceConnection
import android.os.IBinder
import android.util.Log
import com.test.MyBoundService
class MainActivity : AppCompatActivity() {
private val serviceConnection: ServiceConnection = object: ServiceConnection {
override fun onServiceDisconnected(p0: ComponentName?) {
Log.i("MainActivity", "Service disconnected")
}
override fun onServiceConnected(p0: ComponentName?, p1: IBinder?) {
Log.i("MainActivity", "Service connected")
p1?.let {
(p1 as MyBoundService.MyBinder).getService().increment()
}
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
btn_create.setOnClickListener {
val i = Intent(this#MainActivity, MyBoundService::class.java)
startService(i)
}
btn_bind.setOnClickListener {
val i = Intent(this#MainActivity, MyBoundService::class.java)
bindService(i, serviceConnection, Context.BIND_AUTO_CREATE)
}
}
override fun onPause() {
super.onPause()
unbindService(serviceConnection)
}
}
Related
I'm trying to make an app that is able to handle (data-)messages sent by the Azure Notification Hubs. At the current state it sends a Notification when recieving a payload by Azure. While the app is running in the foreground (or still open in the Quick Panel) it has no problems at all and onPushNotificationReceived() handles the incoming message just fine, but when removing the app from the Quick Panel I get an error for trying to invoke a null object refrence:
Logcat
2021-07-22 15:27:33.675 23017-23053/com.example.fcmtutorial1app E/AndroidRuntime: FATAL EXCEPTION: Firebase-Messaging-Intent-Handle
Process: com.example.fcmtutorial1app, PID: 23017
java.lang.NullPointerException: Attempt to invoke interface method 'void com.microsoft.windowsazure.messaging.notificationhubs.NotificationListener.onPushNotificationReceived(android.content.Context, com.google.firebase.messaging.RemoteMessage)' on a null object reference
at com.microsoft.windowsazure.messaging.notificationhubs.FirebaseReceiver.onMessageReceived(FirebaseReceiver.java:52)
at com.google.firebase.messaging.FirebaseMessagingService.dispatchMessage(com.google.firebase:firebase-messaging##22.0.0:13)
at com.google.firebase.messaging.FirebaseMessagingService.passMessageIntentToSdk(com.google.firebase:firebase-messaging##22.0.0:8)
at com.google.firebase.messaging.FirebaseMessagingService.handleMessageIntent(com.google.firebase:firebase-messaging##22.0.0:3)
at com.google.firebase.messaging.FirebaseMessagingService.handleIntent(com.google.firebase:firebase-messaging##22.0.0:3)
at com.google.firebase.messaging.EnhancedIntentService.lambda$processIntent$0$EnhancedIntentService(com.google.firebase:firebase-messaging##22.0.0:1)
at com.google.firebase.messaging.EnhancedIntentService$$Lambda$0.run(Unknown Source:6)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at com.google.android.gms.common.util.concurrent.zza.run(Unknown Source:6)
at java.lang.Thread.run(Thread.java:923)
This only happens when sending data messages, since the Firebase Service handles Messages with notification payload without invoking onPushNotificationReceived().
I've tried the following to fix this:
Extending CustomNotificationListener.class with android.app.Service
Replacing onPushNotificationReceived() with Thunderbirds onMessageReceived()
The first solution resulted in the same error and the second one resulted in no messages at all.
If someone has a way to fix this or knows what could be the fault, I'd be really be happy if you could write an answer :)
Here is the code for both classes (android.app.Service is still included although it didn't work for me). Thanks in advance!
MainActivity.class
package com.example.fcmtutorial1app;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.NotificationCompat;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.content.Context;
import android.os.Build;
import android.os.Bundle;
import android.util.Log;
import com.microsoft.windowsazure.messaging.notificationhubs.NotificationHub;
public class MainActivity extends AppCompatActivity
{
public static final String CHANNEL_1_ID = "Channel1";
public static final String CHANNEL_2_ID = "Channel2";
public static String editTextTitle;
public static String editTextMessage;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
createNotificationsChannels();
NotificationHub.setListener(new CustomNotificationListener());
NotificationHub.start(this.getApplication(), "spfcmtutorial1nhub", "Endpoint=sb://azurecloudmessaging.servicebus.windows.net/;SharedAccessKeyName=DefaultListenSharedAccessSignature;SharedAccessKey=abc[...]xyz");
}
public static void sendCloudMessage(Context context)
{
editTextTitle = CustomNotificationListener.title;
editTextMessage = CustomNotificationListener.body;
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(context, CHANNEL_1_ID)
.setSmallIcon(R.drawable.ic_launcher)
.setContentTitle(editTextTitle)
.setContentText(editTextMessage)
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setCategory(NotificationCompat.CATEGORY_MESSAGE);
NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(1, notificationBuilder.build());
Log.v("MSG", "SENDCLOUDMESSAGE WAS ACTIVATED");
}
public void createNotificationsChannels() //Channel 2 is for tests only
{
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
{
NotificationChannel channel1 = new NotificationChannel(
CHANNEL_1_ID,
"Channel 1",
NotificationManager.IMPORTANCE_HIGH
);
channel1.setDescription("This is Channel 1");
NotificationChannel channel2 = new NotificationChannel(
CHANNEL_2_ID,
"Channel 2",
NotificationManager.IMPORTANCE_LOW
);
channel2.setDescription("This is Channel 2");
NotificationManager manager = getSystemService(NotificationManager.class);
manager.createNotificationChannel(channel1);
manager.createNotificationChannel(channel2);
}
}
}
CustomNotificationListener.class
package com.example.fcmtutorial1app;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;
import androidx.annotation.Nullable;
import com.google.firebase.messaging.RemoteMessage;
import com.microsoft.windowsazure.messaging.notificationhubs.NotificationListener;
import java.util.Map;
public class CustomNotificationListener extends Service implements NotificationListener
{
private static final String TAG = "Message";
public static String title;
public static String body;
public static String dataTitle;
public static String dataBody;
#Override
public int onStartCommand(Intent intent, int flags, int startId)
{
Log.d(TAG, "Service started");
return Service.START_NOT_STICKY;
}
#Override
public void onPushNotificationReceived(Context context, RemoteMessage message) //FATAL EXEPTION: Firebase-Messaging-Intent-Handle HERE
{
RemoteMessage.Notification notification = message.getNotification();
try { title = notification.getTitle(); } catch(Exception e) {}
try { body = notification.getBody(); } catch (Exception e) {}
Map<String, String> data = message.getData();
//region LOGGING
if (message != null)
{
Log.d(TAG, "Message Notification Title: " + title);
Log.d(TAG, "Message Notification Body: " + body);
}
else { Log.e(TAG, "ERROR, no message found"); }
if (data != null)
{
for (Map.Entry<String, String> entry : data.entrySet())
{
Log.d(TAG, "key, " + entry.getKey() + "value " + entry.getValue());
}
}
else { Log.e(TAG, "ERROR, no data found"); }
//endregion
Log.v("VERBOSE", data.get("property1"));
MainActivity.sendCloudMessage(context);
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
}
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.fcmtutorial1app">
<application
android:allowBackup="true"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/Theme.FCMTutorial1App">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name=".CustomNotificationListener"></service>
</application>
</manifest>
To answer this question, we'll need to discuss some Android lifecycle concepts as documented at https://developer.android.com:
Process and Application Lifecycle
Activity Lifecycle
In the code you provide above, you call NotificationHub.setListener in your application's primary entrypoint, MainActivity. As you see, this works when your end user has started the application manually because MainActivity.onCreate gets invoked.
However, there's a second entrypoint in your scenario: FirebaseMessagingService starting the application when a data-only notification is received in the background. This is subtle and easy to miss - because if the payload contains a notification component, Android will still route to MainActivity when the notification is clicked in the system tray.
In this case MainActivity isn't involved, so MainActivity.onCreate and NotificationHub.setListener are never called as the application initialized, and the following line from the stack trace encounters a null reference:
mHub.getInstanceListener().onPushNotificationReceived(this.getApplicationContext(), remoteMessage);
To fix this, you'll need to call NotificationHub.setListener somewhere that gets called anytime the application gets initialized, regardless of the entrypoint.
The most natural choice is to setup the NotificationHub at the Application level by extending android.app.Application, overriding the onCreate() method, and updating your manifest.
I'm developing an android app with Unity that requires a foreground service. To do that I've made an android module with android studio. The problem is that my service is never started but at the same time there aren't errors and the aplication still running, for example after my start service I can show a toast.
Unity - C# - AndroidPluginManager.cs
I'm using this class to instantiate the module and call the function to start the service. The function StartAndroidService() is called using the onClick() feature of Unity inspector.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class AndroidPluginManager : MonoBehaviour
{
private AndroidJavaObject androidPlugin = null;
private AndroidJavaObject unityContext = null;
private AndroidJavaObject unityActivity = null;
private AndroidJavaClass unityClass = null;
void Start() {
//Get unity activity and context
unityClass = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
unityActivity = unityClass.GetStatic<AndroidJavaObject>("currentActivity");
unityContext = unityActivity.Call<AndroidJavaObject>("getApplicationContext");
//Create android plugin object
androidPlugin = new AndroidJavaObject("com.androidplugin.stepcounterlibrary.ApiStepCounter");
//Set activity and context to the module
androidPlugin.Call("setActivity", unityActivity);
androidPlugin.Call("setContext", unityContext);
}
//Start Service
public void StartAndroidService() {
androidPlugin.Call("startStepCounter");
androidPlugin.Call("showMessage", "Hello World");
}
}
Android Studio - Java - ApiStepCounter.java
For the time being I'm using this class only to start the service and create a toast to check if the module is working correctly.
package com.androidplugin.stepcounterlibrary;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.widget.Toast;
public class ApiStepCounter{
private Activity activity;
private Context context;
public ApiStepCounter() {}
public void setActivity(Activity activity){
this.activity = activity;
}
public void setContext(Context context){
this.context = context;
}
public void showMessage(String message){
Toast.makeText(this.context, message, Toast.LENGTH_LONG).show();
}
public void startStepCounter(){
Intent serviceIntent = new Intent(this.context, StepCounterService.class);
this.context.startService(serviceIntent);
}
}
Android Studio - Java - StepCounterService.java
This class should start the foreground service and show a notification but it doesn't. It's the first time that I try to use an Android service so I don't know if I'm doing something wrong. Also I've tried to execute some Log.d inside each method (onCreate(), onStartCommand(), onDestroy()) and no one is printed so I guess that the service is not started.
package com.androidplugin.stepcounterlibrary;
import android.app.Notification;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.support.annotation.Nullable;
import android.support.v4.app.NotificationCompat;
import android.widget.Toast;
public class StepCounterService extends Service {
public StepCounterService(){}
#Override
public void onCreate() {
super.onCreate();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, "TestChannel");
builder.setSmallIcon(R.drawable.ic_android)
.setContentText("Text of notification")
.setContentTitle("Title of notification");
Notification notification = builder.build();
startForeground(1, notification);
return START_STICKY;
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onDestroy() {
super.onDestroy();
}
}
Android Studio - Manifest - AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.androidplugin.stepcounterlibrary">
<application>
<service android:name=".StepCounterService"/>
</application>
</manifest>
I've been trying for 2 days how to create the foreground service using Unity with an Android module so if someone could help me I would appreciate it a lot. Feel free to ask me anything that you need, I think this is all that I need to create a foreground service but maybe I'm missing something.
I'm trying to find out how to run a service (Any service, may be foreground or background) when device boots. I've tried implementing broadcast receiver but it seems not to work.
Below is my full code.
1.AndroidManifext.xml - I made sure I included the service and broadcast receiver here. Are there any permissions I may be lacking?
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.example.testboot">
<!-- Example need below permission. -->
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme"
tools:ignore="GoogleAppIndexingWarning">
<activity android:name="com.example.testboot.MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<receiver
android:name="com.example.testboot.BootDeviceReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<action android:name="android.intent.action.QUICKBOOT_POWERON" />
<action android:name="com.htc.intent.action.QUICKBOOT_POWERON" />
</intent-filter>
</receiver>
<service
android:name="com.example.testboot.RunAfterBootService"
android:enabled="true"
android:exported="true"></service>
</application>
</manifest>
2.MainActivity.java - This is the launch class, I made it call the broadcast receiver class. Asides from that, it doesn't have anything else.
package com.example.testboot;
import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent intent = new Intent("com.example.testboot.BootDeviceReceiver");
sendBroadcast(intent);
}
}
3.BootDeviceReceiver.java -This is the class responsible for knowing when device has booted up (Extends Broadcast receiver)
package com.example.testboot;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
import android.widget.Toast;
public class BootDeviceReceiver extends BroadcastReceiver {
private static final String TAG_BOOT_BROADCAST_RECEIVER = "BOOT_BROADCAST_RECEIVER";
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
String message = "BootDeviceReceiver onReceive, action is " + action;
Toast.makeText(context, message, Toast.LENGTH_LONG).show();
Log.d(TAG_BOOT_BROADCAST_RECEIVER, action);
if(Intent.ACTION_BOOT_COMPLETED.equals(action))
{
//startServiceDirectly(context);
startServiceByAlarm(context);
}
}
/* Start RunAfterBootService service directly and invoke the service every 10 seconds. */
private void startServiceDirectly(Context context)
{
try {
while (true) {
String message = "BootDeviceReceiver onReceive start service directly.";
Toast.makeText(context, message, Toast.LENGTH_LONG).show();
Log.d(TAG_BOOT_BROADCAST_RECEIVER, message);
// This intent is used to start background service. The same service will be invoked for each invoke in the loop.
Intent startServiceIntent = new Intent(context, RunAfterBootService.class);
context.startService(startServiceIntent);
// Current thread will sleep one second.
Thread.sleep(10000);
}
}catch(InterruptedException ex)
{
Log.e(TAG_BOOT_BROADCAST_RECEIVER, ex.getMessage(), ex);
}
}
/* Create an repeat Alarm that will invoke the background service for each execution time.
* The interval time can be specified by your self. */
private void startServiceByAlarm(Context context)
{
// Get alarm manager.
AlarmManager alarmManager = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
// Create intent to invoke the background service.
Intent intent = new Intent(context, RunAfterBootService.class);
PendingIntent pendingIntent = PendingIntent.getService(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
long startTime = System.currentTimeMillis();
long intervalTime = 60*1000;
String message = "Start service use repeat alarm. ";
Toast.makeText(context, message, Toast.LENGTH_LONG).show();
Log.d(TAG_BOOT_BROADCAST_RECEIVER, message);
// Create repeat alarm.
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, startTime, intervalTime, pendingIntent);
}
}
3.RunAfterBootService.java - This is the service class, should be displayed after device completes booting up.
package com.example.testboot;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.widget.Toast;
public class RunAfterBootService extends Service {
private static final String TAG_BOOT_EXECUTE_SERVICE = "BOOT_BROADCAST_SERVICE";
public RunAfterBootService() {
}
#Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
throw new UnsupportedOperationException("Not yet implemented");
}
#Override
public void onCreate() {
super.onCreate();
Log.d(TAG_BOOT_EXECUTE_SERVICE, "RunAfterBootService onCreate() method.");
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
String message = "RunAfterBootService onStartCommand() method.";
Toast.makeText(getApplicationContext(), message, Toast.LENGTH_LONG).show();
Log.d(TAG_BOOT_EXECUTE_SERVICE, "RunAfterBootService onStartCommand() method.");
Intent i = new Intent();
i.setClass(RunAfterBootService.this,MainActivity.class);
startActivity(i);
return super.onStartCommand(intent, flags, startId);
}
#Override
public void onDestroy() {
super.onDestroy();
}
}
So far, when I restart my device nothing happens at all.
Has your app an icon ? you must open your app one time then you can receive the boot_complete broadcast.
I want to programing app for data track in background , so I use service .
I want to write a program that monitors all data sent and received by the device, and when the total volume of received or received messages reaches a specified value, the Internet device is turned off.
So I used the following code to monitor the data:
mStartRX = TrafficStats.getTotalRxBytes ();
mStartTX = TrafficStats.getTotalTxBytes ();
And I used the services to work on the background in the background.
To specify the download or upload limit from the user with edittext, I requested this limit in mainactivity and send this value to the service.
The problem is when: When I destroy the program, I will restart the service and get the NULL value and the program crashes.
My application code:
Main Activity :
package ir.alexandre9009.service;
import android.app.AlertDialog;
import android.content.Context;
import android.net.TrafficStats;
import android.os.Bundle;
import android.app.Activity;
import android.content.Intent;
import android.os.Handler;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
public class MainActivity extends Activity {
public static Handler mHandler = new Handler();
public static long UPP;
public static long DLL;
Button startService,stopService;
public Context context=this;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (FirstService.mStartRX == TrafficStats.UNSUPPORTED || FirstService.mStartTX == TrafficStats.UNSUPPORTED) {
AlertDialog.Builder alert = new AlertDialog.Builder(this);
alert.setTitle("Uh Oh!");
alert.setMessage("Your device does not support traffic stat monitoring.");
alert.show();
} else {
mHandler.postDelayed(mRunnable, 1000);
}
startService=(Button)findViewById(R.id.startService);
stopService=(Button)findViewById(R.id.stopService);
startService.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
EditText UP = (EditText) findViewById(R.id.UP);
String UPPP = UP.getText().toString();
UPP=Long.parseLong(UPPP);
EditText DL = (EditText) findViewById(R.id.DL);
String DLLL = DL.getText().toString();
DLL=Long.parseLong(DLLL);
Intent intent = new Intent(getApplicationContext(), FirstService.class);
String myString = DLLL;
intent.putExtra("StringName", myString);
startService(intent);
}
});
stopService.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
stopService(new Intent(getBaseContext(),FirstService.class));
}
});
}
public final Runnable mRunnable = new Runnable() {
public void run() {
TextView RX = (TextView)findViewById(R.id.RX);
TextView TX = (TextView)findViewById(R.id.TX);
RX.setText(Long.toString(FirstService.rxBytes));
TX.setText(Long.toString(FirstService.txBytes));
mHandler.postDelayed(mRunnable, 1000);
}
};
}
Service :
package ir.alexandre9009.service;
import android.app.AlertDialog;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.net.TrafficStats;
import android.net.wifi.WifiManager;
import android.os.Handler;
import android.os.IBinder;
import android.widget.TextView;
import android.widget.Toast;
public class FirstService extends Service{
public static long mStartRX ;
public static long mStartTX ;
public static long rxBytes ;
public static long txBytes ;
public long dl=MainActivity.DLL;
Context context=this;
private final Runnable mRunnable = new Runnable() {
public void run() {
rxBytes = (TrafficStats.getTotalRxBytes()- mStartRX)/1048576;
txBytes = (TrafficStats.getTotalTxBytes()- mStartTX)/1048576;
if (rxBytes==2) {
stopService(new Intent(getBaseContext(),FirstService.class));
Intent i = new Intent(context,MainActivity.class);
context.startActivity(i);
// WifiManager wifiManager = (WifiManager)getApplicationContext().getSystemService(Context.WIFI_SERVICE);
// wifiManager.setWifiEnabled(false);
//معرفی توست برای نمایش یک پیام کوتاه به کاربر در هنگام خاموش کردن وای فای
Toast.makeText(FirstService.this, "هشدار", Toast.LENGTH_LONG).show();
}
mHandler.postDelayed(mRunnable, 1000);
}
};
private Handler mHandler = new Handler();
#Override
public IBinder onBind(Intent arg0) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Toast.makeText(this,"staart",Toast.LENGTH_LONG).show();
mStartTX=0;
mStartRX=0;
mStartRX = TrafficStats.getTotalRxBytes();
mStartTX = TrafficStats.getTotalTxBytes();
mHandler.postDelayed(mRunnable, 1000);
return Service.START_STICKY;
}
#Override
public void onDestroy() {
TrafficStats.clearThreadStatsTag();
Toast.makeText(this,"FirstService Stoped",Toast.LENGTH_LONG).show();
mStartTX=0;
mStartRX=0;
super.onDestroy();
}
}
AndroidManifest :
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="ir.alexandre9009.service">
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>
<uses-permission android:name="android.permission.UPDATE_DEVICE_STATS" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name=".FirstService"
>
</service>
</application>
</manifest>
please help me ...
The problem is with this line
public long dl=MainActivity.DLL;
You're referring to a variable in the Activity, surly when the Activity is destroyed, this variable is no longer in scope, thus you get Null Exception.
You must get this value using the intent.
The other problem is that you can't prevent any service from being killed by the system except foreground services which need to show a notification to the user. But this is not suitable for your situation.
Therefore, the best approach for you is to check whether intent is null or not. If it is not null, you get the value and save it into Preferences or Database or somewhere, if it is null, you retrieve the value from where you stored it before.
I am trying to get my Android app to respond to changes in the local address book and sync with it on a need basis.
I understand that in order to do that, I need to create a service to run in the background. I did.
But it isn't working... when my app runs and I try to initiate the service, it fails with :
[exec] [DEBUG] I/ActivityManager( 60): Starting activity: Intent { cmp=ti.test/my.Activity (has extras) }
[exec] [DEBUG] E/aas ( 1812): (main) [490639,495460] people uri:content://contacts/people
[exec] [DEBUG] W/ActivityManager( 60): Unable to start service Intent { cmp=ti.test/.MyService }: not found
this is how I try to run it:
startService(new Intent(activity, MyService.class));
this is part of my manifest.xml fie:
<android xmlns:android="http://schemas.android.com/apk/res/android">
<manifest android:versionCode="1" android:versionName="1">
<uses-sdk android:minSdkVersion="4"/>
<supports-screens android:anyDensity="true"
android:largeScreens="true" android:normalScreens="true" android:smallScreens="true"/>
<application>
<service android:name="ti.test.MyService"/>
</application>
</manifest>
</android>
this is the service class:
package ti.test;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;
import android.database.ContentObserver;
import android.provider.Contacts.People;
public class MyService extends Service
{
private static final String TAG = "MyService";
private class MyContentObserver extends ContentObserver {
public MyContentObserver() {
super(null);
}
#Override
public void onChange(boolean selfChange) {
super.onChange(selfChange);
Log.e ("DatabaseTable" , "****************************** contact database change detected *************************************");
}
#Override
public boolean deliverSelfNotifications() {
return true;
}
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
Log.d("MyService", "starting........");
MyContentObserver contentObserver = new MyContentObserver();
getContentResolver().registerContentObserver (People.CONTENT_URI, true, contentObserver);
}
#Override
public void onDestroy() {
Log.d("MyService", "stopping........");
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i("LocalService", "Received start id " + startId + ": " + intent);
// We want this service to continue running until it is explicitly
// stopped, so return sticky.
return START_STICKY;
}
#Override
public void onStart(Intent intent, int startid) {
Log.d("MyService", "onStart........");
}
}
thanks!
you should not create class in service.
you should define a contectResolver class and register it in an activity or where you want to use it.