How to display log message when an activity is started in Android - android

I am in one activity say Activity A. I am calling another activity B.
In activity A I write the following Statement:
startActivity(new Intent(this,ActivityB.class));
Now, I want to log a debug message only when Activity A is able to successfully launch ActivityB.
How can I achieve this feature in Android.
Any kind of Help is appreciated
Thanks,

You can use the startActivityForResult method to achieve this. Use this in your Activity "A"
Or else if thats not what you are looking for, I am guessing you want to log when activity B starts and stos. Activity class provides lifecycle methods for start, stop, pause resume, etc.
Override them and put your logging code in there:
public class B extends Activity {
private static final String TAG = "B-Activity";
#Override
public void onCreate(Bundle savedInstanceState) {
Log.i(TAG, "Activity created"); // or Log.d for debug
}
#Override
public void onStart() {
Log.i(TAG, "Activity started"); // or Log.d for debug
}
}

Related

Android | Print activity task stack/s in LogCat

I want to print all the tasks that my Android app has initiated with the names of the activities within them on LogCat. Is there any API in the SDK that can provide me this information?
p.s. I can't and don't want to use the adb shell commands as I want to print the logs in LogCat.
Note: I've searched quite a bit and all I've found are the adb shell commands which I can't use. Please keep that in mind while answering.
UPDATE:
Here's an example of what I want with 2 scenarios:
App starts with activity A, I finish it and start activity B. Then I
press a button on activity B that starts activity C. Now my default
task would like C -> B i.e. when I press back, I'll see activity
B and on pressing back app would finish and the launcher will be
displayed.
I open activity A, B & C consecutively then I launch an
activity X with intent flags Intent.FLAG_ACTIVITY_NEW_TASK |
Intent.FLAG_ACTIVITY_CLEAR_TASK and then open activities Y & Z. The
current task will now look like Z -> Y -> X.
So, I want to print these in logcat:
C -> B in case 1
Z -> Y -> X in case 2
What I am trying to do isn't possible out of the box using APIs within the SDK as of now. More info can be found in this link:
How to get a list of my app's tasks and the stack of their Activities?
My Solution:
I had to add logging in base class of my app, printing the activity's name with its task ID to debug the problem I'm facing. Here's the code of my base activity class:
public abstract class BaseAppActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.i("TESTING", "CREATED: " + getClass().getSimpleName() + " -- TASK ID: " + getTaskId());
}
#Override
protected void onDestroy() {
super.onDestroy();
Log.i("TESTING", "DESTROYED: " + getClass().getSimpleName() + " -- TASK ID: " + getTaskId());
}
}
You can generate an activity state report in Android Studio. It gives you the states and routes of activities of the activity you are currently(running) in.
Find the System Information tab in Android Monitor.
Then, Activity Manager State.
Then, it shall generate you stack of your activities. Look for ACTIVITY(all caps).
Hope it helps, although if it is not the log approach.
As time moves on, some folks might have moved on to (Kotlin and) a "single activity with multiple fragments" pattern. Whichs' backstack we can log:
fun FragmentManager.printBackStack() {
Log.d("TAG", "BackStackEntryCount = $backStackEntryCount")
for (i in 0 until backStackEntryCount) {
Log.d("TAG", " #$i is ${getBackStackEntryAt(i)}")
}
}
Calling this from an activity would look like:
supportFragmentManager.printPackStack()
Please keep in mind, that fragment-transactions work asynchronously.
Therefore, the following code will produce unexpected results:
addSomeFragmentToBackStack("MyFragmentTag")
printBackStack()
// result doesn't include "MyFragmentTag"
Instead, you will need to execute the printing delayed:
addSomeFragmentToBackStack("MyFragmentTag")
Handler().postDelayed(
{ printBackStack() },
500 // ms delay
)
This solution definitely isn't perfect, but it's ok for debugging (e.g. will produce unexpected results when called in a loop due to the Handler)
It seems you are interested in logging life-cycle of your app(for components Activity,Fragments,App,Service,BroadcastReciever,etc). You can do so by making a super class and extend it to print Log in its life cycle method ,so that you need not to print it every time.You need to make a super-Activity,super-Fragment etc
For example following will log every time app is initialized by OS (by launcher, by BroadcastReciever)
public class LifeCycleApp extends Application {
String TAG = "GUFRAN " + LifeCycleApp.class.getName();
public LifeCycleApp() {
Log.d(TAG, "LifeCycleApp: constructor");
}
#Override
public void onCreate() {
super.onCreate();
Log.d(TAG, "onCreate: ");
}
// Called by the system when the device configuration changes while your component is running.
// Overriding this method is totally optional!
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
}
// This is called when the overall system is running low on memory,
// and would like actively running processes to tighten their belts.
// Overriding this method is totally optional!
//Called when the overall system is running low on memory, and actively running processes should trim their memory usage
#Override
public void onLowMemory() {
super.onLowMemory();
}
#Override
protected void finalize() throws Throwable {
super.finalize();
Log.d(TAG, "finalize: ");
}
}
You might want to look at this
https://github.com/guffyWave/LifeCycle
According to Android Developers
Generally, you should use the Log.v(), Log.d(), Log.i(), Log.w(), and Log.e() methods to write logs. You can then view the logs in logcat.
import android.util.Log;
public class MyActivity extends Activity{
private static final String TAG = "MyActivity";
#Override
public void onCreate(Bundle bundle){
Log.v(TAG, "on create");
}
}
update
Since you want to track the active activities and you know how activity cycle works. The solution would be like this:
#Override
public void onPause(Bundle bundle){
Log.v(TAG," activity A paused"); // or whatever
}
Other solution would be to do this before the startActivity
something like this:
Intent i = new Intent(ThisActivity.class,AnotherActivity.class);
Log.v(TAG,"A->b");
// Log.v(TAG,"Z -> Y -> X"); or what ever message you want to print
startActivity(i);
Third solution would be to provide some info if you are not sure which activity will start which intent.
In activity A do this before starting the intent:
intent.putExtra("UActivity", "From A");
In activity B do this in onCreate:
String from = getIntent().getStringExtra("UActivity");
if("From A".equals(from){
Log.v(TAG,"A->B");
}else if("From C".equals(from){
Log.v(TAG,"C->B");
}// etc else if
so just follow up the activity lifecycle and print the correct log messages at the correct methods and this should make it work.

return to the same activity, When restart the app

I have a lot of activities in my app, and I want that if the user closes the app in activity 13 for example, when opening the app at another time the activity returns in activitty n° 13. how can I do this? thank in advance
You could use SharedPreferences to keep track of the last used activity.
Then you can redirect the user in the onCreate of your main activity to the correct activity, and call finish on your main activity.
This could look something like this:
#Override
protected void onCreate(Bundle savedInstanceState)
(...)
int last_activity = getLastActivityIdFromSharedPreferences();
if (last_activity == 1)
{
this.startActivity(new Intent(this, ActivityOne.class));
finish();
}
(...)
}

How to always start from a startup activity on Android?

There are three different cases:
1) A user launches an app, navigates in it, pressed home and click on the app icon again to launch our app again.
2) A user launches an app, navigates in it, presses home, chooses recent and click on the app to launch our app again.
3) A user launches an app, navigates in it, click something in the app (TextView with a link), which calls another app (as example Email) and user clicks back button, which bring us back to our app.
I know about flag "clearTaskOnLaunch" flag, it solves case #1.
I know about about flag "excludeFromRecents", it solves case #2 (may be not the most user friendly solution, but it works).
What about case #3? I have a workaround right now. However, I will have to put it on all activities which can be lead to another app. I wonder, whether there is better way to solve it (without handling it in all such activities).
This should be handled on the Application level.
For API level 14, you can register an ActivityLifeCycleCallback in your Application class
public void registerActivityLifecycleCallbacks (Application.ActivityLifecycleCallbacks callback)
You can use it, to know on an Application level, which activities are destroyed, paused, resumed etc etc. Whenever, an activity is paused, without a new activity being created/resumed, you should clear the Activity stack, and re-launch your startActivity
If you target SDK versions < 14, you should implement your own method, to know which activities are created/resumed and paused, and do the same whenever an activity is paused, without a new activity being created/resumed
1) define a public static normalPause = true variable in a Class.
2) in onPause method of all of your activities set it false (I am worry. We might not be in a normal pause)
2) in onCreate method of all of your activities set it true (Do not worry. We are in a normal pause)
3) in onResume of all of your Activities:
if(!Utilities.normalPause)
{
this.finish()
}
Enjoy!
It seems a similar question has already been asked. It sounds like the OP came up with a working solution. How do I collapse "child activities"?
EDIT:
Instead of using a button you can use a boolean to tell whether or not you need to collapse back to the main activity. Have your root activity extend from Activity and the child activities extend from CollapsableActivity. To get this to work in all cases I added startOutsideActivity() and startOutsideActivityForResult().
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
public class CollapsableActivity extends Activity {
private boolean returnToRoot;
public static final int COLLAPSE_BACK = -1; // something other than RESULT_CANEL (0)
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
returnToRoot = true;
}
#Override
protected void onStart() {
super.onStart();
returnToRoot = true;
}
#Override
protected void onRestart() {
super.onRestart();
// start collapsing the stack
if (returnToRoot) {
setResult(COLLAPSE_BACK);
finish();
}
}
#Override
public void startActivityForResult(Intent intent, int requestCode) {
super.startActivityForResult(intent, requestCode);
returnToRoot = false;
}
public void startOutsideActivityForResult(Intent intent, int requestCode) {
super.startActivityForResult(intent, requestCode);
returnToRoot = true;
}
#Override
public void startActivity(Intent intent) {
// call startActivityForResult to make sure and catch the collapse condition
super.startActivityForResult(intent, 0);
returnToRoot = false;
}
public void startOutsideActivity(Intent intent) {
super.startActivity(intent);
returnToRoot = true;
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == COLLAPSE_BACK) {
returnToRoot = true;
}
}
}
This worked properly for me in all cases you listed. The only difference is you need to call startOutsideActivity() or startOutsideActivityForResult() when you navigate away from you app. Personally, I think this adds clarity to your intentions. Hope it helps!
I know you don't want to manage it in all activities but you can do this and still handle the code in one place with a super activity
public abstract class BlundellActivity extends Activity {
#Override
public void onPause(){
// Whatever strategy you want
}
}
public class SomeActivity extends BlundellActivity {
// Do whatever you normally want to do
}
public class SomeActivity extends BlundellActivity {
// Do whatever you normally want to do here as well
}
Perhaps, android:noHistory is what you're looking for. If you declare all your activities except StartupActivity with this attribute, then they will be finished as the user navigates away from them and only StartupActivity will appear.
You can try this steps:
use one boolean static flag isFinish in StartupActivity with default false value.
in onCreate() of StartupActivity set isFinish value to false.
write below code in onResume() method of all activities in your project.
if(isFinish)
{
finish();
}
set isFinish value to true when you open any native app like email, browser etc.
or
5 . set isFinish value to true in onBackPress() method whenever you want to close application on back press.
Case 6: if android browser open on clicking on any link then use below code is onPause() method
if(isBrowserRunning("com.android.browser"))
{
isFinish = true;
finish();
}
////////////////
private boolean isBrowserRunning(String processName)
{
ActivityManager manager = (ActivityManager) this.getSystemService(ACTIVITY_SERVICE);
String packageName = manager.getRunningTasks(1).get(0).topActivity.getPackageName();
Log.i("LogTest", "Current process package name: " + packageName);
return processName.equalsIgnoreCase(packageName);
}
You can create a sample project to know other browser package name like opera mini, US browser etc.
add below permission in manifest:
<uses-permission
android:name="android.permission.GET_TASKS" />
You can call this.finish() on the onPause() of your Activity, that way the activity will be closed in the three cases.
You need to use bundle and pass appropriate parameter/or parameters from the calling app (i.e. click something in the app (TextView with a link)).
Retrieve the parameter in the called app (Email app).
You can send the name of the activity in the parameter.
Now being in Email app(the called app) Click of back button navigate back to your calling application.
Optionally you can save the state of activity from the caller program, as required.
You need to use Bundle, and Intent to implement this logic.
Code snippet:
In the calling program, we need to store parameters/data required for back button functionality in the called program.
Bundle bndleData = new Bundle();
Use putString(), putInt() methods of Bundle class.
String prefix = getPackageName().toString();
(this prefix can be stored in application level constants.java file as applicable)
bndleData.putString("ParentActivity", this.getLocalClassName());
Also store additional parameters if required
bndleData.putString("paramName", valueofParamName);
bndleData.putInt("IntChannelImage", chImageInt);
Intent intent = new Intent(v.getContext(), AMRChannelPlayer.class);
intent.putExtra(prefix + "bndleChnlData", bndleData);
startActivity(intent);
Caller Program:
Retrive the data, activity nae from bundle and use it in back button implementation:
prefix = getPackageName().toString();
Bundle extras = getIntent().getBundleExtra(prefix + "bndleData");
String parentActivity = extras.getString("ParentActivity");
extras.getString("paramName");
I hope this helps you.
Instead of using multiple solutions you can use a single one that solves all the problems.
Check this answer:
https://stackoverflow.com/a/8576529/327011
With a Broadcast and BroadcastReceivers in each activities of your application you can kill all activities whenever your application goes to background.
UPDATE:
To detect if your application when to background you can use onStop, check this to understand the theory: Activity side-by-side lifecycle
And this is the implementation: https://stackoverflow.com/a/5862048/327011
I think this is all you need :-)

Notification opens activity, press back button, prevent opening back stack activity?

This looks very similar to my previous question because it's some sort of follow up. I was not very happy with the only solution given; also, the solution was for a problem slightly different from this one. So let me try to explain the problem again...
A notification is created at boot (with a BroadcastReceiver).
My app main activity is opened and the home button is pressed (the activity will be sent to the back stack).
I pull down the status bar and press on the notification previously created at boot.
That will start some activity, different from the main one.
I press the back button and the main activity is displayed.
This is not very different from my previous question... The thing is, "main activity" was just an example. I could have opened the app main activity and then opened the about activity through a menu option and pressed the home button. The back stack would now be MainActivity » AboutActivity. Which means that when the back button is pressed while in "some activity" (started by pressing the notification), we would be brought to the top of the back stack, that is, the about activity.
What basically want is to prevent any other activity to be opened when I press the back button while in "some activity" (again, started by pressing the notification). I want to be brought exactly where I was, that could be the desktop or some other app's activity, but not my app's MainActivity nor AboutAcitivity cause that's not where I was, those were in the back stack, "sleeping" in the background.
I have come up with a solution, but I don't think it's very elegant and I was looking for something more, well, elegant... If you have any other suggestion, please, let me know.
Anyway, this is my proposed solution:
// I use this class for public static (or public static final) members and
// methods
public final class AppHelper {
public static final String KEY_RESUME_FROM_NOTIFICATION = "resumeFromNotification";
private static boolean sResumeFromNotification = false;
public static boolean getResumeFromNotification() {
return sResumeFromNotification;
}
public static void setResumeFromNotification(boolean resumeFromNotification) {
sResumeFromNotification = resumeFromNotification;
}
}
public class MainActivity extends ListActivity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
(...)
}
#Override
protected void onResume() {
super.onResume();
if(AppHelper.getResumeFromNotification()) {
AppHelper.setResumeFromNotification(false);
moveTaskToBack(true);
}
}
}
public class AboutActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
(...)
}
#Override
protected void onResume() {
super.onResume();
if(AppHelper.getResumeFromNotification()) {
AppHelper.setResumeFromNotification(false);
moveTaskToBack(true);
}
}
}
public class SomeActivity extends Activity {
// This will be called when the notification is pressed and the activity is
// not opened yet
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
(...)
extractIntentExtras(intent);
}
// This will be called if the activity is already opened and the
// notification is pressed
#Override
protected void onNewIntent(Intent intent) {
extractIntentExtras(intent);
super.onNewIntent(intent);
}
private void extractIntentExtras(Intent intent) {
Bundle bundleExtras = intent.getExtras();
if(bundleExtras != null) {
// These intent extras are set on the Intent that starts this activity
// when the notification is pressed
AppHelper.setResumeFromNotification(bundleExtras.getBoolean(
AppHelper.KEY_RESUME_FROM_NOTIFICATION));
mRowId = bundleExtras.getLong(AgendaNotesAdapter.KEY_ROW_ID);
populateNoteUpdateFields();
}
}
}
I don't know, but this solution doesn't look very elegant to me (but it works as I expect it) and I'm looking for alternatives or for strong opinions on my proposed solution as an acceptable and good solution. Thoughts?
After doing some more reading perhaps this is the combination of flags you need:
Intent intent = new Intent(mContext, SomeActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
startActivity(intent);
I think that should force your SomeActivity class to be launched in a completely new task.
When launching the Activity from the notification, you can control how the Activity you are about to open is put on the back stack, and what task it's associated with with Intent flags. You can try something like:
Intent intent = new Intent(mContext, SomeActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
If that doesn't work, try setting a few of the other flags until you get the desired behavior.
Do you ever want your MainActivity to stay in history? If not then my simple, crude solution is to finish the MainActivity when it is paused.
(Call this in your MainActivity)
#Override
public void onPause() {
finish();
}
This will ensure that your MainActivity is removed from history when you navigate away from it, and will never appear when the back button is pressed.
This could be used for AboutActivity as well.

How to kill app on button press

I have an app that has a lot of activities. In the "Settings" page there is a delete account button that is supposed to reset all the saved variables and exit the app. I haven't found a simple solution to exiting the app (eg calling finish only destroys the current activity) What do I call to close the app on a button press (eg when I reopen the the app it should start from the first activity)
Easiest way to do this is to register a BroadcastReceiver in all Activity classes that listens for a specific Intent. When you want to close everything then just fire the matching Intent, and in the BroadcastReceiver in each Activity call finish.
Try System.exit(0), although you're technically suppose to use finish() on all the activities. This does the same, but quickly.
Use this:
Process.killProcess(Process.myPid());
Or there is another more safer approach. Just subclass all of your activities, from one parent Activity and keep list of all alive activities and then when necessary close them all using exit():
public class ControlActivity extends Activity
{
private static ArrayList<Activity> activities=new ArrayList<Activity>();
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
activities.add(this);
}
#Override
public void onDestroy()
{
super.onDestroy();
activities.remove(this);
if(activities.size()==0) //last activity
//release resources and so on
}
//close all activities, when necessary
public static void exit()
{
for(Activity activity:activities)
activity.finish();
}
}

Categories

Resources