I am new to Android development and I would like to understand why my application is using this much memory when it starts. Right now, it starts off with 18MB of memory (using the memory monitor in Android Studio). I have added Firebase Analytics and Admob to it. I am worried that these are culprits of using this large amount of memory.
By doing some digging in, I found out that SharedPreferenceImpl and its children objects (FastXmlSerializer and ByteBuffer) were taking up 50% of the memory! I am pretty shocked. Next, I try to see which thread is generating these objects. I found out that the thread name is "thread-1-pool-1".
Here is the stacktrace responsible for creating this large amount of memory:
at java.nio.ByteBuffer.allocate(ByteBuffer.java:56)
at com.android.internal.util.FastXmlSerializer.<init>(FastXmlSerializer.java:62)
at com.android.internal.util.XmlUtils.writeMapXml(XmlUtils.java:188)
at android.app.SharedPreferencesImpl.writeToFile(SharedPreferencesImpl.java:600)
at android.app.SharedPreferencesImpl.-wrap2(SharedPreferencesImpl.java)
at android.app.SharedPreferencesImpl$2.run(SharedPreferencesImpl.java:515)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588)
at java.lang.Thread.run(Thread.java:818)
I have a LoopThread that calls a method in a service. I am wondering if this could cause the large consumption of memory. My service class and loop thread contains no references to SharedPreferences though. So, I am very confuse why this happens. Any pointers would be appreciated.
The code may not be very clean and it is long. But here it is. The idea of this app is to bring up a screen saver when the power button is pressed.
This is the service class.
//SaverService.java
#Override
public void onCreate() {
Log.d("SaverService","Created saver service...");
super.onCreate();
loopThread = new LoopThread();
loopThread.createHandler(this);
loopThread.start();
startSaverMethod();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Intent notificationIntent = new Intent(this, StartSaver.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this)
.setSmallIcon(R.drawable.pokeball)
.setContentTitle("Go-Saver's running")
.setContentText("Tap here to cancel")
.setContentIntent(pendingIntent);
Notification notification = mBuilder.build();
startForeground(1001, notification);
return START_STICKY;
}
//SharedPreference should be a singleton
private void startSaverMethod() {
//sharedPreferences = getSharedPreferences("GoSaverPrefs", Context.MODE_PRIVATE);
try {
//SharedPreferences.Editor editor = sharedPreferences.edit();
screenBrightness = Settings.System.getInt(getContentResolver(), Settings.System.SCREEN_BRIGHTNESS);
previousScreenBrightness = screenBrightness;
//editor.putInt("screenBrightness", screenBrightness);
//editor.commit();
screenBrightnessMode = Settings.System.getInt(getContentResolver(), Settings.System.SCREEN_BRIGHTNESS_MODE);
previousScreenBrightnessMode = screenBrightnessMode;
//editor.putInt("screenBrightnessMode",screenBrightnessMode);
//editor.commit();
screenOffTimeout = Settings.System.getInt(getContentResolver(), Settings.System.SCREEN_OFF_TIMEOUT);
previousScreenOffTimeout = screenOffTimeout;
//editor.putInt("screenOffTimeout",screenOffTimeout);
//editor.commit();
} catch (Settings.SettingNotFoundException e) {
e.printStackTrace();
}
//Registerting receiver
screenOffReceiver = new ScreenOffReceiver();
screenOffReceiver.setSaverService(this);
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_SCREEN_OFF);
filter.addAction(Intent.ACTION_SCREEN_ON);
registerReceiver(screenOffReceiver, filter);
Settings.System.putInt(getContentResolver(), Settings.System.SCREEN_OFF_TIMEOUT, 3600000);
pressedMillisec = getPressedMillisec();
}
#Override
public void onDestroy() {
Log.d("SaverService","Destroying saver service...");
disableSaverSettings();
//screenOffTimeout = sharedPreferences.getInt("screenOffTimeout", 30000);
screenOffTimeout = previousScreenOffTimeout;
Settings.System.putInt(getContentResolver(), Settings.System.SCREEN_OFF_TIMEOUT, screenOffTimeout);
unregisterReceiver(screenOffReceiver);
removeScreenSaver();
//sharedPreferences = null;
windowManager = null;
screenOffReceiver = null;
Message killMessage = loopThread.handler.obtainMessage(LoopThread.KILL);
loopThread.handler.sendMessage(killMessage);
loopThread.handler.getLooper().quit();
super.onDestroy();
System.gc();
}
public boolean isScreenSaver() {
if(screenSaver != null) {
return screenSaver.isShown();
} else {
return false;
}
}
private boolean isSaverBrightness() {
try {
int brightness = Settings.System.getInt(getContentResolver(), Settings.System.SCREEN_BRIGHTNESS);
int brightnessMode = Settings.System.getInt(getContentResolver(), Settings.System.SCREEN_BRIGHTNESS_MODE);
return brightness == 1 && brightnessMode == Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL;
} catch (Exception e) {
Log.e("SaverService", "Cannot get brightness");
return false;
}
}
public void startScreenSaverAsync() {
Message onMessage = loopThread.handler.obtainMessage(LoopThread.ON);
loopThread.handler.sendMessage(onMessage);
}
public void startScreenSaver() {
Log.d("SaverService","######################################");
boolean isRightState = !isScreenSaver() && !isSaverBrightness();
if (!isRightState) {
Log.e("SaverService","Invalid state. Stopping service");
stopSelf();
}
long currentMillisec = getPressedMillisec();
if (currentMillisec - pressedMillisec < 2000) {
Log.d("SaverService","Pressed too fast. Ignoring the second press.");
return;
}
//Creating screenSaver
windowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
LayoutInflater li = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE);
screenSaver = li.inflate(R.layout.screen_saver, null);
long startTime = System.currentTimeMillis();
WindowManager.LayoutParams params = new WindowManager.LayoutParams(
WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE |
WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE |
WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN |
WindowManager.LayoutParams.FLAG_FULLSCREEN |
WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS |
WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR |
View.SYSTEM_UI_FLAG_HIDE_NAVIGATION |
View.SYSTEM_UI_FLAG_IMMERSIVE,
PixelFormat.TRANSLUCENT);
long totalTime = System.currentTimeMillis() - startTime;
Log.d("SaverService","params Time: " + totalTime);
startTime = System.currentTimeMillis();
enableSaverSettings();
totalTime = System.currentTimeMillis() - startTime;
Log.d("SaverService","enableSaverSettings Time: " + totalTime);
startTime = System.currentTimeMillis();
removeScreenSaver();
totalTime = System.currentTimeMillis() - startTime;
Log.d("SaverService","removeScreenSaver Time: " + totalTime);
Log.d("SaverService", "Adding Screen Saver");
startTime = System.currentTimeMillis();
windowManager.addView(screenSaver, params);
totalTime = System.currentTimeMillis() - startTime;
Log.d("SaverService","addView Time: " + totalTime);
Log.d("SaverService", "Turning On Screen");
startTime = System.currentTimeMillis();
turnOnScreen(this);
totalTime = System.currentTimeMillis() -startTime;
Log.d("SaverService","turnOnScreen Time: " + totalTime);
pressedMillisec = getPressedMillisec();
Log.d("SaverService", "Current time - " + pressedMillisec);
Log.d("SaverService","######################################");
}
public void stopScreenSaverAsync() {
Message offMessage = loopThread.handler.obtainMessage(LoopThread.OFF);
loopThread.handler.sendMessage(offMessage);
}
public void stopScreenSaver() {
Log.d("SaverService","######################################");
long currentMillisec = getPressedMillisec();
if (currentMillisec - pressedMillisec < 2000) {
Log.d("SaverService","Pressed too fast. Ignoring the second press.");
return;
}
disableSaverSettings();
removeScreenSaver();
turnOnScreen(this);
pressedMillisec = getPressedMillisec();
Log.d("SaverService", "Current time - " + pressedMillisec);
Log.d("SaverService","######################################");
}
private long getPressedMillisec() {
return Calendar.getInstance().getTimeInMillis();
}
private void removeScreenSaver() {
try {
windowManager.removeViewImmediate(screenSaver);
screenSaver = null;
} catch (Exception e) {
Log.w("SaverService", "Could not remove screen saver...");
}
}
private void enableSaverSettings() {
Settings.System.putInt(getContentResolver(), Settings.System.SCREEN_BRIGHTNESS_MODE, Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL);
Settings.System.putInt(getContentResolver(), Settings.System.SCREEN_BRIGHTNESS, 1);
}
private void disableSaverSettings() {
screenBrightness = previousScreenBrightness;
screenBrightnessMode = previousScreenBrightnessMode;
//screenBrightness = sharedPreferences.getInt("screenBrightness", 50);
//screenBrightnessMode = sharedPreferences.getInt("screenBrightnessMode", Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC);
Settings.System.putInt(getContentResolver(), Settings.System.SCREEN_BRIGHTNESS_MODE, screenBrightnessMode);
Settings.System.putInt(getContentResolver(), Settings.System.SCREEN_BRIGHTNESS, screenBrightness);
}
private void turnOnScreen(Context context) {
//Wait for screen is off
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
boolean isScreenOn = pm.isScreenOn();
while (isScreenOn) {
try {
Thread.sleep(2);
isScreenOn = pm.isScreenOn();
} catch (Exception e) {
Log.i("Issue", "Could not sleep...");
}
}
Intent intentNew = new Intent(context.getApplicationContext(), Transparent.class);
intentNew.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | IntentCompat.FLAG_ACTIVITY_CLEAR_TASK);
context.startActivity(intentNew);
}
This is the class that listens for a Power button press:
public class ScreenOffReceiver extends BroadcastReceiver {
private SaverService saverService = null;
private static boolean anyThreadRunning = false;
void setSaverService(SaverService saverService){
this.saverService = saverService;
}
#Override
public void onReceive(Context context, Intent intent) {
runMethod2(context, intent);
}
private void runMethod2(Context context, Intent intent) {
String action = intent.getAction();
Log.d("SaverService", action);
if(anyThreadRunning) {
Log.d("SaverService","Another thread is using ScreenOffReceiver. Skipping... ");
return;
}
if(action.equals(Intent.ACTION_SCREEN_OFF) && !saverService.isScreenSaver()){
anyThreadRunning = true;
Log.d("SaverService","Turning on screen saver.");
saverService.startScreenSaverAsync();
}
else if(action.equals(Intent.ACTION_SCREEN_OFF) && saverService.isScreenSaver()){
anyThreadRunning = true;
Log.d("SaverService","Turning off screen saver." );
saverService.stopScreenSaverAsync();
}
anyThreadRunning = false;
}
}
This the loop thread class:
public class LoopThread extends Thread {
public Handler handler = null;
public static final int ON = ScreenOffHandler.ON;
public static final int OFF = ScreenOffHandler.OFF;
public static final int KILL = ScreenOffHandler.KILL;
private SaverService saverService;
public void run(){
Looper.prepare();
handler = new ScreenOffHandler(saverService);
Looper.loop();
}
public void createHandler(SaverService saverService){
this.saverService = saverService;
}
private static class ScreenOffHandler extends Handler {
private SaverService saverService;
public static final int ON = 1;
public static final int OFF = 0;
public static final int KILL = -100;
public ScreenOffHandler(SaverService saverService) {
this.saverService = saverService;
}
public void handleMessage(Message msg) {
// ...Run in background
int what = msg.what;
switch (what){
case ON:
saverService.startScreenSaver();
break;
case OFF:
saverService.stopScreenSaver();
break;
case KILL:
saverService = null;
break;
}
}
}
}
Related
to be able using a remote service through localhost IP (to hide real address from users in other intents) I am using this service to port-forwarding :
public class PortForward extends Service implements Runnable {
private static final String TAG = "Port Forward";
private int localPort;
private int remotePort;
private String remoteHost;
private boolean running = false;
private int lastUp = -1;
private int lastDown = -1;
private int bUp = 0;
private int bDown = 0;
LocalBroadcastManager bm;
private Thread t;
ServerSocketChannel serverSocketChannel = null;
public Handler sendBroadcastHandler = new Handler() {
public void handleMessage(Message msg) {
Intent i = new Intent().setAction(MainActivity.USAGE_UPDATE);
i.putExtra("bUp", bUp);
i.putExtra("bDown", bDown);
bm.sendBroadcast(i);
}
};
public Handler sendDeathHandler = new Handler() {
public void handleMessage(Message msg) {
Bundle b = msg.getData();
String causeOfDeath = b.getString("causeOfDeath", "unknown");
Notification note = new Notification.Builder(PortForward.this)
.setContentTitle("TCP forwarding thread dead")
.setContentText("Cause of death: " + causeOfDeath)
.setSmallIcon(R.drawable.ic_launcher).build();
NotificationManager mNotificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
mNotificationManager.notify(1338, note);
}
};
private void updateCounts() {
updateCounts(false);
}
private void updateCounts(boolean force) {
if (!force && (bUp - lastUp < 10000 && bDown - lastDown < 10000)) {
return;
}
lastUp = bUp;
lastDown = bDown;
Message msg = sendBroadcastHandler.obtainMessage();
sendBroadcastHandler.sendMessage(msg);
}
#Override
public void onDestroy() {
Log.d(TAG, "Service onDestroy");
if (t != null) {
t.interrupt();
try {
t.join();
} catch (InterruptedException e) {
Log.d(TAG, "couldn't join forwarder-thread");
System.exit(1);
}
}
Log.d(TAG, "Killed it");
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(TAG, "Service onStart");
if (running){
updateCounts(true);
return START_REDELIVER_INTENT;
}
running = true;
bm = LocalBroadcastManager.getInstance(this);
localPort = intent.getIntExtra("localPort", -1);
remotePort = intent.getIntExtra("remotePort", -1);
remoteHost = intent.getStringExtra("remoteHost");
t = new Thread(this);
t.start();
Log.d(TAG, "launching a thread");
Notification note = new Notification.Builder(this)
.setContentTitle("Forwarding TCP Port")
.setContentText(String.format(
"localhost:%s -> %s:%s", localPort, remoteHost, remotePort))
.setSmallIcon(R.drawable.ic_launcher)
.build();
Intent i = new Intent(this, MainActivity.class);
i.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
PendingIntent pi = PendingIntent.getActivity(this, 0, i, 0);
note.contentIntent = pi;
note.flags |= Notification.FLAG_NO_CLEAR;
startForeground(1337, note);
Log.d(TAG, "doing startForeground");
updateCounts(true);
return START_REDELIVER_INTENT;
}
private void reportException(Exception e){
StringWriter sw = new StringWriter();
e.printStackTrace(new PrintWriter(sw));
Message msg = sendDeathHandler.obtainMessage();
Bundle b = msg.getData();
b.putString("causeOfDeath", sw.toString());
sendDeathHandler.sendMessage(msg);
}
private void finish(Selector s){
try {
serverSocketChannel.close();
} catch (IOException e){ }
Set<SelectionKey> selectedKeys = s.keys();
Iterator<SelectionKey> keyIterator = selectedKeys.iterator();
while (keyIterator.hasNext()) {
closeConnectionForKey(keyIterator.next());
}
}
private void closeChannel(SocketChannel c){
if (c != null){
try {
if (c != null){
c.close();
}
} catch (IOException e){ }
}
}
private void closeConnectionForKey(SelectionKey key){
PFGroup g = null;
try {
g = (PFGroup)key.attachment();
} catch (Exception e){
return;
}
if (g == null) {return;}
closeChannel(g.iChannel);
closeChannel(g.oChannel);
}
#Override
public void run() {
String causeOfDeath = null;
System.out.println("Server online");
Selector selector = null;
try {
selector = Selector.open();
serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.socket().bind(new InetSocketAddress(localPort));
serverSocketChannel.configureBlocking(false);
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
} catch (IOException e) {
reportException(e);
return;
}
System.out.println("Server socket bound.");
while (true) {
System.out.println("Waiting for conn");
updateCounts();
int readyChannels = 0;
try {
readyChannels = selector.select();
} catch (IOException e) {
reportException(e);
continue;
}
if (Thread.currentThread().isInterrupted()) {
finish(selector);
return;
}
if (readyChannels == 0) {
continue;
}
Set<SelectionKey> selectedKeys = selector.selectedKeys();
Iterator<SelectionKey> keyIterator = selectedKeys.iterator();
while (keyIterator.hasNext()) {
//System.out.println("Ready on " + readyChannels);
SelectionKey key = keyIterator.next();
keyIterator.remove();
if (!key.isValid()) {
continue;
} else if (key.isAcceptable()) {
System.out.println("Acceptable!");
PFGroup g = new PFGroup();
// 512KB buffers
g.iBuffer = ByteBuffer.allocate(512000);
g.oBuffer = ByteBuffer.allocate(512000);
boolean iConnected = false;
try {
g.iChannel = serverSocketChannel.accept();
iConnected = g.iChannel.finishConnect();
if (iConnected){
g.sidesOn++;
}
g.iChannel.configureBlocking(false);
g.iKey = g.iChannel.register(selector, 0, g);
g.oChannel = SocketChannel.open();
g.oChannel.configureBlocking(false);
g.oChannel.connect(new InetSocketAddress(remoteHost, remotePort));
g.oKey =g.oChannel.register(selector, SelectionKey.OP_CONNECT, g);
} catch (IOException e) {
continue;
}
} else if (key.isConnectable()) {
System.out.println("connectable!");
try {
SocketChannel c = (SocketChannel) key.channel();
PFGroup g = (PFGroup)key.attachment();
if (!c.finishConnect()) {
System.out.println("couldn't finish conencting");
continue;
}
g.sidesOn++;
System.out.println("Initilized the bidirectional forward");
key.interestOps(SelectionKey.OP_READ);
g.iKey = g.iChannel.register(selector, SelectionKey.OP_READ, g);
} catch (IOException e) {
continue;
}
} else if (key.isReadable()) {
try {
ByteBuffer b = null;
SocketChannel from = null;
SocketChannel to = null;
PFGroup g = (PFGroup)key.attachment();
String label = null;
if (key.channel() == g.iChannel){
from = g.iChannel;
to = g.oChannel;
b = g.iBuffer;
label = "incoming";
} else if (key.channel() == g.oChannel){
from = g.oChannel;
to = g.iChannel;
b = g.oBuffer;
label = "outgoing";
}
int i = from.read(b);
b.flip();
while (b.hasRemaining()) {
int bytes = to.write(b);
if(label.equals("incoming")){
bUp += bytes;
} else {
bDown += bytes;
}
}
b.clear();
if (i == -1) {
key.cancel();
g.sidesOn--;
if (g.sidesOn == 0){
System.out.println("Done, closing keys");
closeConnectionForKey(key);
}
}
} catch (IOException e){
Log.d(TAG, "closing connection for key.");
closeConnectionForKey(key);
}
}
}
}
}
public class PFGroup {
public ByteBuffer iBuffer;
public ByteBuffer oBuffer;
public SocketChannel iChannel;
public SocketChannel oChannel;
public int sidesOn = 0;
SelectionKey iKey;
SelectionKey oKey;
}
}
and in my main activity i used it like this:
Intent i=new Intent(this, PortForward.class)
.putExtra("localPort", 1195)
.putExtra("remotePort", port)
.putExtra("remoteHost", address);
startService(i);
but it does not work. when app is in background i can not use address:port through 127.0.0.1:1195 .
and also no related log appeasers in logcat.
I am trying to run chronometer inside a Service. But I am not able to run it. I press a button in Activity and that event is passed to the Service. If the button in pressed then start the Chronometer but problem is setOnChronometerTickListener is called only once and it stops. Where am I making mistake? Here is my Service and Activity class:
Service class:
public class TimerService extends Service {
NotificationManager notificationManager;
NotificationCompat.Builder mBuilder;
Callbacks activity;
private final IBinder mBinder = new LocalBinder();
private Chronometer chronometer;
SharedPreferences sharedPreferences;
private int state = 0; //0 means stop state,1 means play, 2 means pause
private boolean running = false;
private long pauseOffSet = -1;
#Subscribe(threadMode = ThreadMode.MAIN)
public void onMessageEvent(MessageEvent event) {
if (event.message) {
if (!running) {
if (pauseOffSet != -1) {
pauseOffSet = sharedPreferences.getLong("milli", -1);
}
chronometer.setBase(SystemClock.elapsedRealtime() - pauseOffSet);
chronometer.start();
state = 1;
pauseOffSet = 0;
running = true;
}
} else {
if (running) {
chronometer.stop();
pauseOffSet = SystemClock.elapsedRealtime() - chronometer.getBase();
state = 2;
running = false;
}
}
}
#Override
public void onCreate() {
super.onCreate();
EventBus.getDefault().register(this);
}
#Override
public void onDestroy() {
EventBus.getDefault().unregister(this);
super.onDestroy();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
sharedPreferences = getSharedPreferences("myprefs", MODE_PRIVATE);
chronometer = new Chronometer(this);
state = sharedPreferences.getInt("state", 0);
chronometer.setOnChronometerTickListener(new Chronometer.OnChronometerTickListener() {
#Override
public void onChronometerTick(Chronometer chronometer) {
Log.e("TimerService","timer");
pauseOffSet = SystemClock.elapsedRealtime() - chronometer.getBase();
if (pauseOffSet >= 79200000) {
chronometer.setBase(SystemClock.elapsedRealtime());
chronometer.stop();
running = false;
// progressBar.setProgress(0);
} else {
chronometer.setText(setFormat(pauseOffSet));
// int convertTime = (int) pauseOffSet;
// progressBar.setProgress(convertTime);
}
if (activity != null) {
activity.updateClient(pauseOffSet);
}
}
});
if (state == 1) { // its in play mode
running = true;
chronometer.setBase(SystemClock.elapsedRealtime() - sharedPreferences.getLong("milli", 0));
chronometer.start();
} else if (state == 2) { //its in pause mode
running = false;
pauseOffSet = sharedPreferences.getLong("milli", -1);
long time = SystemClock.elapsedRealtime() - pauseOffSet;
chronometer.setBase(time);
int convertTime = (int) pauseOffSet;
// progressBar.setProgress(convertTime);
} else {
running = false;
}
//Do what you need in onStartCommand when service has been started
return START_NOT_STICKY;
}
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
//returns the instance of the service
public class LocalBinder extends Binder {
public TimerService getServiceInstance() {
return TimerService.this;
}
}
//Here Activity register to the service as Callbacks client
public void registerClient(Activity activity) {
this.activity = (Callbacks) activity;
}
//callbacks interface for communication with service clients!
public interface Callbacks {
public void updateClient(long data);
}
String setFormat(long time) {
int h = (int) (time / 3600000);
int m = (int) (time - h * 3600000) / 60000;
int s = (int) (time - h * 3600000 - m * 60000) / 1000;
String hh = h < 10 ? "0" + h : h + "";
String mm = m < 10 ? "0" + m : m + "";
String ss = s < 10 ? "0" + s : s + "";
return hh + ":" + mm + ":" + ss;
}
}
This is my Activity class:
public class MainActivity extends AppCompatActivity implements View.OnClickListener, TimerService.Callbacks {
private static final String TAG = MainActivity.class.getSimpleName();
Chronometer tvTextView;
Button btnStart, btnStop;
private int state = 0; //0 means stop state,1 means play, 2 means pause
SharedPreferences sharedPreferences;
private boolean running = false;
private long pauseOffSet = -1;
ProgressBar progressBar;
Intent serviceIntent;
TimerService myService;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tvTextView = findViewById(R.id.textview);
progressBar = findViewById(R.id.puzzleProgressBar);
btnStart = findViewById(R.id.button1);
btnStop = findViewById(R.id.button2);
btnStart.setOnClickListener(this);
btnStop.setOnClickListener(this);
serviceIntent = new Intent(this, TimerService.class);
sharedPreferences = getSharedPreferences("myprefs", MODE_PRIVATE);
state = sharedPreferences.getInt("state", 0);
tvTextView.setOnChronometerTickListener(new Chronometer.OnChronometerTickListener() {
#Override
public void onChronometerTick(Chronometer chronometer) {
long time = SystemClock.elapsedRealtime() - chronometer.getBase();
pauseOffSet = time;
Log.e(TAG, "pauseOffSet " + pauseOffSet);
if (time >= 79200000) {
tvTextView.setBase(SystemClock.elapsedRealtime());
tvTextView.stop();
running = false;
progressBar.setProgress(0);
} else {
chronometer.setText(setFormat(time));
int convertTime = (int) time;
progressBar.setProgress(convertTime);
}
}
});
startService(serviceIntent); //Starting the service
bindService(serviceIntent, serviceConnection, Context.BIND_AUTO_CREATE); //Binding to the service!
}
private ServiceConnection serviceConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
TimerService.LocalBinder binder = (TimerService.LocalBinder) service;
myService = binder.getServiceInstance();
myService.registerClient(MainActivity.this);
Log.e(TAG, "service connected");
}
#Override
public void onServiceDisconnected(ComponentName name) {
Log.e(TAG, "service disconnected");
}
};
public void onClick(View v) {
if (btnStart == v) {
EventBus.getDefault().post(new MessageEvent(true));
} else if (btnStop == v) {
EventBus.getDefault().post(new MessageEvent(false));
}
}
#Override
protected void onStop() {
super.onStop();
sharedPreferences.edit().putLong("milli", pauseOffSet).commit();
sharedPreferences.edit().putInt("state", state).commit();
}
String setFormat(long time) {
int h = (int) (time / 3600000);
int m = (int) (time - h * 3600000) / 60000;
int s = (int) (time - h * 3600000 - m * 60000) / 1000;
String hh = h < 10 ? "0" + h : h + "";
String mm = m < 10 ? "0" + m : m + "";
String ss = s < 10 ? "0" + s : s + "";
return hh + ":" + mm + ":" + ss;
}
#Override
public void updateClient(long data) {
Log.d(TAG, "Data from service" + data);
}
}
The Chronometer is a View, that is, a UI element. You never add your Chronometer to any layout, I guess that's why it's never updating.
You could try using a CountDownTimer or a Handler / Runnable combination.
http://developer.android.com/reference/android/os/CountDownTimer.html http://developer.android.com/reference/android/os/Handler.html
Here's an example using Handler / Runnable, I've even thrown in a stopTimer() method for good measure:
private Handler timerHandler;
private Runnable timerRunnable;
// ...
#Override
public void onCreate() {
super.onCreate();
Log.d(LOG_TAG, "TimerService created");
timerHandler = new Handler();
timerRunnable = new Runnable() {
#Override
public void run() {
Log.d(LOG_TAG, "TICK");
timerHandler.postDelayed(timerRunnable, 1000);
}
};
}
public void startTimer() {
Log.d(LOG_TAG, "Timer started");
timerHandler.post(timerRunnable);
}
public void stopTimer() {
Log.d(LOG_TAG, "Timer stopped");
timerHandler.removeCallbacks(timerRunnable);
}
Here is a video which do not use Handler and directly implement the chronometer ,
Do check it out...
https://youtu.be/RLnb4vVkftc
Plus I had this problem I solved by removing
android:format="00:00"
from Chronometer in activity_main.xml
So my code looks like this :
<Chronometer
android:id="#+id/chronometer"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:height="20sp"
android:foregroundGravity="fill_horizontal|top|bottom|center|fill_vertical|fill"
android:maxLines="2"
android:minLines="2"
android:textColor="#FFF"
android:textSize="40sp"
android:verticalScrollbarPosition="defaultPosition"
app:layout_constraintBottom_toBottomOf="#+id/progress_breathing"
app:layout_constraintEnd_toEndOf="#+id/progress_breathing"
app:layout_constraintStart_toStartOf="#+id/progress_breathing"
app:layout_constraintTop_toTopOf="#+id/progress_breathing"
app:layout_constraintVertical_bias="0.43" />
Application is working with in Kitkat version. After lollipop version application is not working properly. I am thinking problem with getRunningTasks() . Could you please give me guidance ,How to overcome this problem.
public class StartupServiceReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
//Log.d("Detector", "Auto Start" + AppLockerPreference.getInstance(context).isAutoStart());
if (intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED)){
if (AppLockerPreference.getInstance(context).isAutoStart()){
if (AppLockerPreference.getInstance(context).isServiceEnabled()){
context.startService(new Intent(context, DetectorService.class));
}else{
AppLockerPreference.getInstance(context).saveServiceEnabled(false);
}
}
return;
}else if (AppLockerPreference.getInstance(context).isServiceEnabled()){
Toast.makeText(context, "App------>6", Toast.LENGTH_SHORT).show();
context.startService(new Intent(context, DetectorService.class));
}
}
}
DetectorService
public class DetectorService extends Service {
//public static final String ACTION_DETECTOR_SERVICE = "com.gueei.detector.service";
#Override
public IBinder onBind(Intent intent) {
return null;
}
private static final Class<?>[] mStartForegroundSignature = new Class[] {
int.class, Notification.class};
private static final Class<?>[] mStopForegroundSignature = new Class[] {
boolean.class};
private NotificationManager mNM;
private Method mStartForeground;
private Method mStopForeground;
private Object[] mStartForegroundArgs = new Object[2];
private Object[] mStopForegroundArgs = new Object[1];
/**
* This is a wrapper around the new startForeground method, using the older
* APIs if it is not available.
*/
void startForegroundCompat(int id, Notification notification) {
// If we have the new startForeground API, then use it.
if (mStartForeground != null) {
mStartForegroundArgs[0] = Integer.valueOf(id);
mStartForegroundArgs[1] = notification;
try {
mStartForeground.invoke(this, mStartForegroundArgs);
} catch (InvocationTargetException e) {
// Should not happen.
//debug: log.w("Detector", "Unable to invoke startForeground", e);
} catch (IllegalAccessException e) {
// Should not happen.
//debug: log.w("Detector", "Unable to invoke startForeground", e);
}
return;
}
// Fall back on the old API.
stopForeground(true);
mNM.notify(id, notification);
}
/**
* This is a wrapper around the new stopForeground method, using the older
* APIs if it is not available.
*/
void stopForegroundCompat(int id) {
// If we have the new stopForeground API, then use it.
if (mStopForeground != null) {
mStopForegroundArgs[0] = Boolean.TRUE;
try {
mStopForeground.invoke(this, mStopForegroundArgs);
} catch (InvocationTargetException e) {
// Should not happen.
//debug: log.w("Detector", "Unable to invoke stopForeground", e);
} catch (IllegalAccessException e) {
// Should not happen.
//debug: log.w("Detector", "Unable to invoke stopForeground", e);
}
return;
}
// Fall back on the old API. Note to cancel BEFORE changing the
// foreground state, since we could be killed at that point.
mNM.cancel(id);
stopForeground(false);
}
#Override
public void onCreate() {
//debug: log.i("Detector","Service.Oncreate");
initConstant();
mNM = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
try {
mStartForeground = getClass().getMethod("startForeground",
mStartForegroundSignature);
mStopForeground = getClass().getMethod("stopForeground",
mStopForegroundSignature);
} catch (NoSuchMethodException e) {
// Running on an older platform.
mStartForeground = mStopForeground = null;
}
}
#Override
public void onDestroy() {
//debug: log.i("Detector","Service.Ondestroy");
mThread.interrupt();
// Make sure our notification is gone.
stopForegroundCompat(R.string.service_running);
}
// This is the old onStart method that will be called on the pre-2.0
// platform. On 2.0 or later we override onStartCommand() so this
// method will not be called.
#Override
public void onStart(Intent intent, int startId) {
//debug: log.i("Detector","Service.Onstart");
handleCommand(intent);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
//debug: log.i("Detector","Service.OnStartCommand");
handleCommand(intent);
// We want this service to continue running until it is explicitly
// stopped, so return sticky.
return Service.START_STICKY;
}
private void handleCommand(Intent intent){
// In this sample, we'll use the same text for the ticker and the expanded notification
CharSequence text = getText(R.string.service_running);
// Set the icon, scrolling text and timestamp
Notification notification = new Notification(R.drawable.statusbar_icon, text,
System.currentTimeMillis());
// The PendingIntent to launch our activity if the user selects this notification
PendingIntent contentIntent = PendingIntent.getActivity(this, 0,
new Intent(this, AppLockerActivity.class), 0);
// Set the info for the views that show in the notification panel.
notification.setLatestEventInfo(this, text,
text, contentIntent);
startForegroundCompat(R.string.service_running, notification);
startMonitorThread((ActivityManager)this.getSystemService(Context.ACTIVITY_SERVICE));
}
private void startMonitorThread(final ActivityManager am){
if (mThread!=null)
mThread.interrupt();
mThread = new MonitorlogThread(new ActivityStartingHandler(this));
mThread.start();
}
private static Thread mThread;
private static boolean constantInited = false;
private static Pattern ActivityNamePattern;
private static String logCatCommand;
private static String ClearlogCatCommand;
private void initConstant() {
//debug: log.i("Detector","Service.OninitConstant");
if (constantInited) return;
String pattern = getResources().getString(R.string.activity_name_pattern);
//debug: log.d("Detector", "pattern: " + pattern);
ActivityNamePattern = Pattern.compile(pattern, Pattern.CASE_INSENSITIVE);
logCatCommand = getResources().getString(R.string.logcat_command);
ClearlogCatCommand = getResources().getString(R.string.logcat_clear_command);
}
MonitorlogThread
private class MonitorlogThread extends Thread{
ActivityStartingListener mListener;
public MonitorlogThread(ActivityStartingListener listener){
//debug: log.i("Detector","Monitor//debug: logThread");
mListener = listener;
}
BufferedReader br;
private Context context;
#Override
public void run() {
//debug: log.i("Detector","RUN!");
while(!this.isInterrupted() ){
try {
Thread.sleep(100);
////debug: log.i("Detector","try!");
//This is the code I use in my service to identify the current foreground application, its really easy:
ActivityManager am = (ActivityManager) getBaseContext().getSystemService(ACTIVITY_SERVICE);
// The first in the list of RunningTasks is always the foreground task.
//Toast.makeText(context, "App------>7", Toast.LENGTH_SHORT).show();
Log.d("Android", "App------>7----"+am);
//RunningTaskInfo foregroundTaskInfo = am.getRunningTasks(1).get(0);
RunningTaskInfo foregroundTaskInfo = am.getRunningTasks(1).get(0);
Log.d("Android", "App------>8----"+foregroundTaskInfo);
//Toast.makeText(context, "App------>7"+foregroundTaskInfo, Toast.LENGTH_SHORT).show();
//Thats it, then you can easily access details of the foreground app/activity:
String foregroundTaskPackageName = foregroundTaskInfo.topActivity.getPackageName();
PackageManager pm = getBaseContext().getPackageManager();
PackageInfo foregroundAppPackageInfo = null;
String foregroundTaskAppName = null;
String foregroundTaskActivityName = foregroundTaskInfo.topActivity.getShortClassName().toString();
try {
foregroundAppPackageInfo = pm.getPackageInfo(foregroundTaskPackageName, 0);
foregroundTaskAppName = foregroundAppPackageInfo.applicationInfo.loadLabel(pm).toString();
//debug: log.i("Detector",foregroundTaskAppName);
} catch (NameNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if (mListener!=null){
//mListener.onActivityStarting(foregroundAppPackageInfo.packageName,foregroundTaskAppName);
mListener.onActivityStarting(foregroundAppPackageInfo.packageName,foregroundTaskActivityName);
}
} catch (InterruptedException e) {
// good practice
Thread.currentThread().interrupt();
return;
}
}
}
}
Use this code for above 5.0
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
try {
UsageStatsManager usageStatsManager = (UsageStatsManager) ctx.getSystemService("usagestats");
long milliSecs = 60 * 1000;
Date date = new Date();
List<UsageStats> queryUsageStats = usageStatsManager.queryUsageStats(UsageStatsManager.INTERVAL_DAILY, date.getTime() - milliSecs, date.getTime());
if (queryUsageStats.size() > 0) {
Log.i(TAG, "UsageStats size: " + queryUsageStats.size());
}
long recentTime = 0;
String recentPkg = "";
for (int i = 0; i < queryUsageStats.size(); i++) {
UsageStats stats = queryUsageStats.get(i);
if (i == 0 && !getPackageName().equals(stats.getPackageName())) {
Log.i(TAG, "PackageName: " + stats.getPackageName() + " " + stats.getLastTimeStamp());
}
if (stats.getLastTimeStamp() > recentTime) {
String recentTime = stats.getLastTimeStamp();
String recentPkg = stats.getPackageName();
}
};
} catch (Exception e) {
e.printStackTrace();
}
}
Can you try this.
ActivityManager am = (ActivityManager) getBaseContext().getSystemService(ACTIVITY_SERVICE);
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT) {
ActivityManager.RunningAppProcessInfo runningAppProcessInfo = (ActivityManager.RunningAppProcessInfo) am.getRunningAppProcesses();
String foregroundTaskPackageName = runningAppProcessInfo.pkgList.getClass().getPackage().getName();
PackageManager pm = getBaseContext().getPackageManager();
PackageInfo foregroundAppPackageInfo = null;
String foregroundTaskAppName = null;
String foregroundTaskActivityName = runningAppProcessInfo.pkgList.getClass().getName();
try {
foregroundAppPackageInfo = pm.getPackageInfo(foregroundTaskPackageName, 0);
foregroundTaskAppName = foregroundAppPackageInfo.applicationInfo.loadLabel(pm).toString();
//debug: log.i("Detector",foregroundTaskAppName);
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
} else {
ActivityManager.RunningTaskInfo foregroundTaskInfo = am.getRunningTasks(1).get(0);
String foregroundTaskPackageName = foregroundTaskInfo.topActivity.getPackageName();
PackageManager pm = getBaseContext().getPackageManager();
PackageInfo foregroundAppPackageInfo = null;
String foregroundTaskAppName = null;
String foregroundTaskActivityName = foregroundTaskInfo.topActivity.getShortClassName().toString();
try {
foregroundAppPackageInfo = pm.getPackageInfo(foregroundTaskPackageName, 0);
foregroundTaskAppName = foregroundAppPackageInfo.applicationInfo.loadLabel(pm).toString();
//debug: log.i("Detector",foregroundTaskAppName);
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
}
Use RunningAppProcessInfo instead of getRunningTasks for SDK versions greater than KitKat.
ActivityManager am = (ActivityManager) getBaseContext().getSystemService(Context.ACTIVITY_SERVICE);
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT) {
List<ActivityManager.RunningAppProcessInfo> runningProcesses = am.getRunningAppProcesses();
...
} else {
List<ActivityManager.RunningTaskInfo> taskInfo = am.getRunningTasks(1);
...
}
I am creating a music player in Android, but unfortunately Mediaplayer stops unexpectedly. If app being opened, there is no problem. But when app go to background, it stops without showing any logs.
Does anyone know what is the reason?
Thanks in advance
public class MusicService extends Service implements MediaPlayer.OnPreparedListener,
MediaPlayer.OnErrorListener, MediaPlayer.OnCompletionListener {
private boolean checkError = true;
public MediaPlayer mPlayer;
private Uri mSongUri;
private Bitmap mSongBitmap;
public static PlayingFragment playingFragment;
private int songDuration;
private ArrayList<Song> mListSongs;
private int SONG_POS = 0;
private final IBinder musicBind = new PlayerBinder();
private final String ACTION_STOP = "com.emptylist.tabplayer.STOP";
private final String ACTION_NEXT = "com.emptylist.tabplayer.NEXT";
private final String ACTION_PREVIOUS = "com.emptylist.tabplayer.PREVIOUS";
private final String ACTION_PAUSE = "com.emptylist.tabplayer.PAUSE";
public static final int STATE_PAUSED = 1;
public static final int STATE_PLAYING = 2;
public int mState = 0;
private static final int REQUEST_CODE_PAUSE = 101;
private static final int REQUEST_CODE_PREVIOUS = 102;
private static final int REQUEST_CODE_NEXT = 103;
private static final int REQUEST_CODE_STOP = 104;
public static int NOTIFICATION_ID = 11;
private Notification.Builder notificationBuilder;
private Notification mNotification;
private SharedPreferences prefs;
private SharedPreferences.Editor editor;
public class PlayerBinder extends Binder {
public MusicService getService() {
Log.d("test", "getService()");
return MusicService.this;
}
}
#Override
public IBinder onBind(Intent intent) {
Log.d("test", "onBind Called ");
return musicBind;
}
#Override
public void onCreate() {
super.onCreate();
mPlayer = new MediaPlayer();
initPlayer();
mPlayer.setOnPreparedListener(this);
mPlayer.setOnCompletionListener(this);
mPlayer.setOnErrorListener(this);
notificationBuilder = new Notification.Builder(getApplicationContext());
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (intent != null) {
String action = intent.getAction();
if (!TextUtils.isEmpty(action)) {
if (action.equals(ACTION_PAUSE)) {
playPauseSong();
} else if (action.equals(ACTION_NEXT)) {
nextSong();
} else if (action.equals(ACTION_PREVIOUS)) {
previousSong();
} else if (action.equals(ACTION_STOP)) {
stopSong();
stopSelf();
}
}
}
return super.onStartCommand(intent, flags, startId);
}
#Override
public boolean onUnbind(Intent intent) {
mPlayer.stop();
mPlayer.release();
return false;
}
#Override
public void onCompletion(MediaPlayer mp) {
if (checkError == false) {
startSong(mListSongs.get(SONG_POS).getSongUri(), mListSongs.get(SONG_POS).getSongName(), mListSongs.get(SONG_POS).getmSongAlbumArt(), SONG_POS);
checkError = true;
} else {
mPlayer.reset();
try {
if (SONG_POS != mListSongs.size() - 1) {
SONG_POS++;
setSongDetails(SONG_POS);
} else {
SONG_POS = 0;
setSongDetails(SONG_POS);
}
mPlayer.setDataSource(getApplicationContext(), mListSongs.get(SONG_POS).getSongUri());
} catch (Exception e) {
Log.e("MUSIC SERVICE", "Error setting data source", e);
}
mPlayer.prepareAsync();
if (mState == STATE_PLAYING) {
MainActivity.imgPlayPause.setImageResource(R.drawable.pause);
} else
MainActivity.imgPlayPause.setImageResource(R.drawable.play);
editor = getSharedPreferences("MusicPref", MODE_PRIVATE).edit();
editor.putInt("SongPosition", SONG_POS);
editor.putString("SongURI", mListSongs.get(SONG_POS).getSongUri().toString());
editor.commit();
}
}
#Override
public boolean onError(MediaPlayer mp, int what, int extra) {
Log.d("EEE", String.valueOf(what) + "," + String.valueOf(extra));
checkError = false;
return false;
}
#Override
public void onPrepared(MediaPlayer mp) {
mp.start();
new ProgressUpdater();
}
private void initPlayer() {
mPlayer.setWakeMode(getApplicationContext(), PowerManager.PARTIAL_WAKE_LOCK);
mPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
if (android.os.Build.VERSION.SDK_INT > android.os.Build.VERSION_CODES.KITKAT) {
try {
Class<?> cMediaTimeProvider = Class.forName("android.media.MediaTimeProvider");
Class<?> cSubtitleController = Class.forName("android.media.SubtitleController");
Class<?> iSubtitleControllerAnchor = Class.forName("android.media.SubtitleController$Anchor");
Class<?> iSubtitleControllerListener = Class.forName("android.media.SubtitleController$Listener");
Constructor constructor = cSubtitleController.getConstructor(new Class[]{Context.class, cMediaTimeProvider, iSubtitleControllerListener});
Object subtitleInstance = constructor.newInstance(getApplicationContext(), null, null);
Field f = cSubtitleController.getDeclaredField("mHandler");
f.setAccessible(true);
try {
f.set(subtitleInstance, new Handler());
} catch (IllegalAccessException e) {
} finally {
f.setAccessible(false);
}
Method setsubtitleanchor = mPlayer.getClass().getMethod("setSubtitleAnchor", cSubtitleController, iSubtitleControllerAnchor);
setsubtitleanchor.invoke(mPlayer, subtitleInstance, null);
//Log.e("", "subtitle is setted :p");
} catch (Exception e) {
}
}
}
public void startSong(Uri songuri, String songName, Bitmap bitmap, int position) {
//Set data & start playing music
setSongDetails(position);
mPlayer.reset();
mState = STATE_PLAYING;
mSongUri = songuri;
mSongBitmap = bitmap;
try {
mPlayer.setDataSource(getApplicationContext(), mSongUri);
} catch (Exception e) {
Log.e("MUSIC SERVICE", "Error setting data source", e);
}
mPlayer.prepareAsync();
if (mState == STATE_PLAYING) {
MainActivity.imgPlayPause.setImageResource(R.drawable.pause);
} else {
MainActivity.imgPlayPause.setImageResource(R.drawable.play);
}
Log.d("EEESonfPOs", String.valueOf(position));
editor = getSharedPreferences("MusicPref", MODE_PRIVATE).edit();
editor.putInt("SongPosition", SONG_POS);
editor.putString("SongURI", mListSongs.get(SONG_POS).getSongUri().toString());
editor.commit();
updateNotification(songName);
}
public void playPauseSong() {
if (mState == STATE_PAUSED) {
mState = STATE_PLAYING;
mPlayer.start();
MainActivity.imgPlayPause.setImageResource(R.drawable.pause);
} else {
mState = STATE_PAUSED;
mPlayer.pause();
MainActivity.imgPlayPause.setImageResource(R.drawable.play);
}
}
public boolean isPlayingg() {
return mPlayer.isPlaying();
}
public int getPosn() {
return mPlayer.getCurrentPosition();
}
public int getDur() {
int n = songDuration;
return songDuration;
}
public void pausePlayer() {
mPlayer.pause();
}
private void setSongDetails(int position) {
MediaMetadataRetriever mmr = new MediaMetadataRetriever();
byte[] rawArt;
Bitmap art = null;
BitmapFactory.Options bfo = new BitmapFactory.Options();
mmr.setDataSource(getApplicationContext(), mListSongs.get(position).getSongUri());
rawArt = mmr.getEmbeddedPicture();
// if rawArt is null then no cover art is embedded in the file or is not
// recognized as such.
if (null != rawArt) {
Bitmap bm = Bitmap.createScaledBitmap(BitmapFactory.decodeByteArray(rawArt, 0, rawArt.length, bfo),
100, 100,
true);
MainActivity.imgSongArt.setImageBitmap(bm);
MainActivity.tvSongName.setText(mListSongs.get(position).getSongName());
MainActivity.tvSongArtist.setText(mListSongs.get(position).getmSongArtist());
} else {
MainActivity.imgSongArt.setImageResource(R.drawable.default_album_art);
MainActivity.tvSongName.setText(mListSongs.get(position).getSongName());
MainActivity.tvSongArtist.setText(mListSongs.get(position).getmSongArtist());
}
}
public void stopSong() {
mPlayer.stop();
NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
manager.cancel(NOTIFICATION_ID);
//System.exit(0);
}
public void nextSong() {
if (SONG_POS != mListSongs.size() - 1) {
startSong(mListSongs.get(SONG_POS + 1).getSongUri(), mListSongs.get(SONG_POS + 1).getSongName(), mListSongs.get(SONG_POS + 1).getmSongAlbumArt(), SONG_POS + 1);
SONG_POS++;
} else {
SONG_POS = 0;
startSong(mListSongs.get(0).getSongUri(), mListSongs.get(0).getSongName(), mListSongs.get(0).getmSongAlbumArt(), 0);
}
editor = getSharedPreferences("MusicPref", MODE_PRIVATE).edit();
editor.putInt("SongPosition", SONG_POS);
editor.putString("SongURI", mListSongs.get(SONG_POS).getSongUri().toString());
editor.commit();
}
public void previousSong() {
if (SONG_POS != 0) {
startSong(mListSongs.get(SONG_POS - 1).getSongUri(), mListSongs.get(SONG_POS - 1).getSongName(), mListSongs.get(SONG_POS - 1).getmSongAlbumArt(), SONG_POS - 1);
SONG_POS--;
} else {
startSong(mListSongs.get(mListSongs.size() - 1).getSongUri(), mListSongs.get(mListSongs.size() - 1).getSongName(), mListSongs.get(mListSongs.size() - 1).getmSongAlbumArt(), mListSongs.size() - 1);
SONG_POS = mListSongs.size() - 1;
}
editor = getSharedPreferences("MusicPref", MODE_PRIVATE).edit();
editor.putInt("SongPosition", SONG_POS);
editor.putString("SongURI", mListSongs.get(SONG_POS).getSongUri().toString());
editor.commit();
}
public void setSongURI(Uri uri) {
this.mSongUri = uri;
}
public void setmSongBitmap(Bitmap mSongBitmap) {
this.mSongBitmap = mSongBitmap;
}
public void setSelectedSong(int pos, int notification_id) {
SONG_POS = pos;
NOTIFICATION_ID = notification_id;
setSongURI(mListSongs.get(SONG_POS).getSongUri());
setmSongBitmap(mListSongs.get(SONG_POS).getmSongAlbumArt());
showNotification();
startSong(mListSongs.get(SONG_POS).getSongUri(), mListSongs.get(SONG_POS).getSongName(), mListSongs.get(SONG_POS).getmSongAlbumArt(), SONG_POS);
}
public void setSongList(ArrayList<Song> listSong) {
mListSongs = listSong;
}
public void showNotification() {
PendingIntent pendingIntent;
Intent intent;
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
RemoteViews notificationView = new RemoteViews(getPackageName(), R.layout.notification_mediacontroller);
notificationView.setTextViewText(R.id.notify_song_name, mListSongs.get(SONG_POS).getSongName());
intent = new Intent(ACTION_STOP);
pendingIntent = PendingIntent.getService(getApplicationContext(), REQUEST_CODE_STOP, intent, PendingIntent.FLAG_UPDATE_CURRENT);
notificationView.setOnClickPendingIntent(R.id.notify_btn_stop, pendingIntent);
intent = new Intent(ACTION_PAUSE);
pendingIntent = PendingIntent.getService(getApplicationContext(), REQUEST_CODE_PAUSE, intent, PendingIntent.FLAG_UPDATE_CURRENT);
notificationView.setOnClickPendingIntent(R.id.notify_btn_pause, pendingIntent);
intent = new Intent(ACTION_PREVIOUS);
pendingIntent = PendingIntent.getService(getApplicationContext(), REQUEST_CODE_PREVIOUS, intent, PendingIntent.FLAG_UPDATE_CURRENT);
notificationView.setOnClickPendingIntent(R.id.notify_btn_previous, pendingIntent);
intent = new Intent(ACTION_NEXT);
pendingIntent = PendingIntent.getService(getApplicationContext(), REQUEST_CODE_NEXT, intent, PendingIntent.FLAG_UPDATE_CURRENT);
notificationView.setOnClickPendingIntent(R.id.notify_btn_next, pendingIntent);
mNotification = notificationBuilder
.setSmallIcon(R.drawable.ic_launcher).setOngoing(true)
.setWhen(System.currentTimeMillis())
.setContent(notificationView)
.setDefaults(Notification.FLAG_NO_CLEAR)
.build();
notificationManager.notify(NOTIFICATION_ID, mNotification);
}
private void updateNotification(String songName) {
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
mNotification.contentView.setTextViewText(R.id.notify_song_name, songName);
mNotification.contentView.setImageViewBitmap(R.id.img_notification, mListSongs.get(SONG_POS).getmSongAlbumArt());
notificationManager.notify(NOTIFICATION_ID, mNotification);
}
}
I think you need to release media player reference in the onPause method. Try it out. It may work!
I have android background service to connect with my RabbitMQ server. My background service listen incoming rabbitmq message. Everything is working well but the problem is appear while screen goes off. My android client disconnect when phone screen goes off. What should I do to always connected with my android rabbitmq client and rabbitmq server ?
My code are below :
public class RabbitmqPushService extends Service{
private Thread subscribeThread;
private ConnectionFactory factory;
private Connection connectionSubscribe;
private Channel channelSubscribe;
private NotificationManager mNotificationManager;
public static int NOTIFICATION_ID = 0;
private static final String HOST_NAME = Constant.HOST_NAME; //Rabbitmq Host Name
private static final int PORT_ADDRESS = 5672;
private static final String EXCHANGE_NAME = "fanout_msg";
private static String QUEUE_NAME = Constant.phone_number+"_queue"; //Queue Name
private static String[] ROUTE_KEY = {"all", Constant.phone_number};
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
NOTIFICATION_ID = 0;
setupConnectionFactory();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
if(connectionSubscribe != null)
{
if(!connectionSubscribe.isOpen())
{
connect();
}
}
else
{
connect();
}
return Service.START_STICKY;
}
#Override
public void onDestroy() {
if(connectionSubscribe != null)
{
disconnectSubscribe();
}
NOTIFICATION_ID = 0;
}
private void setupConnectionFactory() {
factory = new ConnectionFactory();
factory.setHost(HOST_NAME);
factory.setPort(PORT_ADDRESS);
factory.setUsername(Constant.USERNAME);
factory.setPassword(Constant.PASSWORD);
factory.setRequestedHeartbeat(60);
}
private void connect()
{
final Handler incomingMessageHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
String message = msg.getData().getString("msg");
try {
JSONObject jsonObject = new JSONObject(message);
BeepHelper.msgBeep(getApplicationContext());
sendNotification("From : " + jsonObject.getString("from"), jsonObject.getString("message"));
} catch (JSONException e) {
e.printStackTrace();
}
}
};
subscribe(incomingMessageHandler);
publishToAMQP();
}
private void disconnectSubscribe()
{
subscribeThread.interrupt();
try {
channelSubscribe.close();
connectionSubscribe.close();
} catch (IOException e) {
e.printStackTrace();
}
catch (TimeoutException e) {
e.printStackTrace();
}
}
void subscribe(final Handler handler)
{
subscribeThread = new Thread()
{
#Override
public void run() {
while(true) {
try {
connectionSubscribe = factory.newConnection();
channelSubscribe = connectionSubscribe.createChannel();
channelSubscribe.exchangeDeclare(EXCHANGE_NAME, "fanout");
channelSubscribe.queueDeclare(QUEUE_NAME, true, false, false, null);
for(int i = 0; i<ROUTE_KEY.length; i++)
{
channelSubscribe.queueBind(QUEUE_NAME, EXCHANGE_NAME, ROUTE_KEY[i]);
}
QueueingConsumer consumer = new QueueingConsumer(channelSubscribe);
channelSubscribe.basicConsume(QUEUE_NAME, false, consumer);
while (true) {
QueueingConsumer.Delivery delivery = consumer.nextDelivery();
String message = new String(delivery.getBody());
Message msg = handler.obtainMessage();
Bundle bundle = new Bundle();
bundle.putString("msg", message);
msg.setData(bundle);
handler.sendMessage(msg);
channelSubscribe.basicAck(delivery.getEnvelope().getDeliveryTag(), false);
}
} catch (InterruptedException e) {
break;
} catch (Exception e1) {
try {
Thread.sleep(4000); //sleep and then try again
} catch (InterruptedException e) {
break;
}
}
}
}
};
subscribeThread.start();
}
#Override
public void publishMessage(String message) {
try {
queue.putLast(message);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private void sendNotification(String title, String msg) {
mNotificationManager = (NotificationManager)
getApplicationContext().getSystemService(Context.NOTIFICATION_SERVICE);
PendingIntent contentIntent = PendingIntent.getActivity(getApplicationContext(), 0,
new Intent(getApplicationContext(), MainActivity.class), 0);
NotificationCompat.Builder mBuilder =
new NotificationCompat.Builder(getApplicationContext())
.setSmallIcon(R.mipmap.ic_launcher)
.setContentTitle(title)
.setStyle(new NotificationCompat.BigTextStyle()
.bigText(msg))
.setContentText(msg);
mBuilder.setContentIntent(contentIntent);
mNotificationManager.notify(NOTIFICATION_ID++, mBuilder.build());
}
}
You need a Wake Lock to keep the phone running when screen is off. Wake locks allow your application to control the power state of the host device.
Add the WAKE_LOCK permission to your application's manifest file:
<uses-permission android:name="android.permission.WAKE_LOCK" />
Then add the following in onCreate():
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
wakelock= pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, getClass().getCanonicalName());
wakelock.acquire();
If your app includes a broadcast receiver that uses a service to do some work, you can manage your wake lock through a WakefulBroadcastReceiver. This is the preferred approach. If your app doesn't follow that pattern, you set a wake lock directly.