简体   繁体   中英

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?

ps 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:

  1. 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 ie when I press back, I'll see activity B and on pressing back app would finish and the launcher will be displayed.
  2. 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 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:

  1. C -> B in case 1
  2. 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 (eg will produce unexpected results when called in a loop due to the Handler )

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.

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM