【问题标题】:Result of query is setting application variable late查询结果是延迟设置应用程序变量
【发布时间】:2018-07-29 14:30:14
【问题描述】:

我有一个Fragment。对于片段中所有视图的OnClickListener(),我制作了另一个class UtilClickListener。我正在使用room persistence databasespinner onItemSelected 进行数据库调用。 database 调用首先将数据插入到表中,然后更新我的应用程序中的应用程序变量。

所以我试图在数据库调用之后访问 spinner onItemSelected() 上更新的应用程序变量。但是该变量不会立即更新,稍后当我单击fragment 的其他视图时,我会得到更新的值。

Fragment代码:

public class Calculator extends Fragment   {

 @Nullable
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        Spinner ageSpinner = rootView.findViewById(R.id.spinner_how_old);
        ageSpinner.setOnItemSelectedListener(new UtilOnClickListener(this));
CRSCalculatorAdapter ageListAdapter = new CRSCalculatorAdapter(rootView.getContext(),
                android.R.layout.simple_spinner_item,Arrays.asList(rootView.getContext().getResources().getStringArray(R.array.age_group)) );
        ageSpinner.setAdapter(ageListAdapter);
}
}

UtilOnClickListener 类代码:

public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
 switch (parentSpinnerId[1]) {

            case "spinner_how_old}":

                mGlobals.setAge(parent.getSelectedItem().toString());
                CRSDatabaseInitializer.populateAsync(CRSDatabase.getDatabase(view.getContext()), crsCalculator.getContext(), Constants.QUERY_TYPE_ALL);
               mListener.onChangeActionBarTitle(Integer.valueOf(mGlobals.getFinalScore())); // Here I am updating score in the action bar which is updating late on the next view click

                break;
}

“CRSDatabaseInitializer”正在为数据库调用调用 Asynctask。

这里是数据库初始化代码:

public class CRSDatabaseInitializer {
  public static void populateAsync(@NonNull final CRSDatabase db, Context context, String typeOfQuery) {

        PopulateDbAsync task = new PopulateDbAsync(db, typeOfQuery);
}

 private static class PopulateDbAsync extends AsyncTask<Void, Void, Void> {

        private final CRSDatabase mDb;
        private final String mQueryType;

        PopulateDbAsync(CRSDatabase db, String queryType) {
            mDb = db;
            mQueryType = queryType;
        }

        @Override
        protected Void doInBackground(final Void... params) {

 int scoreOfAge = Integer.valueOf(getScoreOnAge(mDb));
            mGlobals.setFinalScore(scoreOfAge); // this is the application variable I need to update.
return null;

}

public static int getScoreOnAge(CRSDatabase db) {

        int userScore = 0;
        if (mGlobals.getAge() != null) {
            userScore = Integer.valueOf(db.ageScoreDao().getScore(mGlobals.getAge(), mGlobals.getMarriedOrNot()));
        }
        return userScore;
    }
}

从我将数据插入房间数据库的 CRSDatabaseInitializer 添加更多代码:

private static void insertNocCode(CRSDatabase db) {


        NocCode nocData = new NocCode();
        List<String[]> str = insertData(db, "nocCodes.csv");
        for (int i = 0; i < str.size(); i++) {
            nocData.setmNocCode(str.get(i)[0]);
            nocData.setmTitle(str.get(i)[1]);
            nocData.setmSkilltype(str.get(i)[2]);
            addCRSData(db, nocData);


        }
    }

插入数据(数据库数据库,字符串文件名);是我读取 csv 文件并在 csv 文件中插入所有列的方法。

public static List<String[]> insertData(CRSDatabase db, String fileName) {
        String[] str = new String[5];
        ArrayList<String[]> stringArray = new ArrayList<>();

        try {

            InputStreamReader is = new InputStreamReader(mContext.getAssets()
                    .open(fileName));

            BufferedReader reader = new BufferedReader(is);

            String line = "";

            while ((line = reader.readLine()) != null) {
                str = line.split(",");
                stringArray.add(str);
            }

        } catch (IOException ex) {
            ex.printStackTrace();

        } finally

        {
        }
        return stringArray;
    }

以及插入方法定义:

private static NocCode addCRSData(final CRSDatabase db, NocCode nocCode) {
        db.nocCodeDao().insert(nocCode);
        return nocCode;
    }

【问题讨论】:

  • 您要更新哪个变量?
  • mGlobals.setFinalScore(scoreOfAge);我正在更新这个变量..我稍后会从片段类访问它。
  • 如果你得到你的答案,你可以离开这个讨论。您在哪里向表中插入数据?
  • 我在其 doInBackground 方法中的 Database Initializer 类“CRSDatabaseInitializer”中插入数据。
  • 房间数据库处于 WAL 模式。直到插入数据库的数据被提交后,才能从其他线程执行其他读取操作。但是您正在使用同一线程进行插入和读取,因此在插入操作完成之前您无法读取。如果您也可以提供插入操作的代码,将会很有帮助。一个好的解决方案是将您的读取操作包装在事务中,然后仅在插入完成时执行读取。不过我会建议你使用 Rx-java。

标签: android fragment android-room


【解决方案1】:

所以这是我正在经历的这个问题的更新。我使用处理程序解决了这个问题。当我进行数据库调用时,我让数据库首先更新变量,然后我运行一个处理程序来稍后在片段中获取更新的值。 这是我在 UtilOnClickListener 类中更新的代码。

private static class MyHandler extends Handler {}
    private final MyHandler mHandler = new MyHandler();

    public static class UtilRunner implements Runnable {
        private final WeakReference<Calculator> mActivity;

        public UtilRunner(Calculator activity) {
            mActivity = new WeakReference<Calculator>(activity);
        }

        @Override
        public void run() {
            Calculator activity = mActivity.get();

            if (activity.getContext() instanceof MainActivity) {
                OnActionBarListener   mListener = (OnActionBarListener) activity.getContext();
                Globals mGlobals = (Globals) activity.getActivity().getApplicationContext();
                mListener.onChangeActionBarTitle(mGlobals.getFinalScore());

            }
        }
    }

我正在从视图的 OnClick 运行处理程序:

mHandler.postDelayed(mRunnable, 200);

【讨论】:

    【解决方案2】:

    有多种方法可以处理这个问题。在您的情况下,即使您从同一个线程插入和读取,我也无法理解为什么在提交插入数据之前执行读取操作。你可以看看这个讨论:stackOverFlow,我从这个讨论中学到的是,控制在你手中总是更好,因为数据库内部实现可能会不时改变。让我们看看解决方案:

    1. 通过在 Dao 类中使用注解 @Transaction 或将插入代码包装在 db.beginTransaction 和 db.endTransaction.devGuide 中,将读取查询包装在事务中。这可确保在写入数据库时​​不会发生读取。

    2. 我发现最好的方法是使用 Rx-Java See Introdution。您可以进行插入,然后在插入完成并执行读取操作时收到通知。由于插入操作不会返回任何内容,因此将其包装在 Completable.fromAction 中。 Completable observable 具有运算符 obs1.andThen(obs2),从名称中可以清楚地看出,首先完成 obs1,然后只执行 obs2。请注意,您的 db.ageScoreDao().getScore(..) 方法应该返回一个 observable,因此将返回值包装在一个 Observable 中;

      Completable.fromAction(new Action(){

          @Override
          public void run() throws Exception {
              db.nocCodeDao().insert(nocCode);
          }
      }).andThen(return db.ageScoreDao().getScore(..)
        .subscribeOn(Scheduler.io())   //do database query on io thread
        .observeOn(AndroidScheduler.mainThread())
        .subscribeWith(new DisposableObserver<Object>(){
      
            @Override
            public void onNext(Object o) {
                 //Here you update the variable
            }
            @Override
            public void onError(Throwable e) {..}
            @Override
            public void onComplete() {..}
        });
      

    【讨论】:

      猜你喜欢
      • 2021-02-11
      • 1970-01-01
      • 2012-06-28
      • 1970-01-01
      • 2011-04-22
      • 2018-12-31
      • 1970-01-01
      • 1970-01-01
      • 2015-01-23
      相关资源
      最近更新 更多