Abstract.
기존에 하던 프로젝트를 완전 싹 갈아 엎어야 하는 일이 생겨서 프로젝트를 새로 만들었다. 안드로이드 스튜디오에는 DataBinding이라는 것이 있는데 이 기능을 사용하여 개발을하면 코드를 훨씬 간편하게 짤 수 있기 때문에 DataBinding을 사용하는 것을 염두해두고 프로젝트의 화면 하나를 만들었다. 여기서 에러가 하나 발생하게 되는데, 간단히 요약하자면 xml 파일에서 작성한 레이아웃을 DataBinding을 사용하기 위해 <layout> 태그로 감싸놓았는데 이 화면을 사용하는 자바코드에서 DataBinding 설정을 하지 않아 발생한 내용이다.
1. 에러 내용
프로젝트에서 DataBinding을 사용할 것을 생각하고 화면을 정의하는 xml 레이아웃 파일과 자바코드를 작성했다. 간단히 커스텀 타이틀바와 커스텀 버튼이 정상 작동하는지 테스트 하기 위함이었다.
xml 코드
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto">
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:id="@+id/content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/grey1"
android:orientation="vertical"
>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/grey1"
android:orientation="vertical">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="60dp"
android:background="@color/white"
android:contentInsetEnd="0dp"
android:contentInsetStart="0dp"
tools:targetApi="lollipop">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/iv_back"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingBottom="5dp"
android:paddingEnd="21dp"
android:paddingStart="21dp"
android:paddingTop="5dp"
android:src="@drawable/ic_arrowleft_black"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/tv_title"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:gravity="center"
android:lineSpacingExtra="8.7dp"
android:textColor="@color/black"
android:textSize="17dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="Title" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.appcompat.widget.Toolbar>
<include layout="@layout/view_divider_thin" />
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:orientation="vertical"
android:paddingTop="20dp"
android:paddingBottom="20dp">
<TextView
android:id="@+id/tv_save"
style="@style/BtnGreen"
android:layout_width="match_parent"
android:layout_height="67dp"
android:layout_margin="21dp"
android:gravity="center"
android:text="@string/save"
android:textSize="17sp"
android:theme="@style/RegularText" />
</LinearLayout>
</ScrollView>
</LinearLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
</layout>
자바코드
public class BasicSurveyActivity extends BaseActivity implements View.OnClickListener {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_basic_survey);
initToolbar();
}
private void initToolbar() {
Toolbar toolbar = findViewById(R.id.toolbar);
toolbar.setContentInsetsRelative(0, 0);
ImageView ivBack = toolbar.findViewById(R.id.iv_back);
TextView tvToolbarTitle = toolbar.findViewById(R.id.tv_title);
ivBack.setOnClickListener(this);
tvToolbarTitle.setText(R.string.survey_basic);
findViewById(R.id.tv_save).setOnClickListener(this);
}
@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.iv_back: {
// TODO :: 뒤로가기 버튼 눌렀을 때 동작
}
break;
case R.id.iv_cancel: {
// TODO ::
}
break;
case R.id.tv_save:
// proceedPost();
break;
}
}
}
Notice : BaseActivity는 이 프로젝트에서 사용하는 Activity들의 공통 기능을 담아 놓은 Activity다. 재사용을 위해 만들어 놓은 Activity로 AppCompatActivity를 상속받는다.(본 포스팅에서는 딱히 몰라도 되는 내용)
이 에러에서 주목할 내용은 다음 두 가지다.
- BasicSurveyActivity.java:23
- E/AndroidRuntime: Caused by: java.lang.ClassNotFoundException: Didn't find class "android.view.layout" on path:
BasicSurveyActivity.java:23의 내용을 보면 알 수 있듯이, BasicSurveyActivity.java 파일의 23번째 줄에서 에러가 발생했다는데, 확인해보니 다음 코드에서 에러가 발생했다.
setContentView(R.layout.activity_basic_survey);
E/AndroidRuntime: Caused by: java.lang.ClassNotFoundException: Didn't find class "android.view.layout" on path: 에서 알 수 있는 내용은 layout을 찾지 못했다는 것인데, <layout> 태그와 관련된 것임을 알 수 있다.
문제는 여기서 발생했다. xml 레이아웃 파일에 태그로 감싸놓은 것이 원인이었다. DataBinding을 사용하지 않는데 태그를 사용하였고 그것을 그대로 빌드해 앱을 테스트하니까 발생한 에러였다. 빌드는 당연히 문제가 없다. 문제가 생기는 부분은 해당 레이아웃이 앱에서 보여지는 순간 에러가 발생하여 종료되는 것이다.
2. 에러 해결
위에서 파악한 에러 원인을 바탕으로 다음과 같이 두 가지 해결 방법이 있다.
1. <layout> 태그를 제거한다.
2. DataBinding을 사용한다.
<layout> 태그를 제거하는 것은 간단하다. 해당 xml 파일에서 가장 바깥에 위치한 <layout> 태그를 모두 제거하면 된다.
DataBinding을 사용하는 방법은 다음과 같다.
- build.gradle(Module :app)에서 databinding 사용 설정
- xml 파일이 연결된 자바코드에서 DataBinding 관련 코드 작성
먼저 app단에서의 build.gradle을 실행하여 android{} 안에 다음과 같이 dataBindig 관련 코드를 넣어준다.
android {
...
dataBinding {
enabled = true
}
}
이 코드는 dataBinding을 사용하겠다는 의미이다.
다음으로 자바코드에서 dataBinding을 사용해야한다. 다음과 같이 자바코드를 작성하면 된다.
public class BasicSurveyActivity extends BaseActivity implements View.OnClickListener {
ActivityBasicSurveyBinding binding;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = DataBindingUtil.setContentView(this, R.layout.activity_basic_survey);
initToolbar();
}
...
}
build.gradle에서 dataBinding 사용 설정을 해주면 본 프로젝트에서 사용하는 activity_basic_survey.xml의 이름을 따온 ActivityBasicSurveyBinding을 사용하여 databinding을 할 수 있다.
다음 두 코드를 추가함으로써 문제 해결이 완료된다.
ActivityBasicSurveyBinding binding;
binding = DataBindingUtil.setContentView(this, R.layout.activity_basic_survey);
댓글