【问题标题】:Cannot instance a View Model because the table is empty无法实例化视图模型,因为表为空
【发布时间】:2021-05-31 18:17:13
【问题描述】:

我正在我的活动中创建一个视图模型,以便通过方法将对象添加到数据库中。但是视图模型表示的是一个空表,它导致了这个堆栈跟踪和应用程序的完全崩溃:

E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.gmproxy.pastilarma, PID: 9827
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.gmproxy.pastilarma/com.gmproxy.pastilarma.UserAddScreen}: java.lang.RuntimeException: Cannot create an instance of class com.gmproxy.Util.PathologyUserViewModel
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3449)
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3601)
    at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:85)
    at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
    at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2066)
    at android.os.Handler.dispatchMessage(Handler.java:106)
    at android.os.Looper.loop(Looper.java:223)
    at android.app.ActivityThread.main(ActivityThread.java:7656)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)
 Caused by: java.lang.RuntimeException: Cannot create an instance of class com.gmproxy.Util.PathologyUserViewModel
    at androidx.lifecycle.ViewModelProvider$AndroidViewModelFactory.create(ViewModelProvider.java:275)
    at androidx.lifecycle.SavedStateViewModelFactory.create(SavedStateViewModelFactory.java:112)
    at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.java:185)
    at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.java:150)
    at com.gmproxy.pastilarma.UserAddScreen.onCreate(UserAddScreen.java:84)
    at android.app.Activity.performCreate(Activity.java:8000)
    at android.app.Activity.performCreate(Activity.java:7984)
    at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1309)
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3422)
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3601) 
    at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:85) 
    at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135) 
    at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95) 
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2066) 
    at android.os.Handler.dispatchMessage(Handler.java:106) 
    at android.os.Looper.loop(Looper.java:223) 
    at android.app.ActivityThread.main(ActivityThread.java:7656) 
    at java.lang.reflect.Method.invoke(Native Method) 
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592) 
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947) 
 Caused by: java.lang.reflect.InvocationTargetException
    at java.lang.reflect.Constructor.newInstance0(Native Method)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:343)
    at androidx.lifecycle.ViewModelProvider$AndroidViewModelFactory.create(ViewModelProvider.java:267)
    at androidx.lifecycle.SavedStateViewModelFactory.create(SavedStateViewModelFactory.java:112) 
    at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.java:185) 
    at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.java:150) 
    at com.gmproxy.pastilarma.UserAddScreen.onCreate(UserAddScreen.java:84) 
    at android.app.Activity.performCreate(Activity.java:8000) 
    at android.app.Activity.performCreate(Activity.java:7984) 
    at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1309) 
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3422) 
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3601) 
    at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:85) 
    at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135) 
    at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95) 
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2066) 
    at android.os.Handler.dispatchMessage(Handler.java:106) 
    at android.os.Looper.loop(Looper.java:223) 
    at android.app.ActivityThread.main(ActivityThread.java:7656) 
    at java.lang.reflect.Method.invoke(Native Method) 
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592) 
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947) 
 Caused by: java.lang.IllegalStateException: Cannot access database on the main thread since it may potentially lock the UI for a long period of time.
    at androidx.room.RoomDatabase.assertNotMainThread(RoomDatabase.java:385)
    at androidx.room.RoomDatabase.query(RoomDatabase.java:441)
    at androidx.room.util.DBUtil.query(DBUtil.java:83)
    at com.gmproxy.DAO.PathologyUserDAO_Impl.getAllObjects(PathologyUserDAO_Impl.java:154)
    at com.gmproxy.DAO.PathologyUserRepository.getAllObjects(PathologyUserRepository.java:19)
    at com.gmproxy.Util.PathologyUserViewModel.<init>(PathologyUserViewModel.java:19)
    at java.lang.reflect.Constructor.newInstance0(Native Method) 
    at java.lang.reflect.Constructor.newInstance(Constructor.java:343) 
    at androidx.lifecycle.ViewModelProvider$AndroidViewModelFactory.create(ViewModelProvider.java:267) 
    at androidx.lifecycle.SavedStateViewModelFactory.create(SavedStateViewModelFactory.java:112) 
    at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.java:185) 
    at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.java:150) 
    at com.gmproxy.pastilarma.UserAddScreen.onCreate(UserAddScreen.java:84) 
    at android.app.Activity.performCreate(Activity.java:8000) 
    at android.app.Activity.performCreate(Activity.java:7984) 
    at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1309) 
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3422) 
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3601) 
    at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:85) 
    at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135) 
    at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95) 
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2066) 
    at android.os.Handler.dispatchMessage(Handler.java:106) 
    at android.os.Looper.loop(Looper.java:223) 
    at android.app.ActivityThread.main(ActivityThread.java:7656) 
    at java.lang.reflect.Method.invoke(Native Method) 
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592) 
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947) 

我一进入所述活动就会发生这种情况。在数据库中有记录的其他视图模型创建没有问题,但是在数据库中缺少任何对象的其他视图模型也无法创建。我是否故意需要添加记录才能创建这些记录?

这分别是activity和view model的代码:

活动:

package com.gmproxy.pastilarma;

import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;

import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.provider.MediaStore;
import android.util.Log;
import android.view.View;
import android.view.Window;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.Spinner;
import android.widget.Toast;

import androidx.lifecycle.ViewModelProvider;

import com.gmproxy.DAO.PathologyUserDAO;
import com.gmproxy.DAO.UserDAO;
import com.gmproxy.Entities.Pathology;
import com.gmproxy.Entities.User;
import com.gmproxy.Util.AlarmUserViewModel;
import com.gmproxy.Util.ImageConverter;
import com.gmproxy.Util.PathologyUserViewModel;
import com.gmproxy.Util.UserViewModel;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;

public class UserAddScreen extends AppCompatActivity {

    Button gotoBack, addObservation, saveUser, addPathologies;
    EditText addUsername, addSurname, addAge, addRoomNumber;
    Spinner addGender;
    ImageView selectImage;
    String obs;
    Pathology paths;
    Context context;
    UserViewModel userViewModel;
    PathologyUserViewModel pathologyUserViewModel;
    int pathAct = 0;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        super.onCreate(savedInstanceState);
        Intent intent = this.getIntent();
        context = this.getApplicationContext();
        Bundle bundle = new Bundle();
        pathAct = getIntent().getIntExtra("path-record",0);
        if (pathAct == 1){
            onRestoreInstanceState(bundle);
        }


        setContentView(R.layout.activity_user_add_screen);
        gotoBack = findViewById(R.id.GotoBack);
        addObservation = findViewById(R.id.AddObservation);
        saveUser = findViewById(R.id.SaveUser);
        addPathologies = findViewById(R.id.AddPathologies);
        addUsername = findViewById(R.id.AddUsername);
        addSurname = findViewById(R.id.AddSurname);
        addAge = findViewById(R.id.AddAge);
        addRoomNumber = findViewById(R.id.AddRoomNumber);
        addGender = findViewById(R.id.AddGender);
        selectImage = findViewById(R.id.SelectImage);

        userViewModel = new ViewModelProvider(this).get(UserViewModel.class);
        pathologyUserViewModel = new ViewModelProvider(this).get(PathologyUserViewModel.class);

        List<String> genderList = new ArrayList<>();
        genderList.add("M");
        genderList.add("F");

        ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,android.R.layout.simple_spinner_item,genderList);
        adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
        addGender.setAdapter(adapter);


        obs = intent.getStringExtra("observation");
        paths = (Pathology) intent.getSerializableExtra("paths");
    }

    public void gotoBack(View view) {
        Intent mainAct = new Intent(UserAddScreen.this, UserListScreen.class);
        startActivity(mainAct);
    }

    public void addObservation(View view) {
        Intent mainAct = new Intent(UserAddScreen.this, UserObservationScreen.class);
        startActivity(mainAct);

    }

    public void addPathology(View view) {
        Intent mainAct = new Intent(UserAddScreen.this, PathologiesSearchScreen.class);
        startActivity(mainAct);

    }

    @Override
    public void onSaveInstanceState(Bundle savedInstanceState) {
        savedInstanceState.putString("Nombre_usuario",addUsername.getText().toString());
        savedInstanceState.putString("Apellido_usuario",addSurname.getText().toString());
        savedInstanceState.putString("Edad_usuario",addAge.getText().toString());
        savedInstanceState.putString("Habitacion_usuario",addRoomNumber.getText().toString());
        savedInstanceState.putInt("Sexo_usuario",addGender.getSelectedItemPosition());
        savedInstanceState.putString("Observacion-usuario", obs);
        savedInstanceState.putSerializable("Patologia-usuario", paths);
        super.onSaveInstanceState(savedInstanceState);
    }

    public void onRestoreInstanceState(Bundle savedInstanceState) {
        super.onRestoreInstanceState(savedInstanceState);
        addUsername.setText(savedInstanceState.getString("Nombre_usuario"));
        addSurname.setText(savedInstanceState.getString("Apellido_usuario"));
        addAge.setText(savedInstanceState.getString("Edad_usuario"));
        addRoomNumber.setText(savedInstanceState.getString("Habitacion_usuario"));
        addGender.setSelection(savedInstanceState.getInt("Sexo_usuario"));
        obs = savedInstanceState.getString("Observacion-usuario");
        paths = (Pathology) savedInstanceState.getSerializable("Patologia-usuario");

    }

    public void selectImageAction(View view) {
        final CharSequence[] options = {"Hacer una foto", "Elegir de la galería", "Usar una genérica" , "Cancelar"};
        AlertDialog.Builder builder = new AlertDialog.Builder(UserAddScreen.this);
        builder.setTitle("¡Añade una foto!");
        builder.setItems(options, new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int item) {
                if (options[item].equals("Hacer una foto")) {
                    Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
                    File f = new File(android.os.Environment.getExternalStorageDirectory(), "temp.jpg");
                    intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(f));
                    startActivity(intent);
                } else if (options[item].equals("Elegir de la galería")) {
                    Intent intent = new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
                    startActivity(intent);
                } else if (options[item].equals("Cancelar")) {
                    dialog.dismiss();
                } else if(options[item].equals("Usar una genérica")){
                    selectImage.setImageResource(R.drawable.ic_user_generic_foreground);
                    selectImage.setBackgroundResource(R.drawable.ic_user_generic_foreground);
                }
            }
        });
        builder.show();
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (resultCode == RESULT_OK) {
            if (requestCode == 1) {
                File f = new File(Environment.getExternalStorageDirectory().toString());
                for (File temp : f.listFiles()) {
                    if (temp.getName().equals("temp.jpg")) {
                        f = temp;
                        break;
                    }
                }
                try {
                    Bitmap bitmap;
                    BitmapFactory.Options bitmapOptions = new BitmapFactory.Options();
                    bitmap = BitmapFactory.decodeFile(f.getAbsolutePath(),
                            bitmapOptions);
                    selectImage.setImageBitmap(bitmap);
                    String path = android.os.Environment
                            .getExternalStorageDirectory()
                            + File.separator
                            + "Phoenix" + File.separator + "default";
                    f.delete();
                    OutputStream outFile = null;
                    File file = new File(path, String.valueOf(System.currentTimeMillis()) + ".jpg");
                    try {
                        outFile = new FileOutputStream(file);
                        bitmap.compress(Bitmap.CompressFormat.JPEG, 85, outFile);
                        outFile.flush();
                        outFile.close();
                    } catch (FileNotFoundException e) {
                        e.printStackTrace();
                    } catch (IOException e) {
                        e.printStackTrace();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            } else if (requestCode == 2) {
                Uri selectedImage = data.getData();
                String[] filePath = {MediaStore.Images.Media.DATA};
                Cursor c = getContentResolver().query(selectedImage, filePath, null, null, null);
                c.moveToFirst();
                int columnIndex = c.getColumnIndex(filePath[0]);
                String picturePath = c.getString(columnIndex);
                c.close();
                Bitmap thumbnail = (BitmapFactory.decodeFile(picturePath));
                Log.w("..******************...", picturePath + "");
                ImageView viewImage;
                selectImage.setImageBitmap(thumbnail);
            }
        }
    }




    public void saveUser(View view) {

        //Just this to turn the image into a blob

        Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(),R.id.SelectImage);
        ImageConverter imgCon = new ImageConverter();
        byte[] bytearray = imgCon.bitmapToBiteArray(bitmap);


        Toast.makeText(this, "Usuario creado.", Toast.LENGTH_SHORT).show();
        User user = new User(addUsername.getText().toString(), addSurname.getText().toString(), addAge.getText().toString(),
                Integer.parseInt(addRoomNumber.getText().toString()), addGender.getSelectedItem().toString(), obs, bytearray);
        userViewModel.insert(user);
        pathologyUserViewModel.insert(userViewModel.getIdByNameAndSurname(addUsername.getText().toString(),addSurname.getText().toString()), paths.getId_pathology());
        Toast.makeText(this, "Patología " + paths.getPathologyName() + " añadida", Toast.LENGTH_SHORT).show();
        Intent mainAct = new Intent(UserAddScreen.this, UserListScreen.class);
        startActivity(mainAct);
        finish();
    }
}

查看模型:

package com.gmproxy.Util;

import android.app.Application;

import androidx.lifecycle.AndroidViewModel;

import com.gmproxy.DAO.PathologyUserRepository;
import com.gmproxy.Entities.PathologyUser;

import java.util.List;

public class PathologyUserViewModel extends AndroidViewModel {
        private PathologyUserRepository repository;
        public List<PathologyUser> pathologyUsers;

        public PathologyUserViewModel(Application application) {
                super(application);
                repository = new PathologyUserRepository(application);
                pathologyUsers = repository.getAllObjects();
        }

        List<PathologyUser> getAll() { return pathologyUsers; }

        public List<PathologyUser> getAllFromUser(int i) { return repository.getAllFromUser(i); }

        public void insert(int i, int j) { repository.insertObject(i,j); }

        public void delete(PathologyUser obj) { repository.deleteObject(obj); }
}

我不太记得在文档中无法使用空表创建视图模型的任何内容,也许我遗漏了什么?

【问题讨论】:

  • 您的崩溃表明错误在com.gmproxy.pastilarma.UserAddScreen.onRestoreInstanceState(UserAddScreen.java:125);这与您的 ViewModel 无关。你能包括你的UserAddScreen吗?
  • 这是在视图模型上编码的活动。是的,忘记了一件非常重要的事情,现在会解决它,给我一分钟

标签: java android android-room viewmodel


【解决方案1】:

代替行:

pathologyUserViewModel = new ViewModelProvider(this).get(PathologyUserViewModel.class);

你可以使用:

pathologyUserViewModel = new ViewModelProvider
        .AndroidViewModelFactory(this.getApplication())
        .create(PathologyUserViewModel.class);

或者,

pathologyUserViewModel = ViewModelProvider(
            this,
            ViewModelProvider.AndroidViewModelFactory(application)
        ).get(PathologyUserViewModel::class.java)

【讨论】:

  • 恐怕你提供的代码并不能阻止程序出现同样的错误和崩溃
【解决方案2】:

如果您查看日志,您正在尝试访问主线程上的数据库:-

Caused by: java.lang.IllegalStateException: Cannot access database on the main thread since it may potentially lock the UI for a long period of time 

在线:-

pathologyUsers = repository.getAllObjects();

您要么需要在另一个线程上运行它,要么交替(不推荐)允许它在主线程上运行,这可以通过使用来完成:-

.allowMainThreadQueries()

在构建房间数据库时。例如:-

Room.databaseBuilder(context, TheDatabase::class.java, "thedatabasefile.db")
                    .allowMainThreadQueries() //<<<<<<<<<< allow main thread run
                    .build()

我是否故意需要添加记录才能创建这些记录?

只要你正确处理返回的列表并且不假设它们不为空,应该没有问题。

【讨论】:

  • 我如何与他们合作以假设他们可以是空的?
  • @Cpt-Proxy 更重要的是不要做任何假设它们不为空的事情,例如不要尝试直接访问元素 n 而是检查是否存在元素,例如使用if (list.size() &gt;= n) ....。即你可能不需要做任何特别的事情(你不会做的)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-03-01
  • 1970-01-01
  • 1970-01-01
  • 2014-07-28
  • 2011-12-20
相关资源
最近更新 更多