#kotlin #android-fragments #filter #cursor #send
#kotlin #android-фрагменты #Фильтр #курсор #Отправить
Вопрос:
Я все еще делаю свои первые шаги в разработке приложений, поэтому я был бы признателен за любые отзывы о моем коде. К моей проблеме. Я получил два фрагмента: «ListFragment.kt» и «SetListFilters.kt». Я намерен создать экземпляр курсора в SetListFilters, а затем, когда я нажимаю кнопку «применить», я выполняю popBackStack при отправке экземпляра курсора в ListFrament. Насколько я понимаю, ListFragment вызовет onCreateView(), и там я хочу передать новый курсор моему адаптеру, чтобы Recyclerview был отфильтрован. Я перепробовал так много вещей, но у меня ничего не получалось. Надеюсь, вы сможете мне помочь. Вот мой код:
class SetListFilters(var transactionDB: SQLiteDatabase, var adapter: TransactionAdapter):Fragment(R.layout.fragment_set_list_filters), DataPassListener {
private lateinit var gridView : GridView
private lateinit var btnYearFilter : Button
private lateinit var btnMonthFilter : Button
private lateinit var btnWeekFilter : Button
private lateinit var btnRevenueFilter : Button
private lateinit var btnExpeneseFilter : Button
private lateinit var btnNeutralFilter : Button
private lateinit var btnSbmtFilter : Button
private lateinit var tvShowAmountFilter : TextView
private lateinit var sbAmountFilters : SeekBar
private val viewModel: ListViewModel by activityViewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val view = inflater.inflate(R.layout.fragment_set_list_filters, container, false)
setUpViews(view)
setUpButtonOnclick()
setUpSeekbar()
val arrayAdapter: ArrayAdapter<CategoryEnum> = ArrayAdapter<CategoryEnum>(activity!!, android.R.layout.simple_list_item_multiple_choice, CategoryEnum.values())
gridView.setAdapter(arrayAdapter)
// When the user clicks on the GridItem
/*gridView.setOnItemClickListener(OnItemClickListener { a, v, position, id ->
val o: Any = gridView.getItemAtPosition(position)
})*/
return view
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
viewModel.filters.observe(viewLifecycleOwner, Observer { set ->
// Update the selected filters UI
}
}
fun onFilterSelected(filter: Filter) = viewModel.addFilter(filter)
fun onFilterDeselected(filter: Filter) = viewModel.removeFilter(filter)
private fun upDateQueryForDB(){
}
private fun getAllItemsNeu(): Cursor {
val selArgs = arrayOf("r")
return transactionDB!!.query(
TransactionList.TransactionEntry.TABLE_NAME,
null,
"type = ?",
selArgs,
null,
null,
TransactionList.TransactionEntry.COLUMN_CREATEDAT " DESC")
}
private fun setUpViews(view: View){
gridView = view.findViewById(R.id.gvCategoryFilter )
btnExpeneseFilter = view.findViewById(R.id.btnExpenseFilter)
btnMonthFilter = view.findViewById(R.id.btnMonthFilter)
btnWeekFilter = view.findViewById(R.id.btnWeekFilter)
btnNeutralFilter = view.findViewById(R.id.btnNeutralFilter)
btnRevenueFilter = view.findViewById(R.id.btnRevenueFilter)
btnSbmtFilter = view.findViewById(R.id.btnSbmtFilter)
btnYearFilter = view.findViewById(R.id.btnYearFilter)
sbAmountFilters = view.findViewById(R.id.seekBar)
tvShowAmountFilter = view.findViewById(R.id.tvFilterAmount)
}
private fun setUpButtonOnclick(){
btnExpeneseFilter.setOnClickListener { changeButtonAppearance(btnExpeneseFilter) }
btnMonthFilter.setOnClickListener { changeButtonAppearance(btnMonthFilter) }
btnWeekFilter.setOnClickListener { changeButtonAppearance(btnWeekFilter) }
btnNeutralFilter.setOnClickListener { changeButtonAppearance(btnNeutralFilter) }
btnRevenueFilter.setOnClickListener { changeButtonAppearance(btnRevenueFilter) }
btnYearFilter.setOnClickListener { changeButtonAppearance(btnYearFilter) }
btnSbmtFilter.setOnClickListener{
mainActivity.passDataCom(getAllItemsNeu())
activity!!.supportFragmentManager.popBackStack()
}
}
private fun changeButtonAppearance(button:Button) {
if(button.tag == "notPressed"){
button.setBackgroundResource(R.drawable.rounded_select_button_pressed)
button.setTextColor(Color.WHITE)
button.tag = "pressed"
}else{
button.setBackgroundResource(R.drawable.rounded_select_button)
button.setTextColor(ContextCompat.getColor(context!!,R.color.mainBlue))
button.tag ="notPressed"
}
}
private fun setUpSeekbar(){
sbAmountFilters.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
override fun onProgressChanged(seekBar: SeekBar, i: Int, b: Boolean) {
// Display the current progress of SeekBar
tvShowAmountFilter.text = "< $i"
}
override fun onStartTrackingTouch(seekBar: SeekBar) {
// Do something
//Toast.makeText(context!!,"start tracking",Toast.LENGTH_SHORT).show()
}
override fun onStopTrackingTouch(seekBar: SeekBar) {
// Do something
//Toast.makeText(context!!,"stop tracking",Toast.LENGTH_SHORT).show()
if(tvShowAmountFilter.text.toString()=="< 0"){
tvShowAmountFilter.text = "none"
}
}
})
}
override fun onAttach(context: Context) {
super.onAttach(context)
try{
mCallback = (OnImageClickListener) //folled the tutorial, dont know what to replace it with
}
}
}
class ListFragment:Fragment(R.layout.fragment_list) {
lateinit var transactionDB : SQLiteDatabase
lateinit var adapter : TransactionAdapter
private lateinit var filterBtn : ImageButton
private lateinit var flActBtn : FloatingActionButton
var mCursorFilter : Cursor? = null
private val viewModel: ListViewModel by activityViewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val dbHelper = TransactionDBHelper(activity)
transactionDB = dbHelper.writableDatabase
adapter = TransactionAdapter(activity!!, getAllItems())
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
viewModel.filteredList.observe(viewLifecycleOwner, Observer { list ->
//TODO
}
}
private fun addRandomTransactionItem() {
var a = 1234.56
for (i in 0..10) {
if(i%2==0){
transactionDB.execSQL("INSERT INTO transactionList (type, amount, category, createdAt) VALUES('r', ${a}, 'K', CURRENT_TIMESTAMP)")
adapter.swapCursor(getAllItems())
}else if(i%5==0){
transactionDB.execSQL("INSERT INTO transactionList (type, amount, category, createdAt) VALUES('ne', ${a}, 'K', CURRENT_TIMESTAMP)")
adapter.swapCursor(getAllItems())
}else if(i%6==0){
transactionDB.execSQL("INSERT INTO transactionList (type, amount, category, createdAt) VALUES('ne', ${a}, 'K', CURRENT_TIMESTAMP)")
adapter.swapCursor(getAllItems())
}else{
transactionDB.execSQL("INSERT INTO transactionList (type, amount, category, createdAt) VALUES('e', ${a}, 'K', CURRENT_TIMESTAMP)")
adapter.swapCursor(getAllItems())
}
}
}
private fun getAllItems(): Cursor {
return transactionDB!!.query(
TransactionList.TransactionEntry.TABLE_NAME,
null,
null,
null,
null,
null,
TransactionList.TransactionEntry.COLUMN_CREATEDAT " DESC")
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val view = inflater.inflate(R.layout.fragment_list, container, false)
val rvRecyclerView = view.findViewById<RecyclerView>(R.id.rvRecyclerView)
rvRecyclerView.layoutManager = LinearLayoutManager(activity)
if(mCursorFilter!=null){
adapter.swapCursor(mCursorFilter!!)
}
rvRecyclerView.adapter = this.adapter
rvRecyclerView.addItemDecoration(MarginItemDecoration(10))
flActBtn = view.findViewById(R.id.floatingActionButton)
flActBtn.setOnClickListener {
var ft:FragmentTransaction = activity!!.supportFragmentManager.beginTransaction()
ft.replace(R.id.flFrameLayout, AddItemFragment(transactionDB, adapter))
ft.addToBackStack(null)
ft.commit()
}
filterBtn=view.findViewById(R.id.ibFilterBtn)
filterBtn.setOnClickListener {
var ft:FragmentTransaction = activity!!.supportFragmentManager.beginTransaction()
ft.replace(R.id.flFrameLayout, SetListFilters(transactionDB, adapter))
ft.addToBackStack(null)
ft.commit()
}
addRandomTransactionItem()
return view
}
}
class MainActivity() : AppCompatActivity() {
var mCursorFilters: Cursor? = null
private val viewModel: ItemViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
viewModel.selectedItem.observe(this, Observer { item ->
// TODO
})
val homeFragment = HomeFragment()
val listFragment = ListFragment()
val profileFragment = ProfileFragment()
setCurrentFragment(homeFragment)
val bottomNavigationView = findViewById<BottomNavigationView>(R.id.bottomNavigationView)
bottomNavigationView.setOnNavigationItemSelectedListener {
var ft: FragmentTransaction = this.supportFragmentManager.beginTransaction()
when (it.itemId) {
R.id.pageHome -> ft.replace(R.id.flFrameLayout, homeFragment) // setCurrentFragment(homeFragment)
R.id.pageList -> ft.replace(R.id.flFrameLayout, listFragment) //setCurrentFragment(listFragment)
R.id.pageProfile -> ft.replace(R.id.flFrameLayout, profileFragment) //setCurrentFragment(profileFragment)
}
// ft.replace(R.id.flFrameLayout, AddItemFragment())
ft.addToBackStack(null)
ft.commit()
true
}
}
private fun setCurrentFragment(fragment: Fragment){
supportFragmentManager.beginTransaction().apply {
replace(R.id.flFrameLayout, fragment)
commit()
}
}
}
Комментарии:
1. Типичной стратегией для ViewModel было бы предоставление SharedFlow или LiveData курсора. Удалите
getAllItems()
его из своего фрагмента и вместо этого подпишитесь на поток или LiveData. ViewModel также предоставит функцию для фильтрующего фрагмента, чтобы установить, что такое фильтр, и эта функция выполнит новый запрос и заменит курсор в потоке или LiveData. Поэтому первому фрагменту не нужно ничего знать о создании запросов, изменении курсоров или изменении фильтров. Второй фрагмент не должен ничего знать о запросах, просто как установить фильтр.2. Кстати, у вас не может быть аргументов конструктора для фрагмента. Это приведет к сбою в любой ситуации, когда фреймворк воссоздает фрагмент, например, вращение экрана или перемещение по стеку. Вам необходимо переместить свойство базы данных в вашу ViewModel. Вы можете создать ViewModelFactory для передачи свойства конструктору ViewModel.
3. Спасибо! Мне удалось реализовать свою viewmodel и передать курсор. А также спасибо за совет относительно параметров в конструкторах фрагментов!!