【问题标题】:Android - RxJava - Race conditionAndroid - RxJava - 竞争条件
【发布时间】:2022-12-14 16:47:27
【问题描述】:

我是多线程概念的新手,也是 RxJava 的新手。我想我在我的 Android 项目中遇到了竞争条件。 为了能够更好地演示它,我下载了 google codelabs 示例 RoomWithAView 并实现了与我自己的项目中相同的竞争条件。

WordDao

@Dao
public interface WordDao {
    @Insert()
    void insert(Word word);

    @Query("SELECT EXISTS(SELECT word FROM WORD_TABLE WHERE word = :word)")
    Single<Integer> wordExists(String word);
}

词库

class WordRepository {

    private WordDao mWordDao;
    private boolean mWordRedundant;
    private final CompositeDisposable mCompositeDisposable = new CompositeDisposable();

    WordRepository(Application application) {
        WordRoomDatabase db = WordRoomDatabase.getDatabase(application);
        mWordDao = db.wordDao();
    }

    void insert(Word word) {
        WordRoomDatabase.databaseWriteExecutor.execute(() -> {
            mWordDao.insert(word);
        });
    }

    public boolean isWordRedundant(String word) {
        mCompositeDisposable.add(
        mWordDao.wordExists(word)
                .subscribeOn(Schedulers.computation())
                .subscribe(integer -> mWordRedundant = integer == 1));
        return mWordRedundant;
    }

WordViewModel

public class WordViewModel extends AndroidViewModel {

    private WordRepository mRepository;

    public WordViewModel(Application application) {
        super(application);
        mRepository = new WordRepository(application);
    }

    public boolean isWordRedundant(String word) {
        return mRepository.isWordRedundant(word);
    }

    public void insert(Word word) {
        mRepository.insert(word);
    }
}

新词活动

public class NewWordActivity extends AppCompatActivity {

    public static final String EXTRA_REPLY = "com.example.android.wordlistsql.REPLY";

    private EditText mEditWordView;
    private WordViewModel mWordViewModel;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_new_word);
        mWordViewModel = new ViewModelProvider(this).get(WordViewModel.class);
        mEditWordView = findViewById(R.id.edit_word);

        final Button button = findViewById(R.id.button_save);
        button.setOnClickListener(view -> {
            Intent replyIntent = new Intent();

            if (TextUtils.isEmpty(mEditWordView.getText())) {
                System.out.println("Word empty");
                setResult(RESULT_CANCELED, replyIntent);
            }

            // possible race condition?
            else if (mWordViewModel.isWordRedundant(mEditWordView.getText().toString())) {
                System.out.println("Word redundant");
                setResult(RESULT_CANCELED, replyIntent);
            }

            else {
                String word = mEditWordView.getText().toString();
                System.out.println("Word acceptable");
                replyIntent.putExtra(EXTRA_REPLY, word);
                setResult(RESULT_OK, replyIntent);
            }
            finish();
        });
    }
}

在我的例子中,方法isPlayerNameRedundant()总是返回false。我在 App Inspection 中测试了 SQL 查询,它返回 1,所以 isPlayerNameRedundant() 方法应该返回 true。 我怀疑因为我在存储库中使用了Schedulers.computation(),所以查询是在后台线程上执行的,并且在该线程完成其任务之前,主线程返回mWordRedundant。 那是对的吗?

如果是这样,解决这个问题的方法是什么?

先感谢您。

【问题讨论】:

    标签: java android rx-java rx-android


    【解决方案1】:

    你在滥用 Rx-java。

    正确方法:

    词库

    public Single<Boolean> isWordRedundant(String word) {
        return mWordDao.wordExists(word)
                .subscribeOn(Schedulers.io()) //computation() is for CPU intensive operation. Not for DB read/write. This is a tiny error.
                .map(i -> i == 1 ? true : false)
    }
    

    WordViewModel

    public Single<Boolean> isWordRedundant(String word) {
        return mRepository.isWordRedundant(word);
    }
    

    新词活动

        button.setOnClickListener(view -> {
            Intent replyIntent = new Intent();
    
            if (TextUtils.isEmpty(mEditWordView.getText())) {
                System.out.println("Word empty");
                setResult(RESULT_CANCELED, replyIntent);
                finish();
            } else {
                //Your CompositDisposable in activity
                compositDisposable.add(
                    mWordViewModel.isWordRedundant(mEditWordView.getText().toString())
                        .observeOn(AndroidSchedulers.mainThread())
                        .subscribe(isRedundant -> {
                            if (isRedundant) {
                                System.out.println("Word redundant");
                                setResult(RESULT_CANCELED, replyIntent);
                            } else {
                                String word = mEditWordView.getText().toString();
                                System.out.println("Word acceptable");
                                replyIntent.putExtra(EXTRA_REPLY, word);
                                setResult(RESULT_OK, replyIntent);
                            }
                            finish();
                        }, error -> {/* handle error here. Maybe a Toast or something. */})
                );
            }
        });
    

    那么,为什么您之前的代码不起作用?让我们看看代码词库之前(注意cmets):

    
    class WordRepository {
    
        private WordDao mWordDao;
        private boolean mWordRedundant; //field variable. Not initiate. So is the default value: **false**.
        private final CompositeDisposable mCompositeDisposable = new CompositeDisposable();
    
        public boolean isWordRedundant(String word) {
            //Main thread enter here.
            //Main thread step 1: Create an Observable i.e.(mWordDao.wordExists(word)). And subscribe on it.
            mCompositeDisposable.add(
                mWordDao.wordExists(word)
                    .subscribeOn(Schedulers.computation())
                    .subscribe(integer -> mWordRedundant = integer == 1)); //We process it and observe the result in computation() thread. Then change the filed variable "mWordRedundant" value.
            
            //Main thread step 2: return the field variable **immediately**! Not wait for the result from computation() thread. That is why you can not get the right result.
            return mWordRedundant;
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-12-02
      • 2022-01-23
      • 2018-10-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多