I've Created an service for lock screen service the purpose of the service is to register and unregistered receiver but it is causing memory leak because of the my application crashes when there is not enough memory left to consume
Here is my code
package com.itstars.daynightlockscreen;
import android.app.KeyguardManager;
import android.app.KeyguardManager.KeyguardLock;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.graphics.PixelFormat;
import android.media.AudioManager;
import android.os.IBinder;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.WindowManager;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.Toast;
public class LockService extends Service {
public static boolean wal;
public static boolean isRunning;
public static TimeChangeReceiver receiver;
KeyguardManager keyguardManager;
KeyguardLock lock;
#Override
public IBinder onBind(Intent arg0) {
// TODO Auto-generated method stub
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
keyguardManager = (KeyguardManager) getSystemService(Service.KEYGUARD_SERVICE);
lock = keyguardManager.newKeyguardLock(KEYGUARD_SERVICE);
lock.disableKeyguard();
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_SCREEN_OFF);
wal = intent.getBooleanExtra("wal", false);
isRunning = intent.getBooleanExtra("locker",false);
receiver = new TimeChangeReceiver();
registerReceiver(receiver, filter);
isRunning = true;
return START_STICKY;
}
#Override
public void onDestroy() {
super.onDestroy();
unregisterReceiver(receiver);
isRunning = false;
keyguardManager = (KeyguardManager) getSystemService(Service.KEYGUARD_SERVICE);
lock = keyguardManager.newKeyguardLock(KEYGUARD_SERVICE);
lock.reenableKeyguard();
}
}
Have you define Service in Manifest? If Yes,
then Have you give permission
`android.permission.DISABLE_KEYGUARD`
in manifest ? If yes, then
Put a code in try-catch block in onStartCommand , put a debug point on first line of onStartCommand method observe line where it jump to catch block.
Because error must be in your onStartCommand method only.
START_NOT_STICKY
Constant to return from onStartCommand(Intent, int, int): if this service's process is killed while it is started (after returning from onStartCommand(Intent, int, int)), and there are no new start intents to deliver to it, then take the service out of the started state and don't recreate until a future explicit call to Context.startService(Intent).
START_STICKY
Constant to return from onStartCommand(Intent, int, int): if this service's process is killed while it is started (after returning from onStartCommand(Intent, int, int)), then leave it in the started state but don't retain this delivered intent.
Using above description decide where you want to use sticky intent or not ?
Related
I'm trying to make a service that works 24/7 and it's been working until I updated to Android 12. I've checked the new foreground restrictions but still don't understand why it isn't working since I'm starting it from an activity.
ACTIVITY
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.view.View;
import android.widget.EditText;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
public class TestActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.test);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
startForegroundService(new Intent(TestActivity.this, TestService.class));
}
}
SERVICE
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.support.v4.media.MediaBrowserCompat;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.app.NotificationCompat;
import androidx.media.MediaBrowserServiceCompat;
import java.util.List;
public class TestService extends MediaBrowserServiceCompat {
#Override
public BrowserRoot onGetRoot(#NonNull String clientPackageName, int clientUid, #Nullable Bundle rootHints) { return null; }
#Override
public void onLoadChildren(#NonNull String parentId, #NonNull Result<List<MediaBrowserCompat.MediaItem>> result) { result.sendResult(null); }
#Override
public int onStartCommand(Intent ii, int flags, int startId) {
//CREATE NOTI CHANNEL
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel channel = new NotificationChannel(
"test", "Test Notifications",
NotificationManager.IMPORTANCE_HIGH);
((NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE)).createNotificationChannel(channel);
}
//CREATE NOTI
Notification notification = new NotificationCompat.Builder(this, "test")
.setSmallIcon(R.drawable.icon)
.setContentTitle("title")
.setContentText("test")
.setChannelId("test")
.setOngoing(true)
.setSilent(true)
.build();
//START FOREGROUND
startForeground(101, notification);
return START_STICKY;
}
}
I tried creating a new app with just these lines of code and it works fine so it must be something else making the service close after a minute.
Turns out samsung put my app on deep sleep which caused it to close itself if not used for a minute. Also thanks to the people who took their time to try and help.
Even though you are correct in wanting a foreground Service here, it seems as if you want it to stay alive whenever you app in the background, or not running at all, as you don't intend your app to be running 24/7, do you?
Since it seems as if you're trying to use a MediaBrowserServiceCompat in your example, I would suggest you do so using a companion instance of a MediaSessionCompat in order to have the media session control the lifecycle of your Service on it's own.
Implementing a media Service is not the most straightforward task in Android; they're still trying to fix some of its prevailing issues with the latest release of Android 13. Therefore, I would also suggest you follow this official Android guide if you're attempting to create an audio app with a media foreground Service.
I have been learning jobscheduler in andorid. I have trying to show a toast message in the onstartjob() after every 1minute. But its not showing up. Any help will be grateful.
jobschedul_service .class:
package com.prajwal.jobscheduler;
import android.app.Service;
import android.app.job.JobParameters;
import android.app.job.JobScheduler;
import android.app.job.JobService;
import android.content.Intent;
import android.os.IBinder;
import android.widget.Toast;
public class jobschedul_service extends JobService {
#Override
public boolean onStartJob(JobParameters jobParameters) {
Toast.makeText(getApplicationContext(), "After 15 minutes", Toast.LENGTH_SHORT).show();
return false;
}
#Override
public boolean onStopJob(JobParameters jobParameters) {
return true;
}
}
MainActivity.class:
package com.prajwal.jobscheduler;
import androidx.appcompat.app.AppCompatActivity;
import android.app.job.JobInfo;
import android.app.job.JobScheduler;
import android.content.ComponentName;
import android.content.Context;
import android.os.Bundle;
public class MainActivity extends AppCompatActivity {
private static final int LOAD_ARTWORK_JOB_ID = 1;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
JobScheduler jobScheduler =
(JobScheduler) getSystemService(JOB_SCHEDULER_SERVICE);
jobScheduler.schedule(new JobInfo.Builder
(LOAD_ARTWORK_JOB_ID, new ComponentName(this, jobschedul_service.class))
.setPeriodic(900000)
.build());
}
}
Manifest.xml:
<service
android:name=".jobschedul_service"
android:enabled="true"
android:exported="true"
android:permission="android.permission.BIND_JOB_SERVICE"></service>
Got the answer!
The reason was the setperiodic(long interval).
As per the ss below:
This function was added in API 21 i.e Lolipop version. Whereas I was running the app on version > Lolipop.
Whereas this new function in the image below:
was added in API 24 i.e. Nougat
Hence, if you are targetting your app below Nougat i.e < Nougat but >= Lolipop then use setPeriodic(long interval) method whereas if u r targetting >= Nougat then use setPeriodic(long interval, long flexinterval).
Solution
if(Build.VERSION.SDK_INT > Build.VERSION_CODES.N)
{
builder.setPeriodic(900000,6000);
}
else
{
builder.setPeriodic(900000);
}
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)
}
}
The main thing i just want to do is that i have to check on me webservice when my application is closed when it gets any alert on webservice then it shows notification or activity.
I read about services and make an example but when i remove the application from recent apps then some time the service is restarted or some the service got killed to.
Code:
package com.usamaakmal.startedservice;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.SystemClock;
import android.widget.Toast;
public class NewService extends Service {
public NewService() {
}
int i = 0;
Handler handler = new Handler();
Thread runnable = new Thread() {
#Override
public void run() {
i++;
Toast.makeText(getBaseContext(), "Hello World! " + i, Toast.LENGTH_SHORT).show();
handler.postDelayed(this,1000);
}
};
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
Toast.makeText(this, "Service Started", Toast.LENGTH_SHORT).show();
handler.postDelayed(runnable,2000);
}
#Override
public void onDestroy() {
Toast.makeText(this, "Service Destroyed", Toast.LENGTH_SHORT).show();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_STICKY;
}
}
Removing app from recent apps list kills app process. Returning START_STICKY from onStartCommand() means you want the system to restart the service after it was killed (either because you removed the app from recents list or system killed service because it ran out of resources).
If you want to keep your service (and it's process) alive you will need foreground service.
System tries to keep foreground services alive as long as possible.
See: Running service in foreground
I have a litle problem while programing on my application. I'm programing a service which shows me how many times my phone was active in the last 24 hours.
I’m doing this by listening for screen on/off action, and I’m getting more and more receives by pusshing the button.
Actually I gat a pattern in it, so:
logs getherd = logs getterd in the previus button puss * 2 - 8
My Reciver class:
package com.example.balinator.androidprojekt.services.screenonservice;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.hardware.display.DisplayManager;
import android.os.Bundle;
import android.os.PowerManager;
import android.telephony.TelephonyManager;
import android.util.Log;
import android.view.Display;
import com.example.balinator.androidprojekt.database.Database;
import java.util.Set;
/**
* Created by Balinator on 2016. 12. 15..
*/
public class MyScreenOnOffReciver extends BroadcastReceiver {
private static final String tag = "MyScreenOnOffReciver";
private Database db;
#Override
public void onReceive(Context context, Intent intent) {
String state = intent.getAction();
if (state.equals(Intent.ACTION_SCREEN_ON)) {
if(db == null){
db = new Database(context);
}
db.open();
long id = db.getService(MyScreenOnService.sName).getId();
db.createServiceLog(id,System.currentTimeMillis() + ":on");
db.close();
Log.d(tag,"screen on log");
}else if(state.equals(Intent.ACTION_SCREEN_OFF)) {
if (db == null) {
db = new Database(context);
}
db.open();
long id = db.getService(MyScreenOnService.sName).getId();
db.createServiceLog(id, System.currentTimeMillis() + ":off");
db.close();
Log.d(tag, "screen off log");
}
}
}
I think you registered your receiver 2 times
At activity
manifest
Register your receiver one time by using any one of the above.. then it ll b fyn