1
00:00:04,380 --> 00:00:06,220
G'day, welcome back.

2
00:00:06,220 --> 00:00:12,920
Okay, the title of this video's probably given away what the problem is, with the way we're doing things.

3
00:00:12,920 --> 00:00:15,420
With the old CursorLoader class,

4
00:00:15,420 --> 00:00:20,320
the Loader made sure that the database
accesses were performed on a background thread.

5
00:00:20,320 --> 00:00:25,120
We're moving away from loaders, and now we have to take care of that ourselves.

6
00:00:25,120 --> 00:00:29,940
In Kotlin, it's incredibly easy,
using an extension function.

7
00:00:29,940 --> 00:00:35,180
Let's start by seeing how we can tell whether something's running on the main thread, or not.

8
00:00:35,180 --> 00:00:53,720
Run the app again, then open the logcat.

9
00:00:53,720 --> 00:00:57,660
You may find that you're still getting
all sorts of events being logged,

10
00:00:57,660 --> 00:01:02,720
even when you've got the 'show only selected application' filter set.

11
00:01:02,720 --> 00:01:10,399
If that happens, use the second drop-down from the left, to choose your application again.

12
00:01:10,399 --> 00:01:14,210
That seems to put it right, and prevent all
that extra stuff from appearing.

13
00:01:14,210 --> 00:01:18,380
Each entry in the logcat starts with the date and the time.

14
00:01:18,380 --> 00:01:24,000
After that, are the process ID and the thread ID, separated by a dash.

15
00:01:24,000 --> 00:01:31,880
The main UI thread has the same ID as the app's process.
Any new threads that are created will have a new ID,

16
00:01:31,880 --> 00:01:35,440
which will be a number greater than the process ID.

17
00:01:35,440 --> 00:01:39,260
A quick way to see everything is executing on a background thread,

18
00:01:39,260 --> 00:01:42,900
is to search for the process and thread ID of the app.

19
00:01:42,900 --> 00:01:50,840
For example, my process and thread IDs for the main thread are both 7972.

20
00:01:50,840 --> 00:01:57,900
So I'll select 7972-7972 in the logcat,

21
00:01:57,900 --> 00:02:11,580
and use ctrl F (command F on a Mac) to highlight all the matches.

22
00:02:11,580 --> 00:02:16,540
That highlights all the entries that are
created by code running on the main thread.

23
00:02:16,540 --> 00:02:19,440
Everything else is running on a background thread,

24
00:02:19,440 --> 00:02:23,900
and the highlighting makes it easy to pick those entries out of the list.

25
00:02:23,900 --> 00:02:28,900
The app hasn't done much,  but there may still be some
background threads started.

26
00:02:28,900 --> 00:02:33,340
When the OpenGL renderer logs its initialization, for example,

27
00:02:33,340 --> 00:02:35,560
that should be on another thread.

28
00:02:35,560 --> 00:02:41,820
You may also see zygote logging code cache collection,
when garbage collection is performed.

29
00:02:41,820 --> 00:02:47,400
We're interested in database access -
the entries logged by AppProvider.

30
00:02:47,400 --> 00:02:52,200
SingletonHolder and AppDatabase are all on the main thread.

31
00:02:52,200 --> 00:02:55,000
That's not good, so let's fix it.

32
00:02:55,000 --> 00:02:58,040
I'm going to show you two easy ways to do that.

33
00:02:58,040 --> 00:03:03,960
The first will involve creating a new thread.
The other way is to use a coroutine.

34
00:03:03,960 --> 00:03:09,320
These are much cheaper to use, there's far fewer overheads when using a Coroutine,

35
00:03:09,320 --> 00:03:11,320
rather than creating a new thread.

36
00:03:11,320 --> 00:03:20,420
Okay, back to our TaskTimerViewModel code.

37
00:03:20,420 --> 00:03:27,020
To access the database on a background
thread, all we have to do is use the thread extension function,

38
00:03:27,020 --> 00:03:29,660
and pass our code to it as a lambda block.

39
00:03:29,660 --> 00:03:36,420
I'll start with the deleteTask function,
because that's very short and simple.

40
00:03:36,420 --> 00:03:44,620
We simply log what's happening,
and surround the existing code with a thread.

41
00:03:44,620 --> 00:03:45,920
That's it.

42
00:03:45,920 --> 00:03:50,280
The extension function uses default
values for all the other settings

43
00:03:50,280 --> 00:03:54,180
the thread class needs, and starts the
thread for us.

44
00:03:54,180 --> 00:04:04,100
Let's see that working before we change the rest of the code.
Run the app

45
00:04:04,100 --> 00:04:08,740
and search for the process and thread ID of the main thread again.

46
00:04:08,740 --> 00:04:16,420
It'll be a different number this time.

47
00:04:16,420 --> 00:04:26,480
On the emulator, delete task 3.

48
00:04:26,480 --> 00:04:33,520
Now the entries for AppProvider and SingletonHolder have a different thread ID, when we delete the task.

49
00:04:33,520 --> 00:04:39,100
Scroll through the logcat, and the AppProvider entries that
appear when the database is re-queried,

50
00:04:39,100 --> 00:04:42,920
are still running on the main thread. That's easy to fix.

51
00:04:42,920 --> 00:04:52,260
We just need to use a thread for the
database access code in the load tasks function.

52
00:04:52,260 --> 00:04:59,800
All we need to do is to wrap the existing code into a thread.

53
00:04:59,800 --> 00:05:04,920
Before running the app again, open the terminal pane,

54
00:05:04,920 --> 00:05:16,640
and enter the command
adb shell setprop log.tag.SQLiteQueryBuilder DEBUG

55
00:05:16,640 --> 00:05:21,960
That turns on debug logging for the query builder,
as we did a few videos ago.

56
00:05:21,960 --> 00:05:28,740
Now we'll also see the query being created, and can confirm that that's happening on a separate thread too.

57
00:05:28,740 --> 00:05:32,900
If you're doing this on a physical device, rather than an emulator,

58
00:05:32,900 --> 00:05:36,220
remember to reboot your device when you've finished.

59
00:05:36,220 --> 00:05:42,560
Otherwise the debug logging will stay in effect,
and the performance of your phone may suffer.

60
00:05:42,560 --> 00:05:46,560
When you don't need to work with the results of a code block straight away,

61
00:05:46,560 --> 00:05:50,360
this is a very easy way to run it on a separate thread.

62
00:05:50,360 --> 00:05:55,620
In these two cases, we're not interested in waiting for the
database accesses to complete.

63
00:05:55,620 --> 00:06:02,040
When deleting a task,
the ViewModel will get a notification by its ContentObserver,

64
00:06:02,040 --> 00:06:04,400
and it will re-query the database.

65
00:06:04,400 --> 00:06:09,380
There's no need for the ViewModel to wait for the delete operation to complete.

66
00:06:09,380 --> 00:06:16,040
All the code that responds to a delete will be executed,
when the delete is eventually performed.

67
00:06:16,040 --> 00:06:18,900
The same is true for querying the database.

68
00:06:18,900 --> 00:06:23,700
When the query finishes, and we get a new cursor back in loadTasks,

69
00:06:23,700 --> 00:06:28,240
the database cursor live data object gets
that new cursor.

70
00:06:28,240 --> 00:06:33,140
That causes MainActivityFragment to swap the adapter's cursor,

71
00:06:33,140 --> 00:06:38,260
because MainActivityFragment is observing the live data object.

72
00:06:38,260 --> 00:06:43,880
Run the app again, and search for the new process ID main thread ID.

73
00:06:43,880 --> 00:07:05,260
Remember that they change every time you restart the app.

74
00:07:05,260 --> 00:07:13,140
Scrolling through the logcat, you can see that the AppProvider query function is being called on a separate thread.

75
00:07:13,140 --> 00:07:20,660
You can see the entry "forming query, select ID, name, description, sort order from tasks,

76
00:07:20,660 --> 00:07:25,340
order by sort order and name" running on that different thread.

77
00:07:25,340 --> 00:07:28,860
All the database access is also happening on that thread.

78
00:07:28,860 --> 00:07:32,960
That's seriously cool. It really is that easy.

79
00:07:32,960 --> 00:07:35,000
I'll stop this video here.

80
00:07:35,000 --> 00:07:40,420
In the next video, we'll see how to
do the same thing using Coroutines.

81
00:07:40,420 --> 00:07:42,120
See you in the next one.

