Accessing context from another thread - java

I am starting to migrate some PC Java applications to Android environments being a complete newbie concerning Android platform.
I found a problem when I tried to use a Service reference as context for a Toast message.
This is the relevant part of my Service code:
public class ServicePFPE extends Service {
Timer messageSimulator;
TimerTask messagePoll;
private class MessageReceptionTask extends TimerTask
{
public MessageReceptionTask(Context c) {
context = c;
}
#Override
public void run() {
String shownText = "Message received!! on " + (new Date(System.currentTimeMillis())).toString();
//doToast(shownText, context); //THIS LINE MAKES THE APP CRASH!
System.out.println(shownText); //But I can do this
}
private Context context;
}
public ServicePFPE() {
super();
messageSimulator = new Timer();
messagePoll = new MessageReceptionTask(this);
}
#Override
public IBinder onBind(Intent intent)
{
doToast("Service: onBind");
return null;
}
...
...
...
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
doToast("Service: onStartCommand");
messageSimulator.schedule(messagePoll, 5000, 5000);
return super.onStartCommand(intent, flags, startId);
}
...
...
...
private void doToast(String msg) { doToast(msg, this); }
private void doToast(String msg, Context con) {
Toast.makeText(con,msg,Toast.LENGTH_SHORT).show();
}
}
When the scheduled task runs reaching doToast call Android notifies that "Unfortunatelly, myAPP has stopped".
I think it has something to do with the fact I am using the service context in a different thread but I don't know for sure.
Could you confirm if that is the case? What is the right way to run a timer from a service and be able to use its context? If that is not possible, can I get a context for that thread so I can generate Toasts user messages.

It depends on what you really need, if you are planning to show simple notifications, maybe instead of toasts you can use Android notification bar (which is the standard way to show them). For example you can use:
/**
* Show a notification while this service is running.
*/
private void showNotification() {
// In this sample, we'll use the same text for the ticker and the expanded notification
CharSequence text = getText(R.string.local_service_started);
NotificationManager mNM;
mNM = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
// Set the icon, scrolling text and timestamp
Notification notification = new Notification(R.drawable.stat_sample, text,
System.currentTimeMillis());
// The PendingIntent to launch our activity if the user selects this notification
PendingIntent contentIntent = PendingIntent.getActivity(this, 0,
new Intent(this, LocalServiceActivities.Controller.class), 0);
// Set the info for the views that show in the notification panel.
notification.setLatestEventInfo(this, getText(R.string.local_service_label),
text, contentIntent);
// Send the notification.
mNM.notify(NOTIFICATION, notification);
}
however, if you just want toasts, you can show them from the service, your problem is that the timertask is being executed in a different thread that the UI thread (where the service is running). to "post" this code to the UI thread you can do it directly with something like this:
Handler handler;
#Override
public void onCreate() {
// Handler will get associated with the current thread,
// which is the main thread.
handler = new Handler();
super.onCreate();
}
private void runOnUiThread(Runnable runnable) {
handler.post(runnable);
}
Source
And finally if you want fully interaction between service and activities, you have several ways:
Use binders, for simple communications, this is moreless what you need.
Use a messenger, to more complicated communications.
If you only need dialogs you are always able to launch new activities in dialog mode.
AIDL...
Documentation about 1 & 2 here and here
Binders:
They let you bind different objects in your application letting them access directly to the object itself and its functions, example from android doc:
public class LocalService extends Service {
// Binder given to clients
private final IBinder mBinder = new LocalBinder();
// Random number generator
private final Random mGenerator = new Random();
/**
* Class used for the client Binder. Because we know this service always
* runs in the same process as its clients, we don't need to deal with IPC.
*/
public class LocalBinder extends Binder {
LocalService getService() {
// Return this instance of LocalService so clients can call public methods
return LocalService.this;
}
}
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
/** method for clients */
public int getRandomNumber() {
return mGenerator.nextInt(100);
}
}
public class BindingActivity extends Activity {
LocalService mService;
boolean mBound = false;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
#Override
protected void onStart() {
super.onStart();
// Bind to LocalService
Intent intent = new Intent(this, LocalService.class);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
}
#Override
protected void onStop() {
super.onStop();
// Unbind from the service
if (mBound) {
unbindService(mConnection);
mBound = false;
}
}
/** Called when a button is clicked (the button in the layout file attaches to
* this method with the android:onClick attribute) */
public void onButtonClick(View v) {
if (mBound) {
// Call a method from the LocalService.
// However, if this call were something that might hang, then this request should
// occur in a separate thread to avoid slowing down the activity performance.
int num = mService.getRandomNumber();
Toast.makeText(this, "number: " + num, Toast.LENGTH_SHORT).show();
}
}
/** Defines callbacks for service binding, passed to bindService() */
private ServiceConnection mConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName className,
IBinder service) {
// We've bound to LocalService, cast the IBinder and get LocalService instance
LocalBinder binder = (LocalBinder) service;
mService = binder.getService();
mBound = true;
}
#Override
public void onServiceDisconnected(ComponentName arg0) {
mBound = false;
}
};
}
Messenger:
More advanced & complicated, in this way you can send messages from one object to another:
public class MessengerService extends Service {
/** Command to the service to display a message */
static final int MSG_SAY_HELLO = 1;
/**
* Handler of incoming messages from clients.
*/
class IncomingHandler extends Handler {
#Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_SAY_HELLO:
Toast.makeText(getApplicationContext(), "hello!", Toast.LENGTH_SHORT).show();
break;
default:
super.handleMessage(msg);
}
}
}
/**
* Target we publish for clients to send messages to IncomingHandler.
*/
final Messenger mMessenger = new Messenger(new IncomingHandler());
/**
* When binding to the service, we return an interface to our messenger
* for sending messages to the service.
*/
#Override
public IBinder onBind(Intent intent) {
Toast.makeText(getApplicationContext(), "binding", Toast.LENGTH_SHORT).show();
return mMessenger.getBinder();
}
}
public class ActivityMessenger extends Activity {
/** Messenger for communicating with the service. */
Messenger mService = null;
/** Flag indicating whether we have called bind on the service. */
boolean mBound;
/**
* Class for interacting with the main interface of the service.
*/
private ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
// This is called when the connection with the service has been
// established, giving us the object we can use to
// interact with the service. We are communicating with the
// service using a Messenger, so here we get a client-side
// representation of that from the raw IBinder object.
mService = new Messenger(service);
mBound = true;
}
public void onServiceDisconnected(ComponentName className) {
// This is called when the connection with the service has been
// unexpectedly disconnected -- that is, its process crashed.
mService = null;
mBound = false;
}
};
public void sayHello(View v) {
if (!mBound) return;
// Create and send a message to the service, using a supported 'what' value
Message msg = Message.obtain(null, MessengerService.MSG_SAY_HELLO, 0, 0);
try {
mService.send(msg);
} catch (RemoteException e) {
e.printStackTrace();
}
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
#Override
protected void onStart() {
super.onStart();
// Bind to the service
bindService(new Intent(this, MessengerService.class), mConnection,
Context.BIND_AUTO_CREATE);
}
#Override
protected void onStop() {
super.onStop();
// Unbind from the service
if (mBound) {
unbindService(mConnection);
mBound = false;
}
}
}
In case you want to show activities as fancy dialogs to show the updates you can use a regular activity with this theme:
<activity android:theme="#android:style/Theme.Dialog" />

Any UI related code should be ran on the UI thread using RunOnUiThread method.

you should set a global context like this:
public static Activity currentActivity=null;
and after run your main activity or any activity that runs service set context like this:
MainActivity.currentActivity = this;
after that in toast use this context:
Toast.makeText(MainActivity.currentActivity," text", Toast.LENGTH_LONG);
hope use full

Related

Service doesn't work properly when device go to sleep mode

I created a simple android app that will send notification every minutes. For that I use Service in this app. Look the Service code bellow.
public class notiService extends Service {
private final static int interval = 1000 * 60;
Handler myHandler;
Runnable myRunable;
MediaPlayer mp;
Intent intent;
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
super.onCreate();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
mp = MediaPlayer.create(this,R.raw.noti2);
createRunnable();
startHandler();
return Service.START_STICKY;
}
#Override
public void onDestroy() {
/**
* Destroy Handler and Runnable
*/
myHandler.removeCallbacks(myRunable);
super.onDestroy ();
}
/**
* Runnable method
*/
public void createRunnable(){
myRunable = new Runnable() {
#Override
public void run() {
mp.start();
send_notification("Notification title", "10");
myHandler.postDelayed(this, interval); /* The interval time */
}
};
}
/**
* Handler method
*/
public void startHandler(){
myHandler = new Handler();
myHandler.postDelayed(myRunable, 0);
}
/**
* Notification method
*/
public void send_notification(String title, String min){
intent = new Intent(getApplicationContext(),MainActivity.class);
//intent.putExtra("open_fragment","open_f2");
PendingIntent my_pIntent = PendingIntent.getActivities(notiService.this,0, new Intent[]{intent},0);
Notification mynoti = new Notification.Builder(notiService.this)
.setContentTitle(title)
.setContentText("It will be start after "+min+" minutes.")
.setSmallIcon(R.mipmap.ic_launcher)
.setContentIntent(my_pIntent).getNotification();
mynoti.flags = Notification.FLAG_AUTO_CANCEL;
NotificationManager nm = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
nm.notify(0,mynoti);
}
}
It work properly when the app running. But if I close the app and device go to sleep mode, this code don't work properly.
This time it send notification after 10 minutes or more.
I can't understand why it behave like this! How I can fixed this problem?
Thank you for your response.
you are using handler for this. Handler does not work when device goes to sleep . you can see this link for running handler in sleep mode

Android Request to server before application compeletly closed

I have just one Activity , when user close the application (from os clear list of recent apps) I want to send a request to my server api and change user status.
so I make IntentService and call it in my onDestroy() method of activity, but it dosn't work. how do it? is there any way else to do this(send request to server before application killed compeletly)?
my code :
Activity:
#Override
protected void onDestroy() {
Intent intent = new Intent(this, MakeOfflineIntentService.class);
intent.putExtra(Variables.INTENT_TOKEN, Token);
intent.setAction("ACTION_MAKE_OFFLINE");
startService(intent);
super.onDestroy();
}
and in my IntentService:
public class MakeOfflineIntentService extends IntentService {
private static final String ACTION_MAKE_OFFLINE = "ACTION_MAKE_OFFLINE";
private static final String EXTRA_TOKEN = Variables.INTENT_TOKEN;
public MakeOfflineIntentService() {
super("MakeOfflineIntentService");
}
public static void startActionFoo(Context context, String param1) {
Intent intent = new Intent(context, MakeOfflineIntentService.class);
intent.setAction(ACTION_MAKE_OFFLINE);
intent.putExtra(EXTRA_TOKEN, param1);
context.startService(intent);
}
#Override
protected void onHandleIntent(Intent intent) {
if (intent != null) {
final String action = intent.getAction();
if (ACTION_MAKE_OFFLINE.equals(action)) {
final String param1 = intent.getStringExtra(EXTRA_TOKEN);
retrofitBaseInformationChange(param1,Variables.OFFLINE,1);
}
}
}
private void retrofitBaseInformationChange(final String Token, final int online, int vehicle){
RetrofitCallServer retrofitCallServer = new RetrofitCallServer(WebServiceUrls.RETROFIT_INFORMATION_CHEETAH_MAN);
OnCallBackRetrofit onCallBackRetrofit = retrofitCallServer.getResponse();
Call<OBRbaseInfromationChange> call = onCallBackRetrofit.askBaseInformationChange(Token,online,vehicle);
call.enqueue(new Callback<OBRbaseInfromationChange>() {
#Override
public void onResponse(Call<OBRbaseInfromationChange> call, Response<OBRbaseInfromationChange> response) {
/*response gotten maybe success or not*/
if (response.isSuccessful()){
OBRbaseInfromationChange obr = response.body();
if(obr.code == 200){
Log.i(Variables.APP_TAG,"BaseInformationChange successful");
}
else{
Log.i(Variables.APP_TAG,"BaseInformationChange error code: "+obr.code);
}
}// end if response successful
else {
Log.i(Variables.APP_TAG,"BaseInformationChange not Successful: "+response.code());
}
}
#Override
public void onFailure(Call<OBRbaseInfromationChange> call, Throwable t) {
/*our request not sent or conversion problem*/
Log.i(Variables.APP_TAG,"onFailure BaseInformationChange: "+t.getMessage());
}
});
}
// end retrofitBaseInformationChange()
}
and finally here is in my manifest:
<service
android:name=".Services.MakeOfflineIntentService"
android:exported="false"
android:stopWithTask="false"/>
Have you tried to return START_STICKY in the onStartCommand override?
After you sent your request you can then call stopService to stop yourself.
As far as I know, even sticky services might be "recreated" when you kill the app. So maybe, an Intent is not the best way to use here.
I'd go with SharedPreferences here:
The onCreate of your app sets the key "app_offline" to "false"
The onDestroy sets this key to "true" and starts the service
The service is START_STICKY and when it finds the "app_offline" as true, sends its request, updates "app_offline" to false (resets it) and then performs a self-shutdown.
Something like that.
Hope this helps, cheers, Gris
thanks for Grisgram answer, I solve the issue and paste my code here for more complete answer :
I make a variable in SharedPreferences name IS_APP_CLOSED.
when application open in onCreate :
saveL.saveInLocalStorage(Variables.IS_APP_CLOSED,false);
startServiceToMakeOffline();
method startServiceToMakeOffline() is :
private void startServiceToMakeOffline(){
Intent intent= new Intent(this, MakeOfflineService.class);
startService(intent);
}
in onDestroy of this activity :
#Override
protected void onDestroy() {
saveL.saveInLocalStorage(Variables.IS_APP_CLOSED,true);
super.onDestroy();
}
and here is my service class :
public class MakeOfflineService extends Service {
private boolean isAppClosed = false;
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
loadInfoFromLocalStorage();
if(isAppClosed){
askServer();
}
return Service.START_STICKY;
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
private void loadInfoFromLocalStorage() {
SharedPreferences prefs = getApplicationContext().getSharedPreferences(Variables.CHEETAH_NORMAL, 0);
isAppClosed = prefs.getBoolean(Variables.IS_APP_CLOSED, false);
prefs = null;
}
// end loadInfoFromLocalStorage()
private void askServer() {
//TODO: request server than when result gotten:
stopSelf();
}
}
and here is my manifest :
<service
android:name=".Services.MakeOfflineService"
android:stopWithTask="false"/>

Send data to activity from already running sticky service

I created sticky background service, that should be started on boot:
public class AutostartReceiver extends BroadcastReceiver
{
public AutostartReceiver()
{
}
#Override
public void onReceive(Context context, Intent intent)
{
context.startService(new Intent(context, MyService.class));
}
}
My service is intended to do some work in background, it's implemented by creating thread for this. Also there is Messenger class used for sending work status to my main activity:
#Override
public int onStartCommand(Intent intent, int flags, int startId)
{
Log.i(TAG, "Service onStartCommand " + startId);
final int currentId = startId;
Messenger callback = null;
if(intent!=null)
{
callback = intent.getParcelableExtra("messenger");
}
final Messenger finalCallback = callback;
Runnable r = new Runnable()
{
public void run()
{
... do something, then stop
stopSelf();
}
};
if(t == null)
{
t = new Thread(r);
t.start();
}
return Service.START_STICKY;
}
Main activity receives messages sent from background thread running inside my service (some commands, that service is sending periodically:
Handler mHandler = new Handler()
{
#Override
public void handleMessage(Message msg)
{
switch (msg.what)
{
case 0:
Toast.makeText(MainActivity.this,"Service runing", Toast.LENGTH_LONG).show();
break;
}
}
};
This works only if I start my service from activity, with activity's context. Obviously, if service is started on boot, or my app was closed (removed from last app list) and opened again, my activity is unable to get any messages from service any more.
If I invoke start service while service is already running, it will simply run OnStartCommand again, so either new thread will be created (I don't want it) or I need to destroy running thread and run thread again.
Is there any way to get my activity receiving messages from service, without actually touching already running thread inside it? I know about bound services, but it's not clear for me how to use them in my specific case.
As Alternate way You can use LocalBroadcastManager to send Data from Service to Activity.
Broadcast Your message from Service:
private void broadcastMessage(Context context){
Intent intent = new Intent("UI_UPDATE_BROADCAST");
intent.putExtra("MESSAGE", "MyMessage");
LocalBroadcastManager.getInstance(context).sendBroadcast(intent);
}
Register Broadcast Receiver in your activity to receive messages:
#Override
public void onResume() {
super.onResume();
LocalBroadcastManager.getInstance(mContext).registerReceiver(mMessageReceiver, new IntentFilter("UI_UPDATE_BROADCAST"));
}
#Override
public void onPause() {
super.onPause();
LocalBroadcastManager.getInstance(mContext).unregisterReceiver(mMessageReceiver);
}
private BroadcastReceiver mMessageReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
//Do Something With Received Data
String msg = intent.getStringExtra("MESSAGE");
}
};
I would use a broadcast receiver for Service-to-Activity communication.
Code:
public class MyActivity extends Activity {
private BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
//Toast here
}
#Override
protected void onCreate(Bundle savedInstanceState) {
LocalBroadcastManager.getInstance(this).registerReceiver(broadcastReceiver, new IntentFilter("message-name"));
}
#Override
public void onDestroy() {
LocalBroadcastManager.getInstance(this).unregisterReceiver(broadcastReceiver);
super.onDestroy();
}
}
Then in your service you would broadcast the message like this:
Intent intent = new Intent("message-name");
intent.putExtra("data", 1);
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);

java.lang.ClassCastException: android.os.BinderProxy cannot be cast to com.leonard.sg.okcoin.service.SyncAndTradeService$SyncAndTradeBinder

I tried to bind the MainActivity to a foreground service, then got the following Exceptions, already searched more than one hour, no idea what i did wrongly, pls save me.
java.lang.ClassCastException: android.os.BinderProxy cannot be cast to com.leonard.sg.okcoin.service.SyncAndTradeService$SyncAndTradeBinder
at com.leonard.sg.okcoin.MainActivity$1.onServiceConnected(MainActivity.java:50)
at android.app.LoadedApk$ServiceDispatcher.doConnected(LoadedApk.java:1101)
at android.app.LoadedApk$ServiceDispatcher$RunConnection.run(LoadedApk.java:1118)
at android.os.Handler.handleCallback(Handler.java:725)
at android.os.Handler.dispatchMessage(Handler.java:92)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:5227)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:795)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:562)
at dalvik.system.NativeStart.main(Native Method)
The code in my MainActivity:
private SyncAndTradeService syncAndTradeService;
private boolean hasBounded = false;
private Intent syncAndTradeServiceIntent;
private ServiceConnection syncAndTradeServiceConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
SyncAndTradeService.SyncAndTradeBinder syncAndTradeBinder = (SyncAndTradeService.SyncAndTradeBinder) service;
syncAndTradeService = syncAndTradeBinder.getSyncAndTradeService();
hasBounded = true;
}
#Override
public void onServiceDisconnected(ComponentName name) {
syncAndTradeService = null;
hasBounded = false;
}
};
And i tried to do this in onCreate method:
syncAndTradeServiceIntent = new Intent(this, SyncAndTradeService.class);
bindService(syncAndTradeServiceIntent, syncAndTradeServiceConnection, Context.BIND_AUTO_CREATE);
And this is my service code:
public class SyncAndTradeService extends Service {
public static final int MY_FOREGROUND_SERVICE_START_ID = 996539;
private IBinder syncAndTradeBinder = new SyncAndTradeBinder();
#Override
public void onCreate() {
super.onCreate();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
startSyncAndTradeService();
return Service.START_REDELIVER_INTENT;
}
#Override
public IBinder onBind(Intent intent) {
return syncAndTradeBinder;
}
#Override
public boolean onUnbind(Intent intent) {
return false;
}
#Override
public void onRebind(Intent intent) {
super.onRebind(intent);
}
#Override
public void onDestroy() {
super.onDestroy();
}
public class SyncAndTradeBinder extends Binder {
public SyncAndTradeService getSyncAndTradeService() {
return SyncAndTradeService.this;
}
}
private void startSyncAndTradeService() {
startForeground(MY_FOREGROUND_SERVICE_START_ID, buildFixedNotification());
}
private Notification buildFixedNotification() {
Intent notificationIntent = new Intent(this, MainActivity.class);
notificationIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
Notification notification = new Notification.Builder(this)
.setContentTitle("OKCoin Robot")
.setContentText("OKCoin robot is running in background")
.setSmallIcon(R.drawable.bitcoin)
.setContentIntent(pendingIntent)
.build();
return notification;
}
}
And this is my declaration of my service in the Manifest.xml
<service
android:name=".service.SyncAndTradeService"
android:exported="false"
android:icon="#drawable/bitcoin"
android:process=":SyncAndTrade">
</service>
can't wait, so kept researching when i was free for the whole day, fortunately found the solution, hope this can help some beginners like me.
if u run the service in the same process with ur application, that means u should declare the service in the Manifest.xml without 'android:process', if u do this, then the above absolutely works fine.
the above exception will be threw when u try to bind ur app component to a service which is run in a different process
so the solution is wrapping ur IBinder with AIDL.
following is the code based the above one
define ur AIDL interface
package com.leonard.sg.okcoin.service.robot.aidl;
interface ISyncAndTradeService {
boolean startTradeEngine();
}
then change the onBind method in ur service to this:
#Override
public IBinder onBind(Intent intent) {
return new ISyncAndTradeService.Stub() {
#Override
public boolean startTradeEngine() throws RemoteException {
return false;
}
};
}
then refine the build service connection class to this:
private ISyncAndTradeService syncAndTradeService;
private boolean hasBounded = false;
private Intent syncAndTradeServiceIntent;
private ServiceConnection syncAndTradeServiceConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
syncAndTradeService = ISyncAndTradeService.Stub.asInterface((IBinder) service);
hasBounded = true;
}
#Override
public void onServiceDisconnected(ComponentName name) {
syncAndTradeService = null;
hasBounded = false;
}
};
then everything will work fine
but this raise another problem, according to the google documentation of the attribute 'android:process' of service declaration, we can do this:
android:process
The name of the process where the service is to run. Normally, all components of an application run in the default process created for the application. It has the same name as the application package. The element's process attribute can set a different default for all components. But component can override the default with its own process attribute, allowing you to spread your application across multiple processes.
If the name assigned to this attribute begins with a colon (':'), a new process, private to the application, is created when it's needed and the service runs in that process. If the process name begins with a lowercase character, the service will run in a global process of that name, provided that it has permission to do so. This allows components in different applications to share a process, reducing resource usage.
but in practice, if i declare the 'android:process' start with character, no matter lowercase or uppercase, i will get this error:
DEVICE SHELL COMMAND: pm install -r "/data/local/tmp/com.leonard.sg.okcoin"
pkg: /data/local/tmp/com.leonard.sg.okcoin
Failure [INSTALL_PARSE_FAILED_MANIFEST_MALFORMED]
the only choice is start with ':' or '.'
I just remove the below line in my activity. it is working fine.
android:process=":UsbEventReceiverActivityProcess"

EventListener for Power Button press in a Service

I want to listen the power key event in the service.
How can in do that ?
Currently I am working with an app, where I need to listen the power button for some events, from a service which is running in a background, even when the app is killed or stopped.
Somehow I can manage to get it.
But when I kill/stop the app, the service is getting stopped.
How can i overcome this ?
Currently the code i am using this :
Service Class:
public class SampleService extends Service
{
SettingContentObserver mSettingsContentObserver;
AudioManager mAudioManager;
private ComponentName mRemoteControlResponder;
private Intent intent;
#Override
public int onStartCommand(Intent intent, int flags, int startId)
{
Log.v("StartServiceAtBoot", "StartAtBootService -- onStartCommand()");
// 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) {
boolean screenOn = intent.getBooleanExtra("screen_state", false);
if (!screenOn) {
Toast.makeText(getApplicationContext(), "On", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(getApplicationContext(), "Off", Toast.LENGTH_SHORT).show();
}
}
public void onCreate()
{
mSettingsContentObserver = new SettingContentObserver(this,new Handler());
getApplicationContext().getContentResolver().registerContentObserver
(android.provider.Settings.System.CONTENT_URI, true, mSettingsContentObserver );
mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
mRemoteControlResponder = new ComponentName(getPackageName(),
StartAtBootServiceReceiver.class.getName());
IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_ON);
filter.addAction(Intent.ACTION_SCREEN_OFF);
BroadcastReceiver mReceiver = new StartAtBootServiceReceiver();
registerReceiver(mReceiver, filter);
}
#Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
public void onDestroy()
{
getApplicationContext().getContentResolver().unregisterContentObserver(mSettingsContentObserver);
}
}
BroadcastReceiver Class:
public class StartAtBootServiceReceiver extends BroadcastReceiver
{
static boolean wasScreenOn;
private boolean screenOff;
public void onReceive(Context context, Intent intent)
{
if(intent.getAction().equals(Intent.ACTION_SCREEN_OFF))
{
wasScreenOn = false;
Toast.makeText(context, "Power Off", Toast.LENGTH_SHORT).show();
}
else if(intent.getAction().equals(Intent.ACTION_SCREEN_ON))
{
wasScreenOn = true;
}
Intent i = new Intent(context, SampleService.class);
i.putExtra("screen_state", screenOff);
i.setAction("com.example.antitheft.SampleService");
context.startService(i);
//
if (intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED)) {
Intent i1 = new Intent();
i1.setAction("com.example.sampleonkeylistener.MainActivity");
context.startService(i1);
}
}
}
given above is the sample code and i have created AndroidManifest.xml files also with user's permission but i cannot get the app continue service if it is killed or stopped.
Thanks in Advance.
#Override
public void onDestroy() {
super.onDestroy();
startService(new Intent(this, SampleService.class));
}
This is one way to ensure that service will never stop even user want to destroy it.
This is one Just ONE of ways to achieve what you are trying to achieve.
Secondly, you can try and run service in "foreground" by using startForeground().
Also, make sure that in you return "START_STICKY" (which you are doing in the sample code that you shared and I trust that you are also doing in App's code too :) ) in Services's onStartCommand().
This will ensure that 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. Later the system will try to re-create the service.
And you may find some additional pointers/hints to make sure your service is not stopped at below link.
How can we prevent a Service from being killed by OS?
Just pick and choose the approach that best suits YOUR Need/implementation.

Categories