Strange problem I'm facing. I want to start a Service when my Activity is created. Here is my Service's code (very simple, as you'll see):
package com.nblmedia.service;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;
public class ServiceSynchro extends Service {
public ServiceSynchro()
{
Log.i(XXX.LOG, "ServiceSynchro");
}
#Override
public IBinder onBind(Intent intent) {
Log.i(XXX.LOG, "onBind");
// TODO Auto-generated method stub
return null;
}
#Override
public void onCreate() {
// TODO Auto-generated method stub
Log.i(XXX.LOG, "onCreate");
super.onCreate();
}
#Override
public void onDestroy() {
Log.i(XXX.LOG, "onDestroy");
// TODO Auto-generated method stub
super.onDestroy();
}
}
In my AndroidManifest.xml I have declared the Service as follow :
<service android:name=".ServiceSynchro"></service>
Finaly, to start my Service, I call the startService method in the onCreate :
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
startService(new Intent(UserMenuActivity.this, ServiceSynchro.class));
}
And nothing happens. If I check the device's running services, there are no service named ServiceSyncho running. If I check the Logcat, nothing is outputted. Same for the breakpoints, the app doesn't cycle thru the Service's lifecycle events. Any idea what could be my problem?
I found the problem. In my AndroidManifest.xml file, the service:name attribute wasn't refering to the fully qualified classname of the service. As example, I was using this :
<service android:name=".ServiceSynchro"></service>
When I needed :
<service android:name="com.xxx.service.ServiceSynchro"></service>
For the people interested in the application from the documentation, here is the link to view it.
android:name
The name of the Service subclass that implements the service. This should be a fully qualified class name (such as, "com.example.project.RoomService"). However, as a shorthand, if the first character of the name is a period (for example, ".RoomService"), it is appended to the package name specified in the element.
Lastly, I updated the code to override the onStartCommand command since the onStart method is deprecated.
public int onStartCommand(Intent intent, int flags, int startId)
Get rid of your constructor. Never implement a constructor in a component (sole current exception: IntentService).
Also, when you do implement constructors elsewhere in Java, chain to the superclass.
I looked everywhere when my service didnt start.
Nothing worked out.Finally debugging of the third hour ı found out that my package name was not the standart format xx.xx.xx package names.I fixed and it worked.
For your information.
Related
In my activity, there's a variable (objectList) which I would like to access from a Service (TestService):
public class MainActivity extends AppCompatActivity
{
List<MyObject> objectList;
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
startService( new Intent( getBaseContext(), TestService.class )
);
}
And I have a skeleton for the Service:
public class TestService extends Service
{
#Override
public IBinder onBind(Intent intent)
{
return null;
}
#Override
public void onCreate()
{
super.onCreate();
}
#Override
public int onStartCommand( Intent intent, int flags, int startId )
{
return super.onStartCommand(intent, flags, startId);
}
#Override
public void onDestroy()
{
super.onDestroy();
}
}
My goal is to loop through every item in the objectList from the TestService every x seconds, process some data, and then update this particular item with new data.
The MyObject class has a lot of properties which I need to update. What is the proper way to pass the objectList from mainActivity to the TestService so I can work with the object list directly? Thanks!
By maintaining a reference to an Activity in a Service, you introduce a memory leak since you prevent the system from garbage collecting the Activity when the view is destroyed as a result of the Activity progressing through its lifecycle.
Instead, you should communicate the changes made by the Service to the Activity using a BroadcastReceiver as explained by #NongthonbamTonthoi in the comment. Basically the Activity should instantiate a BroadcastReceiver that listens for a specific type of broadcasts (identified by a unique key defined by you) which are sent by the Service whenever it performs an update.
Furthermore, I suggest that you move the list so that it is stored in the Service and then make the Activity retrieve the list from the Service by binding to the Service and then invoking a method defined in your IBinder implementation (an instance of which should be returned from onBind(Intent)). This way you can confine all code that makes changes to your model to the Service and keep the Activity as a (dumb) view that simply renders the model. Morover, with this design, you can make your list outlast the Activity by also starting the Service (note: in addition to binding to it) so that you can retain the state of your list even if your Activity is destroyed (e.g., as a result of your application being put to the background). If you choose this design, the broadcast sent by the Service can simply be a notification that the list has changed, and the Activity can then retrieve the updated list by invoking the getList method specified in your IBinder implementation.
I have to clear the data from SharedPreference when the app is cleared from recent list.
Is there any way for that ?
Which activity is called when app removed from recent list in android?
The above link tells you how to enter a callback method on removing app from recent list. You can then update your shared variable in that function.
I don't think so,when the app is cleared from the background the onDestroy() method does not get called most of the times. Hence the app does not get any callback method to do so.
If you want to do that then why don't you use some static variable or objects (if that is possible) in application class,depending on the requirement. They will get reinitialized each time the application launches, may be if that can help you.
As already said, there is no guarantee that you will receive a callback when you app is killed no matter what callback you try to use. However, I'm still wondering why you are using the SharedPreferences if you do not want that data to be persistent, it's beside the point of this class. That being said, you should handle the data like any other data inside your app.
If you are required to use the SharedPreferences for some reason, then the proper way to clear it is when you start the application, not when you kill it. This way, you won't have any problems.
You could do that using a Service.
Create a Sticky Service:
and override the onTaskRemoved function to clear your Shared Preferences.
public class CheckAppRemovedService extends Service {
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_STICKY;
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onTaskRemoved(Intent rootIntent) {
super.onTaskRemoved(rootIntent);
//YOUR CODE TO CLEAR SHARED PREFS.
}
}
Start the service when you start your activity.
Intent intent = new Intent(MyActivity.this, CheckAppRemovedService.class);
startService(intent);
When an app is cleared from the recent list, the onDestroy() method will be called. So clear your SharedPreference values when the onDestroy() method will be called.
#Override
protected void onDestroy() {
super.onDestroy();
SharedPreferences.Editor editor = getSharedPreferences("APP", MODE_PRIVATE).edit();
editor.putString("YOUR_DATA_KEY", "").apply(); //data nullified
}
See the lifecycle of an activity in android below:
I was wondering how to keep a record of launched activites for logging purposes. what broadcast receiver I have to subscribe to intercept this intent? or what intent-filter to use? I figure that I must use some type of long-running service in the background.
My first objetive is to track main-focus applications, some sort of history.
Want to get finally some similar to:
- Launched app com.android.xxx
- Launched app xx.yy.zz
- App xx.yy.zz lost focus
Thanks in advance
EDIT - Just see that app MyAppRank , that does exactly what i mean
What i'm able to figure out from your question is that you want to keep track of all the activities when they are launched in your application. If that is correct, the solution may work for you:
Crate a BaseActivity which all of your Activities should extend
public class BaseActivity extends Activity
{
private Activity activity;
public static final String INTENTFILTER_TRACK_MY_ACTIVITIES="INTENTFILTER_TRACK_MY_ACTIVITIES";
public static final String INTENTFILTER_REMOVE_MY_ACTIVITIES="INTENTFILTER_REMOVE_MY_ACTIVITIES";
public void setActivity(Activity act)
{
activity = act;
}
public Activity getActivity()
{
return activity;
}
#Override protected void onCreate(Bundle savedInstanceState)
{
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
Intent intent = new Intent();
intent.setAction(INTENTFILTER_TRACK_MY_ACTIVITIES);
intent.putExtra("activityName", activity.getClass().getSimpleName());
sendBroadcast(intent);
}
#Override protected void onDestroy()
{
// TODO Auto-generated method stub
super.onDestroy();
Intent intent = new Intent();
intent.setAction(INTENTFILTER_REMOVE_MY_ACTIVITIES);
intent.putExtra("activityName", activity.getClass().getSimpleName());
sendBroadcast(intent);
setActivity(null);
}
}
Now extend above BaseActivity for all your activities. i.e instead of extending your Activities should extend BaseActivity and call setActivity(this); in onCreate like below:
public class MyActivity extends Activity
{
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setActivity(this);
//write your other code form here
}
}
3.Then write a BroadcastReceiver like below:
class TrackActivitiesReceiver extends BroadcastReceiver
{
private static final Object SEPERATOR = ",";// use , as seperator
String sb="";
#Override
public void onReceive(Context context, Intent intent)
{
if(intent.getAction().equalsIgnoreCase(BaseActivity.INTENTFILTER_TRACK_MY_ACTIVITIES))
{
sb+=intent.getStringExtra("activityName");
sb+=SEPERATOR;
}
else if(intent.getAction().equalsIgnoreCase(BaseActivity.INTENTFILTER_REMOVE_MY_ACTIVITIES))
{
sb=sb.replace(intent.getStringExtra("activityName")+SEPERATOR, "");
}
}}
4Finally, Register above Receiver in your AndroidManifest.xml
<receiver
android:name="TrackActivitiesReceiver"
android:exported="false" >
<intent-filter>
<action android:name="INTENTFILTER_TRACK_MY_ACTIVITIES" />
</intent-filter>
</receiver>
Hope this solves your problem. cheers!
There are no Intents broadcast when applications are started or when applications come to the foreground. There isn't anything that you can hook into as a listener to get these events.
The way you can do this (which is the way apps like MyAppRank do it) is to use the methods of the ActivityManager:
getRunningTasks()
getRunningAppProcesses()
getRecentTasks()
You create a Service which runs all the time and at regular intervals calls methods of the ActvityManager to determine which task is in the foreground and you can "infer" what the user has done (or is doing). It isn't an exact science.
Note: You will need android.permission.GET_TASKS and none of this works anymore as of API 21 (Android 5, Lollipop). As of API 21 the security has been tightened and an application can only get information about its own tasks, not other tasks in the system.
I would like to start a Thread when the Android started, so I made something like this
public class StartUpWelcomer extends BroadcastReceiver {
#Override
public void onReceive(Context arg0, Intent arg1) {
// TODO Auto-generated method stub
arg0.startService(new Intent(arg0, StartUpService.class));
}
With my Manifest:
<receiver android:name=".StartUpWelcomer">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
<service android:enabled="true" android:name=".StartUpService" />
And this is my StartUpService class
public class StartUpService extends Service {
#Override
public IBinder onBind(Intent arg0) {
// TODO Auto-generated method stub
return null;
}
public void onCreate()
{
BackgroundApplication application = (BackgroundApplication)this.getApplication();
ReminderThread reminderThread = new ReminderThread(null);
if(!reminderThread.failed)
{
reminderThread.start();
application.setRunningThread(reminderThread);
Log.d("SERVICE", "CREATION CONFIRMED");
}
else
{
Log.d("SERVICE", "CREATION CANCELLED");
}
}
And here's the code for the ReminderThread class
public ReminderThread(Context ctx)
{
this.ctx = ctx;
db = new SQLdb(ctx);
//And there's some other code here that accessed the database functions.
}
OK, so here's my intention... I would like the StartUpWelcomer to activate the StartUpService (and it's working).
StartUpService will instantiate a new Thread, activating it and keeping it accessible in my application (which is called as BackgroundApplication class).
And here's the problem... The ReminderThread actually need to access database (SQLite here), so the ReminderThread instantiated the database to access it. But, my database constructor need a Context to be instantiated. I have no idea where to get the Context here (from the Service class) where I usually get it from Activity class.... (temporarily I put "null" there)
Another problem is, somehow I found that this always cause a NullPointerException...
If you initialize ReminderThread in Service then use ApplicationContect like new ReminderThread(getApplicationContext()); which is found in Service class.
I got an null pointer exception on Android 3.2 emulator on a simple Android project created by Wizerd with a service in separated process, when I switch between "Stretch to fill screen" to "Zoom to fill screen". This crash will not happen if the service is put into the same process with main activity, namely "android:process" attribute not specified. While it only happens when I add "android:process" to manifest file for my test service.
The exception is:
FATAL EXCEPTION: main
java.lang.NullPointerException
at android.view.WindowManagerImpl.reportNewConfiguration(WindowManagerImpl.java:427)
at android.app.ActivityThread.handleUpdatePackageCompatibilityInfo(ActivityThread.java:2801)
at android.app.ActivityThread.access$2700(ActivityThread.java:122)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1151)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:132)
at android.app.ActivityThread.main(ActivityThread.java:4123)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:491)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:841)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:599)
at dalvik.system.NativeStart.main(Native Method)
My test code:
TestActivity.java (Generated by Wizerd)
package com.test;
import android.app.Activity;
public class TestActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Intent intent = new Intent(this, TestService.class);
startService(intent);
}
}
TestService.java (Most of the functions are empty)
Package com.test;
import android.content.ComponentName;
public class TestService extends Service {
private boolean m_connected = false;
private ServiceConnection m_connInitService = new ServiceConnection() {
public void onServiceConnection(ComponentName className, IBinder service) {
m_connected = true;
}
public void onServiceDisconnected(ComponentName className) {
}
};
public static class TestServiceBinder extends Binder {
}
public IBinder onBind(Intent intent) {
return new TestServiceBinder();
}
public void onDestroy() {
super.onDestroy();
}
public int onStartCommand(Intent intent, int flags, int startId) {
return 1;
}
}
If I run the test app without service or with service in the same process the screen compatibility switch will not cause any problem. However, I do not understand why service can cause system exception during screen compatibility switch. Is this because service process is a non-UI process? Which could potentially triggers a bug inside the Android core code?
I've found in the documentation the following thing:
android:process
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.
Thus, if you assign process name that starts with lowercase you should have permissions to do this. But I do not know where these permissions are checked. Maybe they are checked in the WindowManagerImpl and it cannot find this global process and thus returns null. This is just an assumption.
The reason causing this issue is Screen Compatibility Mode, see how to disable it for your app:
http://developer.android.com/guide/practices/screen-compat-mode.html#Disable