Java 从Android Room检索双精度值导致NullPointerException

Java 从Android Room检索双精度值导致NullPointerException,java,android,database,nullpointerexception,android-room,Java,Android,Database,Nullpointerexception,Android Room,我有一个安卓房间DB和下一个POJO Entity(tableName = "transactions") public class BoardItem { @PrimaryKey(autoGenerate = true) int itemID; String account; String date; String category; double value: //

我有一个安卓房间DB和下一个POJO

  Entity(tableName = "transactions")
    public class BoardItem {
        @PrimaryKey(autoGenerate = true)
        int itemID;
        String account;
        String date;
        String category;
        double value:
//getters and setters
    }
对于指定类别的所有值的加载和,我尝试使用下一个DAO

@Query ("SELECT category, SUM (value) as total FROM transactions WHERE category =:transactionCategory GROUP BY category ")
double getAllTransactionInCategory(String transactionCategory);
以及存储库android室中的下一个代码:

public class RoomTransactionsRepository {
    private final RoomTransactionsDAO mTransactionsDao;
    private final LiveData<List<TransactionBoardItem>> mAllTransactions;

    RoomTransactionsRepository(Application application){
            RoomTransactionsDatabase db = RoomTransactionsDatabase.getDatabase(application);
            mTransactionsDao = db.transactions_dao();
            mAllTransactions = mTransactionsDao.getAllTransactions();
    }

    LiveData<List<TransactionBoardItem>> getAllTransactions(){
        return mAllTransactions;
    }

    double getAllTransactionInCategory (String category){
        return mTransactionsDao.getAllTransactionInCategory (category);
    }

    //Livedata code...
要显示,我使用下一个代码:

public class StatisticActivity extends AppCompatActivity {
    RoomTransactionsRepository repository;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // init code 

         binding.totalValue.setText (String.valueOf (repository.getAllTransactionInCategory ("Food")));
    }
}
RoomTransactionsViewModel model = new ViewModelProvider (this).get(RoomTransactionsViewModel.class);

        model.getAllTransactionInCategory("Food", item -> {
            binding.totalValue.setText (String.valueOf (item.getTransactionValue ()));
            binding.category.setText (String.valueOf (item.getTransactionCategory ()));
        });
在DAO或存储库代码中,当我试图显示要从db中提取的双精度值时,我做错了什么导致了NullPointerException? 提前谢谢

更新:VievModel类。在单独的活动中,动态地将数据库中的数据插入到RecyclerView中是很有用的

public class RoomTransactionsViewModel extends AndroidViewModel {
    private final RoomTransactionsRepository mRepo;
    private final LiveData<List<TransactionItem>> mAllTransactions;

    public RoomTransactionsViewModel(Application application){
        super(application);
        mRepo = new RoomTransactionsRepository(application);
        mAllTransactions  = mRepo.getAllTransactions();
    }

    LiveData<List<TransactionBoardItem>> getAllTransactions(){
        return mAllTransactions;
    }

    public void insert(TransactionItem item){mRepo.insertTransaction(item);}
    public void deleteAll(){mRepo.deleteAllTransactions();}
    
}
步骤2:我创建了应答中的接口,但将double替换为POJO class
void onReturned(TransactionStatististicItem项)
步骤3:根据答案升级存储库代码,但有更改:

//To retrieve data asynchronous from DB you can use : ExecutorService (java) / Coroutines (kotlin) or AsyncTask (deprecated in API level 30)
 public static final ExecutorService singleThreadExecutor =
            Executors.newSingleThreadExecutor();

    void getAllTransactionInCategory (String category, TransactionStatisticListener listener){
            singleThreadExecutor.execute(() -> listener.onReturned(mTransactionsDao.getAllTransactionInCategory (category)));
        }
第4步:在ViewModel中添加以下几行

 void getAllTransactionInCategory (String category, TransactionStatisticListener listener){
        mRepo.getAllTransactionInCategory (category, listener);
    }
步骤5:最后在活动中,我添加了下一个代码:

public class StatisticActivity extends AppCompatActivity {
    RoomTransactionsRepository repository;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // init code 

         binding.totalValue.setText (String.valueOf (repository.getAllTransactionInCategory ("Food")));
    }
}
RoomTransactionsViewModel model = new ViewModelProvider (this).get(RoomTransactionsViewModel.class);

        model.getAllTransactionInCategory("Food", item -> {
            binding.totalValue.setText (String.valueOf (item.getTransactionValue ()));
            binding.category.setText (String.valueOf (item.getTransactionCategory ()));
        });
最后,我能够检索下一个示例数据:“食品”类别中所有事务的总和

为了遵循Google MVVM准则,您不应该从活动访问存储库,因为它被认为是数据库的一个层,不应该由视图处理,而应该由
ViewModel

另一个问题是,在不使用侦听器的情况下从数据库返回一个双精度值;由于从数据库获取值需要一些时间,因此
getAllTransactionCategory()
不会返回预期值。这可以通过使用侦听器接口来解决,或者返回
LiveData
并在活动中观察它

应用它:

因此,建议您通过
ViewModel
访问此选项:

Dao:返回一个
LiveData

更新:

“这可以通过使用监听器界面来解决”你能详细说明一下吗

要使用侦听器,您需要一个接口,该接口具有一个回调方法,该方法接受您希望从文件室返回的类型,在本例中,它是一个
double

public interface TransactionListener {
     void onReturned(double count);
}
然后在Room返回如下值时使用此接口的实现:

道:

视图模型:

public class RoomTransactionsViewModel extends AndroidViewModel {
   
   // ...
    
    
    LiveData<Double> getAllTransactionInCategory (String category){
        return mRepo.getAllTransactionInCategory (category);
    }
}
public class RoomTransactionsViewModel extends AndroidViewModel {
   
   // ...
    
    
    void getAllTransactionInCategory (String category, TransactionListener listener){
        mRepo.getAllTransactionInCategory (category, listener);
    }
}
存储库:

public class RoomTransactionsRepository {

    //.....
    
    LiveData<Double> getAllTransactionInCategory (String category){
        return mTransactionsDao.getAllTransactionInCategory (category);
    }
public class RoomTransactionsRepository {

    //.....
    
    void getAllTransactionInCategory (String category, TransactionListener listener){
 
        listener.onReturned(mTransactionsDao.getAllTransactionInCategory (category));
    }
活动:

public class StatisticActivity extends AppCompatActivity {
    RoomTransactionsRepository repository;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // init code 
        
        
        RoomTransactionsViewModel model = new ViewModelProvider(this).get(RoomTransactionsViewModel.class);
        
            
        model.getAllTransactionInCategory("Food", new TransactionListener() {
            @Override
            public void onReturned(double count) {
                binding.totalValue.setText (String.valueOf (count));
            }
        });
        
    }
}

能否显示您在何处初始化视图模型
RoomTransactionRepository
instances@Zain更新,这是吗?独立活动中涉及的ViewModel允许在RecyclerView中动态插入POJO项目。谢谢!“这可以通过使用监听器界面来解决”你能详细说明一下吗?我还更新了帖子,提供了关于我想要什么的其他信息。@GremlinShX请在回答中查看更新部分。谢谢你,我使用你的回答作为回答我自己问题的基础,但是如果有更改,你可以在问题中查看更新3。还有一件事,您有一个错误:ViewModel类中的void GetAllTransactionCategory不应该使用“return”关键字。
@Query ("SELECT category, SUM (value) as total FROM transactions WHERE category =:transactionCategory GROUP BY category ")
double getAllTransactionInCategory(String transactionCategory);
public class RoomTransactionsViewModel extends AndroidViewModel {
   
   // ...
    
    
    void getAllTransactionInCategory (String category, TransactionListener listener){
        mRepo.getAllTransactionInCategory (category, listener);
    }
}
public class RoomTransactionsRepository {

    //.....
    
    void getAllTransactionInCategory (String category, TransactionListener listener){
 
        listener.onReturned(mTransactionsDao.getAllTransactionInCategory (category));
    }
public class StatisticActivity extends AppCompatActivity {
    RoomTransactionsRepository repository;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // init code 
        
        
        RoomTransactionsViewModel model = new ViewModelProvider(this).get(RoomTransactionsViewModel.class);
        
            
        model.getAllTransactionInCategory("Food", new TransactionListener() {
            @Override
            public void onReturned(double count) {
                binding.totalValue.setText (String.valueOf (count));
            }
        });
        
    }
}