I have an application which utilizes a splash screen and a choice screen, as depicted in the following manifest:
<application
android:name="com.example.CoolApp"
android:label="#string/app_name"
android:icon="#drawable/app_icon_debug"
android:theme="#style/Theme.NoBackground">
<activity
android:name="com.example.Splash"
android:label="#string/app_name"
android:screenOrientation="portrait"
android:noHistory="true"
android:launchMode="singleTop">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
<data android:scheme="coolappscheme"/>
</intent-filter>
</activity>
<activity
android:name="com.example.ChoiceActivity"
android:screenOrientation="portrait"
android:windowSoftInputMode="stateHidden"/>
</application>
The splash screen shows for about 2 seconds, and then navigates to the ChoiceActivity via the following code:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
... some stuff for showing the Splash screen ...
Thread mythread = new Thread() {
#Override
public void run() {
try {
.. animation stuff for fading in ...
while (splashActive && ms < splashTime) {
if(!paused)
ms=ms+100;
sleep(100);
}
} catch(Exception e) {
} finally {
Intent intent = new Intent(Splash.this, ChoiceActivity.class);
startActivity(intent);
}
}
};
Now, clearly there are a number of things wrong with this code (starting with why the author decided to use a separate Thread instead of an AsyncTask. However, putting that stuff aside for the moment, if the user performs the following actions:
Launch the application & see the splash screen.
Force the application into the background (e.g. the user receives a phone call, or maybe just hits the 'home' button).
Then, when the Thread completes (i.e. the finally block is reached and the Intent is created), the new ChoiceActivity is created, but it also brings the application to the foreground. I want to disable this behavior. That is, I want the activity to be loaded, but the application to remain in the background. If that's not possible, then I want the application to delay loading of the new Activity (//any// new Activity) until after the Application has been resumed.
How can I achieve this?
Activities are meant to run in foreground..There is a given lifecycle which is based on how the user interacts with the app. Therefore you actually shouldn't be trying to "start your activity in background", because it does not make sense..What you can do though is somehow alter how the activity reacts on events from outside of it..
You can for example create a new boolean field in your activity and set it to false everytime in onPause() and to true in onResume()...
You could then check for it when starting the new activity and actually only start it when true. Otherwise just set the field to true and then in onResume() start the activity when the field would be true..
Also you should take in account, that background activity could be killed by the system at any time. Activity should deallocate all system resources and stop it's work when it goes to background..Only then you can be sure your app won't go into an unpredictable state..
For background tasks you should go with services, which are basically "activities without UI" (I don't believe I've said that) - parts of your app running in the background.
Related
I am working on a application and my requirement is to store all incoming and outgoing call details like number,duration,time
I am using broadcast receiver for this along with run time permissions READ_PHONE_STATE,READ_CALL_LOG
With the current code app is working fine when app is in foreground as well as background BUT when I kills the app,it is not working,it is not detecting incoming/outgoing calls.
Below is my code of manifest file
<receiver
android:name=".utils.CallReceiver"
android:enabled="true"
android:exported="true">
<intent-filter >
<action android:name="android.intent.action.PHONE_STATE" />
<action android:name="android.intent.action.NEW_OUTGOING_CALL" />
<action android:name="android.provider.Telephony.SMS_RECEIVED" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<category android:name="android.intent.category.HOME" />
<action android:name="android.intent.action.QUICKBOOT_POWERON" />
</intent-filter>
</receiver>
Broadcast receiver
override fun onReceive(context: Context?, intent: Intent) {
//We listen to two intents. The new outgoing call only tells us of an outgoing call. We use it to get the number.
if (intent.action == "android.intent.action.NEW_OUTGOING_CALL") {
savedNumber = intent.extras!!.getString("android.intent.extra.PHONE_NUMBER")
} else {
val stateStr =
intent.extras!!.getString(TelephonyManager.EXTRA_STATE)
val number =
intent.extras!!.getString(TelephonyManager.EXTRA_INCOMING_NUMBER)
var state = 0
if (stateStr == TelephonyManager.EXTRA_STATE_IDLE) {
state = TelephonyManager.CALL_STATE_IDLE
} else if (stateStr == TelephonyManager.EXTRA_STATE_OFFHOOK) {
state = TelephonyManager.CALL_STATE_OFFHOOK
} else if (stateStr == TelephonyManager.EXTRA_STATE_RINGING) {
state = TelephonyManager.CALL_STATE_RINGING
}
if (number != null && !number.isEmpty() && !number.equals("null")) {
onCallStateChanged(context, state, number);
Log.d("TEST :","NUMBER =>"+number);
return;
}
}
I need solution which can detect incoming call when app is killed like true caller app and want to start receiver on Android 7,8,9 when call happens
when an app is killed via "FORCE CLOSE" by the user, all the app's broadcast receiver are immediately put on pause, and the system prevents them from receiving future broadcasts until the user manually reopens that app.
This is to prevent apps working around a force-close by the user that obviously wants that app shutdown, while an incoming broadcast receiver can wake that app up again.
see here
This rule has one exception - if the app had been set to be the default Phone/SMS app, it will still be able to wake up upon getting a call / sms.
I assume TrueCaller was set as a default handler to be able to workaround this limitation.
To become the default Phone handler on Android P and below - see the documentation here: https://developer.android.com/reference/android/telecom/TelecomManager#ACTION_CHANGE_DEFAULT_DIALER
On Android Q, call this method: https://developer.android.com/reference/android/app/role/RoleManager#createRequestRoleIntent(java.lang.String) with ROLE_DIALER
I am using Android Studio.
I added a BroadcastReceiver for my app that receives android.intent.action.BOOT_COMPLETED, the receiver just shows up a Toast for testing. The problem is I get "App has stopped" message just after Android starts up.
My first question is: is there anyway to debug that at startup and see where is the problem by myself? Because I can't see any log referring to that problem in Android Studio.
My second question is related to the problem itself. Here is the code:
XML:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="myapp">
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity android:name="MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<receiver
android:name=".AutoStartReceiver"
android:enabled="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
</application>
</manifest>
Java: BroadcastReceiver
public class AutoStartReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "loaded", Toast.LENGTH_LONG).show();
throw new UnsupportedOperationException("Not yet implemented");
}
}
The third question is: Is it OK to do some heavy work (read some files and set the AlarmManager) in the receiver rather than creating a service? because as of API 26 Android is putting a lot of restriction to services.
Thank you
For the debugging part I used this (in the Terminal, when the emulator is on) :
adb shell am set-debug-app -w --persistent <your.app.package>
to start debugging, then click Attach debugger to android process when the app prompts for it on the emulator.
To disable this:
adb shell am clear-debug-app <your.app.package>
Found answer here : https://medium.com/#elye.project/debug-app-deeplink-at-launch-time-bdb2cf04a9e6
Apps that launch on boot can be debugged the second your device gets a debugging connection, which usually happens just before the app itself would boot. Just open logcat and watch for the device and app to pop up after reboot. Note that this assumes the app is debuggable. Apps that aren't will simply not show any logs.
You get the MyApp has unfortunately stopped message for the obvious reason of this code:
public class AutoStartReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "loaded", Toast.LENGTH_LONG).show();
throw new UnsupportedOperationException("Not yet implemented");
}
}
You throw an exception, meaning it'll stop.
As for what you do in the service, as long as it uses within a reasonable amount of RAM and processor (extremely heavy services are more likely to be killed to save battery and memory) you're good to go
This question already has answers here:
The application may be doing too much work on its main thread
(21 answers)
Closed 7 years ago.
I keep on getting this error when I try to run my app and I think it might be because I have too many activities/intents as I got the error after I included them. Still I'm unsure if this may be the problem. Also the activities for my options menu open once but when I try to open them again they don't anymore and I think this error may be the problem.
Here is my code for the intents:
MainActivity
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.action_home) {
Intent intent = new Intent(this, MainActivity.class);
startActivity(intent);
} else if (id == R.id.action_eda) {
Intent intent2 = new Intent(this, EdaInfoActivity.class);
startActivity(intent2);
} else if (id == R.id.action_about) {
Intent intent3 = new Intent(this, AboutMe.class);
startActivity(intent3);
}
return true;
}
and my Android Manifest
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
<meta-data
android:name="android.app.searchable"
android:resource="#xml/searchable"/>
</activity>
<activity
android:name=".NewsItemActivity"
android:parentActivityName=".MainActivity">
</activity>
<activity android:name=".EdaInfoActivity">
<intent-filter>
<action android:name="android.intent.action.INFO"/>
</intent-filter>
</activity>
<activity android:name=".AboutMe">
<intent-filter>
<action android:name="android.intent.action.ABOUT"/>
</intent-filter>
</activity>
</application>
I think it might be because I have too many activities/intents as I got the error after I included them.
This is NOT the problem. You do not have more than one of these Activities running at once, so it isn't what is causing your error. (could be coincidence of adding in some activity that HAS the below error. (Detailed explanation in this link from Deividi Cavarzan's comment above)
The problem is that you are doing 'long running(blocking)' processing on the foreground thread.
Android has a "Looper" that a thread can have. The UI Thread has one by default, This is what processes messages and runnables via a handler. When this Looper blocks for more than 5 seconds you get an ANR (Application Not Responsive) error.
When your application takes too long within the UI Thread, but NOT that long, you can get the error above that you are getting.
You should look to see what computationally complex operation(s) you are running and -at least- run them in a AsyncTask. or run them as a runnable.
Concurrency in Android is such a complex topic that I don't even want to really touch on how to 'solve it' for you.
Doug Schmidt (Full disclosure, my PhD adviser, and I helped in creating some of the examples he shows in class, etc.) has made some good videos where he lectured for his 282 Class (Systems programming (on the android platform) Where you learn concurrency & services)
Here is the playlist of those class lectures:
https://www.youtube.com/playlist?list=PLZ9NgFYEMxp4KSJPUyaQCj7x--NQ6kvcX
I know, I am not the first onbe with this problem, but I tried so many solutions, I have found and no one works... maybe you could find the error
The error (also came so without .class and with /.Client depending on other settings)
12-02 16:40:15.359: W/ActivityManager(74): Unable to start service
Intent { act=com.android.fh.EnOceanApp.Client.class }: not found
In the manifest, this is included in application, out of activities (tried it also in activities and with ".Client"
The code in onCreate()
startService(new Intent(this, Client.class));
or
startService(new Intent(this.getApplicationContext(), Client.class));
or
Intent intent=new Intent("com.android.fh.EnOceanApp.Client.class");
this.startService(intent);
or
Intent intent=new Intent("com.android.fh.EnOceanApp.Client");
this.startService(intent);
And now, I dont have an Idea anymore....
com.android.fh.EnOceanApp is the package, Client.java the service-class in this package
and the manifest I forgot:
<application
android:icon="#drawable/ic_launcher"
android:label="#string/app_name" >
<activity
android:label="#string/app_name"
android:name=".EnOceanAppActivity" >
<intent-filter >
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".ListView"
android:label="List View">
</activity>
<activity android:name=".GraphView"
android:label="Graph View">
</activity>
<service
android:name=".Client"></service> //with and without ., of course without this comment
</application>
Thanks to user njzk2 for letting me notice what was happening.
I've had the same problem. It seem that Android OS can't find the service class that you've requested if you haven't registered before in the manifest file of your proyect.
Remember that a service is like an activity but without graphic interface. It means that the services needs to be registered before you can use them
This is how you register the service in your Android project:
<application>
<!-- your code -->
<activity>
<!-- your code -->
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name="com.your.own.service.class"></service>
</application>
Just Remember that YourService class needs to extend from Service, if not your class won't be a service.
public class YourService extends Service{}
Sometimes you'll need to fully qualify your class name in the manifest, rather than using the shortform (.classname). I've seen that when I used classes from a different package, but perhaps it would help here since the service intent may go outside of the app.
So.. just to eventually help others or not:
I made a new project, copied the sources and tried to run it: the service was found now.
What was the difference, or in other words: what do I think, might give problems:
the long package name or the beginning with com.android... In the new project I just chose com.enocean
Despite ALL the answers in this post and many related Unable to start service Intent: not found Unable to start Service Intent , I still struggled and it took some time for me to get this going. My scenario was slightly more complicated since I'm trying to start a service in a DIFFERENT app that the one I'm calling it with. I figured it out and here are ALL the details, along with some bonus code.
MainActivity of calling intent (or whereever)
Intent intent=new Intent("com.example.core.MusicService.1234");
//Or Intent intent=new Intent("com.example.core.MusicService.TOGGLE_PLAYBACK");
PendingIntent pendingIntent = PendingIntent.getService(this, 99, intent, PendingIntent.FLAG_CANCEL_CURRENT);
Manifest: of Service (Service tag inside Application tag)
It's
<service android:name="com.example.core.MusicService">
<intent-filter>
<action android:name="com.example.core.MusicService1234"></action>
</intent-filter>
<intent-filter>
<action android:name="com.example.core.MusicService.TOGGLE_PLAYBACK"></action>
</intent-filter>
</service>
MusicService.java
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
if(intent != null){
if(intent.getAction() != null){
if(intent.getAction().contentEquals("com.example.core.MusicService.TOGGLE_PLAYBACK")){
//Do work here
}
}
}
}
Notes
Service does NOT need to be started, this intent will start it
"com.example.core.MusicService1234" and "com.example.core.MusicService.TOGGLE_PLAYBACK" can be whatever you want it to be, but obviously needs to match the intent-filter in the service manifest with the calling intent. You can put multiple of these so you can do different actions when your service starts depending on the value from your intent
99 can be whatever you want, but must be unique if you're using notifications
I'm not sure it's possible to call a service in a different app (like this) without using the intent-filter - if it is, someone please enlighten us. I tried and it doesn't work.
Credit to: the cumulative information from all the posts :)
I made the silly mistake of adding the tag to a separate in the manifest.
In that case, the current application was unable to find the service defined.
Hope you skip that mistake :)
Thanks.
It is stupid mistake of android
This will not work
<service
android:name=".classname"/>
But this will work, have separate closing tag
<service
android:name=".classname"></service>
Well, in my case i had to clean the project. It sometimes happens when you have made a new Java class for the service in your package/project but did not build/clean the project afterwords. In my case, i just had to clean the project to get rid of the error.
If anyone sees this and has the same problem that I did, it was because I followed a guide and used context.startService() instead of context.startActivity()
I have an Android app with 2 activities defined below. In the MainMenu.oncreate(), I have an AlarmManager kicked off to periodically query a server for data and update the text of a button in the PlayBack UI. Can I access the Playback object via a global reference or do I need to kick off the AlarmManager in the Playback.oncreate() instead so I can pass a reference to it? If so, should this be done with a BroadcastReceiver and Intent as I'm doing in the MainMenu shown below?
<application android:icon="#drawable/icon" android:label="#string/app_name">
<activity android:name=".MainMenu"
android:label="#string/app_name">
</activity>
<activity android:name=".Playing" android:label="#string/playing_title">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<receiver android:name=".NotificationUpdateReceiver" android:process=":remote" />
<service android:name="org.chirpradio.mobile.PlaybackService"
public class MainMenu extends Activity implements OnClickListener {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_menu);
View playingButton = findViewById(R.id.playing_button);
playingButton.setOnClickListener(this);
try {
Long firstTime = SystemClock.elapsedRealtime();
// create an intent that will call NotificationUpdateReceiver
Intent intent = new Intent(this, NotificationUpdateReceiver.class);
// create the event if it does not exist
PendingIntent sender = PendingIntent.getBroadcast(this, 1, intent, PendingIntent.FLAG_UPDATE_CURRENT);
// call the receiver every 10 seconds
AlarmManager am = (AlarmManager) getSystemService(ALARM_SERVICE);
am.setRepeating(AlarmManager.ELAPSED_REALTIME, firstTime, 10000, sender);
} catch (Exception e) {
Log.e("MainMenu", e.toString());
}
}
}
I have an Android app with 2 activities defined below.
You only have one activity.
In the MainMenu.oncreate(), I have an AlarmManager kicked off to periodically query a server for data and update the text of a button in the PlayBack UI.
Why? Do you intend for these alarms to go on even after the user exits out of the activity?
Can I access the Playback object via a global reference or do I need to kick off the AlarmManager in the Playback.oncreate() instead so I can pass a reference to it?
Neither.
Using AlarmManager means that you want the periodic work to continue even after the user exits the activity. Hence, it is very likely that there is no "Playback object", since the user probably is not in your activity. Your service can send its own broadcast Intent to be picked up if the Playback activity is still around. This sample project demonstrates using an ordered broadcast for this, so that if the activity is not around, a Notification is raised instead.
If, on the other hand, you do not want the periodic work to continue if the user gets out of the activity, then do not use AlarmManager. Use postDelayed() within the activity, using a Runnable that triggers your service via startService(), then reschedules itself via postDelayed(). In this case, you can consider using something like a Messenger as a way to have the service let the activity know what is going on, if the activity is still around. This sample project demonstrates the use of a Messenger in this fashion.