J, 57 bytes
,&([:(0#@-.~~.@,)](*@[*[:>./((,-)#:i.3)|.!.0])^:_ i.@$)-.
This is one of those where the idea is incredibly simple (and I think fun), but executing it had some mechanical lengthiness which masks the simplicity... eg, shifting the original matrix in all directions with 0 fill is the verbose ((,-)#:i.3) |.!.0
.
It's likely this mechanical lengthiness can be golfed further, and I may try tomorrow evening, but I'll post the crux of it now.
Say our input is:
0 0 0 0
1 1 1 1
0 0 0 0
1 1 1 1
We start with a matrix of unique integers the same size:
0 1 2 3
4 5 6 7
8 9 10 11
12 13 14 15
Then for each cell we find the max of all its neighbors, and multiply by the input mask:
0 0 0 0
8 9 10 11
0 0 0 0
13 14 15 15
We iterate this process until the matrix stops changing:
0 0 0 0
11 11 11 11
0 0 0 0
15 15 15 15
And then count the number of unique, non-zero elements. That tells us the number of 1-islands.
We apply the same process to "1 minus the input" to get the number of 0-islands.