RecyclerView 项目在我滚动它之前不会出现

RecyclerView Items doesn't appear until i scroll it

我在 Fragment 后面的 Google's sample of MVP Android architecture and I tried to make the View part passive as possible following this article 中使用 Recyclerview ,这使得数据模型和演示者的整个 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) {


    }


}

这里是FragmentXML

<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>

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

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

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

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

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

您需要使用runOnUiThread。

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

       }
 }

看看这个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 
    if (!mRequestedLayout) {
        mRequestedLayout = true;
        this.post(() -> {
            mRequestedLayout = false;
            layout(getLeft(), getTop(), getRight(), getBottom());
            onLayout(false, getLeft(), getTop(), getRight(), getBottom());
        });
    }
}

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