Информация со stackoverflow:
Если в классе активити для установки связи с SurfaceView используется xml-разметка, например setContentView(R.layout.main) , то в подклассе SurfaceView будет вызываться метод onDraw().
Преимущества: легко реализуется прокрутка и масштабирование канваса.
Недостатки: при каждом вызове onDraw() канвас должен перерисовываться полностью. При рисовании пальцем он вызывается при смещении на каждый пиксель. Попытка рисовать вне onDraw() - см. мой вопрос выше.
Примечание: В конструкторе подкласса SurfaceView кроме аргумента Context должен быть аргумент AttributeSet, иначе приложение сразу завершается с ошибкой.
Если в активити для установки вью используется экземпляр SurfaceView, например setContentView(new MySurfaceView(this)), метод onDraw() не вызывается. Получение канваса методом lockCanvas и последующее рисование возможно. Но здесь начинается своя головная боль.
Например, нарисованное в методе onSurfaceCreated() не сохраняется при последующих попытках рисовать. Документация говорит, что методу lockCanvas можно передать "грязный" прямоугольник, вне которого пиксели между вызовами lockCanvas будут сохраняться. Но это не работает. Переданный аргументом типа Rect "грязный" прямоугольник будет растянут на весь экран. (Проверено методом drawRect, которому передан тот же прямоугольник.
Ну и, что неудивительно, с прокруткой и масштабированием все будет сложнее.
Примечание: пример выше годится для конструктора с одним аргументом типа Context. Здесь AttributeSet не обязателен. Если же этот второй аргумент присутствует, ему можно передать NULL.
Таким образом, метод setContentView() задает один из подходов к рисованию на холсте.