Reputation: 37
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
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