I have recyclerview and there is a one button.
This button can change Boolean state from true to false, false to true.
And I want to change the button's background color according to its boolean state.
Below is my code
class ProjectFeedBigAdapter : ListAdapter<Project, ProjectFeedBigAdapter.ProjectFeedBigViewHolder>(
ProjectFeedDiffUtil()
) {
val db: FirebaseFirestore = FirebaseFirestore.getInstance()
val projects: ArrayList<Project> = arrayListOf()
init {
db.collection("projects")
.orderBy("timeStamp", Query.Direction.DESCENDING)
.addSnapshotListener { querySnapshot, exception ->
projects.clear()
if(querySnapshot == null) return#addSnapshotListener
for(snapshot in querySnapshot.documents) {
val project = snapshot.toObject(Project::class.java)
projects.add(project!!)
}
submitList(projects)
}
}
override fun onCreateViewHolder...{...}
override fun onBindViewHolder(holder: ProjectFeedBigViewHolder, position: Int) {
val item = getItem(position)
holder.apply {
when(item.booleanState) {
true -> {
// Button BackgroundColor Change
}
else -> {
// Button BackgroundColor Change
}
}
stateButton.setOnClickListener {
val project = db.collection("projects").document(item.projectId)
item.booleanState?.let {
project
.update("booleanState", !it)
.addOnSuccessListener { Toast.makeText(//context, "Success", Toast.LENGTH_SHORT).show() }
.addOnFailureListener { e -> }
}
}
}
}
inner class ProjectFeedBigViewHolder(private val view: View): RecyclerView.ViewHolder(view) {
...
}
}
class ProjectFeedDiffUtil: DiffUtil.ItemCallback<Project>() {
override fun areItemsTheSame(oldItem: Project, newItem: Project): Boolean {
return oldItem.timeStamp == newItem.timeStamp
}
override fun areContentsTheSame(oldItem: Project, newItem: Project): Boolean {
return oldItem == newItem
}
}
when I click 'stateButton',
Boolean state changes occur. (I can see the data is changing on Firebase Cloud)
Also, can see that pass the submitList().
But not enter onBindViewHolder, so stateButton's background color doesn't change.
How can I solve this problem?
Related
i want to avoid fragment recreation by using BottomNavigationView
i read about that FragmentTransaction.replace is the problem and changing to add would help, but that didn't work for me..
maybe you can see here where i'm wrong
this is my Host Activity which hosting 3 fragments with BottomNavigationView
'''
class Host : AppCompatActivity() {
var fragment: Fragment? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_host)
//for hide the actionBar (contains Fragment name) on top of the screen
val actionBar = supportActionBar
actionBar?.hide()
val navController = Navigation.findNavController(this, R.id.nav_host_fragment)
val navView = findViewById<BottomNavigationView>(R.id.nav_view)
navView?.setupWithNavController(navController)
NavigationUI.setupWithNavController(navView, navController)
mAdapter = NfcAdapter.getDefaultAdapter(this)
fragmentStayAlive()
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
for (fragment in supportFragmentManager.fragments) {
fragment.onActivityResult(requestCode, resultCode, data)
}
}
fun ByteArray.toHexString() = joinToString("") { "%02x".format(it) }
private fun fragmentStayAlive(){
val fragment1: Fragment = LobbyFragment()
val fragment2: Fragment = GameSessionFragment()
val fragment3: Fragment = UserStatusFragment()
val fm: FragmentManager = supportFragmentManager
var active = fragment1
fm.beginTransaction().add(R.id.nav_host_fragment, fragment3, "UserStatusFragment").hide(
fragment3
).commit();
fm.beginTransaction().add(R.id.nav_host_fragment, fragment2, "GameSessionFragment").hide(
fragment2
).commit();
fm.beginTransaction().add(R.id.nav_host_fragment, fragment1, "LobbyFragment").commit();
val mOnNavigationItemSelectedListener: BottomNavigationView.OnNavigationItemSelectedListener =
object : BottomNavigationView.OnNavigationItemSelectedListener {
override fun onNavigationItemSelected(item: MenuItem): Boolean {
when (item.getItemId()) {
R.id.lobbyFragment -> {
fm.beginTransaction().hide(active).show(fragment1).commit()
active = fragment1
return true
}
R.id.gameSessionFragment -> {
fm.beginTransaction().hide(active).show(fragment2).commit()
active = fragment2
return true
}
R.id.userStatusFragment -> {
fm.beginTransaction().hide(active).show(fragment3).commit()
active = fragment3
return true
}
}
replaceFragment(active, null, true, true)
return false
}
}
}
fun replaceFragment(
fragment: Fragment,
#Nullable bundle: Bundle?,
popBackStack: Boolean,
findInStack: Boolean
) {
val fm = supportFragmentManager
val ft: FragmentTransaction = fm.beginTransaction()
val tag = fragment.javaClass.name
val parentFragment: Fragment?
parentFragment = if (findInStack && fm.findFragmentByTag(tag) != null) {
fm.findFragmentByTag(tag)
} else {
fragment
}
// if user passes the #bundle in not null, then can be added to the fragment
if (bundle != null) {
parentFragment!!.arguments = bundle
} else {
parentFragment!!.arguments = null
}
// this is for the very first fragment not to be added into the back stack.
if (popBackStack) {
fm.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE)
} else {
ft.addToBackStack(parentFragment.javaClass.name + "")
}
ft.add(R.id.nav_view, parentFragment, tag)
ft.commit()
fm.executePendingTransactions()
}
'''
thanks for all the helpers!
I have one activity with 2 recyclerViews, both recyclers are used with Firebase. One of the recyclers displays the results of a query, the other recycler has a listener that updates every time there is an update in Firebase. I added a searchView to filter the results from Firebase. The issue I'm having is when I'm trying to search the results from the Firebase query, when I start typing I see results but when I click the X to stop searching, the adapter does not reload the array and i don't see the list of items unless I reload the activity. I'm not sure what I'm missing here. Any help/suggestion is greatly appreciated. Here is my code:
Adapter
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Filter
import android.widget.Filterable
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import com.eduardoz.ezmdapp.Model.Charges
import com.eduardoz.ezmdapp.R
class ChargesAdapter (private var charges: ArrayList<Charges>
, private var chargesAll: ArrayList<Charges>
, private val itemClick: (Charges) -> Unit)
: RecyclerView.Adapter<ChargesAdapter.ViewHolder>()
, Filterable {
inner class ViewHolder(itemView: View, val itemClick: (Charges) -> Unit) :
RecyclerView.ViewHolder(itemView) {
private val chargeCode = itemView.findViewById<TextView>(R.id.chargeCodeTxt)
private val chargeDescription = itemView.findViewById<TextView>(R.id.chargeDescriptionTxt)
fun bindCharges(charges: Charges) {
chargeCode?.text = charges.chargeCode
chargeDescription?.text = charges.chargeDescription
itemView.setOnClickListener { itemClick(charges) }
}
}
init {
this.charges = charges
chargesAll = java.util.ArrayList(charges)
}
override fun getItemCount(): Int {
return charges.count()
}
override fun onBindViewHolder(holder: ChargesAdapter.ViewHolder, position: Int) {
holder.bindCharges(charges[position])
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ChargesAdapter.ViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.charges_list, parent, false)
return ViewHolder(view, itemClick)
}
override fun getFilter(): Filter {
return searchFilter
}
private val searchFilter: Filter = object: Filter() {
override fun performFiltering(constraint: CharSequence?): FilterResults {
val filteredList: ArrayList<Charges> = ArrayList()
if (constraint!!.isEmpty()) {
filteredList.addAll(chargesAll)
} else {
for(item in chargesAll) {
if
(item.chargeDescription.toLowerCase().contains(constraint.toString().toLowerCase())) {
filteredList.add(item)
}
}
}
val searchResults = FilterResults()
searchResults.values = filteredList
return searchResults
}
override fun publishResults(constraint: CharSequence?, results: FilterResults?) {
charges.clear()
charges.addAll(results!!.values as Collection<Charges>)
notifyDataSetChanged()
}
}
}
Activity
descriptionSearch.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
override fun onQueryTextSubmit(query: String): Boolean {
return false
}
override fun onQueryTextChange(newText: String): Boolean {
if (newText.isNotEmpty()) {
searchViewBar(newText)
} else {
if (newText.isEmpty()) { //I ADDED THIS TO RELOAD THE ADAPTER
charges.clear()
chargeList()
}
}
return false
}
})
private fun searchViewBar(newText: String) {
chargesListener = chargesCollectionRef
.whereGreaterThanOrEqualTo(CHARGE_DESCRIPTION, newText)
.whereLessThanOrEqualTo(CHARGE_DESCRIPTION, newText+"z")
.addSnapshotListener(this) { snapshot, exception ->
if (exception != null) {
println("error")
}
if (snapshot != null) {
charges.clear()
parseData(snapshot)
}
}
}
fun parseData(snapshot: QuerySnapshot) {
for (document in snapshot.documents) {
val data = document.data
val chargeCode = data!![CHARGE_CODE] as String
val chargeDescription = data[CHARGE_DESCRIPTION] as String
val chargeSpecialty = data[CHARGE_SPECIALTY] as String
val newChargeList = Charges(chargeCode, chargeDescription, chargeSpecialty)
charges.add(newChargeList)
}
chargesFromAdapter.notifyDataSetChanged()
}
I am very new using Kotlin and programming and I am currently making a calendar with events. My problem comes when I want to connect these events to firebase.
I am using an example that I found in git (https://github.com/kizitonwose/CalendarView) that uses the ThreeTen library for dates. This is the Event object:
class Event (val id: String, val text: String, val date: LocalDate) : Serializable
The data variable is of the LocalData type and this is what is causing me problems since it seems that Firebase only accepts variables of type String, Int, etc ...
I tried to pass the variable to String with toString and with Gson (), without success.
Here is the code if it helps
private val inputDialog by lazy {
val editText = AppCompatEditText(requireContext())
val layout = FrameLayout(requireContext()).apply {
// Setting the padding on the EditText only pads the input area
// not the entire EditText so we wrap it in a FrameLayout.
setPadding(20, 20, 20, 20)
addView(editText, FrameLayout.LayoutParams(MATCH_PARENT, WRAP_CONTENT))
}
AlertDialog.Builder(requireContext())
.setTitle(getString(R.string.example_3_input_dialog_title))
.setView(layout)
.setPositiveButton(R.string.save) { _, _ ->
saveEvent(editText.text.toString())
// Prepare EditText for reuse.
editText.setText("")
}
.setNegativeButton(R.string.close, null)
.create()
.apply {
setOnShowListener {
// Show the keyboard
editText.requestFocus()
context.inputMethodManager.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0)
}
setOnDismissListener {
// Hide the keyboard
context.inputMethodManager.toggleSoftInput(InputMethodManager.HIDE_IMPLICIT_ONLY, 0)
}
}
}
private var selectedDate: LocalDate? = null
private val today = LocalDate.now()
private val titleSameYearFormatter = DateTimeFormatter.ofPattern("MMMM")
private val titleFormatter = DateTimeFormatter.ofPattern("MMM yyyy")
private val selectionFormatter = DateTimeFormatter.ofPattern("yyyy MM dd")
private val events = mutableMapOf<LocalDate, List<Event>>()
private var prueba = Gson().toJson(events)
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.fragment_calendar, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
mDatabaseReference = mDatabase!!.reference.child("events")
exThreeRv.layoutManager = LinearLayoutManager(requireContext(), RecyclerView.VERTICAL, false)
exThreeRv.adapter = eventsAdapter
exThreeRv.addItemDecoration(DividerItemDecoration(requireContext(), RecyclerView.VERTICAL))
val daysOfWeek = daysOfWeekFromLocale()
val currentMonth = YearMonth.now()
exThreeCalendar.setup(currentMonth.minusMonths(10), currentMonth.plusMonths(10), daysOfWeek.first())
exThreeCalendar.scrollToMonth(currentMonth)
if (savedInstanceState == null) {
exThreeCalendar.post {
// Show today's events initially.
selectDate(today)
}
}
class DayViewContainer(view: View) : ViewContainer(view) {
lateinit var day: CalendarDay // Will be set when this container is bound.
val textView = view.exThreeDayText
val dotView = view.exThreeDotView
init {
view.setOnClickListener {
if (day.owner == DayOwner.THIS_MONTH) {
selectDate(day.date)
}
}
}
}
exThreeCalendar.dayBinder = object : DayBinder<DayViewContainer> {
override fun create(view: View) = DayViewContainer(view)
override fun bind(container: DayViewContainer, day: CalendarDay) {
container.day = day
val textView = container.textView
val dotView = container.dotView
textView.text = day.date.dayOfMonth.toString()
if (day.owner == DayOwner.THIS_MONTH) {
textView.makeVisible()
when (day.date) {
today -> {
textView.setTextColorRes(R.color.white)
textView.setBackgroundResource(R.drawable.today_bg)
dotView.makeInVisible()
}
selectedDate -> {
textView.setTextColorRes(R.color.white)
textView.setBackgroundResource(R.drawable.selected_bg)
dotView.makeInVisible()
}
else -> {
textView.setTextColorRes(R.color.black)
textView.background = null
dotView.isVisible = events[day.date].orEmpty().isNotEmpty()
}
}
} else {
textView.makeInVisible()
dotView.makeInVisible()
}
}
}
exThreeCalendar.monthScrollListener = {
requireActivity().home.text = if (it.year == today.year) {
titleSameYearFormatter.format(it.yearMonth)
} else {
titleFormatter.format(it.yearMonth)
}
// Select the first day of the month when
// we scroll to a new month.
selectDate(it.yearMonth.atDay(1))
}
class MonthViewContainer(view: View) : ViewContainer(view) {
val legendLayout = view.legendLayout
}
exThreeCalendar.monthHeaderBinder = object : MonthHeaderFooterBinder<MonthViewContainer> {
override fun create(view: View) = MonthViewContainer(view)
override fun bind(container: MonthViewContainer, month: CalendarMonth) {
// Setup each header day text if we have not done that already.
if (container.legendLayout.tag == null) {
container.legendLayout.tag = month.yearMonth
container.legendLayout.children.map { it as TextView }.forEachIndexed { index, tv ->
tv.text = daysOfWeek[index].name.first().toString()
tv.setTextColorRes(R.color.black)
}
}
}
}
exThreeAddButton.setOnClickListener {
inputDialog.show()
}
}
private fun selectDate(date: LocalDate) {
if (selectedDate != date) {
val oldDate = selectedDate
selectedDate = date
oldDate?.let { exThreeCalendar.notifyDateChanged(it) }
exThreeCalendar.notifyDateChanged(date)
updateAdapterForDate(date)
}
}
private fun saveEvent(text: String) {
if (text.isBlank()) {
Toast.makeText(requireContext(),
R.string.example_3_empty_input_text, Toast.LENGTH_LONG).show()
} else {
selectedDate?.let {
events[it] = events[it].orEmpty().plus(
Event(
UUID.randomUUID().toString(),
text,
it
)
)
uploadFirebase()
updateAdapterForDate(it)
}
}
}
private fun deleteEvent(event: Event) {
val date = event.date
events[date] = events[date].orEmpty().minus(event)
updateAdapterForDate(date)
}
private fun updateAdapterForDate(date: LocalDate) {
eventsAdapter.events.clear()
eventsAdapter.events.addAll(events[date].orEmpty())
eventsAdapter.notifyDataSetChanged()
exThreeSelectedDateText.text = selectionFormatter.format(date)
}
fun uploadFirebase(){
val newEvent = mDatabaseReference.push()
newEvent.setValue(events)
}
override fun onStart() {
super.onStart()
}
override fun onStop() {
super.onStop()
}
}
There is no way you can add a property of type LocalDate in a Firebase Realtime database because it is not a supported data-type. However, there are two ways in which you can solve this:
You save the date as a ServerValue.TIMESTAMP, which basically means that you save the number of seconds that have elapsed since the Unix epoch. In this case, the server writes the current date in the database. To achieve this, please see my answer from the following post:
How to save the current date/time when I add new value to Firebase Realtime Database
You specify a custom long value for your date field. In this case, it's up to you to determine what date is written.
Unfortunately, there is no way you can combine these two options, you can use one or the other.
When talking about a LocalDate, we usually talk about an offset, in which case, this what I'll do. I'll store a Timestamp property, as explained at point one, that will let the server populate with the server Timestamp, as well as an offset property, that should be populated with the offset in days/hours.
I am making a children's app where the child can fingerpaint on a book spread as seen below.
The main view is not an ImageView. Rather, it is a custom view extending from GLSurfaceView to allow a pagecurl animation when flipping pages. In order to make a canvas, when a crayon is clicked, my code launches a fragment with a transparent layout to enable drawing on top of the custom view.
It works for each separate color. But when a new color is clicked, the old lines are removed (because a new fragment is launched) and I can draw again using the new color.
However, the ideal behavior is that the old drawing is retained (using the previous color), and the user should be able to keep on drawing with the new color without the fragment being re-launched.
As a test, I've only used the first 3 colors for now.
In the DrawingFragment, I've actually been able to change the color programmatically from the fragment (to CYAN) by calling the method changeColor. However, I still need to get the click event from the Activity that corresponds to each color.
Main Problems:
App should launch the fragment only once on the first instance any
crayon is clicked.
App should identify if the fragment is already created, and if so, pass the button click event from Activity to Fragment each time a crayon is clicked.
I have a vague idea that maybe I should use an interface but I've yet to fully understand what this does. I'm pretty new to kotlin and android and any help or suggestion will be greatly appreciated.
Main Activity
class ReadBooksActivity : Activity() {
var mCurlView: CurlView? = null
var reading_toolbar : View? = null
var isUp = false
var drawColor : Int? = null
var isDrawing = false
public override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.readbooks_layout)
// Start Page Curl for each page
mCurlView = findViewById(R.id.curl)
mCurlView!!.setSizeChangedObserver(SizeChangedObserver())
mCurlView!!.setCurrentIndex(index)
var bookId = intent.getIntExtra("ID", 0)
Thread(Runnable {
fetchbookpages()
mCurlView!!.setBitmapProvider(BitmapProvider(mBitmaps))
}).start()
mCurlView!!.setEnableTouchPressure(true)
mCurlView!!.set2PagesLandscape(true)
mCurlView!!.setAllowLastPageCurl(true)
// Toggle Reading Toolbar
reading_toolbar = findViewById(R.id.readingtoolbar) as View
// Enable drawing on View
tabtools.setOnClickListener(View.OnClickListener {
showToolbar()
})
tabexit2.setOnClickListener(View.OnClickListener {
hideToolbar()
})
tabexit.setOnClickListener(View.OnClickListener {
onSlideViewButtonClick(reading_toolbar!!)
})
}
fun buttonClicked(view: View) {
//if (!isDrawing) {
if (view.id == R.id.crayon_black) {
drawColor = Color.BLACK
} else if (view.id == R.id.crayon_blue) {
drawColor = Color.BLUE
} else if (view.id == R.id.crayon_green) {
drawColor = Color.GREEN
}
callDrawFragment(drawColor!!)
// }
// isDrawing = true
}
fun callDrawFragment(drawColor : Int) {
val mFragment = DrawingFragment.newInstance(drawColor)
fragmentManager!!
.beginTransaction()
.replace(R.id.mainreadinglayout, mFragment)
.addToBackStack(null)
.commit()
}
}
DrawingFragment
class DrawingFragment: Fragment() {
var drawColor : Int? = null
var drawingView : DrawingView? = null
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
val view = inflater.inflate(R.layout.drawing_layout, container, false)
val relativeLayout = view.findViewById(R.id.draw_layout) as RelativeLayout
drawColor = arguments.getInt("color")
var drawingView = DrawingView(activity, drawColor!!)
relativeLayout.addView(drawingView)
changeColor(drawingView)
return view
}
fun changeColor(view: DrawingView) {
var currentPaint = Paint()
currentPaint.setColor(Color.CYAN)
currentPaint.isAntiAlias = true
currentPaint.isDither = true
currentPaint.style = Paint.Style.STROKE
currentPaint.strokeJoin = Paint.Join.ROUND
currentPaint.strokeCap = Paint.Cap.ROUND
currentPaint.strokeWidth = 10f
view.setPaint(currentPaint)
}
companion object {
fun newInstance(color: Int): DrawingFragment {
val args = Bundle()
args.putInt("color", color)
val fragment = DrawingFragment()
fragment.arguments = args
return fragment
}
}
}
DrawingView
class DrawingView(context: Context, color : Int) : View(context) {
var mPaint: Paint? = null
val mPath: Path
init {
mPaint = Paint()
mPaint!!.isAntiAlias = true
mPaint!!.isDither = true
mPaint!!.color = color
mPaint!!.style = Paint.Style.STROKE
mPaint!!.strokeJoin = Paint.Join.ROUND
mPaint!!.strokeCap = Paint.Cap.ROUND
mPaint!!.strokeWidth = 10f
mPath = Path()
}
override fun onDraw(canvas: Canvas) {
canvas.drawPath(mPath, mPaint)
super.onDraw(canvas)
canvas.drawColor(Color.TRANSPARENT)
}
fun setPaint(mPaint: Paint) {
this.mPaint = mPaint
return
}
override fun onTouchEvent(event: MotionEvent): Boolean {
when (event.action) {
MotionEvent.ACTION_DOWN -> mPath.moveTo(event.x, event.y)
MotionEvent.ACTION_MOVE -> {
mPath.lineTo(event.x, event.y)
invalidate()
}
MotionEvent.ACTION_UP -> {
}
}
return true
}
}
I figured this out by referencing the activity's buttons from the fragment.
var btn_black = (getActivity()).findViewById(R.id.crayon_black) as ImageView
var btn_blue = (getActivity()).findViewById(R.id.crayon_blue) as ImageView
var btn_green = (getActivity()).findViewById(R.id.crayon_green) as ImageView
And then setting the onclick listeners in the fragment
btn_black.setOnClickListener(View.OnClickListener {
changeColor(drawingView, Color.BLACK)
})
btn_blue.setOnClickListener(View.OnClickListener {
changeColor(drawingView, Color.BLUE)
})
btn_green.setOnClickListener(View.OnClickListener {
changeColor(drawingView, Color.GREEN)
})
And then re-setting the onclicklisteners on the activity on backpressed. I also had a booleanTag to indicate if the fragment is up or not.
override fun onBackPressed() {
setColorOnClickListeners()
booleanTag = "false"
crayon_black.setTag(booleanTag)
if (mCurlView!!.getIsUp()) {
slideDown(reading_toolbar!!)
mCurlView!!.setIsUp(!isUp)
}
super.onBackPressed()
}
The setcolorOnClicklistener() is as follows:
fun setColorOnClickListeners() {
crayon_black.setOnClickListener(View.OnClickListener {
buttonClicked(crayon_black)
})
crayon_blue.setOnClickListener(View.OnClickListener {
buttonClicked(crayon_blue)
})
// etc...
}
buttonClicked:
fun buttonClicked(view: View) {
booleanTag = crayon_black.tag as String
if (booleanTag == "false") {
if (view.id == R.id.crayon_black) {
drawColor = Color.BLACK
} else if (view.id == R.id.crayon_blue) {
drawColor = Color.BLUE
} else if (view.id == R.id.crayon_green) {
drawColor = Color.GREEN
} else if (view.id == R.id.crayon_orange) {
drawColor = Color.parseColor("#FFA500")
} else if (view.id == R.id.crayon_pink) {
drawColor = Color.parseColor("#ec5db8")
} else if (view.id == R.id.crayon_red) {
drawColor = Color.RED
} else if (view.id == R.id.crayon_violet) {
drawColor = Color.parseColor("#8862ba")
} else if (view.id == R.id.crayon_white) {
drawColor = Color.WHITE
} else if (view.id == R.id.crayon_yellow) {
drawColor = Color.YELLOW
}
callDrawFragment(drawColor!!)
booleanTag = "true"
crayon_black.setTag(booleanTag)
}
}
Still need to handle some things on the DrawingView for the color change but this solved most of my problems.
I have cursor returned by an SQLite query, I would like to know correct approach for creating an Observable the emits each row in the cursor.
I created cursor observable as follows, please check if this is the correct:
Observable<Cursor> cursorObservable = Observable.create(new ObservableOnSubscribe<Cursor>() {
#Override
public void subscribe(ObservableEmitter<Cursor> e) throws Exception {
SQLDbHelper dbHelper = SQLDbHelper.getInstance(ctx);
SQLiteDatabase db = dbHelper.getReadableDatabase();
Cursor cursor = db.rawQuery("select * from " + MoviesContract.MovieEntry.TABLE_NAME, null);
if (cursor != null) {
try {
while (cursor.moveToNext() && !e.isDisposed()) {
e.onNext(cursor);
}
} catch (Exception exception) {
e.onError(exception);
} finally {
cursor.close();
}
}
if (!e.isDisposed()) {
e.onComplete();
}
}
});
I thank that you will have better results wrapping the rows into a Map and passing it through the stream than passing cursor itself.
class SimpleTest {
#Test
fun testCursorStream() {
val cursor = fakeCursor()
val stream = getCursorStream(cursor)
stream.subscribe {
Log.d("Test", it.entries.toString())
}
}
private fun fakeCursor() : Cursor {
val columns = arrayOf("id", "name", "age")
val cursor = MatrixCursor(columns)
val row1 = arrayOf(1, "Rodrigo", 26L)
val row2 = arrayOf(2, "Lucas", 23L)
val row3 = arrayOf(3, "Alan", 26L)
cursor.addRow(row1)
cursor.addRow(row2)
cursor.addRow(row3)
return cursor
}
private fun getCursorStream(cursor: Cursor) : Observable<Map<String, Any?>> {
return Observable.create<Map<String, Any?>> {
try {
if (!cursor.moveToFirst()) {
it.onCompleted()
return#create
}
val row = HashMap<String, Any?>()
do {
val lastColumnIndex = cursor.columnCount - 1
for (index in 0..lastColumnIndex) {
val name = cursor.getColumnName(index)
val type = cursor.getType(index)
when (type) {
Cursor.FIELD_TYPE_STRING -> row.put(name, cursor.getString(index))
Cursor.FIELD_TYPE_BLOB -> row.put(name, cursor.getBlob(index))
Cursor.FIELD_TYPE_FLOAT -> row.put(name, cursor.getFloat(index))
Cursor.FIELD_TYPE_INTEGER -> row.put(name, cursor.getInt(index))
Cursor.FIELD_TYPE_NULL -> row.put(name, null)
}
}
it.onNext(row)
} while (cursor.moveToNext())
it.onCompleted()
} catch (e: Exception) {
it.onError(e)
}
}
}
}
Hope that it helps.