如何修复 'Cannot access database on the main thread since it may potentially lock the UI for a long period of time.'
How to fix 'Cannot access database on the main thread since it may potentially lock the UI for a long period of time.'
我正在尝试创建一个 Procduct
变量,但我需要从现有的 java class 调用 suspend fun
,但是当我调用创建它所需的方法:
Process: com.some.app.debug, PID: 6758
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:209)
at androidx.room.RoomDatabase.query(RoomDatabase.java:237)
at com.some.app.thread.local.ProductDAO_Impl.getProductByStyleColor(ProductDAO_Impl.java:513)
at com.some.app.thread.local.ThreadPersister.getProductByStyleColor(ThreadPersister.kt:315)
at com.some.app.user.orders.OrderDetailsFragment.loadDetails(OrderDetailsFragment.java:189)
at com.some.app.user.orders.OrderDetailsFragment.onCreateView(OrderDetailsFragment.java:131)
at androidx.fragment.app.Fragment.performCreateView(Fragment.java:2439)
at androidx.fragment.app.FragmentManagerImpl.moveToState(FragmentManager.java:1460)
at androidx.fragment.app.FragmentManagerImpl.moveFragmentToExpectedState(FragmentManager.java:1784)
at androidx.fragment.app.FragmentManagerImpl.moveToState(FragmentManager.java:1852)
at androidx.fragment.app.BackStackRecord.executeOps(BackStackRecord.java:802)
at androidx.fragment.app.FragmentManagerImpl.executeOps(FragmentManager.java:2625)
at androidx.fragment.app.FragmentManagerImpl.executeOpsTogether(FragmentManager.java:2411)
at androidx.fragment.app.FragmentManagerImpl.removeRedundantOperationsAndExecute(FragmentManager.java:2366)
at androidx.fragment.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:2273)
at androidx.fragment.app.FragmentManagerImpl.run(FragmentManager.java:733)
at android.os.Handler.handleCallback(Handler.java:873)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:6718)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
我正在尝试从 OrderDetailsFragment.java
class 调用方法 getProductByStyleColorSuspended()
。方法在ThreadPersister.kt
这里是 classes:
public class OrderDetailsFragment extends BaseToolbarFragment {
@BindView(R.id.item_order_imageview)
protected ImageView mHeaderItemImageView;
@BindView(R.id.item_order_progressbar)
protected ProgressBar mLoadingProgressBar;
@BindView(R.id.item_order_title_textview)
protected TextView mItemTitleTextView;
@BindView(R.id.item_order_status_textview)
protected TextView mItemStatusTextView;
@BindView(R.id.fragment_order_detail_color_value)
protected TextView mColorTextView;
@BindView(R.id.fragment_order_detail_size_value)
protected TextView mSizeTextView;
@BindView(R.id.fragment_order_detail_order_number_value)
protected TextView mOrderNumberTextView;
@BindView(R.id.fragment_order_detail_order_date_value)
protected TextView mOrderDateTextView;
@BindView(R.id.fragment_order_detail_tax_value)
protected TextView mTaxTextView;
@BindView(R.id.fragment_order_detail_shipping_value)
protected TextView mShippingTextView;
@BindView(R.id.fragment_order_detail_total_value)
protected TextView mTotalTextView;
@BindView(R.id.fragment_order_detail_address_textview)
protected TextView mAddressTextView;
@BindView(R.id.fragment_order_detail_top_button)
protected Button mTopButton;
@BindView(R.id.fragment_order_detail_bottom_button)
protected Button mBottomButton;
@BindView(R.id.fragment_order_detail_relativelayout)
protected RelativeLayout mRelativeLayout;
@BindView(R.id.fragment_order_detail_progressview)
protected ProgressBar mFragmentProgressBar;
@BindView(R.id.fragment_order_detail_tax_title)
protected TextView mTaxTextViewTitle;
@FragmentArgument("order")
protected SnkrsOrder mOrder;
public SnkrsOrder getOrder() {
return mOrder;
}
@SuppressLint("RxLeakedSubscription") @Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
Analytics.with(AnalyticsState.INBOX_ORDER_DETAILS).buildAndSend();
final View rootView = getActivity() instanceof SnkrsActivity ?
super.onCreateView(inflater, container, savedInstanceState) :
inflater.inflate(R.layout.fragment_order_details, container, false);
ButterKnife.bind(this, rootView);
if (mOrder != null) {
if (mOrder.getDetails() == null) {
mRelativeLayout.setVisibility(View.GONE);
mFragmentProgressBar.setVisibility(View.VISIBLE);
mOrderHistoryService.getOrderHistoryDetails(mOrder)
.subscribe(new SimpleSubscriber<SnkrsOrder>() {
@Override
public void onNext(SnkrsOrder order) {
super.onNext(order);
order.setSubmittedDate(order.getDetails().getOrder().getSubmittedDate());
safeRunOnUiThread(() -> loadDetails(order.getDetails().getOrder()));
}
});
} else {
loadDetails(mOrder.getDetails().getOrder());
}
}
return rootView;
}
public void loadDetails(SnkrsOrderDetails.Order detailOrder) {
mItemTitleTextView.setText(detailOrder.getDisplayName());
mItemStatusTextView.setText(detailOrder.getLocalizedStatusText());
mLoadingProgressBar.setVisibility(View.VISIBLE);
String encodedStyleColor = detailOrder.getEncodedStyleColor();
if (!TextUtils.isEmpty(encodedStyleColor)) {
String url = getContext().getString(R.string.style_color_url_format_transparent_bgc,
encodedStyleColor);
loadImage(url);
}
SnkrsOrderDetails.CommerceItem commerceItem = detailOrder.getCommerceItem();
if (commerceItem != null) {
mColorTextView.setText(commerceItem.getColorDescription());
mSizeTextView.setText(commerceItem.getDisplaySize());
}
mOrderNumberTextView.setText(detailOrder.getId());
SimpleDateFormat fromFormat = new SimpleDateFormat("yyyy-MM-dd", Locale.US);
try {
Date date = fromFormat.parse(mOrder.getSubmittedDate());
mOrderDateTextView.setText(TimeFormatter.format("MM/d/yyyy", date));
} catch (ParseException e) {
Timber.e(e, e.getLocalizedMessage());
}
SnkrsOrderDetails.PriceInfo priceInfo = detailOrder.getPriceInfo();
if (priceInfo != null) {
mTaxTextView.setText(priceInfo.getFormattedTax());
mShippingTextView.setText(priceInfo.getFormattedShipping());
mTotalTextView.setText(priceInfo.getFormattedTotal());
if (mFeedLocalizationService.getCurrentFeedLocale() != null
&& (mFeedLocalizationService.getCurrentFeedLocale().isChina() ||
mFeedLocalizationService.getCurrentFeedLocale().isJapan())) {
mTaxTextViewTitle.setVisibility(View.GONE);
mTaxTextView.setVisibility(View.GONE);
}
}
SnkrsAddress address = detailOrder.getShippingGroups().get(0).getShippingAddress();
mAddressTextView.setText(address.getMultilineFormattedNameAndAddress());
if (detailOrder.canBeCancelled()) {
mBottomButton.setText(R.string.orders_details_cancel_order_button);
mBottomButton.setOnClickListener(v -> cancelOrder(detailOrder));
final Product product = threadStore.getThreadRepository()
.getThreadPersister()
// .getProductByStyleColor(detailOrder.getStyleColor());
.getProductByStyleColorSuspended(detailOrder.getStyleColor());
if (product != null) {
final DeferredPaymentOrder deferredPaymentOrder =
mSnkrsDatabaseHelper.getDeferredPaymentOrder(detailOrder.getId());
if (deferredPaymentOrder != null && deferredPaymentOrder.isWaiting()) {
mTopButton.setVisibility(View.VISIBLE);
mTopButton.setText(R.string.cta_go_fund);
mTopButton.setOnClickListener(
v -> ((BaseActivity) getActivity()).fundDeferredPaymentOrder(product,
AnalyticsAction.ORDER_DETAILS_FUND));
} else {
mTopButton.setVisibility(View.GONE);
}
} else {
mTopButton.setVisibility(View.GONE);
}
} else if (detailOrder.canTrackAndReturn()) {
mTopButton.setText(R.string.orders_details_track_order_button);
mBottomButton.setText(R.string.orders_details_return_order_button);
mTopButton.setOnClickListener(v -> trackOrder(detailOrder));
mBottomButton.setOnClickListener(v -> returnOrder(detailOrder));
} else {
mTopButton.setVisibility(View.GONE);
mBottomButton.setVisibility(View.GONE);
}
Activity snkrsActivity = getActivity();
if (snkrsActivity instanceof SnkrsActivity) {
// For some reason, adding only the bottom bar's padding does not give enough padding. However, doubling it seems to work
mRelativeLayout.setPadding(0, 0, 0, ((SnkrsActivity) snkrsActivity).getBottomBarHeight() * 2);
}
mFragmentProgressBar.setVisibility(View.GONE);
mRelativeLayout.setVisibility(View.VISIBLE);
}
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
if (getActivity() instanceof SnkrsActivity) {
//force hide on inbox in case bottom bar animation messes up and leaves it
((SnkrsActivity) getActivity()).clearInboxBadge();
((SnkrsActivity) getActivity()).forceBottomBarVisibility(false);
}
}
@Override
public void onDestroyView() {
super.onDestroyView();
if (getActivity() instanceof SnkrsActivity) {
((SnkrsActivity) getActivity()).forceBottomBarVisibility(true);
}
}
@NonNull
@Override
public String getTitle() {
return safeGetString(R.string.inbox_orders_title).toUpperCase();
}
@Override
public int getLayoutId() {
return R.layout.fragment_order_details;
}
private void cancelOrder(SnkrsOrderDetails.Order order) {
Analytics.with(AnalyticsAction.ORDER_CANCEL).buildAndSend();
String email = mPreferenceStore.getString(R.string.pref_key_email, null);
((BaseActivity) getActivity()).goToXxxxSiteForOrderActions(order.getId(), email);
}
private void trackOrder(SnkrsOrderDetails.Order order) {
Analytics.with(AnalyticsAction.ORDER_TRACK).buildAndSend();
String trackingUrl = order.getShippingGroups().get(0).getTrackingUrl();
if (!TextUtils.isEmpty(trackingUrl)) {
((BaseActivity) getActivity()).goToSite(Uri.parse(trackingUrl));
}
}
private void returnOrder(SnkrsOrderDetails.Order order) {
Analytics.with(AnalyticsAction.ORDER_RETURN).buildAndSend();
String email = mPreferenceStore.getString(R.string.pref_key_email, null);
((BaseActivity) getActivity()).goToXxxxSiteForOrderActions(order.getId(), email);
}
private void loadImage(String url) {
//noinspection CodeBlock2Expr
safeRunOnUiThread(() -> {
ImageUtilities.INSTANCE.displayImage(mHeaderItemImageView, url,
() -> {
if (mLoadingProgressBar != null) {
mLoadingProgressBar.setVisibility(View.INVISIBLE);
}
}
);
});
}
}
这是ThreadPersister.kt
class
class ThreadPersister @Inject constructor(val snkrsDB: SnkrsDB) {
private val config = Builder()
.setPageSize(10)
.setInitialLoadSizeHint(20)
.build()
private val dataSourceFactory = snkrsDB
.threadDAO()
.getPage()
.mapByPage {
it.mapToThreads()
.withCardProducts(snkrsDB)
}
val pages = RxPagedListBuilder(
dataSourceFactory, config
)
.buildObservable()
fun insertThreads(threads: List<Thread>): ThreadDAO {
val threadDAO = snkrsDB.threadDAO()
snkrsDB.runInTransaction {
threads.forEach { thread ->
insertThread(threadDAO, thread)
}
}
return threadDAO
}
fun insertThread(thread: Thread) {
insertThread(snkrsDB.threadDAO(), thread)
}
private fun insertThread(
threadDAO: ThreadDAO,
thread: Thread
) {
thread.productId = thread.product?.id;
threadDAO.insert(thread)
thread.product?.let { insertProduct(it) }
thread.cards?.forEach { card -> insertCard(card, thread) }
thread.relations?.let {
it.forEach { related ->
related.threadId = thread.threadId;snkrsDB.relatedThreadsDAO()
.insert(related)
}
}
}
fun insertProduct(product: Product) {
snkrsDB.productDAO()
.insert(product)
product.skus?.let {
it.forEach { sku ->
sku.productId = product.id; insertSku(sku)
}
}
}
fun insertSku(vararg sku: Sku) {
snkrsDB.skuDAO()
.insert(*sku)
}
private fun insertCard(
card: Card,
thread: Thread
) {
card.threadId = thread.threadId
card.images?.let {
it.forEach { image ->
image.cardId = card.cardId; snkrsDB.imageDAO()
.insert(image)
}
}
card.videos?.let {
it.forEach { video ->
video.cardId = card.cardId; snkrsDB.videoDAO()
.insert(video)
}
}
card.product?.let {
card.productId = it.id
insertProduct(it)
}
snkrsDB.cardDAO()
.insert(card)
}
private fun List<Thread>.withCardProducts(snkrsDB: SnkrsDB): List<Thread> {
val cards = this.mapNotNull { it.cards }
.flatten()
val ids = cards.mapNotNull { it.productId }
val idGroups = ids.chunked(900)
val products = idGroups.map {
snkrsDB.productDAO()
.getProductsById(it)
}
.flatten()
cards.forEach {
if (it.productId != null) {
val productFull =
products.firstOrNull { productFull -> it.productId == productFull.product?.id }
if (productFull != null) {
it.product = productFull.product
it.product?.skus = productFull.skus
}
}
}
val list = this
val filteredList = list.take(10)
.filter {
it.product?.skus?.any { sku -> sku.available } ?: false && it.product?.selectionEngine != "DAN" && it.product?.style != "999999" && it.product?.isOnSale() == false
}
return list
}
@Transaction
private fun Thread.withCardProducts(snkrsDB: SnkrsDB): Thread {
val ids = cards?.filter { it.productId != null }
?.map { it.productId!! }
val products = snkrsDB.productDAO()
.getProductsById(ids!!)
cards?.forEach {
if (it.productId != null) {
val productFull =
products.firstOrNull { productFull -> it.productId == productFull.product?.id }
if (productFull != null) {
it.product = productFull.product
it.product?.skus = productFull.skus
}
}
}
return this
}
@Transaction
fun getThreadsFromDB(): Observable<List<Thread>> {
return snkrsDB.threadDAO()
.getData()
.toObservable()
.map {
it.mapToThreads()
.map { threads -> threads.withCardProducts(snkrsDB) }
}
}
@Synchronized
@Transaction
fun getAllPages(): Single<List<Thread>> {
return snkrsDB.threadDAO()
.getData()
.doOnSuccess { it }
.map { it.mapToThreads() }
.map { it.withCardProducts(snkrsDB) }
}
@Transaction
fun getPage(pageNumber: Int): Maybe<List<Thread>> {
return snkrsDB.threadDAO()
.getPage(50 * pageNumber, 50)
.filter { it.isNotEmpty() }
.firstOrError()
.map { it.mapToThreads() }
.map { it.withCardProducts(snkrsDB) }
.toMaybe()
.doAfterSuccess { it }
}
fun getFeed(): Observable<PagedList<Thread>> {
return pages.throttlePages()
}
private fun Observable<PagedList<Thread>>.throttlePages() =
this.filter { it.size > 0 }
.sample(Observable.interval(0, 5, SECONDS), true)
.distinctUntilChanged()
fun getFirstThreadId(time: Long) =
snkrsDB.threadDAO().getFirstThreadId(time).mapToThread().withCardProducts(snkrsDB)
fun getThreadByInterestId(id: String) =
snkrsDB.threadDAO().getThreadByInterestId(id)?.mapToThread()?.withCardProducts(snkrsDB)
fun getThreadsByRelatedIds(ids: List<String>) =
snkrsDB.threadDAO().getThreadsByRelatedIds(ids).mapToThreads().withCardProducts(snkrsDB)
fun getThreadsByInterestIds(ids: List<String>): List<Thread> =
snkrsDB.threadDAO().getThreadsByAllInterestIds(ids).mapToThreads().withCardProducts(snkrsDB)
fun getThreadByProductId(id: String) =
snkrsDB.threadDAO().getThreadByProductId(id).mapToThread().withCardProducts(snkrsDB)
fun getThreadBySlug(slug: String) =
snkrsDB.threadDAO().getThreadBySlug(slug).mapToThread().withCardProducts(snkrsDB)
@Deprecated(message = "Use safeGetThreadByThreadId")
fun getThreadByThreadId(id: String) =
snkrsDB.threadDAO().getThreadByThreadId(id)!!.mapToThread().withCardProducts(snkrsDB)
//TODO MIKE: Migrate all to safe version
fun safeGetThreadByThreadId(id: String): Thread? {
val thread = snkrsDB.threadDAO()
.getThreadByThreadId(id)
return thread?.mapToThread()
?.withCardProducts(snkrsDB)
}
fun getThreadsById(ids: List<String>) =
snkrsDB.threadDAO().getThreadsByIDs(ids).mapToThreads().withCardProducts(snkrsDB)
fun getThreadByStyleColor(styleColor: String): Thread {
val split = styleColor.split('-')
return snkrsDB.threadDAO()
.getThreadByStyleColor(split[0], split[1])
.mapToThread()
.withCardProducts(snkrsDB)
}
suspend fun getThreadByStyleColorSuspended(styleColor: String): Thread =
withContext(Dispatchers.IO) {
val split = styleColor.split('-')
snkrsDB.threadDAO()
.getThreadByStyleColor(split[0], split[1])
.mapToThread()
.withCardProducts(snkrsDB)
}
fun getThreadsThatMatch(searchTerm: String) =
snkrsDB.threadDAO().getThreadsForSearch(searchTerm).mapToThreads().withCardProducts(snkrsDB)
//TODO MIKE: change to exponential dropoff
fun getInStockThreads() =
snkrsDB.threadDAO().getPurchasableInStockThreads()
// .mergeWith {
// snkrsDB.threadDAO()
// .getDrawInStockThreads()
// }
.toObservable()
.sample(Observable.interval(0, 10, SECONDS), true)
.distinct { it.map { it.thread.lastUpdatedTime } }
.map {
it.distinctBy { it.thread.threadId }
.mapToThreads()
.withCardProducts(snkrsDB)
}
fun getUpcomingThreads() =
snkrsDB.threadDAO().getUpcomingThreads()
.toObservable()
.sample(Observable.interval(0, 10, SECONDS), true)
.distinct { it.map { it.thread.lastUpdatedTime } }
.map {
it.distinctBy { threadFull -> threadFull.thread.threadId }
.mapToThreads()
.withCardProducts(snkrsDB)
}
fun threadsByTags(searchTerm: String) = snkrsDB
.threadDAO()
.getThreadsByTag(searchTerm)
.map { it.map { it.mapToThread() } }
fun threadsByTag(searchTerm: String) = snkrsDB
.threadDAO()
.getThreadByTag(searchTerm)
.map { it.mapToThread() }
suspend fun getProductByProductIdSuspended(id: String): Product? = withContext(Dispatchers.IO) {
getProductByProductId(id)
}
fun getProductByProductId(id: String) = snkrsDB.productDAO().getProductById(id)?.mapToProduct()
suspend fun getProductByStyleColorSuspended(styleColor: String): Product? = withContext(Dispatchers.IO){
getProductByStyleColor(styleColor)
}
fun getProductByStyleColor(styleColor: String?): Product? {
if (styleColor == null) return null
val split = styleColor.split('-')
Timber.d("split string: %s", split)
return snkrsDB.productDAO()
.getProductByStyleColor(split[0], split[1])
.mapToProduct()
}
@Transaction
fun updateProductSkus(productSkus: List<Sku>) {
productSkus.forEach { Timber.i("updating sku with productId ${it.productId} ${it.available}") }
insertSku(*productSkus.toTypedArray())
}
}
我试过使用 AsyncTask
,但没有成功,但我想看看是否有使用 RxJava 的解决方案。还想看看我是否可以使用 Coroutines
找到解决方案
我也试过传递一个 Continuation
参数,但该方法没有返回一个 ``Product``` 对象,但即使转换它,它也会给我一个不同的错误。
我只是想使用 getProductByStyleColorSuspended(detailOrder.getStyleColor())
或 getProductByStyleColor(detailOrders.getStyleColor())
方法从 OrderDetailsFragment.java
成功创建一个 Product
对象
你忘了 subscribeOn 和 observeOn 函数
您应该订阅 IO 线程
在主线程上观察
像那样
mOrderHistoryService.getOrderHistoryDetails(mOrder)
.subscribeOn(Schedulers.io())
.observeOn (AndroidSchedulers.mainThread())
.subscribe(new SimpleSubscriber....
在你的片段中试试这个
Single.fromCallable(new Callable<Product>() {
@Override
public Product call() throws Exception {
return threadStore.getThreadRepository()
.getThreadPersister()
.getProductByStyleColorSuspended(detailOrder.getStyleColor())
}
})
.subscribeOn(Schedulers.io())
.observeOn (AndroidSchedulers.mainThread())
.subscribe(new DisposableSingleObserver<Object>() {
@Override
public void onSuccess(Object o) {
if (product != null) {
final DeferredPaymentOrder deferredPaymentOrder =
mSnkrsDatabaseHelper.getDeferredPaymentOrder(detailOrder.getId());
if (deferredPaymentOrder != null && deferredPaymentOrder.isWaiting()) {
mTopButton.setVisibility(View.VISIBLE);
mTopButton.setText(R.string.cta_go_fund);
mTopButton.setOnClickListener(
v -> ((BaseActivity) getActivity()).fundDeferredPaymentOrder(product,
AnalyticsAction.ORDER_DETAILS_FUND));
} else {
mTopButton.setVisibility(View.GONE);
}
} else {
mTopButton.setVisibility(View.GONE);
}
}
@Override
public void onError(Throwable e) {
}
});
对您访问数据库的任何地方应用相同的方法
我正在尝试创建一个 Procduct
变量,但我需要从现有的 java class 调用 suspend fun
,但是当我调用创建它所需的方法:
Process: com.some.app.debug, PID: 6758
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:209)
at androidx.room.RoomDatabase.query(RoomDatabase.java:237)
at com.some.app.thread.local.ProductDAO_Impl.getProductByStyleColor(ProductDAO_Impl.java:513)
at com.some.app.thread.local.ThreadPersister.getProductByStyleColor(ThreadPersister.kt:315)
at com.some.app.user.orders.OrderDetailsFragment.loadDetails(OrderDetailsFragment.java:189)
at com.some.app.user.orders.OrderDetailsFragment.onCreateView(OrderDetailsFragment.java:131)
at androidx.fragment.app.Fragment.performCreateView(Fragment.java:2439)
at androidx.fragment.app.FragmentManagerImpl.moveToState(FragmentManager.java:1460)
at androidx.fragment.app.FragmentManagerImpl.moveFragmentToExpectedState(FragmentManager.java:1784)
at androidx.fragment.app.FragmentManagerImpl.moveToState(FragmentManager.java:1852)
at androidx.fragment.app.BackStackRecord.executeOps(BackStackRecord.java:802)
at androidx.fragment.app.FragmentManagerImpl.executeOps(FragmentManager.java:2625)
at androidx.fragment.app.FragmentManagerImpl.executeOpsTogether(FragmentManager.java:2411)
at androidx.fragment.app.FragmentManagerImpl.removeRedundantOperationsAndExecute(FragmentManager.java:2366)
at androidx.fragment.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:2273)
at androidx.fragment.app.FragmentManagerImpl.run(FragmentManager.java:733)
at android.os.Handler.handleCallback(Handler.java:873)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:6718)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
我正在尝试从 OrderDetailsFragment.java
class 调用方法 getProductByStyleColorSuspended()
。方法在ThreadPersister.kt
这里是 classes:
public class OrderDetailsFragment extends BaseToolbarFragment {
@BindView(R.id.item_order_imageview)
protected ImageView mHeaderItemImageView;
@BindView(R.id.item_order_progressbar)
protected ProgressBar mLoadingProgressBar;
@BindView(R.id.item_order_title_textview)
protected TextView mItemTitleTextView;
@BindView(R.id.item_order_status_textview)
protected TextView mItemStatusTextView;
@BindView(R.id.fragment_order_detail_color_value)
protected TextView mColorTextView;
@BindView(R.id.fragment_order_detail_size_value)
protected TextView mSizeTextView;
@BindView(R.id.fragment_order_detail_order_number_value)
protected TextView mOrderNumberTextView;
@BindView(R.id.fragment_order_detail_order_date_value)
protected TextView mOrderDateTextView;
@BindView(R.id.fragment_order_detail_tax_value)
protected TextView mTaxTextView;
@BindView(R.id.fragment_order_detail_shipping_value)
protected TextView mShippingTextView;
@BindView(R.id.fragment_order_detail_total_value)
protected TextView mTotalTextView;
@BindView(R.id.fragment_order_detail_address_textview)
protected TextView mAddressTextView;
@BindView(R.id.fragment_order_detail_top_button)
protected Button mTopButton;
@BindView(R.id.fragment_order_detail_bottom_button)
protected Button mBottomButton;
@BindView(R.id.fragment_order_detail_relativelayout)
protected RelativeLayout mRelativeLayout;
@BindView(R.id.fragment_order_detail_progressview)
protected ProgressBar mFragmentProgressBar;
@BindView(R.id.fragment_order_detail_tax_title)
protected TextView mTaxTextViewTitle;
@FragmentArgument("order")
protected SnkrsOrder mOrder;
public SnkrsOrder getOrder() {
return mOrder;
}
@SuppressLint("RxLeakedSubscription") @Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
Analytics.with(AnalyticsState.INBOX_ORDER_DETAILS).buildAndSend();
final View rootView = getActivity() instanceof SnkrsActivity ?
super.onCreateView(inflater, container, savedInstanceState) :
inflater.inflate(R.layout.fragment_order_details, container, false);
ButterKnife.bind(this, rootView);
if (mOrder != null) {
if (mOrder.getDetails() == null) {
mRelativeLayout.setVisibility(View.GONE);
mFragmentProgressBar.setVisibility(View.VISIBLE);
mOrderHistoryService.getOrderHistoryDetails(mOrder)
.subscribe(new SimpleSubscriber<SnkrsOrder>() {
@Override
public void onNext(SnkrsOrder order) {
super.onNext(order);
order.setSubmittedDate(order.getDetails().getOrder().getSubmittedDate());
safeRunOnUiThread(() -> loadDetails(order.getDetails().getOrder()));
}
});
} else {
loadDetails(mOrder.getDetails().getOrder());
}
}
return rootView;
}
public void loadDetails(SnkrsOrderDetails.Order detailOrder) {
mItemTitleTextView.setText(detailOrder.getDisplayName());
mItemStatusTextView.setText(detailOrder.getLocalizedStatusText());
mLoadingProgressBar.setVisibility(View.VISIBLE);
String encodedStyleColor = detailOrder.getEncodedStyleColor();
if (!TextUtils.isEmpty(encodedStyleColor)) {
String url = getContext().getString(R.string.style_color_url_format_transparent_bgc,
encodedStyleColor);
loadImage(url);
}
SnkrsOrderDetails.CommerceItem commerceItem = detailOrder.getCommerceItem();
if (commerceItem != null) {
mColorTextView.setText(commerceItem.getColorDescription());
mSizeTextView.setText(commerceItem.getDisplaySize());
}
mOrderNumberTextView.setText(detailOrder.getId());
SimpleDateFormat fromFormat = new SimpleDateFormat("yyyy-MM-dd", Locale.US);
try {
Date date = fromFormat.parse(mOrder.getSubmittedDate());
mOrderDateTextView.setText(TimeFormatter.format("MM/d/yyyy", date));
} catch (ParseException e) {
Timber.e(e, e.getLocalizedMessage());
}
SnkrsOrderDetails.PriceInfo priceInfo = detailOrder.getPriceInfo();
if (priceInfo != null) {
mTaxTextView.setText(priceInfo.getFormattedTax());
mShippingTextView.setText(priceInfo.getFormattedShipping());
mTotalTextView.setText(priceInfo.getFormattedTotal());
if (mFeedLocalizationService.getCurrentFeedLocale() != null
&& (mFeedLocalizationService.getCurrentFeedLocale().isChina() ||
mFeedLocalizationService.getCurrentFeedLocale().isJapan())) {
mTaxTextViewTitle.setVisibility(View.GONE);
mTaxTextView.setVisibility(View.GONE);
}
}
SnkrsAddress address = detailOrder.getShippingGroups().get(0).getShippingAddress();
mAddressTextView.setText(address.getMultilineFormattedNameAndAddress());
if (detailOrder.canBeCancelled()) {
mBottomButton.setText(R.string.orders_details_cancel_order_button);
mBottomButton.setOnClickListener(v -> cancelOrder(detailOrder));
final Product product = threadStore.getThreadRepository()
.getThreadPersister()
// .getProductByStyleColor(detailOrder.getStyleColor());
.getProductByStyleColorSuspended(detailOrder.getStyleColor());
if (product != null) {
final DeferredPaymentOrder deferredPaymentOrder =
mSnkrsDatabaseHelper.getDeferredPaymentOrder(detailOrder.getId());
if (deferredPaymentOrder != null && deferredPaymentOrder.isWaiting()) {
mTopButton.setVisibility(View.VISIBLE);
mTopButton.setText(R.string.cta_go_fund);
mTopButton.setOnClickListener(
v -> ((BaseActivity) getActivity()).fundDeferredPaymentOrder(product,
AnalyticsAction.ORDER_DETAILS_FUND));
} else {
mTopButton.setVisibility(View.GONE);
}
} else {
mTopButton.setVisibility(View.GONE);
}
} else if (detailOrder.canTrackAndReturn()) {
mTopButton.setText(R.string.orders_details_track_order_button);
mBottomButton.setText(R.string.orders_details_return_order_button);
mTopButton.setOnClickListener(v -> trackOrder(detailOrder));
mBottomButton.setOnClickListener(v -> returnOrder(detailOrder));
} else {
mTopButton.setVisibility(View.GONE);
mBottomButton.setVisibility(View.GONE);
}
Activity snkrsActivity = getActivity();
if (snkrsActivity instanceof SnkrsActivity) {
// For some reason, adding only the bottom bar's padding does not give enough padding. However, doubling it seems to work
mRelativeLayout.setPadding(0, 0, 0, ((SnkrsActivity) snkrsActivity).getBottomBarHeight() * 2);
}
mFragmentProgressBar.setVisibility(View.GONE);
mRelativeLayout.setVisibility(View.VISIBLE);
}
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
if (getActivity() instanceof SnkrsActivity) {
//force hide on inbox in case bottom bar animation messes up and leaves it
((SnkrsActivity) getActivity()).clearInboxBadge();
((SnkrsActivity) getActivity()).forceBottomBarVisibility(false);
}
}
@Override
public void onDestroyView() {
super.onDestroyView();
if (getActivity() instanceof SnkrsActivity) {
((SnkrsActivity) getActivity()).forceBottomBarVisibility(true);
}
}
@NonNull
@Override
public String getTitle() {
return safeGetString(R.string.inbox_orders_title).toUpperCase();
}
@Override
public int getLayoutId() {
return R.layout.fragment_order_details;
}
private void cancelOrder(SnkrsOrderDetails.Order order) {
Analytics.with(AnalyticsAction.ORDER_CANCEL).buildAndSend();
String email = mPreferenceStore.getString(R.string.pref_key_email, null);
((BaseActivity) getActivity()).goToXxxxSiteForOrderActions(order.getId(), email);
}
private void trackOrder(SnkrsOrderDetails.Order order) {
Analytics.with(AnalyticsAction.ORDER_TRACK).buildAndSend();
String trackingUrl = order.getShippingGroups().get(0).getTrackingUrl();
if (!TextUtils.isEmpty(trackingUrl)) {
((BaseActivity) getActivity()).goToSite(Uri.parse(trackingUrl));
}
}
private void returnOrder(SnkrsOrderDetails.Order order) {
Analytics.with(AnalyticsAction.ORDER_RETURN).buildAndSend();
String email = mPreferenceStore.getString(R.string.pref_key_email, null);
((BaseActivity) getActivity()).goToXxxxSiteForOrderActions(order.getId(), email);
}
private void loadImage(String url) {
//noinspection CodeBlock2Expr
safeRunOnUiThread(() -> {
ImageUtilities.INSTANCE.displayImage(mHeaderItemImageView, url,
() -> {
if (mLoadingProgressBar != null) {
mLoadingProgressBar.setVisibility(View.INVISIBLE);
}
}
);
});
}
}
这是ThreadPersister.kt
class
class ThreadPersister @Inject constructor(val snkrsDB: SnkrsDB) {
private val config = Builder()
.setPageSize(10)
.setInitialLoadSizeHint(20)
.build()
private val dataSourceFactory = snkrsDB
.threadDAO()
.getPage()
.mapByPage {
it.mapToThreads()
.withCardProducts(snkrsDB)
}
val pages = RxPagedListBuilder(
dataSourceFactory, config
)
.buildObservable()
fun insertThreads(threads: List<Thread>): ThreadDAO {
val threadDAO = snkrsDB.threadDAO()
snkrsDB.runInTransaction {
threads.forEach { thread ->
insertThread(threadDAO, thread)
}
}
return threadDAO
}
fun insertThread(thread: Thread) {
insertThread(snkrsDB.threadDAO(), thread)
}
private fun insertThread(
threadDAO: ThreadDAO,
thread: Thread
) {
thread.productId = thread.product?.id;
threadDAO.insert(thread)
thread.product?.let { insertProduct(it) }
thread.cards?.forEach { card -> insertCard(card, thread) }
thread.relations?.let {
it.forEach { related ->
related.threadId = thread.threadId;snkrsDB.relatedThreadsDAO()
.insert(related)
}
}
}
fun insertProduct(product: Product) {
snkrsDB.productDAO()
.insert(product)
product.skus?.let {
it.forEach { sku ->
sku.productId = product.id; insertSku(sku)
}
}
}
fun insertSku(vararg sku: Sku) {
snkrsDB.skuDAO()
.insert(*sku)
}
private fun insertCard(
card: Card,
thread: Thread
) {
card.threadId = thread.threadId
card.images?.let {
it.forEach { image ->
image.cardId = card.cardId; snkrsDB.imageDAO()
.insert(image)
}
}
card.videos?.let {
it.forEach { video ->
video.cardId = card.cardId; snkrsDB.videoDAO()
.insert(video)
}
}
card.product?.let {
card.productId = it.id
insertProduct(it)
}
snkrsDB.cardDAO()
.insert(card)
}
private fun List<Thread>.withCardProducts(snkrsDB: SnkrsDB): List<Thread> {
val cards = this.mapNotNull { it.cards }
.flatten()
val ids = cards.mapNotNull { it.productId }
val idGroups = ids.chunked(900)
val products = idGroups.map {
snkrsDB.productDAO()
.getProductsById(it)
}
.flatten()
cards.forEach {
if (it.productId != null) {
val productFull =
products.firstOrNull { productFull -> it.productId == productFull.product?.id }
if (productFull != null) {
it.product = productFull.product
it.product?.skus = productFull.skus
}
}
}
val list = this
val filteredList = list.take(10)
.filter {
it.product?.skus?.any { sku -> sku.available } ?: false && it.product?.selectionEngine != "DAN" && it.product?.style != "999999" && it.product?.isOnSale() == false
}
return list
}
@Transaction
private fun Thread.withCardProducts(snkrsDB: SnkrsDB): Thread {
val ids = cards?.filter { it.productId != null }
?.map { it.productId!! }
val products = snkrsDB.productDAO()
.getProductsById(ids!!)
cards?.forEach {
if (it.productId != null) {
val productFull =
products.firstOrNull { productFull -> it.productId == productFull.product?.id }
if (productFull != null) {
it.product = productFull.product
it.product?.skus = productFull.skus
}
}
}
return this
}
@Transaction
fun getThreadsFromDB(): Observable<List<Thread>> {
return snkrsDB.threadDAO()
.getData()
.toObservable()
.map {
it.mapToThreads()
.map { threads -> threads.withCardProducts(snkrsDB) }
}
}
@Synchronized
@Transaction
fun getAllPages(): Single<List<Thread>> {
return snkrsDB.threadDAO()
.getData()
.doOnSuccess { it }
.map { it.mapToThreads() }
.map { it.withCardProducts(snkrsDB) }
}
@Transaction
fun getPage(pageNumber: Int): Maybe<List<Thread>> {
return snkrsDB.threadDAO()
.getPage(50 * pageNumber, 50)
.filter { it.isNotEmpty() }
.firstOrError()
.map { it.mapToThreads() }
.map { it.withCardProducts(snkrsDB) }
.toMaybe()
.doAfterSuccess { it }
}
fun getFeed(): Observable<PagedList<Thread>> {
return pages.throttlePages()
}
private fun Observable<PagedList<Thread>>.throttlePages() =
this.filter { it.size > 0 }
.sample(Observable.interval(0, 5, SECONDS), true)
.distinctUntilChanged()
fun getFirstThreadId(time: Long) =
snkrsDB.threadDAO().getFirstThreadId(time).mapToThread().withCardProducts(snkrsDB)
fun getThreadByInterestId(id: String) =
snkrsDB.threadDAO().getThreadByInterestId(id)?.mapToThread()?.withCardProducts(snkrsDB)
fun getThreadsByRelatedIds(ids: List<String>) =
snkrsDB.threadDAO().getThreadsByRelatedIds(ids).mapToThreads().withCardProducts(snkrsDB)
fun getThreadsByInterestIds(ids: List<String>): List<Thread> =
snkrsDB.threadDAO().getThreadsByAllInterestIds(ids).mapToThreads().withCardProducts(snkrsDB)
fun getThreadByProductId(id: String) =
snkrsDB.threadDAO().getThreadByProductId(id).mapToThread().withCardProducts(snkrsDB)
fun getThreadBySlug(slug: String) =
snkrsDB.threadDAO().getThreadBySlug(slug).mapToThread().withCardProducts(snkrsDB)
@Deprecated(message = "Use safeGetThreadByThreadId")
fun getThreadByThreadId(id: String) =
snkrsDB.threadDAO().getThreadByThreadId(id)!!.mapToThread().withCardProducts(snkrsDB)
//TODO MIKE: Migrate all to safe version
fun safeGetThreadByThreadId(id: String): Thread? {
val thread = snkrsDB.threadDAO()
.getThreadByThreadId(id)
return thread?.mapToThread()
?.withCardProducts(snkrsDB)
}
fun getThreadsById(ids: List<String>) =
snkrsDB.threadDAO().getThreadsByIDs(ids).mapToThreads().withCardProducts(snkrsDB)
fun getThreadByStyleColor(styleColor: String): Thread {
val split = styleColor.split('-')
return snkrsDB.threadDAO()
.getThreadByStyleColor(split[0], split[1])
.mapToThread()
.withCardProducts(snkrsDB)
}
suspend fun getThreadByStyleColorSuspended(styleColor: String): Thread =
withContext(Dispatchers.IO) {
val split = styleColor.split('-')
snkrsDB.threadDAO()
.getThreadByStyleColor(split[0], split[1])
.mapToThread()
.withCardProducts(snkrsDB)
}
fun getThreadsThatMatch(searchTerm: String) =
snkrsDB.threadDAO().getThreadsForSearch(searchTerm).mapToThreads().withCardProducts(snkrsDB)
//TODO MIKE: change to exponential dropoff
fun getInStockThreads() =
snkrsDB.threadDAO().getPurchasableInStockThreads()
// .mergeWith {
// snkrsDB.threadDAO()
// .getDrawInStockThreads()
// }
.toObservable()
.sample(Observable.interval(0, 10, SECONDS), true)
.distinct { it.map { it.thread.lastUpdatedTime } }
.map {
it.distinctBy { it.thread.threadId }
.mapToThreads()
.withCardProducts(snkrsDB)
}
fun getUpcomingThreads() =
snkrsDB.threadDAO().getUpcomingThreads()
.toObservable()
.sample(Observable.interval(0, 10, SECONDS), true)
.distinct { it.map { it.thread.lastUpdatedTime } }
.map {
it.distinctBy { threadFull -> threadFull.thread.threadId }
.mapToThreads()
.withCardProducts(snkrsDB)
}
fun threadsByTags(searchTerm: String) = snkrsDB
.threadDAO()
.getThreadsByTag(searchTerm)
.map { it.map { it.mapToThread() } }
fun threadsByTag(searchTerm: String) = snkrsDB
.threadDAO()
.getThreadByTag(searchTerm)
.map { it.mapToThread() }
suspend fun getProductByProductIdSuspended(id: String): Product? = withContext(Dispatchers.IO) {
getProductByProductId(id)
}
fun getProductByProductId(id: String) = snkrsDB.productDAO().getProductById(id)?.mapToProduct()
suspend fun getProductByStyleColorSuspended(styleColor: String): Product? = withContext(Dispatchers.IO){
getProductByStyleColor(styleColor)
}
fun getProductByStyleColor(styleColor: String?): Product? {
if (styleColor == null) return null
val split = styleColor.split('-')
Timber.d("split string: %s", split)
return snkrsDB.productDAO()
.getProductByStyleColor(split[0], split[1])
.mapToProduct()
}
@Transaction
fun updateProductSkus(productSkus: List<Sku>) {
productSkus.forEach { Timber.i("updating sku with productId ${it.productId} ${it.available}") }
insertSku(*productSkus.toTypedArray())
}
}
我试过使用 AsyncTask
,但没有成功,但我想看看是否有使用 RxJava 的解决方案。还想看看我是否可以使用 Coroutines
我也试过传递一个 Continuation
参数,但该方法没有返回一个 ``Product``` 对象,但即使转换它,它也会给我一个不同的错误。
我只是想使用 getProductByStyleColorSuspended(detailOrder.getStyleColor())
或 getProductByStyleColor(detailOrders.getStyleColor())
OrderDetailsFragment.java
成功创建一个 Product
对象
你忘了 subscribeOn 和 observeOn 函数
您应该订阅 IO 线程
在主线程上观察
像那样
mOrderHistoryService.getOrderHistoryDetails(mOrder)
.subscribeOn(Schedulers.io())
.observeOn (AndroidSchedulers.mainThread())
.subscribe(new SimpleSubscriber....
在你的片段中试试这个
Single.fromCallable(new Callable<Product>() {
@Override
public Product call() throws Exception {
return threadStore.getThreadRepository()
.getThreadPersister()
.getProductByStyleColorSuspended(detailOrder.getStyleColor())
}
})
.subscribeOn(Schedulers.io())
.observeOn (AndroidSchedulers.mainThread())
.subscribe(new DisposableSingleObserver<Object>() {
@Override
public void onSuccess(Object o) {
if (product != null) {
final DeferredPaymentOrder deferredPaymentOrder =
mSnkrsDatabaseHelper.getDeferredPaymentOrder(detailOrder.getId());
if (deferredPaymentOrder != null && deferredPaymentOrder.isWaiting()) {
mTopButton.setVisibility(View.VISIBLE);
mTopButton.setText(R.string.cta_go_fund);
mTopButton.setOnClickListener(
v -> ((BaseActivity) getActivity()).fundDeferredPaymentOrder(product,
AnalyticsAction.ORDER_DETAILS_FUND));
} else {
mTopButton.setVisibility(View.GONE);
}
} else {
mTopButton.setVisibility(View.GONE);
}
}
@Override
public void onError(Throwable e) {
}
});
对您访问数据库的任何地方应用相同的方法