I've a Fragment fr, Service ser, BroadcastReceiver brc.
In fr I have a switch, when checked it launches ser, when un-checked it stops it, so far so good.
In ser, I have registered a BroadcastReceiver named brc and added an IntentFilter named USER_PRESENT, When the device is locked, I have the Service call stopSelf() and register that BroadcastReceiver, when the phone is unlocked, onReceive() will be called, in that method I've added a code to start the Service again .
Now, the problem .. I can't stop the Service when the switch is un-checked, even though I'm calling stopService(intentname); .
And my guess is, it's a different Intent which launched by a different class. So I've stopped that Intent like this:
stopService(brc.intentname);
Nothing happened and the Service keeps running. What's the solution for this?.
Code:
Fragment:
if ( !Switched ) {
getActivity().startService(ServiceIntent);
}
if( Switched ){
getActivity().stopService(ServiceIntent);
getActivity().stopService(BroadcastTest.ServiceIntent);
}
Service:
if( !isScreenOn && isLocked )
{
this.getApplicationContext().registerReceiver(new BroadcastTest(), new IntentFilter("android.intent.action.USER_PRESENT"));
CancelTimer();
stopSelf();
}
BroadcastTest:
ServiceIntent = new Intent(context, Service.class);
context.startService(ServiceIntent);
Related
In Android official Aidl document, the IPC client example declares an intent explicitly with the target "RemoteService.class". However, when server and client are not in the same package, client should not be aware of what is "RemoteService" if no dependency set. How does the example works?
ref: https://developer.android.com/guide/components/aidl.html
I searched for several working examples, and the intent is set with Action instead of the remote service class object.
In Android docs,
Intent intent = new Intent(Binding.this, RemoteService.class);
intent.setAction(IRemoteService.class.getName());
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
Currently, I expect this should be modified to:
Intent intent = new Intent("<remote-service-intent-filter-in-androidmanifest>");
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
You are on the right path, but if you add the intent action at the manifest, then you should also mention the package name while binding the service.
intent.setPackage("<remote service package name>");
Caution: To ensure that your app is secure, always use an explicit
intent when starting a Service and don't declare intent filters for
your services. Using an implicit intent to start a service is a
security hazard because you cannot be certain of the service that
responds to the intent, and the user cannot see which service starts.
Beginning with Android 5.0 (API level 21), the system throws an
exception if you call bindService() with an implicit intent.
https://developer.android.com/guide/components/services
Snipplet:
Here is how I connect to a remote service on a different application with the setClassName API.
Note: This approach does not need the intent action at the manifest file.
At Client activity.
/**
* Init Service
*/
private void initService() {
if (mSampleService == null) {
Intent i = new Intent();
// set intent action
i.setAction("com.hardian.sample.aidl.ISampleService");
// mention package name with service's canaonical name
i.setClassName("com.hardian.sample", "com.hardian.sample.aidl.SampleAidlService");
// binding to a remote service
bindService(i, mSampleServiceConnection, Service.BIND_AUTO_CREATE);
}
}
At Service
/**
* {#inheritDoc}
*/
#Override
public IBinder onBind(Intent intent) {
Log.d(TAG, "onBind called");
if (ISampleService.class.getName().equals(intent.getAction())) {
return mSampleServiceBinder;
}
return null;
}
I have a class in a service
MyClass m = new MyClass();
and inside my class I check if I have permission to overlay the view; if so, it's ok, otherwise I must start an activity
if (Settings.canDrawOverlays(mContext)) {
// draw over app
} else {
// start the activity
Intent i = new Intent(context,Calls.class);
context.startActivity(i);
}
When I start the activity I have a problem communicating between the class and the activity. I know how to use the interface but how can I register it in activity.
Some time I want to pass an object or data from the class to the activity or from the activity to the class... how can I do that?
I saw many examples in Stack Overflow about how to communicate between service and activity; they suggest to start the class from the activity but this does not work in my app because my class must be running all the time.
Perhaps you could use an event bus like mechanism where you can send or receive events through out your app, Though there are several libraries out there, I would recommend using Otto library for android.
Usage is pretty simple just register in your activity onCreate
Bus bus = new Bus();
bus.register(this);
For sending events
// example data to post
public class TestData {
public String message;
}
// post this data
bus.post(new TestData().message="Hello from the activity");
And subscribe to events like this
#Subscribe public void getMessage(TestData data) {
// TODO: React to the event somehow!
}
More info here
If you want to implement a communication pattern between a Service and an Activity, you should use a LocalBroadcastManager.
It will turn handy because, in case your Service is still on but your Activity
has been destroyed (very common situation), then the 'messagging' between the two will simply have no effect (no NPE or whatsoever will be thrown).
Step 1
Create a BroadcastReceiver in your Activity and define an ID / Filter
this.localBroadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
// Do what you have to do here if you receive data from the Service / Background Task
}
}
public static final IntentFilter SIGNAL_FILTER = new IntentFilter("com.you.yourapp.MY_SIGNAL")
Step 2
In your Activity register the broadcast in onResume() and unregister it in onPause().
#Override
protected void onResume() {
// Listen if a Service send me some data
LocalBroadcastManager.getInstance(getApplicationContext()).registerReceiver(this.localBroadcastReceiver, SIGNAL_FILTER);
}
#Override
protected void onPause() {
// I'm going to the background / or being destroyed: no need to listen to anything anymore...
LocalBroadcastManager.getInstance(getApplicationContext()).unregisterReceiver(this.localBroadcastReceiver);
}
Your Activity is now ready to receive data from any other component in your Application.
If it's in the background, then there is no need to update the UI: in fact the Activity will not respond if in the background.
In the same way, if it's being garbage collected, the Receiver will be unregistered and the Activity will just not respond to anything.
If the Activity is resumed / restarted, onResume() will be triggered and the Receiver will be registered again.
Step 3
All you need to do right now, is send data from the Service.
Simply call
final Intent intent = new Intent();
intent.setAction(SomeActivity.SIGNAL_FILTER);
// put your data in intent
LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(intent);
and your Activity will accordingly respond to the signal.
It's surprising how few people know about the LocalBroadcastManager and instead use some self-implemented callback / singleton pattern, which increases complexity and non-readability.
This pattern is built-in in Android, so you don't need external libraries. As for security, this ensures that your signals stay internal to your application: no data can therefore be read by other apps.
I similarly answered to another question here.
imagine this stack situation :
A - B- C - D - B , A, B and C are activities, but D is a service.
Basically, i have a service (D) and from that service i want to call an already existing activity (B).
I know that if I want to re-use an activity, all i got to do is to use the flags (or change the manifest) SingleTop (will re-use the activity if it is already on top) or SingleTask (will re-use the activity whether it is on top or not).
The problem is that since i am inside a Service, i will have to add the flag FLAG_ACTIVITY_NEW_TASK, so that i can call an activity. Also, i added SingleTask as a launch mode in my manifest so that that activity will be re-used.
This works fine since it re-uses the same activity and comes back to the method onNewIntent(Intent intent). The problem is that everything that i put as an extra on that intent comes as null. I try to send 2 strings and 2 booleans through that intent and all of them reach the onNewIntent(Intent intent) as null.
How can i solve this ? Do I have to do something inside the onNewIntent(Intent intent) method, before getting the extras ? Are there any better alternatives ?
PS:
I heard about the StartActivityForResult or something similar. That would only work 50% of the times, since this is for a " chat-like" application.
So I will be on the "chat", from where I go to another activity where i can select something to send. After that, i will go to the service, where the transfer is done, and then back to the "chat".
But when I receive something, I am already on the "chat", so the startActivityForResult wouldn't work in this case (the service to receive would be running on the background + I don't wan't to finish the receiving part, because i want to be always listening for something).
Here is the code from the service where i try to re-launch the single activity :
Intent transfRec=new Intent(ServerComm.this ,TransferRecordActivity.class);
transfRec.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
transfRec.putExtra("receivedFilePath",appName+".apk");
transfRec.putExtra("joinMode","appselection");
transfRec.putExtra("nameOfTheApp",appName);
transfRec.putExtra("received",false);
transfRec.putExtra("isHotspot",isHotspot);
startActivity(transfRec);
Here is the code of my onNewIntent(Intent intent) :
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
System.out.println("I am here in the new intent");
if(intent==null){
System.out.println("Intent is null inside the new intent method !!!");
}
tmpFilePath=getIntent().getStringExtra("receivedFilePath");
System.out.println("The tmpFilePath is : "+tmpFilePath);
received=getIntent().getBooleanExtra("received",true);
nameOfTheApp=getIntent().getStringExtra("nameOfTheApp");
isHotspot=getIntent().getStringExtra("isHotspot");
System.out.println("O received boolean esta a : : : "+received);
textView.setVisibility(View.GONE);
receivedFilePath= Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) + "/"+tmpFilePath;
System.out.println("transfer REcord Activity _: the received file path is :::: " +receivedFilePath);
getReceivedApps();
adapter= new HighwayTransferRecordCustomAdapter(this,listOfItems);
receivedAppListView.setAdapter(adapter);
EDIT: As you guys can see i check if the intent is null, and it is not, since it doesn't do the system.out.println that there is on that condition !
The issue is that you are calling getIntent() within your onNewIntent(). From the docs for getIntent():
Return the intent that started this activity.
Therefore, you are getting the intent provided to onCreate(). To get the intent supplied to onNewIntent(), you simply use intent which is provided in the method signature:
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
tmpFilePath=intent.getStringExtra("receivedFilePath");
...
}
I am trying to write an app that checks in with a server every X seconds.
I was able to make it work, but only when the application is running and active (not sure if it can be minimized, was not able to test it clearly) and the device is not locked. I would like for the checking to continue even if I lock the device or do other things on it.
From my searches, it seems like I should use service, but I was not able to figure out how to implement it with what I am trying to do. Or is there something else that could do this?
What I need to and failed to do is this:
User checks a CheckBox - start the service
Create the service and pass some information to it
Create an instance of my class in the service using the passed information
Call this instance's method every X seconds in a new thread (the method returns true/false)
Listen to ?something and if the method returns true then stop the service and notify user
If the user unchecks the CheckBox, stop the service.
I tried doing this, but I was unable to get any information out of the thread and out of the service. Is there a way to do so?
Starting the service from activity for example and binding it with your app
//make these 2 variables as fields in Activity for example
YourService yourService = null;
//this variable can be used for checking if your activity are binded already or not
boolean mBounded = false;
Intent mIntent = new Intent(this, YourService.class);
startService(mIntent);
bindService(mIntent, mConnection, BIND_AUTO_CREATE);
ServiceConnection mConnection = new ServiceConnection() {
public void onServiceDisconnected(ComponentName name) {
mBounded = false;
yourService = null;
}
public void onServiceConnected(ComponentName name, IBinder service) {
mBounded = true;
YourService.LocalBinder mLocalBinder = (YourService.LocalBinder) service;
yourService= mLocalBinder.getServerInstance();
}
};
Do not forget that you can use methods from Service in Activity only after it is bound to your Activity. In other words it is available only after onServiceConnected is executed.
So you have now service and activity who can communicate with each other.
For example you can call in Activity some public method of your Service, like
if (yourService != null)
yourService.test();
If you want to call your Activity methods in Service you should pass it to Service with simple setter.
If you want to stop Service its kinda easy too:
Intent mIntent = new Intent(this, YourService.class);
stopService(mIntent);
For doing request every X service:
1) You can do infinity separate thread inside Service and do request after delay for X seconds.
2) For checking every X seconds you can use something like AlarmManager.
3) Also its possible to use CountDownTimer inside your Service to do some requests to server.
If you want to create your Service after reboot if CheckBox was set, its easy too. So you should use simple BroadcastReceiver.
First of all you should save your CheckBox setting in SharedPreferences, then run your Service if you need.
public class SimpleReceiver extends WakefulBroadcastReceiver{
#Override
public void onReceive(Context context, Intent intent) {
//run below code if you need, depends on your saved value of Checkbox in SharedPreferences
Intent serviceIntent = new Intent(context, YourService.class);
context.startService(serviceIntent);
}
}
And for sure dont forget to add in AndroidManifest information about your Service and Receiver to be sure it will run automatically after reboot.
<service
android:name=".package.YourService"
android:enabled="true"
android:exported="false"> </service>
<receiver
android:name=".package.SimpleReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<action adroid:name="android.intent.action.QUICKBOOT_POWERON" />
</intent-filter>
</receiver>
I search a lot and I tried several ways but I couldn't find anything that avoid my error.
I'm working on app for my learning, where is an String in my MainActivity and then I call it in my Service. I tried something like this:
This next one goes in my myService.class
//In my myService.class that extends Service
public class myService extends Service{
AlarmManager manager;
PendingIntent pintent;
String te;
#Override
public void onCreate()
{
manager = (AlarmManager)(this.getSystemService(Context.ALARM_SERVICE));
pintent = PendingIntent.getBroadcast( this, 0, new Intent("blahblah"), 0 );}
#Override
public int onStartCommand(Intent intent, int flags, int startid)
{
super.onStartCommand(intent, flags, startid);
te = intent.getStringExtra("tst"); //if I change this line to te = "something", everything goes fine
BroadcastReceiver receiver = new BroadcastReceiver() {
#Override
public void onReceive( Context context, Intent intent )
{
Toast.makeText(getApplicationContext(),te, Toast.LENGTH_SHORT).show();
}
};
this.registerReceiver(receiver, new IntentFilter("blahblah") );
// set alarm to fire 30 min and waits 2 min
manager.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() + 1000*30*60, 1000*2*60, pintent);
return START_STICKY;}
public IBinder onBind(Intent p1)
{
// TODO: Implement this method
return null;
}
}
Here the code runs perfectly, but when I exit my App, it crashes. After 1 minute, my device shows again that my App crashes, confirming my app "successfully" ran into background. What is wrong with it?
I also learned I could use IntentService instead of Service, wich one is better for long tasks and what is the difference between them ?
EDIT***
I received the following error: java.lang.NullPointerExeption.
So I change this:
te = intent.getStringExtra("tst");
To this:
try
{
te = intent.getStringExtra("tst");
}
catch(NullPointerException e)
{}
When I changed it my app works with any error, but The problem is: I need to retrieve my String from my MainActivity, when I close my app my service runs without errors but my "te" String takes null valor, what can I do to "save" my String in my service, to be able to use it and keeping showing the "working" message after I close my App ? Should I use SharedPreferences ?
Hope I was clear.
IntentService is different from Service.
IntentService Self kills the service as it finishes the task. Whereas Service runs for ever unless you kill it.
For my coding experience, I would use IntentService only for small tasks that run for a couple of seconds and use Service for long running one and call StopSelf() as needed.
Kindly post the log to answer your problem