i am using realm database and create a data provider. after delete a task in taskactivity and return to task fragment, fragment return error object was deleted in other thread.
i have to notifydatasetchanged() on onresume() fragment. but how?
class TaskFragmentDataProvider {
private var mData: MutableList<ConcreteData>
private var mLastRemovedData: ConcreteData? = null
private var mLastRemovedPosition = -1
var realm = RealmManager.getNewInstance()
val count: Int
get() = mData.size
init {
mData = RefreshTaskData()
notifyDataSetChange()
}
fun notifyDataSetChange(){
var objects = TaskManager.findAllAsync(true)
objects!!.addChangeListener { _,_->
RefreshTaskData()
}
}
fun RefreshTaskData(): MutableList<ConcreteData> {
mData = LinkedList()
val objects = TaskManager.findAll(true)
var i=0
objects!!.forEach {
val id = it.id!!
val viewType =i++
val swipeReaction =
RecyclerViewSwipeManager.REACTION_CAN_SWIPE_UP or RecyclerViewSwipeManager.REACTION_CAN_SWIPE_DOWN
mData.add(ConcreteData(id,viewType, swipeReaction,it))
}
return mData
}
fun getItem(index: Int): ConcreteData {
if (index < 0 || index >= count) {
throw IndexOutOfBoundsException("index = $index")
}
return mData[index]
}
fun getTaskItems(position: Int): RealmResults<Entry>? {
return getItem(position).task.entries.where().findAll()
.sort(arrayOf("sortId","id"), arrayOf(Sort.DESCENDING, Sort.ASCENDING))
}
fun undoLastRemoval(): Int {
if (mLastRemovedData != null) {
val insertedPosition: Int = if (mLastRemovedPosition >= 0 && mLastRemovedPosition < mData.size) {
mLastRemovedPosition
} else {
mData.size
}
mData.add(insertedPosition, mLastRemovedData!!)
mLastRemovedData = null
mLastRemovedPosition = -1
return insertedPosition
} else {
return -1
}
}
fun moveItem(fromPosition: Int, toPosition: Int) {
if (fromPosition == toPosition) {
return
}
val item = mData.removeAt(fromPosition)
mData.add(toPosition, item)
mLastRemovedPosition = -1
realm.executeTransaction {
mData.forEach {
it.task.sortId = mData.indexOf(it).toLong()
}
}
}
fun swapItem(fromPosition: Int, toPosition: Int) {
if (fromPosition == toPosition) {
return
}
Collections.swap(mData, toPosition, fromPosition)
mLastRemovedPosition = -1
}
fun removeItem(position: Int) {
val removedItem = mData.removeAt(position)
mLastRemovedData = removedItem
mLastRemovedPosition = position
}
class ConcreteData internal constructor(val id: Long, val viewType: Int, swipeReaction: Int, var task: Task)
}
`
`
internal class TaskAdapter(private val mProvider: TaskFragmentDataProvider, var context: Context?) :
RecyclerView.Adapter<TaskAdapter.BaseViewHolder>(),
DraggableItemAdapter<TaskAdapter.BaseViewHolder> {
open class BaseViewHolder(v: View) : AbstractDraggableItemViewHolder(v)
class HeaderItemViewHolder(v: View) : BaseViewHolder(v)
class NormalItemViewHolder(v: View) : BaseViewHolder(v) {
var mContainer: ViewGroup = v.findViewById(R.id.root)
var title: TextView = v.findViewById(R.id.title)
var items: RecyclerView = v.findViewById(R.id.items)
var pin: ImageView = v.findViewById(R.id.pin)
var percent: PercentView = v.findViewById(R.id.percent)
}
init {
// DraggableItemAdapter requires stable ID, and also
// have to implement the getItemId() method appropriately.
setHasStableIds(true)
}
override fun getItemId(position: Int): Long {
return if (isHeader(position)) {
RecyclerView.NO_ID
} else {
mProvider.getItem(toNormalItemPosition(position)).id
}
}
override fun getItemViewType(position: Int): Int {
return if (isHeader(position)) {
ITEM_VIEW_TYPE_HEADER
} else {
ITEM_VIEW_TYPE_NORMAL_ITEM_OFFSET + mProvider.getItem(toNormalItemPosition(position)).viewType
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BaseViewHolder {
val inflater = LayoutInflater.from(parent.context)
when (viewType) {
ITEM_VIEW_TYPE_HEADER -> {
// NOTE:
// This dummy header item is required to workaround the
// weired animation when occurs on moving the item 0
//
// Related issue
// Issue 99047: Inconsistent behavior produced by mAdapter.notifyItemMoved(indexA,indexB);
// https://code.google.com/p/android/issues/detail?id=99047&q=notifyItemMoved&colspec=ID%20Status%20Priority%20Owner%20Summary%20Stars%20Reporter%20Opened&
val v = inflater.inflate(R.layout.dummy_header_item, parent, false)
return HeaderItemViewHolder(v)
}
else -> {
val v = inflater.inflate(R.layout.row_grid_task, parent, false)
return NormalItemViewHolder(v)
}
}
}
override fun onBindViewHolder(holder: BaseViewHolder, position: Int) {
if (isHeader(position)) {
onBindHeaderViewHolder(holder as HeaderItemViewHolder, position)
} else {
onItemViewHolder(holder as NormalItemViewHolder, toNormalItemPosition(position))
}
}
private fun onBindHeaderViewHolder(holder: HeaderItemViewHolder, position: Int) {
val lp = holder.itemView.layoutParams as StaggeredGridLayoutManager.LayoutParams
lp.isFullSpan = true
}
private fun onItemViewHolder(holder: NormalItemViewHolder, position: Int) {
val obj = mProvider.getItem(position)
holder.title.text = obj.task.title
if (obj.task.pin)holder.pin.visibility = View.VISIBLE
val lyt = LinearLayoutManager(context)
lyt.orientation = RecyclerView.VERTICAL
holder.items.layoutManager = lyt
holder.items.adapter = TaskRowEntriesAdapter(context!!, mProvider.getTaskItems(position) as List<Entry>)
percentPercent(holder.percent,obj.task.donePercent())
holder.mContainer.setOnClickListener {
val intent = Intent(context, TaskActivity::class.java)
intent.putExtra("task_id",obj.task.id)
intent.putExtra("edit",true)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
holder.mContainer.transitionName = obj.task.id.toString()
holder.title.transitionName = obj.task.title
val pair1 = androidx.core.util.Pair(holder.mContainer as View, holder.mContainer.transitionName)
val optionsCompat =
ActivityOptionsCompat.makeSceneTransitionAnimation(context as Activity, pair1)
context!!.startActivity(intent, optionsCompat.toBundle())
}else{
context!!.startActivity(intent)
}
}
holder.items.setOnClickListener {
holder.mContainer.callOnClick()
}
// set item view height
val context = holder.itemView.context
val itemHeight = calcItemHeight(context, obj.task)
val lp = holder.items.layoutParams
if (lp.height != itemHeight) {
lp.height = itemHeight
holder.items.layoutParams = lp
}
// set background resource (target view ID: container)
val dragState = holder.dragState
if (dragState.isUpdated) {
val bgResId: Int = when {
dragState.isActive -> R.drawable.bg_item_dragging_active_state
dragState.isDragging -> R.drawable.bg_item_dragging_state
else -> R.drawable.selector_radius_card_white
}
holder.mContainer.setBackgroundResource(bgResId)
}
}
private fun percentPercent(percent: PercentView, donePercent: Int) {
percent.updatePercentValue(donePercent)
var backPercentColor = when {
donePercent<25 -> ContextCompat.getColor(context!!,R.color.prim_red)
donePercent<50 -> ContextCompat.getColor(context!!,R.color.prim_orange3)
donePercent<75 -> ContextCompat.getColor(context!!,R.color.prim_yellow)
else -> ContextCompat.getColor(context!!,R.color.prim_green)
}
percent.setPercentBackground(Shape.creatShape(
backPercentColor,
Screen.dp2screen(context!!,1),
ContextCompat.getColor(context!!,R.color.header1),
20f,20f,20f,20f))
}
override fun getItemCount(): Int {
val headerCount = headerItemCount
val count = mProvider.count
return headerCount + count
}
override fun onMoveItem(fromPosition: Int, toPosition: Int) {
var fromPosition = fromPosition
var toPosition = toPosition
fromPosition = toNormalItemPosition(fromPosition)
toPosition = toNormalItemPosition(toPosition)
mProvider.moveItem(fromPosition, toPosition)
}
override fun onCheckCanStartDrag(holder: BaseViewHolder, position: Int, x: Int, y: Int): Boolean {
return !isHeader(position)
}
override fun onGetItemDraggableRange(holder: BaseViewHolder, position: Int): ItemDraggableRange? {
val headerCount = headerItemCount
return ItemDraggableRange(headerCount, itemCount - 1)
}
override fun onCheckCanDrop(draggingPosition: Int, dropPosition: Int): Boolean {
return (mProvider.getItem(draggingPosition).task.pin
==
mProvider.getItem(dropPosition).task.pin)
}
override fun onItemDragStarted(position: Int) {
notifyDataSetChanged()
}
override fun onItemDragFinished(fromPosition: Int, toPosition: Int, result: Boolean) {
notifyDataSetChanged()
}
companion object {
private val TAG = "MyDraggableItemAdapter"
private val ITEM_VIEW_TYPE_HEADER = 0
private val ITEM_VIEW_TYPE_NORMAL_ITEM_OFFSET = 1
private val USE_DUMMY_HEADER = true
private val RANDOMIZE_ITEM_SIZE = true
val headerItemCount: Int
get() = if (USE_DUMMY_HEADER) 1 else 0
fun isHeader(position: Int): Boolean {
return position < headerItemCount
}
fun toNormalItemPosition(position: Int): Int {
return position - headerItemCount
}
fun calcItemHeight(context: Context, item: Task): Int {
var tl = 0
item.entries.forEach {
when(it.type){
Is_Item->{
tl++
}
Is_Text->{
tl += StringHelper.countLine(it.text!!.text,20)
}
Is_Task->{
tl++
}
}
}
return (if(tl>10){
10
}else{
tl
})* Screen.dp2screen(context,20)
}
fun swapBit(x: Int, pos1: Int, pos2: Int): Int {
val m1 = 1 shl pos1
val m2 = 1 shl pos2
var y = x and (m1 or m2).inv()
if (x and m1 != 0) {
y = y or m2
}
if (x and m2 != 0) {
y = y or m1
}
return y
}
}
}
`
my fragment:
class TaskFragment : Fragment() {
private var listener: MainNavFragmentInteractionListener? = null
private var mRecyclerView: RecyclerView? = null
private var mLayoutManager: StaggeredGridLayoutManager? = null
private var mAdapter: RecyclerView.Adapter<*>? = null
private var mWrappedAdapter: RecyclerView.Adapter<*>? = null
private var mRecyclerViewDragDropManager: RecyclerViewDragDropManager? = null
private var myItemAdapter:TaskAdapter?=null
var realm = RealmManager.getNewInstance()
var taskDataProvider = TaskFragmentDataProvider()
var position:Int=0
var posArr: IntArray = intArrayOf(0,0)
lateinit var objects : RealmResults<Task>
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
val layout = inflater.inflate(R.layout.task_fragment, container, false)
inite(layout)
return layout
}
private fun inite(l: View) {
mRecyclerView = l.list
initeHeader(l)
reiniteList(position)
}
private fun reiniteList(position:Int) {
taskDataProvider = TaskFragmentDataProvider()
initeList(position)
}
private fun refreshList(position:Int) {
reiniteList(position)
}
private fun initeHeader(layout: View) {
layout.ic_header_nav.setOnClickListener {
listener?.onNavInteraction("change")
}
layout.ic_header_help.setOnClickListener {
}
}
private fun initeList(position: Int) {
mLayoutManager = StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL)
mRecyclerViewDragDropManager = RecyclerViewDragDropManager()
mRecyclerViewDragDropManager!!.setDraggingItemShadowDrawable(
ContextCompat.getDrawable(requireContext(), R.drawable.material_shadow_z3) as NinePatchDrawable?
)
mRecyclerViewDragDropManager!!.setInitiateOnLongPress(true)
mRecyclerViewDragDropManager!!.setInitiateOnMove(false)
mRecyclerViewDragDropManager!!.setLongPressTimeout(750)
mRecyclerView!!.setHasFixedSize(true)
mRecyclerView!!.layoutManager = mLayoutManager
if (supportsViewElevation()) {
} else {
mRecyclerView!!.addItemDecoration(
ItemShadowDecorator(
(ContextCompat.getDrawable(
requireContext(),
R.drawable.material_shadow_z1
) as NinePatchDrawable?)!!
)
)
}
mRecyclerViewDragDropManager!!.attachRecyclerView(mRecyclerView!!)
myItemAdapter = TaskAdapter(taskDataProvider,context)
mAdapter = myItemAdapter
mWrappedAdapter = mRecyclerViewDragDropManager!!.createWrappedAdapter(myItemAdapter!!) // wrap for dragging
mRecyclerView!!.adapter = mWrappedAdapter // requires *wrapped* adapter
}
private fun supportsViewElevation(): Boolean {
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP
}
override fun onAttach(context: Context) {
super.onAttach(context)
if (context is MainNavFragmentInteractionListener) {
listener = context
} else {
throw RuntimeException("$context must implement homeFragmentInteractionListener")
}
}
override fun onResume() {
refreshList(posArr[1])
super.onResume()
}
override fun onPause() {
mRecyclerViewDragDropManager!!.cancelDrag()
posArr = mLayoutManager!!.findFirstCompletelyVisibleItemPositions(posArr)
posArr.forEach {
println(it)
}
super.onPause()
}
override fun onDestroyView() {
if (mRecyclerViewDragDropManager != null) {
mRecyclerViewDragDropManager!!.release()
mRecyclerViewDragDropManager = null
}
if (mRecyclerView != null) {
mRecyclerView!!.itemAnimator = null
mRecyclerView!!.adapter = null
mRecyclerView = null
}
if (mWrappedAdapter != null) {
WrapperAdapterUtils.releaseAll(mWrappedAdapter)
mWrappedAdapter = null
}
mAdapter = null
mLayoutManager = null
super.onDestroyView()
}
override fun onDetach() {
super.onDetach()
listener = null
}
companion object {
fun newInstance() = TaskFragment()
}
i am using realm database and create a data provider. after delete a task in taskactivity and return to task fragment, fragment return error object was deleted in other thread. i have to notifydatasetchanged() on onresume() fragment. but how?
} `
`
}
`
my fragment:
}