From a8894cc46458aa65ffe6134f3c247502efcac584 Mon Sep 17 00:00:00 2001 From: kehaoyuan Date: Mon, 2 Mar 2020 17:04:30 +0800 Subject: [PATCH 1/8] init sync page data --- .../com/gh/common/annotation/SyncPage.java | 12 ++++ .../com/gh/common/syncpage/IAdapterHandler.kt | 11 ++++ .../com/gh/common/syncpage/SyncDataEntity.kt | 9 +++ .../com/gh/common/syncpage/SyncPageAdapter.kt | 8 +++ .../gh/common/syncpage/SyncPageRepository.kt | 31 +++++++++++ .../common/syncpage/example/ExampleAdapter.kt | 55 +++++++++++++++++++ .../syncpage/example/ExampleFragment.kt | 10 ++++ 7 files changed, 136 insertions(+) create mode 100644 app/src/main/java/com/gh/common/annotation/SyncPage.java create mode 100644 app/src/main/java/com/gh/common/syncpage/IAdapterHandler.kt create mode 100644 app/src/main/java/com/gh/common/syncpage/SyncDataEntity.kt create mode 100644 app/src/main/java/com/gh/common/syncpage/SyncPageAdapter.kt create mode 100644 app/src/main/java/com/gh/common/syncpage/SyncPageRepository.kt create mode 100644 app/src/main/java/com/gh/common/syncpage/example/ExampleAdapter.kt create mode 100644 app/src/main/java/com/gh/common/syncpage/example/ExampleFragment.kt diff --git a/app/src/main/java/com/gh/common/annotation/SyncPage.java b/app/src/main/java/com/gh/common/annotation/SyncPage.java new file mode 100644 index 0000000000..775f05c64a --- /dev/null +++ b/app/src/main/java/com/gh/common/annotation/SyncPage.java @@ -0,0 +1,12 @@ +package com.gh.common.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target(ElementType.FIELD) +@Retention(RetentionPolicy.RUNTIME) +public @interface SyncPage { + String syncName(); +} diff --git a/app/src/main/java/com/gh/common/syncpage/IAdapterHandler.kt b/app/src/main/java/com/gh/common/syncpage/IAdapterHandler.kt new file mode 100644 index 0000000000..ea62fb5d66 --- /dev/null +++ b/app/src/main/java/com/gh/common/syncpage/IAdapterHandler.kt @@ -0,0 +1,11 @@ +package com.gh.common.syncpage + +interface IAdapterHandler { + + /** + * Pair first: current position + * Pair second: current data entity + */ + fun findDataBySyncId(syncId: String): Pair? + +} \ No newline at end of file diff --git a/app/src/main/java/com/gh/common/syncpage/SyncDataEntity.kt b/app/src/main/java/com/gh/common/syncpage/SyncDataEntity.kt new file mode 100644 index 0000000000..0801dfa51d --- /dev/null +++ b/app/src/main/java/com/gh/common/syncpage/SyncDataEntity.kt @@ -0,0 +1,9 @@ +package com.gh.common.syncpage + +import androidx.annotation.Keep + +@Keep +data class SyncDataEntity(val syncId: String, + val syncFieldName: String?, + val syncFieldValue: Any, + val remove: Boolean = true) \ No newline at end of file diff --git a/app/src/main/java/com/gh/common/syncpage/SyncPageAdapter.kt b/app/src/main/java/com/gh/common/syncpage/SyncPageAdapter.kt new file mode 100644 index 0000000000..2dc61d7709 --- /dev/null +++ b/app/src/main/java/com/gh/common/syncpage/SyncPageAdapter.kt @@ -0,0 +1,8 @@ +package com.gh.common.syncpage + +import android.content.Context +import com.gh.gamecenter.baselist.ListAdapter + +abstract class SyncPageAdapter(context: Context) : ListAdapter(context), IAdapterHandler { + +} \ No newline at end of file diff --git a/app/src/main/java/com/gh/common/syncpage/SyncPageRepository.kt b/app/src/main/java/com/gh/common/syncpage/SyncPageRepository.kt new file mode 100644 index 0000000000..7b7aded11c --- /dev/null +++ b/app/src/main/java/com/gh/common/syncpage/SyncPageRepository.kt @@ -0,0 +1,31 @@ +package com.gh.common.syncpage + +import androidx.lifecycle.MutableLiveData +import com.gh.common.annotation.SyncPage + +object SyncPageRepository { + val syncPageLiveData = MutableLiveData>() + + + fun clearSyncData() { + + } + + fun postSycnData(entity: SyncDataEntity) { + + } + + fun handleSyncData(rawData: T, syncData: SyncDataEntity): Boolean { + val fields = rawData::class.java.declaredFields + var isNeedNotify = false + for (field in fields) { + if (field.getAnnotation(SyncPage::class.java).syncName == syncData.syncFieldName) { + if (field.get(syncData) != syncData.syncFieldValue) { + field.set(rawData, syncData.syncFieldValue) + if (!isNeedNotify) isNeedNotify = true + } + } + } + return isNeedNotify + } +} \ No newline at end of file diff --git a/app/src/main/java/com/gh/common/syncpage/example/ExampleAdapter.kt b/app/src/main/java/com/gh/common/syncpage/example/ExampleAdapter.kt new file mode 100644 index 0000000000..207f06b86d --- /dev/null +++ b/app/src/main/java/com/gh/common/syncpage/example/ExampleAdapter.kt @@ -0,0 +1,55 @@ +package com.gh.common.syncpage.example + +import android.content.Context +import android.view.View +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView +import com.gh.common.constant.ItemViewType +import com.gh.common.syncpage.SyncPageAdapter +import com.gh.gamecenter.R +import com.gh.gamecenter.adapter.viewholder.FooterViewHolder +import com.gh.gamecenter.baselist.ListAdapter +import com.gh.gamecenter.qa.entity.AnswerEntity +import com.gh.gamecenter.qa.questions.detail.AnswerViewHolder + +class ExampleAdapter(context: Context) : SyncPageAdapter(context) { + + override fun getItemViewType(position: Int): Int { + return if (position == itemCount - 1) ItemViewType.ITEM_FOOTER else ItemViewType.ITEM_BODY + } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { + val view: View + return when (viewType) { + ItemViewType.ITEM_FOOTER -> { + view = mLayoutInflater.inflate(R.layout.refresh_footerview, parent, false) + FooterViewHolder(view) + } + ItemViewType.ITEM_BODY -> { + view = mLayoutInflater.inflate(R.layout.ask_answer_item, parent, false) + AnswerViewHolder(view) + } + else -> throw NullPointerException() + } + } + + override fun getItemCount(): Int { + return if (mEntityList == null || mEntityList.isEmpty()) 0 else mEntityList.size + ListAdapter.FOOTER_ITEM_COUNT + } + + override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) { + + } + + + override fun findDataBySyncId(syncId: String): Pair? { + for (i in 0 until mEntityList.size) { + val entity = mEntityList[i] + if (entity.id == syncId) { + return Pair(i, entity) + } + } + return null + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/gh/common/syncpage/example/ExampleFragment.kt b/app/src/main/java/com/gh/common/syncpage/example/ExampleFragment.kt new file mode 100644 index 0000000000..d194e69761 --- /dev/null +++ b/app/src/main/java/com/gh/common/syncpage/example/ExampleFragment.kt @@ -0,0 +1,10 @@ +package com.gh.common.syncpage.example + +import com.gh.base.fragment.BaseFragment + +class ExampleFragment : BaseFragment() { + override fun getLayoutId(): Int { + TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + } + +} \ No newline at end of file From bebda2de70c81bcdc91719cb0ee1d692e3569c87 Mon Sep 17 00:00:00 2001 From: kehaoyuan Date: Thu, 5 Mar 2020 15:59:56 +0800 Subject: [PATCH 2/8] update --- .../com/gh/common/syncpage/IAdapterHandler.kt | 4 +- .../com/gh/common/syncpage/SyncPageAdapter.kt | 2 +- .../gh/common/syncpage/SyncPageRepository.kt | 9 ++- .../common/syncpage/example/ExampleAdapter.kt | 47 ++++++++++++++- .../syncpage/example/ExampleFragment.kt | 57 +++++++++++++++++-- 5 files changed, 107 insertions(+), 12 deletions(-) diff --git a/app/src/main/java/com/gh/common/syncpage/IAdapterHandler.kt b/app/src/main/java/com/gh/common/syncpage/IAdapterHandler.kt index ea62fb5d66..b576aa0fdf 100644 --- a/app/src/main/java/com/gh/common/syncpage/IAdapterHandler.kt +++ b/app/src/main/java/com/gh/common/syncpage/IAdapterHandler.kt @@ -1,11 +1,11 @@ package com.gh.common.syncpage -interface IAdapterHandler { +interface IAdapterHandler { /** * Pair first: current position * Pair second: current data entity */ - fun findDataBySyncId(syncId: String): Pair? + fun findDataBySyncId(syncId: String): Pair? } \ No newline at end of file diff --git a/app/src/main/java/com/gh/common/syncpage/SyncPageAdapter.kt b/app/src/main/java/com/gh/common/syncpage/SyncPageAdapter.kt index 2dc61d7709..540a67c518 100644 --- a/app/src/main/java/com/gh/common/syncpage/SyncPageAdapter.kt +++ b/app/src/main/java/com/gh/common/syncpage/SyncPageAdapter.kt @@ -3,6 +3,6 @@ package com.gh.common.syncpage import android.content.Context import com.gh.gamecenter.baselist.ListAdapter -abstract class SyncPageAdapter(context: Context) : ListAdapter(context), IAdapterHandler { +abstract class SyncPageAdapter(context: Context) : ListAdapter(context), IAdapterHandler { } \ No newline at end of file diff --git a/app/src/main/java/com/gh/common/syncpage/SyncPageRepository.kt b/app/src/main/java/com/gh/common/syncpage/SyncPageRepository.kt index 7b7aded11c..eb32d83b1e 100644 --- a/app/src/main/java/com/gh/common/syncpage/SyncPageRepository.kt +++ b/app/src/main/java/com/gh/common/syncpage/SyncPageRepository.kt @@ -4,18 +4,21 @@ import androidx.lifecycle.MutableLiveData import com.gh.common.annotation.SyncPage object SyncPageRepository { - val syncPageLiveData = MutableLiveData>() + // 如何移除内部数据??? + val syncPageLiveData = MutableLiveData>() + val syncData = ArrayList() fun clearSyncData() { } fun postSycnData(entity: SyncDataEntity) { - + syncData.add(entity) + syncPageLiveData.postValue(syncData) } - fun handleSyncData(rawData: T, syncData: SyncDataEntity): Boolean { + fun handleSyncData(rawData: Any, syncData: SyncDataEntity): Boolean { val fields = rawData::class.java.declaredFields var isNeedNotify = false for (field in fields) { diff --git a/app/src/main/java/com/gh/common/syncpage/example/ExampleAdapter.kt b/app/src/main/java/com/gh/common/syncpage/example/ExampleAdapter.kt index 207f06b86d..de55721784 100644 --- a/app/src/main/java/com/gh/common/syncpage/example/ExampleAdapter.kt +++ b/app/src/main/java/com/gh/common/syncpage/example/ExampleAdapter.kt @@ -8,9 +8,14 @@ import com.gh.common.constant.ItemViewType import com.gh.common.syncpage.SyncPageAdapter import com.gh.gamecenter.R import com.gh.gamecenter.adapter.viewholder.FooterViewHolder -import com.gh.gamecenter.baselist.ListAdapter +import com.gh.gamecenter.manager.UserManager +import com.gh.gamecenter.qa.answer.CommunityAnswerItemViewHolder +import com.gh.gamecenter.qa.answer.detail.AnswerDetailActivity +import com.gh.gamecenter.qa.article.detail.ArticleDetailActivity import com.gh.gamecenter.qa.entity.AnswerEntity +import com.gh.gamecenter.qa.entity.Questions import com.gh.gamecenter.qa.questions.detail.AnswerViewHolder +import com.gh.gamecenter.qa.questions.detail.QuestionsDetailActivity class ExampleAdapter(context: Context) : SyncPageAdapter(context) { @@ -34,11 +39,45 @@ class ExampleAdapter(context: Context) : SyncPageAdapter(context) } override fun getItemCount(): Int { - return if (mEntityList == null || mEntityList.isEmpty()) 0 else mEntityList.size + ListAdapter.FOOTER_ITEM_COUNT + return if (mEntityList == null || mEntityList.isEmpty()) 0 else mEntityList.size + FOOTER_ITEM_COUNT } override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) { + when (getItemViewType(position)) { + ItemViewType.ITEM_BODY -> { + val answer = mEntityList[position] + if ("community_article" == answer.type) { + val questions = Questions() + questions.title = answer.articleTitle + answer.questions = questions + } + val answerViewHolder = holder as CommunityAnswerItemViewHolder + val binding = answerViewHolder.binding + answerViewHolder.bindAnswerItem(answer, "", getPath()) + binding.title.setOnClickListener { + if ("community_article" == answer.type) { + mContext.startActivity(ArticleDetailActivity.getIntent(mContext, UserManager.getInstance().community, answer.id!!, "", getPath())) + } else { + val questions = answer.questions + mContext.startActivity(QuestionsDetailActivity.getIntent(mContext, questions.id, "", getPath())) + } + } + + answerViewHolder.itemView.setOnClickListener { + if ("community_article" == answer.type) { + mContext.startActivity(ArticleDetailActivity.getIntent(mContext, UserManager.getInstance().community, answer.id!!, "", getPath())) + } else { + mContext.startActivity(AnswerDetailActivity.getIntent(mContext, answer.id, "", getPath())) + } + } + } + ItemViewType.ITEM_FOOTER -> { + val footerViewHolder = holder as FooterViewHolder + footerViewHolder.initItemPadding() + footerViewHolder.initFooterViewHolder(mIsLoading, mIsNetworkError, mIsOver, R.string.ask_loadover_hint) + } + } } @@ -52,4 +91,8 @@ class ExampleAdapter(context: Context) : SyncPageAdapter(context) return null } + fun getPath(): String { + return "问答-推荐-按时间" + } + } \ No newline at end of file diff --git a/app/src/main/java/com/gh/common/syncpage/example/ExampleFragment.kt b/app/src/main/java/com/gh/common/syncpage/example/ExampleFragment.kt index d194e69761..575e5f8c5e 100644 --- a/app/src/main/java/com/gh/common/syncpage/example/ExampleFragment.kt +++ b/app/src/main/java/com/gh/common/syncpage/example/ExampleFragment.kt @@ -1,10 +1,59 @@ package com.gh.common.syncpage.example -import com.gh.base.fragment.BaseFragment +import android.os.Bundle +import android.view.View +import androidx.lifecycle.Observer +import androidx.lifecycle.ViewModelProviders +import androidx.recyclerview.widget.RecyclerView +import com.gh.common.syncpage.IAdapterHandler +import com.gh.common.syncpage.SyncPageRepository +import com.gh.common.view.VerticalItemDecoration +import com.gh.gamecenter.baselist.ListFragment +import com.gh.gamecenter.baselist.NormalListViewModel +import com.gh.gamecenter.manager.UserManager +import com.gh.gamecenter.qa.entity.AnswerEntity +import com.gh.gamecenter.qa.recommends.newest.RecommendNewestAdapter +import com.gh.gamecenter.retrofit.RetrofitManager +import com.halo.assistant.HaloApp +import io.reactivex.Observable -class ExampleFragment : BaseFragment() { - override fun getLayoutId(): Int { - TODO("not implemented") //To change body of created functions use File | Settings | File Templates. +class ExampleFragment : ListFragment>() { + + private var mAdapter: RecommendNewestAdapter? = null + + override fun provideListAdapter(): RecommendNewestAdapter { + if (mAdapter == null) { + mAdapter = RecommendNewestAdapter(context!!) + } + return mAdapter!! + } + + override fun getItemDecoration(): RecyclerView.ItemDecoration { + return VerticalItemDecoration(context, 8F, false) + } + + override fun provideDataObservable(page: Int): Observable> { + return RetrofitManager.getInstance(context).api.getCommunitiesRecommendNewest(UserManager.getInstance().community.id, page) + } + + override fun provideListViewModel(): NormalListViewModel { + val factory = NormalListViewModel.Factory(HaloApp.getInstance().application, this) + return ViewModelProviders.of(this, factory).get(NormalListViewModel::class.java) as NormalListViewModel + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + SyncPageRepository.syncPageLiveData.observe(this, Observer { + it ?: return@Observer + val adapter = mListRv.adapter + if (adapter !is IAdapterHandler) return@Observer + for (syncDataEntity in it) { + val listData = adapter.findDataBySyncId(syncDataEntity.syncId) + listData ?: continue + val isSuccess = SyncPageRepository.handleSyncData(listData.second, syncDataEntity) + if (isSuccess) adapter.notifyItemChanged(listData.first) + } + }) } } \ No newline at end of file From 7f082b7a36c46990130df5ff8c9418e87abf5a05 Mon Sep 17 00:00:00 2001 From: "kehaoyuan@ghzhushou.com" Date: Tue, 10 Mar 2020 10:27:51 +0800 Subject: [PATCH 3/8] update --- .../com/gh/common/syncpage/IAdapterHandler.kt | 2 ++ .../gh/common/syncpage/SyncPageRepository.kt | 17 +++++++++++------ .../common/syncpage/example/ExampleAdapter.kt | 7 +++++++ 3 files changed, 20 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/com/gh/common/syncpage/IAdapterHandler.kt b/app/src/main/java/com/gh/common/syncpage/IAdapterHandler.kt index b576aa0fdf..1b02d1a419 100644 --- a/app/src/main/java/com/gh/common/syncpage/IAdapterHandler.kt +++ b/app/src/main/java/com/gh/common/syncpage/IAdapterHandler.kt @@ -8,4 +8,6 @@ interface IAdapterHandler { */ fun findDataBySyncId(syncId: String): Pair? + fun getSyncKey(position: Int): String? + } \ No newline at end of file diff --git a/app/src/main/java/com/gh/common/syncpage/SyncPageRepository.kt b/app/src/main/java/com/gh/common/syncpage/SyncPageRepository.kt index eb32d83b1e..6a6a91c6ce 100644 --- a/app/src/main/java/com/gh/common/syncpage/SyncPageRepository.kt +++ b/app/src/main/java/com/gh/common/syncpage/SyncPageRepository.kt @@ -5,17 +5,19 @@ import com.gh.common.annotation.SyncPage object SyncPageRepository { - // 如何移除内部数据??? + // 只有在新增操作时,才需要进行页面刷新 val syncPageLiveData = MutableLiveData>() - val syncData = ArrayList() + + // todo 同步操作 + val syncDataList = ArrayList() fun clearSyncData() { - + syncDataList.clear() } - fun postSycnData(entity: SyncDataEntity) { - syncData.add(entity) - syncPageLiveData.postValue(syncData) + fun postSyncData(entity: SyncDataEntity) { + syncDataList.add(entity) + syncPageLiveData.postValue(syncDataList) } fun handleSyncData(rawData: Any, syncData: SyncDataEntity): Boolean { @@ -29,6 +31,9 @@ object SyncPageRepository { } } } + + syncDataList.remove(syncData) // 注意!ConcurrentModificationException + return isNeedNotify } } \ No newline at end of file diff --git a/app/src/main/java/com/gh/common/syncpage/example/ExampleAdapter.kt b/app/src/main/java/com/gh/common/syncpage/example/ExampleAdapter.kt index de55721784..3f350c852a 100644 --- a/app/src/main/java/com/gh/common/syncpage/example/ExampleAdapter.kt +++ b/app/src/main/java/com/gh/common/syncpage/example/ExampleAdapter.kt @@ -81,6 +81,9 @@ class ExampleAdapter(context: Context) : SyncPageAdapter(context) } + /** + * todo 有没有更简洁的获取操作? + */ override fun findDataBySyncId(syncId: String): Pair? { for (i in 0 until mEntityList.size) { val entity = mEntityList[i] @@ -91,6 +94,10 @@ class ExampleAdapter(context: Context) : SyncPageAdapter(context) return null } + override fun getSyncKey(position: Int): String? { + return mEntityList[position].id + } + fun getPath(): String { return "问答-推荐-按时间" } From aadd2071b99816107d33d19fa84fcfc3fcf5b1a7 Mon Sep 17 00:00:00 2001 From: "kehaoyuan@ghzhushou.com" Date: Tue, 10 Mar 2020 18:16:44 +0800 Subject: [PATCH 4/8] update --- .../com/gh/common/syncpage/SyncDataEntity.kt | 3 +- .../gh/common/syncpage/SyncPageRepository.kt | 32 +++++++++++++++++-- .../common/syncpage/example/ExampleAdapter.kt | 17 ++++++---- .../syncpage/example/ExampleFragment.kt | 7 ++-- .../gh/gamecenter/qa/all/AskAllFragment.kt | 7 ++-- .../qa/answer/detail/AnswerDetailViewModel.kt | 4 +++ .../gh/gamecenter/qa/entity/AnswerEntity.kt | 2 ++ 7 files changed, 56 insertions(+), 16 deletions(-) diff --git a/app/src/main/java/com/gh/common/syncpage/SyncDataEntity.kt b/app/src/main/java/com/gh/common/syncpage/SyncDataEntity.kt index 0801dfa51d..40553afe1a 100644 --- a/app/src/main/java/com/gh/common/syncpage/SyncDataEntity.kt +++ b/app/src/main/java/com/gh/common/syncpage/SyncDataEntity.kt @@ -6,4 +6,5 @@ import androidx.annotation.Keep data class SyncDataEntity(val syncId: String, val syncFieldName: String?, val syncFieldValue: Any, - val remove: Boolean = true) \ No newline at end of file + val remove: Boolean = true, + val checkFieldClass: Boolean = false) \ No newline at end of file diff --git a/app/src/main/java/com/gh/common/syncpage/SyncPageRepository.kt b/app/src/main/java/com/gh/common/syncpage/SyncPageRepository.kt index 6a6a91c6ce..eb46c1f097 100644 --- a/app/src/main/java/com/gh/common/syncpage/SyncPageRepository.kt +++ b/app/src/main/java/com/gh/common/syncpage/SyncPageRepository.kt @@ -2,6 +2,12 @@ package com.gh.common.syncpage import androidx.lifecycle.MutableLiveData import com.gh.common.annotation.SyncPage +import com.lightgame.utils.Utils +import java.lang.reflect.Field +import java.util.* +import java.util.Collections.addAll +import kotlin.collections.ArrayList + object SyncPageRepository { @@ -21,19 +27,39 @@ object SyncPageRepository { } fun handleSyncData(rawData: Any, syncData: SyncDataEntity): Boolean { - val fields = rawData::class.java.declaredFields + + val fields = getAllFieldsList(rawData::class.java) + rawData::class.java.isPrimitive var isNeedNotify = false for (field in fields) { - if (field.getAnnotation(SyncPage::class.java).syncName == syncData.syncFieldName) { - if (field.get(syncData) != syncData.syncFieldValue) { + Utils.log("======handleSyncData>>>" + field.name + "====" + field.type) + if (field.getAnnotation(SyncPage::class.java)?.syncName == syncData.syncFieldName) { + field.isAccessible = true + if (field.get(rawData) != syncData.syncFieldValue) { field.set(rawData, syncData.syncFieldValue) if (!isNeedNotify) isNeedNotify = true } } } + + syncDataList.remove(syncData) // 注意!ConcurrentModificationException return isNeedNotify } + + // todo 是否需要获取父类字段进行同步??? 怎么获取Entity下所有的Field????? + fun getAllFieldsList(cls: Class<*>?): List { + if (cls == null) return arrayListOf() + val allFields = arrayListOf() + var currentClass = cls + while (currentClass != null) { + val declaredFields = currentClass.declaredFields + allFields.addAll(declaredFields) + currentClass = currentClass.superclass + } + return allFields + } + } \ No newline at end of file diff --git a/app/src/main/java/com/gh/common/syncpage/example/ExampleAdapter.kt b/app/src/main/java/com/gh/common/syncpage/example/ExampleAdapter.kt index 3f350c852a..d2ab9f1332 100644 --- a/app/src/main/java/com/gh/common/syncpage/example/ExampleAdapter.kt +++ b/app/src/main/java/com/gh/common/syncpage/example/ExampleAdapter.kt @@ -8,6 +8,7 @@ import com.gh.common.constant.ItemViewType import com.gh.common.syncpage.SyncPageAdapter import com.gh.gamecenter.R import com.gh.gamecenter.adapter.viewholder.FooterViewHolder +import com.gh.gamecenter.databinding.CommunityAnswerItemBinding import com.gh.gamecenter.manager.UserManager import com.gh.gamecenter.qa.answer.CommunityAnswerItemViewHolder import com.gh.gamecenter.qa.answer.detail.AnswerDetailActivity @@ -19,8 +20,13 @@ import com.gh.gamecenter.qa.questions.detail.QuestionsDetailActivity class ExampleAdapter(context: Context) : SyncPageAdapter(context) { + override fun areItemsTheSame(oldItem: AnswerEntity?, newItem: AnswerEntity?): Boolean { + return oldItem?.id == newItem?.id + } + override fun getItemViewType(position: Int): Int { - return if (position == itemCount - 1) ItemViewType.ITEM_FOOTER else ItemViewType.ITEM_BODY + if (position == itemCount - 1) return ItemViewType.ITEM_FOOTER + return ItemViewType.ITEM_BODY } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { @@ -30,16 +36,15 @@ class ExampleAdapter(context: Context) : SyncPageAdapter(context) view = mLayoutInflater.inflate(R.layout.refresh_footerview, parent, false) FooterViewHolder(view) } - ItemViewType.ITEM_BODY -> { - view = mLayoutInflater.inflate(R.layout.ask_answer_item, parent, false) - AnswerViewHolder(view) + else -> { + view = mLayoutInflater.inflate(R.layout.community_answer_item, parent, false) + CommunityAnswerItemViewHolder(CommunityAnswerItemBinding.bind(view)) } - else -> throw NullPointerException() } } override fun getItemCount(): Int { - return if (mEntityList == null || mEntityList.isEmpty()) 0 else mEntityList.size + FOOTER_ITEM_COUNT + return if (mEntityList.isNotEmpty()) mEntityList.size + FOOTER_ITEM_COUNT else 0 } override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) { diff --git a/app/src/main/java/com/gh/common/syncpage/example/ExampleFragment.kt b/app/src/main/java/com/gh/common/syncpage/example/ExampleFragment.kt index 575e5f8c5e..543fa78e09 100644 --- a/app/src/main/java/com/gh/common/syncpage/example/ExampleFragment.kt +++ b/app/src/main/java/com/gh/common/syncpage/example/ExampleFragment.kt @@ -15,15 +15,16 @@ import com.gh.gamecenter.qa.entity.AnswerEntity import com.gh.gamecenter.qa.recommends.newest.RecommendNewestAdapter import com.gh.gamecenter.retrofit.RetrofitManager import com.halo.assistant.HaloApp +import com.lightgame.utils.Utils import io.reactivex.Observable class ExampleFragment : ListFragment>() { - private var mAdapter: RecommendNewestAdapter? = null + private var mAdapter: ExampleAdapter? = null - override fun provideListAdapter(): RecommendNewestAdapter { + override fun provideListAdapter(): ExampleAdapter { if (mAdapter == null) { - mAdapter = RecommendNewestAdapter(context!!) + mAdapter = ExampleAdapter(context!!) } return mAdapter!! } diff --git a/app/src/main/java/com/gh/gamecenter/qa/all/AskAllFragment.kt b/app/src/main/java/com/gh/gamecenter/qa/all/AskAllFragment.kt index 72eb83b75c..4f82332593 100644 --- a/app/src/main/java/com/gh/gamecenter/qa/all/AskAllFragment.kt +++ b/app/src/main/java/com/gh/gamecenter/qa/all/AskAllFragment.kt @@ -8,6 +8,7 @@ import androidx.fragment.app.Fragment import androidx.viewpager.widget.ViewPager import com.gh.base.adapter.FragmentAdapter import com.gh.base.fragment.BaseFragment +import com.gh.common.syncpage.example.ExampleFragment import com.gh.common.util.MtaHelper import com.gh.common.view.DrawableView import com.gh.gamecenter.R @@ -24,7 +25,7 @@ class AskAllFragment : BaseFragment() { private val mArticleButton by bindView(R.id.article_button) private lateinit var mQuestionFragment: AskQuestionsNewBodyFragment - private lateinit var mArticleFragment: SimpleArticleListFragment + private lateinit var mArticleFragment: ExampleFragment override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { super.onActivityResult(requestCode, resultCode, data) @@ -54,7 +55,7 @@ class AskAllFragment : BaseFragment() { val fragments = ArrayList() mQuestionFragment = AskQuestionsNewBodyFragment() - mArticleFragment = SimpleArticleListFragment() + mArticleFragment = ExampleFragment() fragments.add(mQuestionFragment) fragments.add(mArticleFragment) mViewPager.adapter = FragmentAdapter(childFragmentManager, fragments) @@ -77,7 +78,7 @@ class AskAllFragment : BaseFragment() { if (currentItem == 0) { mQuestionFragment.scrollToTop(smooth) } else if (currentItem == 1) { - mArticleFragment.scrollToTop(smooth) +// mArticleFragment.scrollToTop(smooth) } } } \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/qa/answer/detail/AnswerDetailViewModel.kt b/app/src/main/java/com/gh/gamecenter/qa/answer/detail/AnswerDetailViewModel.kt index 6ab183c6b3..4edf49a368 100644 --- a/app/src/main/java/com/gh/gamecenter/qa/answer/detail/AnswerDetailViewModel.kt +++ b/app/src/main/java/com/gh/gamecenter/qa/answer/detail/AnswerDetailViewModel.kt @@ -6,6 +6,8 @@ import androidx.lifecycle.AndroidViewModel import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import com.gh.common.history.HistoryHelper +import com.gh.common.syncpage.SyncDataEntity +import com.gh.common.syncpage.SyncPageRepository import com.gh.common.util.* import com.gh.gamecenter.R import com.gh.gamecenter.entity.SpecialColumn @@ -88,6 +90,8 @@ class AnswerDetailViewModel(application: Application) : AndroidViewModel(applica val apiResponse = ApiResponse() apiResponse.data = response mVoteLiveData.postValue(apiResponse) + + SyncPageRepository.postSyncData(SyncDataEntity(answerId, "vote", answerDetail!!.vote, true)) } override fun onFailure(e: HttpException?) { diff --git a/app/src/main/java/com/gh/gamecenter/qa/entity/AnswerEntity.kt b/app/src/main/java/com/gh/gamecenter/qa/entity/AnswerEntity.kt index 2481ca7d78..455b8dd789 100644 --- a/app/src/main/java/com/gh/gamecenter/qa/entity/AnswerEntity.kt +++ b/app/src/main/java/com/gh/gamecenter/qa/entity/AnswerEntity.kt @@ -7,6 +7,7 @@ import androidx.room.Entity import androidx.room.Ignore import androidx.room.PrimaryKey import androidx.room.TypeConverters +import com.gh.common.annotation.SyncPage import com.gh.gamecenter.entity.MeEntity import com.gh.gamecenter.entity.UserEntity import com.gh.gamecenter.room.converter.AnswerUserConverter @@ -47,6 +48,7 @@ class AnswerEntity() : Parcelable { @TypeConverters(CommunityVideoConverter::class) var videos: List = ArrayList() + @SyncPage(syncName = "vote") var vote: Int = 0 @TypeConverters(AnswerUserConverter::class) From b53f769a0d502b02fdedd85a1a3811b2fc60acd9 Mon Sep 17 00:00:00 2001 From: "kehaoyuan@ghzhushou.com" Date: Wed, 11 Mar 2020 17:22:44 +0800 Subject: [PATCH 5/8] update --- .../com/gh/common/syncpage/SyncDataEntity.kt | 3 +- .../gh/common/syncpage/SyncPageRepository.kt | 48 +++++++++++-------- .../java/com/gh/gamecenter/entity/MeEntity.kt | 2 + .../qa/answer/detail/AnswerDetailViewModel.kt | 3 +- gradle.properties | 4 +- 5 files changed, 37 insertions(+), 23 deletions(-) diff --git a/app/src/main/java/com/gh/common/syncpage/SyncDataEntity.kt b/app/src/main/java/com/gh/common/syncpage/SyncDataEntity.kt index 40553afe1a..ca7f49c469 100644 --- a/app/src/main/java/com/gh/common/syncpage/SyncDataEntity.kt +++ b/app/src/main/java/com/gh/common/syncpage/SyncDataEntity.kt @@ -7,4 +7,5 @@ data class SyncDataEntity(val syncId: String, val syncFieldName: String?, val syncFieldValue: Any, val remove: Boolean = true, - val checkFieldClass: Boolean = false) \ No newline at end of file + val checkInherited: Boolean = false, + val checkFieldEntity: Boolean = false) \ No newline at end of file diff --git a/app/src/main/java/com/gh/common/syncpage/SyncPageRepository.kt b/app/src/main/java/com/gh/common/syncpage/SyncPageRepository.kt index eb46c1f097..ce9a54dff6 100644 --- a/app/src/main/java/com/gh/common/syncpage/SyncPageRepository.kt +++ b/app/src/main/java/com/gh/common/syncpage/SyncPageRepository.kt @@ -2,10 +2,8 @@ package com.gh.common.syncpage import androidx.lifecycle.MutableLiveData import com.gh.common.annotation.SyncPage -import com.lightgame.utils.Utils +import com.halo.assistant.HaloApp import java.lang.reflect.Field -import java.util.* -import java.util.Collections.addAll import kotlin.collections.ArrayList @@ -27,30 +25,43 @@ object SyncPageRepository { } fun handleSyncData(rawData: Any, syncData: SyncDataEntity): Boolean { + val fields = if (syncData.checkInherited) { + getAllFieldsList(rawData::class.java) + } else rawData::class.java.declaredFields.toList() - val fields = getAllFieldsList(rawData::class.java) - rawData::class.java.isPrimitive var isNeedNotify = false for (field in fields) { - Utils.log("======handleSyncData>>>" + field.name + "====" + field.type) - if (field.getAnnotation(SyncPage::class.java)?.syncName == syncData.syncFieldName) { - field.isAccessible = true - if (field.get(rawData) != syncData.syncFieldValue) { - field.set(rawData, syncData.syncFieldValue) - if (!isNeedNotify) isNeedNotify = true - } - } + isNeedNotify = replaceSyncData(field, rawData, syncData) + if (isNeedNotify) break } - - - syncDataList.remove(syncData) // 注意!ConcurrentModificationException + if (syncData.remove) syncDataList.remove(syncData) // 注意!ConcurrentModificationException return isNeedNotify } - // todo 是否需要获取父类字段进行同步??? 怎么获取Entity下所有的Field????? - fun getAllFieldsList(cls: Class<*>?): List { + private fun replaceSyncData(field: Field, objects: Any, syncData: SyncDataEntity): Boolean { + if (field.getAnnotation(SyncPage::class.java)?.syncName == syncData.syncFieldName) { + field.isAccessible = true + field.set(objects, syncData.syncFieldValue) + return true + } + + if (syncData.checkFieldEntity) { + val pkgName = field.type.getPackage()?.name ?: return false + if (pkgName.contains(HaloApp.getInstance().application.packageName)) { + field.isAccessible = true + val get = field.get(objects) ?: return false + field.type.declaredFields.forEach { + replaceSyncData(it, get, syncData) + } + } + } + return false + } + + // 包括父类 Field 对象 + private fun getAllFieldsList(cls: Class<*>?): List { if (cls == null) return arrayListOf() val allFields = arrayListOf() var currentClass = cls @@ -61,5 +72,4 @@ object SyncPageRepository { } return allFields } - } \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/entity/MeEntity.kt b/app/src/main/java/com/gh/gamecenter/entity/MeEntity.kt index 2d89277f7c..8a830405c0 100644 --- a/app/src/main/java/com/gh/gamecenter/entity/MeEntity.kt +++ b/app/src/main/java/com/gh/gamecenter/entity/MeEntity.kt @@ -1,6 +1,7 @@ package com.gh.gamecenter.entity import android.os.Parcelable +import com.gh.common.annotation.SyncPage import com.google.gson.annotations.SerializedName import kotlinx.android.parcel.Parcelize @@ -14,6 +15,7 @@ class MeEntity(@SerializedName("is_community_voted") @SerializedName("is_user_invite") var isUserInvite: Boolean = false, + @SyncPage(syncName = "answer_vote") @SerializedName("is_answer_voted") var isAnswerVoted: Boolean = false, diff --git a/app/src/main/java/com/gh/gamecenter/qa/answer/detail/AnswerDetailViewModel.kt b/app/src/main/java/com/gh/gamecenter/qa/answer/detail/AnswerDetailViewModel.kt index 4edf49a368..39311c1554 100644 --- a/app/src/main/java/com/gh/gamecenter/qa/answer/detail/AnswerDetailViewModel.kt +++ b/app/src/main/java/com/gh/gamecenter/qa/answer/detail/AnswerDetailViewModel.kt @@ -91,7 +91,8 @@ class AnswerDetailViewModel(application: Application) : AndroidViewModel(applica apiResponse.data = response mVoteLiveData.postValue(apiResponse) - SyncPageRepository.postSyncData(SyncDataEntity(answerId, "vote", answerDetail!!.vote, true)) + SyncPageRepository.postSyncData(SyncDataEntity(answerId, "vote", answerDetail!!.vote, remove = false)) + SyncPageRepository.postSyncData(SyncDataEntity(answerId, "answer_vote", true, checkFieldEntity = true, remove = false)) } override fun onFailure(e: HttpException?) { diff --git a/gradle.properties b/gradle.properties index f8b765aedc..cc26be162d 100644 --- a/gradle.properties +++ b/gradle.properties @@ -44,8 +44,8 @@ MEIZUPUSH_APPKEY=86792462189846c0b8b701e7bb4d11c1 BUGLY_APPID=d5de44c594 # hosts -DEV_API_HOST=https\://dev.api.ghzs666.com/v4d0d0/ -DEV_COMMENT_HOST=https\://dev.api.ghzs666.com/v4d0d0/ +DEV_API_HOST=https\://dev.api.ghzs666.com/v3d7d4/ +DEV_COMMENT_HOST=https\://dev.api.ghzs666.com/v3d7d4/ DEV_DATA_HOST=https\://data.ghzs.com/ API_HOST=https\://api.ghzs.com/v4d0d0/ From 81dc17530f6b3cd90abf59a077ccca29b58fb99f Mon Sep 17 00:00:00 2001 From: "kehaoyuan@ghzhushou.com" Date: Wed, 11 Mar 2020 17:56:10 +0800 Subject: [PATCH 6/8] update --- .../java/com/gh/common/syncpage/SyncPageRepository.kt | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/com/gh/common/syncpage/SyncPageRepository.kt b/app/src/main/java/com/gh/common/syncpage/SyncPageRepository.kt index ce9a54dff6..f2b7859c4e 100644 --- a/app/src/main/java/com/gh/common/syncpage/SyncPageRepository.kt +++ b/app/src/main/java/com/gh/common/syncpage/SyncPageRepository.kt @@ -40,20 +40,21 @@ object SyncPageRepository { return isNeedNotify } - private fun replaceSyncData(field: Field, objects: Any, syncData: SyncDataEntity): Boolean { + private fun replaceSyncData(field: Field, extractObject: Any, syncData: SyncDataEntity): Boolean { if (field.getAnnotation(SyncPage::class.java)?.syncName == syncData.syncFieldName) { field.isAccessible = true - field.set(objects, syncData.syncFieldValue) + field.set(extractObject, syncData.syncFieldValue) return true } if (syncData.checkFieldEntity) { + // 递归查询 val pkgName = field.type.getPackage()?.name ?: return false if (pkgName.contains(HaloApp.getInstance().application.packageName)) { field.isAccessible = true - val get = field.get(objects) ?: return false + val extractEntityObject = field.get(extractObject) ?: return false field.type.declaredFields.forEach { - replaceSyncData(it, get, syncData) + if (replaceSyncData(it, extractEntityObject, syncData)) return true } } } From c87bf1e613a398ed98b96792ed0208e0bb4742f4 Mon Sep 17 00:00:00 2001 From: "kehaoyuan@ghzhushou.com" Date: Thu, 12 Mar 2020 14:19:45 +0800 Subject: [PATCH 7/8] update --- .../com/gh/base/fragment/BaseFragment.java | 31 ++++++++++++++++++ .../com/gh/common/syncpage/IAdapterHandler.kt | 13 -------- .../gh/common/syncpage/ISyncAdapterHandler.kt | 12 +++++++ .../com/gh/common/syncpage/SyncDataEntity.kt | 2 +- .../com/gh/common/syncpage/SyncPageAdapter.kt | 8 ----- .../gh/common/syncpage/SyncPageRepository.kt | 17 ++++++++-- .../common/syncpage/example/ExampleAdapter.kt | 26 ++++----------- .../syncpage/example/ExampleFragment.kt | 32 +++++++++++-------- .../qa/answer/detail/AnswerDetailViewModel.kt | 7 ++-- 9 files changed, 88 insertions(+), 60 deletions(-) delete mode 100644 app/src/main/java/com/gh/common/syncpage/IAdapterHandler.kt create mode 100644 app/src/main/java/com/gh/common/syncpage/ISyncAdapterHandler.kt delete mode 100644 app/src/main/java/com/gh/common/syncpage/SyncPageAdapter.kt diff --git a/app/src/main/java/com/gh/base/fragment/BaseFragment.java b/app/src/main/java/com/gh/base/fragment/BaseFragment.java index 4e726c12a7..935c1e6add 100644 --- a/app/src/main/java/com/gh/base/fragment/BaseFragment.java +++ b/app/src/main/java/com/gh/base/fragment/BaseFragment.java @@ -12,6 +12,9 @@ import android.view.ViewGroup; import com.gh.base.OnListClickListener; import com.gh.base.OnRequestCallBackListener; import com.gh.common.constant.Constants; +import com.gh.common.syncpage.ISyncAdapterHandler; +import com.gh.common.syncpage.SyncDataEntity; +import com.gh.common.syncpage.SyncPageRepository; import com.gh.gamecenter.BuildConfig; import com.gh.gamecenter.eventbus.EBMiPush; import com.lightgame.OnTitleClickListener; @@ -31,10 +34,12 @@ import androidx.annotation.Nullable; import androidx.annotation.StringRes; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentTransaction; +import androidx.recyclerview.widget.RecyclerView; import butterknife.ButterKnife; import io.reactivex.Observable; import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.schedulers.Schedulers; +import kotlin.Pair; import static com.gh.common.util.EntranceUtils.KEY_ENTRANCE; @@ -141,6 +146,29 @@ public abstract class BaseFragment extends Fragment implements OnRequestCallB ButterKnife.bind(this, mCachedView); initView(mCachedView); + + RecyclerView syncRecyclerView = provideSyncPageRecyclerView(); + if (syncRecyclerView != null) { + initSyncPageObserver(syncRecyclerView); + } + } + + private void initSyncPageObserver(RecyclerView syncRecyclerView) { + SyncPageRepository.INSTANCE.getSyncPageLiveData().observe(this, syncDataEntities -> { + if (syncDataEntities == null || syncDataEntities.isEmpty()) return; + RecyclerView.Adapter adapter = syncRecyclerView.getAdapter(); + if (!(adapter instanceof ISyncAdapterHandler)) return; + for (int i = 0; i < adapter.getItemCount(); i++) { + Pair syncKey = ((ISyncAdapterHandler) adapter).getSyncData(i); + if (syncKey == null) return; + for (SyncDataEntity syncDataEntity : syncDataEntities) { + if (syncDataEntity.getSyncId().equals(syncKey.getFirst())) { + boolean isSuccess = SyncPageRepository.INSTANCE.handleSyncData(syncKey.getSecond(), syncDataEntity); + if (isSuccess) adapter.notifyItemChanged(i); + } + } + } + }); } // 必须的有subscribe才能register @@ -255,4 +283,7 @@ public abstract class BaseFragment extends Fragment implements OnRequestCallB return this; } + protected RecyclerView provideSyncPageRecyclerView() { + return null; + } } diff --git a/app/src/main/java/com/gh/common/syncpage/IAdapterHandler.kt b/app/src/main/java/com/gh/common/syncpage/IAdapterHandler.kt deleted file mode 100644 index 1b02d1a419..0000000000 --- a/app/src/main/java/com/gh/common/syncpage/IAdapterHandler.kt +++ /dev/null @@ -1,13 +0,0 @@ -package com.gh.common.syncpage - -interface IAdapterHandler { - - /** - * Pair first: current position - * Pair second: current data entity - */ - fun findDataBySyncId(syncId: String): Pair? - - fun getSyncKey(position: Int): String? - -} \ No newline at end of file diff --git a/app/src/main/java/com/gh/common/syncpage/ISyncAdapterHandler.kt b/app/src/main/java/com/gh/common/syncpage/ISyncAdapterHandler.kt new file mode 100644 index 0000000000..4fafd0ad62 --- /dev/null +++ b/app/src/main/java/com/gh/common/syncpage/ISyncAdapterHandler.kt @@ -0,0 +1,12 @@ +package com.gh.common.syncpage + +interface ISyncAdapterHandler { + + /** + * @param position position to query + * @return Pair first: item sync id + * Pair second: item data entity + */ + fun getSyncData(position: Int): Pair? + +} \ No newline at end of file diff --git a/app/src/main/java/com/gh/common/syncpage/SyncDataEntity.kt b/app/src/main/java/com/gh/common/syncpage/SyncDataEntity.kt index ca7f49c469..ba97123714 100644 --- a/app/src/main/java/com/gh/common/syncpage/SyncDataEntity.kt +++ b/app/src/main/java/com/gh/common/syncpage/SyncDataEntity.kt @@ -5,7 +5,7 @@ import androidx.annotation.Keep @Keep data class SyncDataEntity(val syncId: String, val syncFieldName: String?, - val syncFieldValue: Any, + val syncFieldValue: Any?, val remove: Boolean = true, val checkInherited: Boolean = false, val checkFieldEntity: Boolean = false) \ No newline at end of file diff --git a/app/src/main/java/com/gh/common/syncpage/SyncPageAdapter.kt b/app/src/main/java/com/gh/common/syncpage/SyncPageAdapter.kt deleted file mode 100644 index 540a67c518..0000000000 --- a/app/src/main/java/com/gh/common/syncpage/SyncPageAdapter.kt +++ /dev/null @@ -1,8 +0,0 @@ -package com.gh.common.syncpage - -import android.content.Context -import com.gh.gamecenter.baselist.ListAdapter - -abstract class SyncPageAdapter(context: Context) : ListAdapter(context), IAdapterHandler { - -} \ No newline at end of file diff --git a/app/src/main/java/com/gh/common/syncpage/SyncPageRepository.kt b/app/src/main/java/com/gh/common/syncpage/SyncPageRepository.kt index f2b7859c4e..5a42265689 100644 --- a/app/src/main/java/com/gh/common/syncpage/SyncPageRepository.kt +++ b/app/src/main/java/com/gh/common/syncpage/SyncPageRepository.kt @@ -4,6 +4,7 @@ import androidx.lifecycle.MutableLiveData import com.gh.common.annotation.SyncPage import com.halo.assistant.HaloApp import java.lang.reflect.Field +import java.util.concurrent.CopyOnWriteArrayList import kotlin.collections.ArrayList @@ -12,14 +13,23 @@ object SyncPageRepository { // 只有在新增操作时,才需要进行页面刷新 val syncPageLiveData = MutableLiveData>() - // todo 同步操作 - val syncDataList = ArrayList() + val syncDataList = CopyOnWriteArrayList() + // todo 对于不是即使删除的数据源(remove = false),该何时删除?? fun clearSyncData() { syncDataList.clear() } fun postSyncData(entity: SyncDataEntity) { + // 检查是否存在重复操作 + for (syncDataEntity in syncDataList) { + if (syncDataEntity.syncId == entity.syncId && syncDataEntity.syncFieldName == entity.syncFieldName) { + syncDataList.remove(syncDataEntity) + syncDataList.add(entity) + return + } + } + syncDataList.add(entity) syncPageLiveData.postValue(syncDataList) } @@ -35,11 +45,12 @@ object SyncPageRepository { if (isNeedNotify) break } - if (syncData.remove) syncDataList.remove(syncData) // 注意!ConcurrentModificationException + if (syncData.remove) syncDataList.remove(syncData) return isNeedNotify } + // 替换同步数据 private fun replaceSyncData(field: Field, extractObject: Any, syncData: SyncDataEntity): Boolean { if (field.getAnnotation(SyncPage::class.java)?.syncName == syncData.syncFieldName) { field.isAccessible = true diff --git a/app/src/main/java/com/gh/common/syncpage/example/ExampleAdapter.kt b/app/src/main/java/com/gh/common/syncpage/example/ExampleAdapter.kt index d2ab9f1332..21aa34a0ea 100644 --- a/app/src/main/java/com/gh/common/syncpage/example/ExampleAdapter.kt +++ b/app/src/main/java/com/gh/common/syncpage/example/ExampleAdapter.kt @@ -5,9 +5,10 @@ import android.view.View import android.view.ViewGroup import androidx.recyclerview.widget.RecyclerView import com.gh.common.constant.ItemViewType -import com.gh.common.syncpage.SyncPageAdapter +import com.gh.common.syncpage.ISyncAdapterHandler import com.gh.gamecenter.R import com.gh.gamecenter.adapter.viewholder.FooterViewHolder +import com.gh.gamecenter.baselist.ListAdapter import com.gh.gamecenter.databinding.CommunityAnswerItemBinding import com.gh.gamecenter.manager.UserManager import com.gh.gamecenter.qa.answer.CommunityAnswerItemViewHolder @@ -15,10 +16,9 @@ import com.gh.gamecenter.qa.answer.detail.AnswerDetailActivity import com.gh.gamecenter.qa.article.detail.ArticleDetailActivity import com.gh.gamecenter.qa.entity.AnswerEntity import com.gh.gamecenter.qa.entity.Questions -import com.gh.gamecenter.qa.questions.detail.AnswerViewHolder import com.gh.gamecenter.qa.questions.detail.QuestionsDetailActivity -class ExampleAdapter(context: Context) : SyncPageAdapter(context) { +class ExampleAdapter(context: Context) : ListAdapter(context), ISyncAdapterHandler { override fun areItemsTheSame(oldItem: AnswerEntity?, newItem: AnswerEntity?): Boolean { return oldItem?.id == newItem?.id @@ -85,22 +85,10 @@ class ExampleAdapter(context: Context) : SyncPageAdapter(context) } } - - /** - * todo 有没有更简洁的获取操作? - */ - override fun findDataBySyncId(syncId: String): Pair? { - for (i in 0 until mEntityList.size) { - val entity = mEntityList[i] - if (entity.id == syncId) { - return Pair(i, entity) - } - } - return null - } - - override fun getSyncKey(position: Int): String? { - return mEntityList[position].id + override fun getSyncData(position: Int): Pair? { + if (position >= mEntityList.size) return null + val entity = mEntityList[position] + return Pair(entity.id ?: "", entity) } fun getPath(): String { diff --git a/app/src/main/java/com/gh/common/syncpage/example/ExampleFragment.kt b/app/src/main/java/com/gh/common/syncpage/example/ExampleFragment.kt index 543fa78e09..636b000f2d 100644 --- a/app/src/main/java/com/gh/common/syncpage/example/ExampleFragment.kt +++ b/app/src/main/java/com/gh/common/syncpage/example/ExampleFragment.kt @@ -5,17 +5,15 @@ import android.view.View import androidx.lifecycle.Observer import androidx.lifecycle.ViewModelProviders import androidx.recyclerview.widget.RecyclerView -import com.gh.common.syncpage.IAdapterHandler +import com.gh.common.syncpage.ISyncAdapterHandler import com.gh.common.syncpage.SyncPageRepository import com.gh.common.view.VerticalItemDecoration import com.gh.gamecenter.baselist.ListFragment import com.gh.gamecenter.baselist.NormalListViewModel import com.gh.gamecenter.manager.UserManager import com.gh.gamecenter.qa.entity.AnswerEntity -import com.gh.gamecenter.qa.recommends.newest.RecommendNewestAdapter import com.gh.gamecenter.retrofit.RetrofitManager import com.halo.assistant.HaloApp -import com.lightgame.utils.Utils import io.reactivex.Observable class ExampleFragment : ListFragment>() { @@ -44,17 +42,23 @@ class ExampleFragment : ListFragment() apiResponse.data = response mVoteLiveData.postValue(apiResponse) + + SyncPageRepository.postSyncData(SyncDataEntity(answerId, "vote", answerDetail!!.vote)) + SyncPageRepository.postSyncData(SyncDataEntity(answerId, "answer_vote", answerDetail?.me?.isAnswerVoted, checkFieldEntity = true)) } override fun onFailure(e: HttpException?) { From 72871e55c633487f15fdb4f97e2c0497ae728caf Mon Sep 17 00:00:00 2001 From: "kehaoyuan@ghzhushou.com" Date: Tue, 24 Mar 2020 15:28:19 +0800 Subject: [PATCH 8/8] =?UTF-8?q?=E6=95=B0=E6=8D=AE=E5=90=8C=E6=AD=A5?= =?UTF-8?q?=E6=A8=A1=E5=9D=97=E5=9F=BA=E6=9C=AC=E5=AE=8C=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/gh/base/fragment/BaseFragment.java | 43 +++++++++------ .../com/gh/common/annotation/SyncPage.java | 2 +- .../com/gh/common/syncpage/SyncDataEntity.kt | 44 +++++++++++++-- .../gh/common/syncpage/SyncFieldConstants.kt | 17 ++++++ .../gh/common/syncpage/SyncPageRepository.kt | 55 +++++++++++++------ .../syncpage/example/ExampleFragment.kt | 13 +++-- .../java/com/gh/gamecenter/entity/MeEntity.kt | 8 ++- .../fragment/MainWrapperFragment.java | 5 ++ .../qa/answer/detail/AnswerDetailViewModel.kt | 19 +++++-- .../article/detail/ArticleDetailViewModel.kt | 22 ++++++++ .../qa/comment/NewCommentFragment.kt | 13 +++++ .../gh/gamecenter/qa/entity/AnswerEntity.kt | 4 +- 12 files changed, 190 insertions(+), 55 deletions(-) create mode 100644 app/src/main/java/com/gh/common/syncpage/SyncFieldConstants.kt diff --git a/app/src/main/java/com/gh/base/fragment/BaseFragment.java b/app/src/main/java/com/gh/base/fragment/BaseFragment.java index 935c1e6add..839daf9081 100644 --- a/app/src/main/java/com/gh/base/fragment/BaseFragment.java +++ b/app/src/main/java/com/gh/base/fragment/BaseFragment.java @@ -147,26 +147,33 @@ public abstract class BaseFragment extends Fragment implements OnRequestCallB initView(mCachedView); - RecyclerView syncRecyclerView = provideSyncPageRecyclerView(); - if (syncRecyclerView != null) { - initSyncPageObserver(syncRecyclerView); + if (addSyncPageObserver()) { + initSyncPageObserver(); } } - private void initSyncPageObserver(RecyclerView syncRecyclerView) { + private void initSyncPageObserver() { SyncPageRepository.INSTANCE.getSyncPageLiveData().observe(this, syncDataEntities -> { - if (syncDataEntities == null || syncDataEntities.isEmpty()) return; - RecyclerView.Adapter adapter = syncRecyclerView.getAdapter(); - if (!(adapter instanceof ISyncAdapterHandler)) return; - for (int i = 0; i < adapter.getItemCount(); i++) { - Pair syncKey = ((ISyncAdapterHandler) adapter).getSyncData(i); - if (syncKey == null) return; - for (SyncDataEntity syncDataEntity : syncDataEntities) { - if (syncDataEntity.getSyncId().equals(syncKey.getFirst())) { - boolean isSuccess = SyncPageRepository.INSTANCE.handleSyncData(syncKey.getSecond(), syncDataEntity); - if (isSuccess) adapter.notifyItemChanged(i); + try { + if (syncDataEntities == null || syncDataEntities.isEmpty()) return; + RecyclerView.Adapter adapter = provideSyncAdapter(); + if (!(adapter instanceof ISyncAdapterHandler)) return; + for (int i = 0; i < adapter.getItemCount(); i++) { + Pair syncKey = ((ISyncAdapterHandler) adapter).getSyncData(i); + if (syncKey == null) return; + for (SyncDataEntity syncDataEntity : syncDataEntities) { + if (syncDataEntity.getSyncId().equals(syncKey.getFirst())) { + boolean isSuccess = SyncPageRepository.INSTANCE.handleSyncData(syncKey.getSecond(), syncDataEntity); + if (isSuccess) adapter.notifyItemChanged(i); + } } } + } catch (Exception e) { + if (BuildConfig.DEBUG) { + throw e; + } else { + e.printStackTrace(); + } } }); } @@ -214,7 +221,7 @@ public abstract class BaseFragment extends Fragment implements OnRequestCallB try { Utils.toast(getContext(), msg); } catch (Exception ignore) { - + } } @@ -283,7 +290,11 @@ public abstract class BaseFragment extends Fragment implements OnRequestCallB return this; } - protected RecyclerView provideSyncPageRecyclerView() { + protected RecyclerView.Adapter provideSyncAdapter() { return null; } + + protected boolean addSyncPageObserver() { + return false; + } } diff --git a/app/src/main/java/com/gh/common/annotation/SyncPage.java b/app/src/main/java/com/gh/common/annotation/SyncPage.java index 775f05c64a..a2a670cb87 100644 --- a/app/src/main/java/com/gh/common/annotation/SyncPage.java +++ b/app/src/main/java/com/gh/common/annotation/SyncPage.java @@ -8,5 +8,5 @@ import java.lang.annotation.Target; @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface SyncPage { - String syncName(); + String[] syncNames(); } diff --git a/app/src/main/java/com/gh/common/syncpage/SyncDataEntity.kt b/app/src/main/java/com/gh/common/syncpage/SyncDataEntity.kt index ba97123714..611445448f 100644 --- a/app/src/main/java/com/gh/common/syncpage/SyncDataEntity.kt +++ b/app/src/main/java/com/gh/common/syncpage/SyncDataEntity.kt @@ -3,9 +3,41 @@ package com.gh.common.syncpage import androidx.annotation.Keep @Keep -data class SyncDataEntity(val syncId: String, - val syncFieldName: String?, - val syncFieldValue: Any?, - val remove: Boolean = true, - val checkInherited: Boolean = false, - val checkFieldEntity: Boolean = false) \ No newline at end of file +data class SyncDataEntity( + /** + * 标识一条数据的唯一ID + * + * 与[ISyncAdapterHandler.getSyncData]返回的Pair first一致 + */ + val syncId: String, + + /** + * 需要同步的字段名 + * + * 与@SyncPage注解的值一致 + */ + val syncFieldName: String?, + + /** + * 需要同步的具体内容 + */ + val syncFieldValue: Any?, + + /** + * 同步完一次是否自动删除 + */ + val remove: Boolean = true, + + /** + * 是否需要查询同步实体的父级字段 + * + * 由于反射可能会导致较大的性能消耗,默认关闭,具体按实际情况开启 + */ + val checkInherited: Boolean = false, + + /** + * 是否需要查询同步实体的嵌套实体内容 + * + * 由于反射可能会导致较大的性能消耗,默认关闭,具体按实际情况开启 + */ + val checkFieldEntity: Boolean = false) \ No newline at end of file diff --git a/app/src/main/java/com/gh/common/syncpage/SyncFieldConstants.kt b/app/src/main/java/com/gh/common/syncpage/SyncFieldConstants.kt new file mode 100644 index 0000000000..dad7d82695 --- /dev/null +++ b/app/src/main/java/com/gh/common/syncpage/SyncFieldConstants.kt @@ -0,0 +1,17 @@ +package com.gh.common.syncpage + +object SyncFieldConstants { + + // 是否点赞 + const val ANSWER_VOTE = "ANSWER_VOTE" + const val ARTICLE_VOTE = "ARTICLE_VOTE" + + // 赞同数量 + const val ANSWER_VOTE_COUNT = "ANSWER_VOTE_COUNT" + const val ARTICLE_VOTE_COUNT = "ARTICLE_VOTE_COUNT" + + // 评论数量 + const val ANSWER_COMMENT_COUNT = "ANSWER_COMMENT_COUNT" + const val ARTICLE_COMMENT_COUNT = "ARTICLE_COMMENT_COUNT" + +} \ No newline at end of file diff --git a/app/src/main/java/com/gh/common/syncpage/SyncPageRepository.kt b/app/src/main/java/com/gh/common/syncpage/SyncPageRepository.kt index 5a42265689..bb52066c4a 100644 --- a/app/src/main/java/com/gh/common/syncpage/SyncPageRepository.kt +++ b/app/src/main/java/com/gh/common/syncpage/SyncPageRepository.kt @@ -2,12 +2,25 @@ package com.gh.common.syncpage import androidx.lifecycle.MutableLiveData import com.gh.common.annotation.SyncPage +import com.gh.common.util.tryCatchInRelease import com.halo.assistant.HaloApp import java.lang.reflect.Field import java.util.concurrent.CopyOnWriteArrayList -import kotlin.collections.ArrayList - +/** + * 页面之间实现数据同步(主要是单个字段的同步) + * + * 实现思路: + * 1.把需要同步的数据以一个特殊ID作为唯一标识,并存于一个全局的仓库 + * 2.利用LiveData进行页面回调,再通过[ISyncAdapterHandler.getSyncData]找到需要被同步的数据 + * 3.最后利用反射进行数据替换,具体请见[SyncPageRepository.replaceSyncData] + * + * 具体的接入方式(以列表为例): + * 1.通过[SyncPageRepository.postSyncData]提交同步数据 + * 2.在Fragment重写[BaseFragment.addSyncPageObserver]开启同步事件监听 + * 3.在Fragment重写[BaseFragment.provideSyncAdapter]提供获取数据的来源 + * - [BaseFragment.provideSyncAdapter]提供的Adapter必须实现[ISyncAdapterHandler]接口 + */ object SyncPageRepository { // 只有在新增操作时,才需要进行页面刷新 @@ -15,23 +28,28 @@ object SyncPageRepository { val syncDataList = CopyOnWriteArrayList() - // todo 对于不是即使删除的数据源(remove = false),该何时删除?? + @JvmStatic fun clearSyncData() { - syncDataList.clear() + tryCatchInRelease { + syncDataList.clear() + } } + // 提交同步数据 fun postSyncData(entity: SyncDataEntity) { - // 检查是否存在重复操作 - for (syncDataEntity in syncDataList) { - if (syncDataEntity.syncId == entity.syncId && syncDataEntity.syncFieldName == entity.syncFieldName) { - syncDataList.remove(syncDataEntity) - syncDataList.add(entity) - return + tryCatchInRelease { + // 检查是否存在重复操作 + for (syncDataEntity in syncDataList) { + if (syncDataEntity.syncId == entity.syncId && syncDataEntity.syncFieldName == entity.syncFieldName) { + syncDataList.remove(syncDataEntity) + syncDataList.add(entity) + return + } } - } - syncDataList.add(entity) - syncPageLiveData.postValue(syncDataList) + syncDataList.add(entity) + syncPageLiveData.postValue(syncDataList) + } } fun handleSyncData(rawData: Any, syncData: SyncDataEntity): Boolean { @@ -50,12 +68,13 @@ object SyncPageRepository { return isNeedNotify } - // 替换同步数据 private fun replaceSyncData(field: Field, extractObject: Any, syncData: SyncDataEntity): Boolean { - if (field.getAnnotation(SyncPage::class.java)?.syncName == syncData.syncFieldName) { - field.isAccessible = true - field.set(extractObject, syncData.syncFieldValue) - return true + field.getAnnotation(SyncPage::class.java)?.syncNames?.forEach { syncName -> + if (syncName == syncData.syncFieldName) { + field.isAccessible = true + field.set(extractObject, syncData.syncFieldValue) + return true + } } if (syncData.checkFieldEntity) { diff --git a/app/src/main/java/com/gh/common/syncpage/example/ExampleFragment.kt b/app/src/main/java/com/gh/common/syncpage/example/ExampleFragment.kt index 636b000f2d..8993998e3e 100644 --- a/app/src/main/java/com/gh/common/syncpage/example/ExampleFragment.kt +++ b/app/src/main/java/com/gh/common/syncpage/example/ExampleFragment.kt @@ -2,11 +2,8 @@ package com.gh.common.syncpage.example import android.os.Bundle import android.view.View -import androidx.lifecycle.Observer import androidx.lifecycle.ViewModelProviders import androidx.recyclerview.widget.RecyclerView -import com.gh.common.syncpage.ISyncAdapterHandler -import com.gh.common.syncpage.SyncPageRepository import com.gh.common.view.VerticalItemDecoration import com.gh.gamecenter.baselist.ListFragment import com.gh.gamecenter.baselist.NormalListViewModel @@ -22,7 +19,7 @@ class ExampleFragment : ListFragment? { + return mListRv.adapter + } + + override fun addSyncPageObserver(): Boolean { + return true } } \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/entity/MeEntity.kt b/app/src/main/java/com/gh/gamecenter/entity/MeEntity.kt index 8a830405c0..4891a4a489 100644 --- a/app/src/main/java/com/gh/gamecenter/entity/MeEntity.kt +++ b/app/src/main/java/com/gh/gamecenter/entity/MeEntity.kt @@ -2,6 +2,7 @@ package com.gh.gamecenter.entity import android.os.Parcelable import com.gh.common.annotation.SyncPage +import com.gh.common.syncpage.SyncFieldConstants import com.google.gson.annotations.SerializedName import kotlinx.android.parcel.Parcelize @@ -15,7 +16,7 @@ class MeEntity(@SerializedName("is_community_voted") @SerializedName("is_user_invite") var isUserInvite: Boolean = false, - @SyncPage(syncName = "answer_vote") + @SyncPage(syncNames = [SyncFieldConstants.ANSWER_VOTE]) @SerializedName("is_answer_voted") var isAnswerVoted: Boolean = false, @@ -52,10 +53,10 @@ class MeEntity(@SerializedName("is_community_voted") @SerializedName("is_toolkit_favorite") var isToolkitFavorite: Boolean = false, - @SerializedName("is_comment_own", alternate = ["is_answer_commented", "is_community_article_commented", "is_video_commented"]) + @SerializedName("is_comment_own", alternate = ["is_answer_commented", "is_community_article_commented", "is_video_commented"]) var isCommentOwner: Boolean = false, // 是否是当前评论的拥有者 - @SerializedName("is_comment_voted", alternate = ["is_answer_comment_voted","is_video_comment_voted", "is_community_article_comment_voted"]) + @SerializedName("is_comment_voted", alternate = ["is_answer_comment_voted", "is_video_comment_voted", "is_community_article_comment_voted"]) var isCommentVoted: Boolean = false, // 是否已经点赞过当前评论 @SerializedName("is_version_requested") @@ -67,6 +68,7 @@ class MeEntity(@SerializedName("is_community_voted") @SerializedName("is_favorite") var isCommunityArticleFavorite: Boolean = false, + @SyncPage(syncNames = [SyncFieldConstants.ARTICLE_VOTE]) @SerializedName("is_vote") var isCommunityArticleVote: Boolean = false, diff --git a/app/src/main/java/com/gh/gamecenter/fragment/MainWrapperFragment.java b/app/src/main/java/com/gh/gamecenter/fragment/MainWrapperFragment.java index e585d02e96..3c5df19ac6 100644 --- a/app/src/main/java/com/gh/gamecenter/fragment/MainWrapperFragment.java +++ b/app/src/main/java/com/gh/gamecenter/fragment/MainWrapperFragment.java @@ -26,6 +26,7 @@ import com.facebook.imagepipeline.image.ImageInfo; import com.gh.base.OnDoubleTapListener; import com.gh.base.fragment.BaseFragment_ViewPager_Checkable; import com.gh.common.constant.Config; +import com.gh.common.syncpage.SyncPageRepository; import com.gh.common.util.DataUtils; import com.gh.common.util.DisplayUtils; import com.gh.common.util.EntranceUtils; @@ -276,6 +277,10 @@ public class MainWrapperFragment extends BaseFragment_ViewPager_Checkable implem super.onResume(); //mViewModel.getDiscoveryData(false); MessageUnreadRepository.INSTANCE.loadMessageUnreadTotal(); + + if (isEverPause) { + mBaseHandler.postDelayed(SyncPageRepository::clearSyncData, 2000); + } } @Override diff --git a/app/src/main/java/com/gh/gamecenter/qa/answer/detail/AnswerDetailViewModel.kt b/app/src/main/java/com/gh/gamecenter/qa/answer/detail/AnswerDetailViewModel.kt index 9134b1d1aa..b1f8f5eb03 100644 --- a/app/src/main/java/com/gh/gamecenter/qa/answer/detail/AnswerDetailViewModel.kt +++ b/app/src/main/java/com/gh/gamecenter/qa/answer/detail/AnswerDetailViewModel.kt @@ -7,6 +7,7 @@ import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import com.gh.common.history.HistoryHelper import com.gh.common.syncpage.SyncDataEntity +import com.gh.common.syncpage.SyncFieldConstants import com.gh.common.syncpage.SyncPageRepository import com.gh.common.util.* import com.gh.gamecenter.R @@ -91,8 +92,13 @@ class AnswerDetailViewModel(application: Application) : AndroidViewModel(applica apiResponse.data = response mVoteLiveData.postValue(apiResponse) - SyncPageRepository.postSyncData(SyncDataEntity(answerId, "vote", answerDetail!!.vote)) - SyncPageRepository.postSyncData(SyncDataEntity(answerId, "answer_vote", answerDetail?.me?.isAnswerVoted, checkFieldEntity = true)) + SyncPageRepository.postSyncData(SyncDataEntity(answerId, + SyncFieldConstants.ANSWER_VOTE_COUNT, + answerDetail?.vote)) + SyncPageRepository.postSyncData(SyncDataEntity(answerId, + SyncFieldConstants.ANSWER_VOTE, + answerDetail?.me?.isAnswerVoted, + checkFieldEntity = true)) } override fun onFailure(e: HttpException?) { @@ -117,8 +123,13 @@ class AnswerDetailViewModel(application: Application) : AndroidViewModel(applica apiResponse.data = response mVoteLiveData.postValue(apiResponse) - SyncPageRepository.postSyncData(SyncDataEntity(answerId, "vote", answerDetail!!.vote)) - SyncPageRepository.postSyncData(SyncDataEntity(answerId, "answer_vote", answerDetail?.me?.isAnswerVoted, checkFieldEntity = true)) + SyncPageRepository.postSyncData(SyncDataEntity(answerId, + SyncFieldConstants.ANSWER_VOTE_COUNT, + answerDetail!!.vote)) + SyncPageRepository.postSyncData(SyncDataEntity(answerId, + SyncFieldConstants.ANSWER_VOTE, + answerDetail?.me?.isAnswerVoted, + checkFieldEntity = true)) } override fun onFailure(e: HttpException?) { diff --git a/app/src/main/java/com/gh/gamecenter/qa/article/detail/ArticleDetailViewModel.kt b/app/src/main/java/com/gh/gamecenter/qa/article/detail/ArticleDetailViewModel.kt index 60275409be..c673aedba6 100644 --- a/app/src/main/java/com/gh/gamecenter/qa/article/detail/ArticleDetailViewModel.kt +++ b/app/src/main/java/com/gh/gamecenter/qa/article/detail/ArticleDetailViewModel.kt @@ -4,6 +4,9 @@ import android.app.Application import androidx.lifecycle.AndroidViewModel import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData +import com.gh.common.syncpage.SyncDataEntity +import com.gh.common.syncpage.SyncFieldConstants +import com.gh.common.syncpage.SyncPageRepository import com.gh.common.util.CollectionUtils import com.gh.common.util.ErrorHelper import com.gh.gamecenter.R @@ -99,6 +102,16 @@ class ArticleDetailViewModel(application: Application) : AndroidViewModel(applic detailEntity!!.count.vote++ like.postValue(response) + + articleId?.apply { + SyncPageRepository.postSyncData(SyncDataEntity(this, + SyncFieldConstants.ARTICLE_VOTE_COUNT, + detailEntity?.count?.vote)) + SyncPageRepository.postSyncData(SyncDataEntity(this, + SyncFieldConstants.ARTICLE_VOTE, + detailEntity?.me?.isAnswerVoted, + checkFieldEntity = true)) + } } override fun onFailure(e: HttpException?) { @@ -119,6 +132,15 @@ class ArticleDetailViewModel(application: Application) : AndroidViewModel(applic detailEntity?.me?.isCommunityArticleVote = false dislike.postValue(true) + articleId?.apply { + SyncPageRepository.postSyncData(SyncDataEntity(this, + SyncFieldConstants.ARTICLE_VOTE_COUNT, + detailEntity?.count?.vote)) + SyncPageRepository.postSyncData(SyncDataEntity(this, + SyncFieldConstants.ARTICLE_VOTE, + detailEntity?.me?.isAnswerVoted, + checkFieldEntity = true)) + } } override fun onFailure(e: HttpException?) { diff --git a/app/src/main/java/com/gh/gamecenter/qa/comment/NewCommentFragment.kt b/app/src/main/java/com/gh/gamecenter/qa/comment/NewCommentFragment.kt index 9ce633f4b1..8fcbf7061f 100644 --- a/app/src/main/java/com/gh/gamecenter/qa/comment/NewCommentFragment.kt +++ b/app/src/main/java/com/gh/gamecenter/qa/comment/NewCommentFragment.kt @@ -21,6 +21,9 @@ import butterknife.BindView import butterknife.OnClick import butterknife.Optional import com.gh.base.fragment.BaseDialogWrapperFragment +import com.gh.common.syncpage.SyncDataEntity +import com.gh.common.syncpage.SyncFieldConstants +import com.gh.common.syncpage.SyncPageRepository import com.gh.common.util.* import com.gh.common.view.VerticalItemDecoration import com.gh.gamecenter.R @@ -93,6 +96,16 @@ open class NewCommentFragment : ListFragment mCommentListener?.onCommentDraftChange("") } commentEt.postDelayed({ setSoftInput(false) }, 100) + + if (mCommentType == CommentType.COMMUNITY_ARTICLE) { + SyncPageRepository.postSyncData(SyncDataEntity(mArticleId, + SyncFieldConstants.ANSWER_COMMENT_COUNT, + mCommentCount)) + } else if (mCommentType == CommentType.ANSWER) { + SyncPageRepository.postSyncData(SyncDataEntity(mAnswerId, + SyncFieldConstants.ANSWER_COMMENT_COUNT, + mCommentCount)) + } } apiResponse.httpException != null -> { mSendingDialog?.dismiss() diff --git a/app/src/main/java/com/gh/gamecenter/qa/entity/AnswerEntity.kt b/app/src/main/java/com/gh/gamecenter/qa/entity/AnswerEntity.kt index 455b8dd789..60b1acf0fe 100644 --- a/app/src/main/java/com/gh/gamecenter/qa/entity/AnswerEntity.kt +++ b/app/src/main/java/com/gh/gamecenter/qa/entity/AnswerEntity.kt @@ -8,6 +8,7 @@ import androidx.room.Ignore import androidx.room.PrimaryKey import androidx.room.TypeConverters import com.gh.common.annotation.SyncPage +import com.gh.common.syncpage.SyncFieldConstants import com.gh.gamecenter.entity.MeEntity import com.gh.gamecenter.entity.UserEntity import com.gh.gamecenter.room.converter.AnswerUserConverter @@ -48,7 +49,7 @@ class AnswerEntity() : Parcelable { @TypeConverters(CommunityVideoConverter::class) var videos: List = ArrayList() - @SyncPage(syncName = "vote") + @SyncPage(syncNames = [SyncFieldConstants.ANSWER_VOTE_COUNT, SyncFieldConstants.ARTICLE_VOTE_COUNT]) var vote: Int = 0 @TypeConverters(AnswerUserConverter::class) @@ -61,6 +62,7 @@ class AnswerEntity() : Parcelable { @SerializedName("community_name") var communityName: String? = null + @SyncPage(syncNames = [SyncFieldConstants.ANSWER_COMMENT_COUNT, SyncFieldConstants.ARTICLE_COMMENT_COUNT]) @SerializedName("comment_count") var commentCount: Int = 0