【问题标题】:RecyclerView Items doesn't appear until i scroll itRecyclerView Items 直到我滚动它才会出现
【发布时间】:2019-08-27 21:15:53
【问题描述】:

我在Fragment 内部使用Recyclerview,在Google's sample of MVP Android 架构之后,我试图使View 部分在this article 之后尽可能被动,这使得整个Recyclerview Adapter 被动数据模型和演示者处理它。

这是我的片段代码:

class OrderHistoryFragment : Fragment(), OrderHistoryContract.View {


    lateinit var mPresenter: OrderHistoryContract.Presenter
    lateinit var rvOrderHistory: RecyclerView
    lateinit var  orderHistoryAdapter : OrderHistoryAdapter


    override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?,
                              savedInstanceState: Bundle?): View? {
        val root = inflater!!.inflate(R.layout.order_history_fragment, container, false)
        rvOrderHistory = root.findViewById<RecyclerView>(R.id.rvOrderHistory)
        rvOrderHistory.layoutManager = LinearLayoutManager(context, LinearLayout.VERTICAL, false)
         orderHistoryAdapter = OrderHistoryAdapter(mPresenter, object : HistoryItemListener {
            override fun onReorder(orderHistory: OrderHistory) {

            }

            override fun onOpenOrder(orderHistory: OrderHistory) {
                val orderIntent = Intent(activity, OrderDetailActivity::class.java)
                orderIntent.putExtra("orderId", orderHistory.id)
                startActivity(orderIntent)

            }
        })
        rvOrderHistory.adapter = orderHistoryAdapter


        return root
    }



    override fun onResume() {
        super.onResume()
        mPresenter.start()

    }

    override fun setPresenter(presenter: OrderHistoryContract.Presenter) {
        mPresenter = checkNotNull<OrderHistoryContract.Presenter>(presenter)

    }


    override fun showLoadingIndicator(load: Boolean?) {


    }


    override fun updateOrdersAdapter() {

        orderHistoryAdapter.notifyDataSetChanged()


    }

    override fun showSnackBar(Message: String) {
        val parentLayout = activity.findViewById<View>(android.R.id.content)
        val snackBar = Snackbar
                .make(parentLayout, Message, Snackbar.LENGTH_INDEFINITE)
        snackBar.setAction("Dismiss") { snackBar.dismiss() }
        snackBar.setActionTextColor(Color.RED)
        snackBar.show()

    }


    interface HistoryItemListener {

        fun onReorder(orderHistory: OrderHistory)

        fun onOpenOrder(orderHistory: OrderHistory)

    }

    companion object {

        fun newInstance(): OrderHistoryFragment {

            return OrderHistoryFragment()
        }
    }

    fun OrderHistoryFragment() {

    }

}

这是我的 RecyclerView 适配器代码

class OrderHistoryAdapter(internal var orderHistoryPresenter: OrderHistoryContract.Presenter, private val listener: OrderHistoryFragment.HistoryItemListener) : RecyclerView.Adapter<OrderHistoryAdapter.ViewHolder>() {


    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        val view = LayoutInflater.from(parent.context)
                .inflate(R.layout.order_history_item, parent, false)
        return ViewHolder(view)

    }

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        orderHistoryPresenter.onBindOrdersRow(position, holder)
        holder.bReOrder!!.setOnClickListener { v -> listener.onReorder(orderHistoryPresenter.getOrderHistoryItem(position)) }
        holder.cvOrderItem!!.setOnClickListener { v -> listener.onOpenOrder(orderHistoryPresenter.getOrderHistoryItem(position)) }


    }

    override fun getItemId(position: Int): Long {
        return position.toLong()
    }

    override fun getItemCount(): Int {
        return orderHistoryPresenter.getOrdersCount()
    }


    class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView), OrderHistoryContract.orderRowView {
        internal var ivOrderVendor: ImageView? = null
        internal var tvOrderId: TextView? = null
        internal var tvOrderItems: TextView? = null
        internal var tvOrderDate: TextView? = null
        internal var tvOrderPrice: TextView? = null
        internal var bReOrder: Button? = null
        internal var cvOrderItem: CardView? = null

        init {
            ivOrderVendor = itemView.findViewById<ImageView>(R.id.ivOrderVendor)
            tvOrderId = itemView.findViewById<TextView>(R.id.tvOrderId)
            tvOrderItems = itemView.findViewById<TextView>(R.id.tvOrderItems)
            tvOrderDate = itemView.findViewById<TextView>(R.id.tvOrderDate)
            tvOrderPrice = itemView.findViewById<TextView>(R.id.tvOrderPrice)
            bReOrder = itemView.findViewById<Button>(R.id.bReOrder)
            cvOrderItem = itemView.findViewById<CardView>(R.id.cvOrderItem)

        }

        override fun setOrderImage(url: String) {
            Glide.with(itemView.context).load(url).into(ivOrderVendor!!)


        }

        override fun setOrderDate(orderDate: String) {
            tvOrderDate!!.text = orderDate


        }

        override fun setOrderId(orderId: String) {
            tvOrderId!!.text = orderId


        }

        override fun setOrderItems(orderItems: ArrayList<String>) {
            val stringBuilder = StringBuilder()
            for (item in orderItems) {
                stringBuilder.append(item)
            }
            tvOrderItems!!.text = stringBuilder.toString()


        }

        override fun setOrderPrice(orderPrice: String) {
            tvOrderPrice!!.text = R.string.price.toString() + " " + orderPrice + " " + R.string.egp

        }
    }


}

这是处理Adapter数据的演示者代码,它绑定到ViewHolder

class OrderHistoryPresenter internal constructor(mDataRepository: DataRepository, mOrdeHistoryView: OrderHistoryContract.View) : OrderHistoryContract.Presenter {


    private val mDataRepository: DataRepository
    //refrence of the View to trigger the functions after proccessing the task
    private val mOrdeHistoryView: OrderHistoryContract.View
    private var orderHistoryItems = ArrayList<OrderHistory>()


    init {
        this.mDataRepository = checkNotNull(mDataRepository, "tasksRepository cannot be null")
        this.mOrdeHistoryView = checkNotNull<OrderHistoryContract.View>(mOrdeHistoryView, "tasksView cannot be null!")

        mOrdeHistoryView.setPresenter(this)
    }


    override fun start() {
        mOrdeHistoryView.showLoadingIndicator(true)
        mDataRepository.getCurrentUser(object : LocalDataSource.userRequestCallback {
            override fun onUserRequestSuccess(botitUser: BotitUser) {
                val urlParams = HashMap<String, String>()
                urlParams.put(Endpoints.USER_ID_KEY, botitUser.userId!!)
                val url = Endpoints.getUrl(Endpoints.urls.ORDER_HISTORY, urlParams)
                mDataRepository.buildEndPointRequest(url, " ", Endpoints.requestsType.GET, object : EndpointDataSource.RequestCallback {
                    override fun onRequestSuccess(Body: String) {
                        try {
                            mOrdeHistoryView.showLoadingIndicator(false)
                            orderHistoryItems = JSONParser.parseData(JSONParser.parsers.ORDER_HISTORY, JSONObject(Body)) as ArrayList<OrderHistory>
                            mOrdeHistoryView.updateOrdersAdapter()
                        } catch (e: JSONException) {
                            e.printStackTrace()
                        }

                    }

                    override fun onRequestError(Body: String) {
                        mOrdeHistoryView.showLoadingIndicator(false)
                        mOrdeHistoryView.showSnackBar("Cannot load data")

                    }
                })

            }

            override fun onUserRequestError(Body: String) {

            }
        })
    }


    override fun refreshData() {


    }

    override fun getOrdersCount(): Int {

            return orderHistoryItems.size


    }

    override fun onBindOrdersRow(position: Int, orderViewHolder: OrderHistoryContract.orderRowView) {
        if (orderHistoryItems.isNotEmpty()) {
            val orderHistory = orderHistoryItems[position]
//            orderViewHolder.setOrderDate(orderHistory.orderDate!!)
            orderViewHolder.setOrderId(orderHistory.orderId!!)
            orderViewHolder.setOrderImage(orderHistory.orderImage!!)
            orderViewHolder.setOrderItems(orderHistory.orderItems)
            orderViewHolder.setOrderPrice(orderHistory.orderPrice!!)
        }


    }

    override fun getOrderHistoryItem(position: Int): OrderHistory {
        return orderHistoryItems[position]
    }

    override fun actionReOrder(ordreId: String) {


    }


}

这里是Fragment XML

<android.support.v7.widget.RecyclerView android:layout_width="match_parent"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/rvOrderHistory"
    android:layout_height="match_parent"
    xmlns:android="http://schemas.android.com/apk/res/android">

        </android.support.v7.widget.RecyclerView>

这里是 RecyclerView 项目 XML order_history_item.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:id="@+id/cvOrderItem"
    android:layout_margin="4dp"
    android:orientation="vertical">

    <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        android:padding="8dp">


        <ImageView
            android:id="@+id/ivOrderVendor"
            android:layout_width="60dp"
            android:layout_height="60dp"
            android:layout_marginEnd="8dp"
            android:layout_marginLeft="8dp"
            android:layout_marginRight="8dp"
            android:layout_marginStart="8dp"
            android:layout_marginTop="8dp"
            app:layout_constraintHorizontal_bias="0.0"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:srcCompat="@drawable/mac" />

        <TextView
            android:id="@+id/tvOrderId"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginEnd="8dp"
            android:layout_marginLeft="8dp"
            android:layout_marginRight="8dp"
            android:layout_marginStart="8dp"
            android:layout_marginTop="8dp"
            android:text="Order #2123"
            android:textAppearance="@style/TextAppearance.AppCompat.Body2"
            app:layout_constraintHorizontal_bias="0.0"
            app:layout_constraintLeft_toRightOf="@+id/ivOrderVendor"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent" />

        <TextView
            android:id="@+id/tvOrderItems"
            android:layout_width="242dp"
            android:layout_height="35dp"
            android:layout_marginEnd="8dp"
            android:layout_marginStart="8dp"
            android:text="MacDonald’s: Big Mac Beef, Big Tasty Beef. El Ezaby: Signal 2, Pantene Shampoo"
            android:textAppearance="@style/TextAppearance.AppCompat.Small"
            android:layout_marginRight="8dp"
            app:layout_constraintRight_toRightOf="parent"
            android:layout_marginTop="8dp"
            app:layout_constraintTop_toBottomOf="@+id/tvOrderId"
            app:layout_constraintLeft_toRightOf="@+id/ivOrderVendor"
            android:layout_marginLeft="8dp"
            app:layout_constraintHorizontal_bias="0.0" />

        <TextView
            android:id="@+id/tvOrderDate"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginBottom="8dp"
            android:layout_marginEnd="16dp"
            android:layout_marginRight="16dp"
            android:layout_marginTop="8dp"
            android:text="03:22 PM 23/2/2017"
            app:layout_constraintBottom_toTopOf="@+id/tvOrderItems"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintVertical_bias="0.0"
            android:layout_marginLeft="8dp"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintHorizontal_bias="1.0" />

        <TextView
            android:id="@+id/tvOrderPrice"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginEnd="8dp"
            android:layout_marginLeft="8dp"
            android:layout_marginRight="8dp"
            android:layout_marginStart="8dp"
            android:layout_marginTop="16dp"
            android:text="Price: 225.50 LE"
            android:textAppearance="@style/TextAppearance.AppCompat.Body2"
            app:layout_constraintHorizontal_bias="0.0"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/tvOrderItems" />

        <Button
            android:id="@+id/bReOrder"
            android:layout_width="wrap_content"
            android:layout_height="35dp"
            android:layout_margin="4dp"
            android:background="@drawable/chip_accent"
            android:foreground="?attr/selectableItemBackground"
            android:orientation="vertical"
            android:padding="8dp"
            android:text="Order Again"
            android:textAllCaps="false"
            android:textColor="@color/colorAccent"
            android:textSize="15sp"
            app:layout_constraintHorizontal_bias="0.937"
            app:layout_constraintLeft_toRightOf="@+id/tvOrderPrice"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/tvOrderItems"
            tools:layout_editor_absoluteY="74dp" />
    </android.support.constraint.ConstraintLayout>
</android.support.v7.widget.CardView>

问题是当我启动 Activity 显示 Fragment 时,RecyclerView 不显示项目。只有当我滚动空白的RecyclerView 或将应用程序留在前台并再次返回时,它才会出现。

在初始化时Adapter 的数据是空的,但onResume() 我提出了一个更新Presenter 数据的请求,然后我在AdapternotifyDataChange() 但没有任何更新。

当我调试时,我发现 onBindViewHolder() 没有在适配器上的 notifyDataChange() 之后调用,所以我不知道为什么 notifyDataChange() 没有通知 Adapter 数据已更改。

任何人有想法或任何可能解决此问题的解决方案?

【问题讨论】:

  • 您找到解决方案了吗?
  • 是的,UI 代码没有在 UI 线程中运行是一个问题,我通过调用 runOnUiThread 并通知其中的适配器来修复它

标签: android android-recyclerview kotlin mvp android-constraintlayout


【解决方案1】:

你需要使用runOnUiThread。

if(activity != null) {
       activity!!.runOnUiThread {
            root.Recycleview.adapter = Adapter(Array)
            Adapter(Array).notifyDataSetChanged()

       }
 }

【讨论】:

  • 我自己已经发现我不在主线程上,非常感谢这是正确的答案
【解决方案2】:

看看这个answer

虽然听起来很愚蠢,但在为 recyclerView 设置数据后调用这行代码,帮助我解决了这个问题:

recyclerView.smoothScrollToPosition(0)

PS:我使用的可能与此有关的技术有:RJava、Retrofit2、NavigationUI、Fragments、LiveData 和 Databinding。

编辑: 我在另一个问题上关注了@SudoPlz 评论和answer,它也有效,你必须扩展 RecyclerView 并覆盖 requestLayout:

private boolean mRequestedLayout = false;

@SuppressLint("WrongCall")
@Override
public void requestLayout() {
    super.requestLayout();
    // We need to intercept this method because if we don't our children will never update
    // Check https://stackoverflow.com/questions/49371866/recyclerview-wont-update-child-until-i-scroll
    if (!mRequestedLayout) {
        mRequestedLayout = true;
        this.post(() -> {
            mRequestedLayout = false;
            layout(getLeft(), getTop(), getRight(), getBottom());
            onLayout(false, getLeft(), getTop(), getRight(), getBottom());
        });
    }
}

尽管如此,我更愿意在 4、5 年后修复此问题,但是,这是一个很好的解决方法,您不会忘记它们。

【讨论】:

  • 谢谢,但当我尝试从后台线程更新回收站视图时,问题已通过所选答案解决
  • 是的,但是由于保存了这一行,如果其他人面临同样的问题,我会发布 :)
【解决方案3】:

我在您的项目 xml 中注意到您的 constraintLayout 高度是 match_parent 对吗? 我建议您将其用作 wrap_content

【讨论】:

  • 尝试在您的项目根元素中使用固定大小。比如 100dp 或 200dp 看看问题是否仍然存在
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-11-12
  • 1970-01-01
  • 1970-01-01
  • 2020-11-05
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多