在我滚动之前,RecyclerView Items不会出现

时间:2017-10-09 12:41:52

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

我在Recyclerview关注Google's sample of MVP Android架构中使用了Fragment,我尝试在this article之后尽可能使View部分被动,使数据模型的整个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 Item 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的{​​{1}}时,Fragment不显示该项。只有当我滚动空RecyclerView或将应用程序保留在前台并再次返回时才会出现。

在初始化时,RecyclerView的数据为空但Adapter我发出了一个请求,该请求更新了Presenter上的数据,然后onResume()上的notifyDataChange()Adapter没有更新。

当我调试时,我发现在适配器onBindViewHolder()之后没有调用notifyDataChange(),所以我不知道为什么notifyDataChange()没有通知Adapter数据发生了变化。

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

3 个答案:

答案 0 :(得分:1)

您需要使用runOnUiThread。

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

       }
 }

答案 1 :(得分:1)

看看这个answer

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

if t <= 0:
    print ('Start_time: ', t)
elif t1 <= 0: 
    print('Start_time: ', t1)
elif t2 <= 0:
    print('Start_time: ', t2)
else: 
    print('Start_time: ',t3) 

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

编辑: 我在另一个问题上关注@SudoPlz注释和answer,它也起作用,您必须扩展RecyclerView并覆盖requestLayout:

recyclerView.smoothScrollToPosition(0)

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

答案 2 :(得分:0)

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