从实用程序类(非活动)访问房间数据库的 NullPointerException

Posted

技术标签:

【中文标题】从实用程序类(非活动)访问房间数据库的 NullPointerException【英文标题】:NullPointerException accessing Room Database from Utility Class (non-Activity) 【发布时间】:2019-06-26 01:50:00 【问题描述】:

我一直在尝试为我的 android 应用程序创建一个实用程序类,而不是每个 Activity 调用 Room 数据库 - 所有操作都将在该一个“实用程序”类中执行,并随时随地从每个 Activity 请求。

我尝试以与在 SettingsActivity 中(在 onCreate 中)以及在负责所需操作的相应类中相同的方式建立与数据库的连接 - 没有任何运气。

首先,从 Activity 类中检索保存在 Room 数据库中的票价数量的代码。

SettingsActivity.java

public void deletingFares(View view) 

// start of attempt of getting the value from QueriesUtility class

    QueriesUtility qu = new QueriesUtility();
    String quString = qu.returnNumberOfFares();

    Toast.makeText(SettingsActivity.this, 
    "Data from Queries Utilities class: (number of fares):" 
                    + quString, Toast.LENGTH_LONG).show();
// end

QueryUtility.java 类的代码:

public class QueriesUtility extends AppCompatActivity 

@Override
protected void onCreate(Bundle savedInstanceState) 
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_settings);

    // FARES DB
    // establishing connection with db
    mFareDAO = Room.databaseBuilder(getApplicationContext(), AppDatabase.class, "db-fares")
            .build()
            .getFareDAO();


public String returnNumberOfFares() 

    CalcNumberOfFares ss = new CalcNumberOfFares();
    ss.execute("");

    return numberOfFares;


String numberOfFares = "d0";
private FareDAO mFareDAO;
/**
 * CALCULATING NUMBER OF FARES
 */
private class CalcNumberOfFares extends AsyncTask<String, Integer, String> 

    // #1 - This is run in a background thread
    @Override
    protected String doInBackground(String... params) 
        // get the string from params, which is an array
        String myString = params[0];

        // FARES DB
        // establishing connection with db
        mFareDAO = Room.databaseBuilder(getApplicationContext(), AppDatabase.class, "db-fares")
                .build()
                .getFareDAO();

        List<Fare> fares = mFareDAO.getAllFares();

        myString = String.valueOf(fares.size());
        numberOfFares = myString;

        return myString;
    


    // #2 - This runs in UI when background thread finishes
    @Override
    protected void onPostExecute(String result) 
        super.onPostExecute(result);
        numberOfFares = result;

// todo


    


/**
 *
 * END
 */

正如你所知道的——我绝望地尝试以两种方式建立与数据库的连接;)(在 onCreate 和 CalcNumberOfFares 中)。 'onCreate' 是否被忽略 - 因为类是非 Activity 类?

以下是出现错误的日志:

E/AndroidRuntime: FATAL EXCEPTION: AsyncTask #4
              Process: com.example.android.taxidriverassistant, PID: 26280
              java.lang.RuntimeException: An error occurred while executing doInBackground()
                  at android.os.AsyncTask$3.done(AsyncTask.java:353)
                  at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:383)
                  at java.util.concurrent.FutureTask.setException(FutureTask.java:252)
                  at java.util.concurrent.FutureTask.run(FutureTask.java:271)
                  at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:245)
                  at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162)
                  at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636)
                  at java.lang.Thread.run(Thread.java:764)
               Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'android.content.Context android.content.Context.getApplicationContext()' on a null object reference
                  at android.content.ContextWrapper.getApplicationContext(ContextWrapper.java:119)
                  at com.example.android.taxidriverassistant.QueriesUtility$CalcNumberOfFares.doInBackground(QueriesUtility.java:57)
                  at com.example.android.taxidriverassistant.QueriesUtility$CalcNumberOfFares.doInBackground(QueriesUtility.java:47)
                  at android.os.AsyncTask$2.call(AsyncTask.java:333)
                  at java.util.concurrent.FutureTask.run(FutureTask.java:266)
                  at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:245) 
                  at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162) 
                  at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636) 
                  at java.lang.Thread.run(Thread.java:764) 
I/Process: Sending signal. PID: 26280 SIG: 9
Application terminated. 

当在 Activity 的类中执行对 Room DB 的调用时 - 一切正常。

这就是在 SettingsActivity.java 中与 Room 数据库建立连接的方式:

    @Override
    protected void onCreate(Bundle savedInstanceState) 
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_settings);

    // FARES DB
    // establishing connection with db
    mFareDAO = Room.databaseBuilder(this, AppDatabase.class, "db-fares")
            .build()
            .getFareDAO();

DeletingFares 的代码(在 SettingsActivity.java 类中工作):

    /**
 * DELETING FARES CLASS
 */
private class DeletingFares extends AsyncTask<String, Integer, String> 

    // #1 - This is run in a background thread
    @Override
    protected String doInBackground(String... params) 
        // get the string from params, which is an array
        String myString = params[0];

        List<Fare> fares = mFareDAO.getAllFares();

        myString = String.valueOf(fares.size());
        numberOfFares = myString;
        // value of myString is send over to onPostExecute and used in the end to make an Alert

        // if there are no fares - no further action should take place
        if (fares.size() > 0) 
            for (int i = 0; i < fares.size(); i++) 
                Fare ff = fares.get(i);
                mFareDAO.delete(ff);
            
        
        return myString;
    


    // #2 - This runs in UI when background thread finishes
    @Override
    protected void onPostExecute(String result) 
        super.onPostExecute(result);

        // invoking method which displays the alert at the end
        alertAfterDeletingFares();


    

据我了解 NullPointerException 背后的概念 - 对 QueriesUtility 类中对象的引用(但从 SettingsActivity 类请求)不存在,因为没有与数据库的连接,因此对象被引用并返回 null(是对吗?)。

如果有人能指出我正确的方向,我将不胜感激。非常感谢!

【问题讨论】:

【参考方案1】:

您需要将context 传递给AsyncTask,而不是使用getApplicationContext()

参考getApplicationContext in AsyncTask class?

【讨论】:

您好 Gokul,非常感谢您的回答。我只是需要澄清一下。我是在onCreate(即使它不是活动)还是在AsyncTask 中使用上下文而不是getApplicationContext()?它应该如下所示吗? private class CalcNumberOfFares extends AsyncTask&lt;String, Integer, String&gt; private Context context; public CalcNumberOfFares(Context context) this.context = context; 非常感谢您迄今为止的帮助。

以上是关于从实用程序类(非活动)访问房间数据库的 NullPointerException的主要内容,如果未能解决你的问题,请参考以下文章

Android - 如何从小部件访问房间数据库

从非活动单例类中获取应用程序上下文

如何在非活动类中显示进度对话框

如何从服务中访问我的活动的 ViewModel?

回收站视图仅在我从房间数据库中删除后重新打开活动时更新

从服务访问应用程序类