Я учусь на втором курсе информатики. У меня есть школьный проект, и я решил сделать фитнес-приложение. Я пытаюсь добавить экран входа / регистрации в приложение, но у меня появляется эта ошибка:
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.fitmania/com.example.fitmania.login_register.LoginActivity}: android.view.InflateException: Binary XML file line #19: Binary XML file line #19: Error inflating class android.support.design.widget.TextInputLayout
Я провел небольшое исследование, чтобы выяснить, могу ли я решить эту проблему, и попробовал эти решения, но ни одно из них не имело сработало.
- Добавьте атрибут
hintTextAppearance
к TextInputLayout
, чтобы тег-метка выглядел следующим образом:
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:hintTextAppearance="@android:style/TextAppearance.Medium">
Убедитесь, что в моем файле Gradle есть следующие зависимости:
compile 'com.android.support:appcompat-v7:22.2.0'
compile 'com.android.support:design:22.2.1'
Я не уверен, что еще я могу сделать, чтобы исправить эту ошибку. Если есть еще код, который вам нужно увидеть, пожалуйста, дайте мне знать. Спасибо
Код для входа (LoginActivity
):
package com.example.fitmania.login_register;
import android.annotation.SuppressLint;
import android.content.Intent;
import android.os.Bundle;
import android.text.Html;
import android.text.Spanned;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
import com.example.fitmania.MainActivity;
import com.example.fitmania.R;
import com.google.android.material.snackbar.Snackbar;
import com.google.android.material.textfield.TextInputLayout;
@SuppressLint("Registered")
public class LoginActivity extends AppCompatActivity {
//Declaration EditTexts
EditText editTextEmail;
EditText editTextPassword;
//Declaration TextInputLayout
TextInputLayout textInputLayoutEmail;
TextInputLayout textInputLayoutPassword;
//Declaration Button
Button buttonLogin;
//Declaration SqliteHelper
SqliteHelper sqliteHelper;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
sqliteHelper = new SqliteHelper(this);
initCreateAccountTextView();
initViews();
//set click event of login button
buttonLogin.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//Check user input is correct or not
if (validate()) {
//Get values from EditText fields
String Email = editTextEmail.getText().toString();
String Password = editTextPassword.getText().toString();
//Authenticate user
User currentUser = sqliteHelper.Authenticate(new User(null, null, Email, Password));
//Check Authentication is successful or not
if (currentUser != null) {
Snackbar.make(buttonLogin, "Successfully Logged in!", Snackbar.LENGTH_LONG).show();
//User Logged in Successfully Launch You home screen activity
Intent intent=new Intent(LoginActivity.this, MainActivity.class);
startActivity(intent);
finish();
} else {
//User Logged in Failed
Snackbar.make(buttonLogin, "Failed to log in , please try again", Snackbar.LENGTH_LONG).show();
}
}
}
});
}
//this method used to set Create account TextView text and click event( maltipal colors
// for TextView yet not supported in Xml so i have done it programmatically)
private void initCreateAccountTextView() {
TextView textViewCreateAccount = (TextView) findViewById(R.id.textViewCreateAccount);
textViewCreateAccount.setText(fromHtml("<font color='#ffffff'>I don't have account yet. </font><font color='#0c0099'>create one</font>"));
textViewCreateAccount.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent(LoginActivity.this, RegisterActivity.class);
startActivity(intent);
}
});
}
//this method is used to connect XML views to its Objects
private void initViews() {
editTextEmail = (EditText) findViewById(R.id.editTextEmail);
editTextPassword = (EditText) findViewById(R.id.editTextPassword);
textInputLayoutEmail = (TextInputLayout) findViewById(R.id.textInputLayoutEmail);
textInputLayoutPassword = (TextInputLayout) findViewById(R.id.textInputLayoutPassword);
buttonLogin = (Button) findViewById(R.id.buttonLogin);
}
//This method is for handling fromHtml method deprecation
@SuppressWarnings("deprecation")
public static Spanned fromHtml(String html) {
Spanned result;
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) {
result = Html.fromHtml(html, Html.FROM_HTML_MODE_LEGACY);
} else {
result = Html.fromHtml(html);
}
return result;
}
//This method is used to validate input given by user
public boolean validate() {
boolean valid = false;
//Get values from EditText fields
String Email = editTextEmail.getText().toString();
String Password = editTextPassword.getText().toString();
//Handling validation for Email field
if (!android.util.Patterns.EMAIL_ADDRESS.matcher(Email).matches()) {
valid = false;
textInputLayoutEmail.setError("Please enter valid email!");
} else {
valid = true;
textInputLayoutEmail.setError(null);
}
//Handling validation for Password field
if (Password.isEmpty()) {
valid = false;
textInputLayoutPassword.setError("Please enter valid password!");
} else {
if (Password.length() > 5) {
valid = true;
textInputLayoutPassword.setError(null);
} else {
valid = false;
textInputLayoutPassword.setError("Password is to short!");
}
}
return valid;
}
}
XML файл для входа (activity_login.xml
):
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/colorPrimary"
android:fitsSystemWindows="true">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:orientation="vertical">
<android.support.design.widget.TextInputLayout
android:id="@+id/textInputLayoutEmail"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:hintTextAppearance="@android:style/TextAppearance.Medium"
tools:ignore="ExtraText">
android:layout_marginTop="16dp"
app:errorEnabled="true">
<android.support.design.widget.TextInputEditText
android:id="@+id/editTextEmail"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/email"
android:inputType="textEmailAddress" />
</android.support.design.widget.TextInputLayout>
<android.support.design.widget.TextInputLayout
android:id="@+id/textInputLayoutPassword"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
app:errorEnabled="true"
app:passwordToggleEnabled="true"
app:passwordToggleTint="@color/colorAccent">
<android.support.design.widget.TextInputEditText
android:id="@+id/editTextPassword"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/password"
android:inputType="textPassword" />
</android.support.design.widget.TextInputLayout>
<Button
android:id="@+id/buttonLogin"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="16dp"
android:background="@color/colorAccent"
android:text="@string/login"
android:textColor="@android:color/white" />
<TextView
android:id="@+id/textViewCreateAccount"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:layout_marginBottom="16dp"
android:gravity="center_horizontal"
android:textColor="@android:color/darker_gray" />
</LinearLayout>
</ScrollView>
Код для регистрации / Register (RegisterActivity
):
package com.example.fitmania.login_register;
import android.os.Bundle;
import android.os.Handler;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import com.example.fitmania.R;
import com.google.android.material.snackbar.Snackbar;
import com.google.android.material.textfield.TextInputLayout;
public class RegisterActivity extends AppCompatActivity {
//Declaration EditTexts
EditText editTextUserName;
EditText editTextEmail;
EditText editTextPassword;
//Declaration TextInputLayout
TextInputLayout textInputLayoutUserName;
TextInputLayout textInputLayoutEmail;
TextInputLayout textInputLayoutPassword;
//Declaration Button
Button buttonRegister;
//Declaration SqliteHelper
SqliteHelper sqliteHelper;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_register);
sqliteHelper = new SqliteHelper(this);
initTextViewLogin();
initViews();
buttonRegister.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (validate()) {
String UserName = editTextUserName.getText().toString();
String Email = editTextEmail.getText().toString();
String Password = editTextPassword.getText().toString();
//Check in the database is there any user associated with this email
if (!sqliteHelper.isEmailExists(Email)) {
//Email does not exist now add new user to database
sqliteHelper.addUser(new User(null, UserName, Email, Password));
Snackbar.make(buttonRegister, "User created successfully! Please Login ", Snackbar.LENGTH_LONG).show();
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
finish();
}
}, Snackbar.LENGTH_LONG);
}else {
//Email exists with email input provided so show error user already exist
Snackbar.make(buttonRegister, "User already exists with same email ", Snackbar.LENGTH_LONG).show();
}
}
}
});
}
//this method used to set Login TextView click event
private void initTextViewLogin() {
TextView textViewLogin = (TextView) findViewById(R.id.textViewLogin);
textViewLogin.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
finish();
}
});
}
//this method is used to connect XML views to its Objects
private void initViews() {
editTextEmail = (EditText) findViewById(R.id.editTextEmail);
editTextPassword = (EditText) findViewById(R.id.editTextPassword);
editTextUserName = (EditText) findViewById(R.id.editTextUserName);
textInputLayoutEmail = (TextInputLayout) findViewById(R.id.textInputLayoutEmail);
textInputLayoutPassword = (TextInputLayout) findViewById(R.id.textInputLayoutPassword);
textInputLayoutUserName = (TextInputLayout) findViewById(R.id.textInputLayoutUserName);
buttonRegister = (Button) findViewById(R.id.buttonRegister);
}
//This method is used to validate input given by user
public boolean validate() {
boolean valid = false;
//Get values from EditText fields
String UserName = editTextUserName.getText().toString();
String Email = editTextEmail.getText().toString();
String Password = editTextPassword.getText().toString();
//Handling validation for UserName field
if (UserName.isEmpty()) {
valid = false;
textInputLayoutUserName.setError("Please enter valid username!");
} else {
if (UserName.length() > 5) {
valid = true;
textInputLayoutUserName.setError(null);
} else {
valid = false;
textInputLayoutUserName.setError("Username is to short!");
}
}
//Handling validation for Email field
if (!android.util.Patterns.EMAIL_ADDRESS.matcher(Email).matches()) {
valid = false;
textInputLayoutEmail.setError("Please enter valid email!");
} else {
valid = true;
textInputLayoutEmail.setError(null);
}
//Handling validation for Password field
if (Password.isEmpty()) {
valid = false;
textInputLayoutPassword.setError("Please enter valid password!");
} else {
if (Password.length() > 5) {
valid = true;
textInputLayoutPassword.setError(null);
} else {
valid = false;
textInputLayoutPassword.setError("Password is to short!");
}
}
return valid;
}
}
XML файл для регистрации / регистрации (activity_register
):
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:tools="http://schemas.android.com/tools"
android:background="@color/colorPrimary"
android:fitsSystemWindows="true">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:orientation="vertical">
<android.support.design.widget.TextInputLayout
app:errorEnabled="true"
android:id="@+id/textInputLayoutUserName"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:hintTextAppearance="@android:style/TextAppearance.Medium"
tools:ignore="ExtraText">
android:layout_marginTop="16dp">
<android.support.design.widget.TextInputEditText
android:id="@+id/editTextUserName"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/username"
android:inputType="textPersonName" />
</android.support.design.widget.TextInputLayout>
<android.support.design.widget.TextInputLayout
android:id="@+id/textInputLayoutEmail"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
app:errorEnabled="true">
<android.support.design.widget.TextInputEditText
android:id="@+id/editTextEmail"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/email"
android:inputType="textEmailAddress" />
</android.support.design.widget.TextInputLayout>
<android.support.design.widget.TextInputLayout
android:id="@+id/textInputLayoutPassword"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
app:errorEnabled="true"
app:passwordToggleEnabled="true"
app:passwordToggleTint="@color/colorAccent">
<android.support.design.widget.TextInputEditText
android:id="@+id/editTextPassword"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/password"
android:inputType="textPassword" />
</android.support.design.widget.TextInputLayout>
<Button
android:id="@+id/buttonRegister"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="@android:color/white"
android:layout_gravity="center_horizontal"
android:layout_marginTop="16dp"
android:layout_weight="1"
android:background="@color/colorAccent"
android:text="@string/register" />
<TextView
android:id="@+id/textViewLogin"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="16dp"
android:gravity="center"
android:text="@string/back_to_login"
android:textColor="@android:color/white" />
</LinearLayout>
</ScrollView>
Java класс для базы данных (SqliteHelper.java
):
package com.example.fitmania.login_register;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
public class SqliteHelper extends SQLiteOpenHelper {
//DATABASE NAME
public static final String DATABASE_NAME = "loopwiki.com";
//DATABASE VERSION
public static final int DATABASE_VERSION = 1;
//TABLE NAME
public static final String TABLE_USERS = "users";
//TABLE USERS COLUMNS
//ID COLUMN @primaryKey
public static final String KEY_ID = "id";
//COLUMN user name
public static final String KEY_USER_NAME = "username";
//COLUMN email
public static final String KEY_EMAIL = "email";
//COLUMN password
public static final String KEY_PASSWORD = "password";
//SQL for creating users table
public static final String SQL_TABLE_USERS = " CREATE TABLE " + TABLE_USERS
+ " ( "
+ KEY_ID + " INTEGER PRIMARY KEY, "
+ KEY_USER_NAME + " TEXT, "
+ KEY_EMAIL + " TEXT, "
+ KEY_PASSWORD + " TEXT"
+ " ) ";
public SqliteHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
@Override
public void onCreate(SQLiteDatabase sqLiteDatabase) {
//Create Table when oncreate gets called
sqLiteDatabase.execSQL(SQL_TABLE_USERS);
}
@Override
public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {
//drop table to create new one if database version updated
sqLiteDatabase.execSQL(" DROP TABLE IF EXISTS " + TABLE_USERS);
}
//using this method we can add users to user table
public void addUser(User user) {
//get writable database
SQLiteDatabase db = this.getWritableDatabase();
//create content values to insert
ContentValues values = new ContentValues();
//Put username in @values
values.put(KEY_USER_NAME, user.userName);
//Put email in @values
values.put(KEY_EMAIL, user.email);
//Put password in @values
values.put(KEY_PASSWORD, user.password);
// insert row
long todo_id = db.insert(TABLE_USERS, null, values);
}
public User Authenticate(User user) {
SQLiteDatabase db = this.getReadableDatabase();
Cursor cursor = db.query(TABLE_USERS,// Selecting Table
new String[]{KEY_ID, KEY_USER_NAME, KEY_EMAIL, KEY_PASSWORD},//Selecting columns want to query
KEY_EMAIL + "=?",
new String[]{user.email},//Where clause
null, null, null);
if (cursor != null && cursor.moveToFirst()) {
//if cursor has value then in user database there is user associated with this given email
User user1 = new User(cursor.getString(0), cursor.getString(1), cursor.getString(2), cursor.getString(3));
//Match both passwords check they are same or not
if (user.password.equalsIgnoreCase(user1.password)) {
return user1;
}
}
//if user password does not matches or there is no record with that email then return @false
return null;
}
public boolean isEmailExists(String email) {
SQLiteDatabase db = this.getReadableDatabase();
Cursor cursor = db.query(TABLE_USERS,// Selecting Table
new String[]{KEY_ID, KEY_USER_NAME, KEY_EMAIL, KEY_PASSWORD},//Selecting columns want to query
KEY_EMAIL + "=?",
new String[]{email},//Where clause
null, null, null);
if (cursor != null && cursor.moveToFirst()) {
//if cursor has value then in user database there is user associated with this given email so return true
return true;
}
//if email does not exist return false
return false;
}
}
Пользователь java класс (User.java
):
package com.example.fitmania.login_register;
public class User {
public String id;
public String userName;
public String email;
public String password;
public User(String id, String userName, String email, String password) {
this.id = id;
this.userName = userName;
this.email = email;
this.password = password;
}
}
Сообщение об ошибке от Logcat:
2020-03-26 19:57:49.069 13742-13742/com.example.fitmania E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.fitmania, PID: 13742
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.fitmania/com.example.fitmania.login_register.LoginActivity}: android.view.InflateException: Binary XML file line #19: Binary XML file line #19: Error inflating class android.support.design.widget.TextInputLayout
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2957)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3032)
at android.app.ActivityThread.-wrap11(Unknown Source:0)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1696)
at android.os.Handler.dispatchMessage(Handler.java:105)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6944)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:327)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1374)
Caused by: android.view.InflateException: Binary XML file line #19: Binary XML file line #19: Error inflating class android.support.design.widget.TextInputLayout
Caused by: android.view.InflateException: Binary XML file line #19: Error inflating class android.support.design.widget.TextInputLayout
Caused by: java.lang.ClassNotFoundException: Didn't find class "android.support.design.widget.TextInputLayout" on path: DexPathList[[zip file "/data/app/com.example.fitmania-z46bMTQglO2kg-ISD_5APw==/base.apk"],nativeLibraryDirectories=[/data/app/com.example.fitmania-z46bMTQglO2kg-ISD_5APw==/lib/arm64, /system/lib64, /system/vendor/lib64]]
at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:93)
at java.lang.ClassLoader.loadClass(ClassLoader.java:379)
at java.lang.ClassLoader.loadClass(ClassLoader.java:312)
at android.view.LayoutInflater.createView(LayoutInflater.java:606)
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:790)
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:730)
at android.view.LayoutInflater.rInflate(LayoutInflater.java:863)
at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:824)
at android.view.LayoutInflater.rInflate(LayoutInflater.java:866)
at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:824)
at android.view.LayoutInflater.inflate(LayoutInflater.java:515)
at android.view.LayoutInflater.inflate(LayoutInflater.java:423)
at android.view.LayoutInflater.inflate(LayoutInflater.java:374)
at androidx.appcompat.app.AppCompatDelegateImpl.setContentView(AppCompatDelegateImpl.java:555)
at androidx.appcompat.app.AppCompatActivity.setContentView(AppCompatActivity.java:161)
at com.example.fitmania.login_register.LoginActivity.onCreate(LoginActivity.java:40)
at android.app.Activity.performCreate(Activity.java:7183)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1220)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2910)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3032)
at android.app.ActivityThread.-wrap11(Unknown Source:0)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1696)
at android.os.Handler.dispatchMessage(Handler.java:105)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6944)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:327)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1374)