Tunny
Tunny

Reputation: 37

How accurate are 'jank' alerts in adroid studio?

I have a simple app which does some not-too-complex calculations in separate threads in a MainViewModel java class, whose methods are called from within a MainActivity.java class which in turn updates a very simple UI with two buttons, two text fields and a text view. I am getting these warnings of high skipped frames:

2024-04-28 15:32:20.893 20041-20041/com.niff.inout I/Choreographer: Skipped 365 frames!  The application may be doing too much work on its main thread.
2024-04-28 15:32:31.805 20041-20041/com.niff.inout I/Choreographer: Skipped 298 frames!  The application may be doing too much work on its main thread.
2024-04-28 15:33:25.564 20041-20041/com.niff.inout I/Choreographer: Skipped 2733 frames!  The application may be doing too much work on its main thread.

I have used the emulator (API level 30) for the most part, but the warnings have also come on my device - on one occasion over 16,000 frames skipped. They seem to come as the app is loading onto the emulator or device. I have overriden the MainActivity's 'onResume()' method to read very simple data from a file (again, on a separate thread in MainViewModel.java). The warnings come randomly and inconsistently - I can go days on end with the numbers of skipped frames below 50, then suddenly they are in the thousands. But I have never noticed any flickering of the screen on the emulator or device, which I understand is the main symptom of 'jank'. I get the warnings on both the debug and release versions, in fact the warning of 16,000 was (I think) on the release version on my device. I don't know how relevant this is, but when I switch between debug and release versions I get an 'IDE error' (Android Studio Chipmunk). I have tried to follow the advice here https://developer.android.com/studio/profile/jank-detection but do not really understand the instructions for use of the profiler. I have only 8Mb of RAM on my laptop - is that a factor? Can forgotten debugging breakpoints in the code affect this issue?

Thanks very much for taking the time to reply! I have actually written this in Java, not Kotlin, but I think I have pretty much done what you suggest. I have this in my onCreate method:`

myViewModel = new ViewModelProvider(this).get(MainViewModel.class);
    final Observer<String> resObserver = new Observer<String>(){
        @Override
        public void onChanged(@Nullable final String result){
            binding.history.setText(result);
        }
    };
    myViewModel.getResult().observe(this, resObserver);

plus every time myViewModel is initialised:

public class MainViewModel extends ViewModel {
private MutableLiveData<String> res = new MutableLiveData<>();
File file;
fric fri;
ArrayList<fric> spends;
StringBuilder sb;
String stats = "";
private DecimalFormat df = new DecimalFormat("#####0.##");
LocalDate today = LocalDate.now();
BigDecimal total = new BigDecimal(0.00);
BigDecimal totals[] = new BigDecimal[12];
boolean isTotal = false;
Month month;
int mois, savedMois;

public MainViewModel() {
    file = new File("data/data/com.niff.inout/files/amounts.dat");
    spends = new ArrayList<fric>();
    month = today.getMonth();
    mois = month.getValue();
}

('fric' is a very simple java class for keeping track of items of expenditure) plus every time onResume is called I have this method in myViewModel:

protected void readObjects(){
    Runnable runnable = new Runnable() {
        @Override
        public void run() {
            if (file.exists()) {
                try {
                    FileInputStream fis = new FileInputStream(file);
                    ObjectInputStream ois = new ObjectInputStream(fis);
                    Object obj = ois.readObject();
                    spends = (ArrayList<fric>) obj;
                    obj = ois.readObject();
                    totals = (BigDecimal[]) obj;
                    savedMois = ois.readInt();
                    ois.close();
                    fis.close();
                } catch (Exception e) {

                }
            }
        }
    };
    Thread myThread = new Thread(runnable);
    myThread.start();
}

I cannot guarantee the quality or accuracy of the code (though it does work!) - I am a complete amateur. Is it too much going on? 16,000 frames skipped is way more than I have seen on any other posts (and above you can see 2733 skipped). And I have mainly been using the emulator, though I take on board your comments about devices - my device is a Motorola Moto e30, a very cheap device though entirely adequate for my needs (long time user of Motorola!).

Upvotes: 0

Views: 84

Answers (1)

Dan Gerchcovich
Dan Gerchcovich

Reputation: 525

Newer devices might not experience issues, but the older ones definitely will notice.

Best thing to do is to abstract as much work as possible into a coroutine, so it runs asynchronously.

https://kotlinlang.org/docs/coroutines-overview.html

Then use LiveData to notify the UI once data is available. https://developer.android.com/topic/libraries/architecture/livedata

Here's an example of a LiveData/Flow implementation with a ViewModel. So, Let's say you have a simple app that writes notes into Room Storage.

Here's the Dao

@Dao
interface NotesHandler{
    fun getNotes() : Flow<List<Notes>>
}

@HiltViewModel
class MyViewModel @Inject constructor (val myDbContext: RoomDatabase): ViewModel(){

     val notesHandler = myDbContext.getNotesHandler().getNotes().asLiveData()
}

Then in your activity/fragment (onCreate):

    private val viewModel by viewModels<MyViewModel>()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        
        viewModel.notesHandler.observe(this){
            // my data is process here
            binding.textView.text = it[0].note
        }
    }

Upvotes: 1

Related Questions