Use interface to pass data in Kotlin - interface

I need to pass data to class from activity. I use interface, but i have problem with initialization.
My class:
class Methods {
fun processingResponse(finalMessage: String) {
var mcontext: Context? = null
var message : Message = Message()
var access = "Access Granted"
var out = "Logged"
var Stateconnect = false
var safetyCheck = 0
if (access in finalMessage) {
val msg = finalMessage.split("=", ":")
accessLevel = msg[0]
sessionId = msg[1].toInt()
safetyCheck = msg[2].toInt()
var namePlc = msg[3]
interfaceData.sendData("Connect")
//Stateconnect = true
} else if (out in finalMessage) {
interfaceData.sendData("Disconnect")
println("log out okey")
}
}}
My interface:
interface SendDataInterface {fun sendData(str: String )}
and My activity:
class LoginIn : AppCompatActivity(), SendDataInterface {
override fun sendData(str: String)
{
var handler = Handler(Looper.getMainLooper())
handler.post( Runnable() {
fun run() {
buttonChange(str)
}
})} fun buttonChange(str : String) {
if (str == "Connect") {
Connection.setBackgroundColor(Color.RED)
Connection.setText("Disconnection")
loadMaintenancePage()
} else if (str == "Disconnect") {
Connection.setBackgroundColor(Color.GREEN)
Connection.setText("Connection")
}
}
}
The error that i have is the interface isn't initialize.
How I can initialize the interface?

You have to create an instance of SendDataInterface in your class Methods.

var interfaceData:SendDtaInterface=Object:SendDtaInterface{
override fun sendData("Connect"){
}
}
interfaceData.sendDat("connect")enter code here

Related

How to print from class with no print lines in class

I am trying to print by making it a string in the class. I am trying not to have any print lines in the class at all. I can't figure out how to not have the print lines in my printBoard method.
class MakeString() {
fun printThis(): String {
var line = arrayOf("hello","printMe")
var addThis = "there"
for (element in array) {
println()
}
return line.toString()
}
override fun toString(): String {
return """
${printThis()}
""".trimIndent()
}
}
You can use a StringBuilder to build the output string:
class Puzzle(var rows :Int,var cols: Int) {
fun printBoard(): String {
var emptyCell = '.'
var board = Array(rows) { Array(cols) { emptyCell } }
val builder = StringBuilder()
for (row in 0 until board.size) {
for (col in 0 until board[row].size) {
builder.append(board[row][col])
}
builder.append('\n')
}
return builder.toString()
}
override fun toString(): String {
return """
${printBoard()}
""".trimIndent()
}
}
fun main () {
var wordss = Puzzle(45, 45)
println(wordss.printBoard())
}

How I can update my adapter for RecyclerView after change my LiveData?

I created a fragment that in the onActivityCreated method fetches Firebase data by limiting the query to a calendar date. Then I place Observers on my LiveData that are inside my ViewModel and that will deliver the list to my Adapter.
If I add, remove or update items in the same list, the changes are sent to firebase and the adapter reflects them on the screen. It works ok.
But, I am trying to develop a filter button, which will basically change the deadline date for the Firebase query. When I select a particular filter, the viewModel needs to retrieve the data from Firebase limited to the filter date. This generates a new list, having a different size from the previous one.
However, when the query occurs, the Adapter's getItemCount() method stores the size of the last list. This fact confuses the Adapter and the functions notifyItemInserted and notifyItemRemoved end up making confusing animations on the screen after changing the filter. I dont know whats is wrong.
How can I correctly observes LiveData and tell the adapter? Am I making a mistake in the MVVM architecture or forgetting some function?
My Fragment:
class HistoryFragment : Fragment(), OnItemMenuRecyclerViewClickListener {
private lateinit var mSecurityPreferences: SecurityPreferences
private lateinit var viewModel: BalancesViewModel
private lateinit var adapter: BalancesAdapter
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
setHasOptionsMenu(true)
viewModel = ViewModelProvider(this).get(BalancesViewModel::class.java)
adapter = BalancesAdapter(requireContext())
mSecurityPreferences = SecurityPreferences(requireContext())
return inflater.inflate(R.layout.fragment_history, container, false)
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
setupFilter()
//Setup adapter
adapter.listenerMenu = this
recycler_view_history.adapter = adapter
//Fetch data based in filter by date
viewModel.fetchBalances(mSecurityPreferences.getStoredLong(FILTER_DATE))
// Put logic to listen RealTimeUpdates
viewModel.getRealTimeUpdates(mSecurityPreferences.getStoredLong(FILTER_DATE))
viewModel.balances.observe(viewLifecycleOwner, Observer {
adapter.setBalances(it)
})
viewModel.balance.observe(viewLifecycleOwner, Observer {
adapter.addBalance(it)
})
}
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
inflater.inflate(R.menu.history_menu_filter, menu)
super.onCreateOptionsMenu(menu, inflater)
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
R.id.item_menu_filter_this_month -> {
updateFilter(THIS_MONTH)
}
R.id.item_menu_filter_two_months -> {
updateFilter(TWO_MONTHS)
}
R.id.item_menu_filter_last_six_months -> {
updateFilter(LAST_SIX_MONTHS)
}
R.id.item_menu_filter_all -> {
updateFilter(ALL_MONTHS)
}
}
return super.onOptionsItemSelected(item)
}
private fun setupFilter() {
var filterOption = mSecurityPreferences.getStoredLong(FILTER_DATE)
if (filterOption == 0L){
filterOption = HandleDate.getLongToFilter(LAST_SIX_MONTHS)
mSecurityPreferences.storeLong(FILTER_DATE, filterOption)
}
}
private fun updateFilter(filterOption: Int){
val newFilterOption = HandleDate.getLongToFilter(filterOption)
mSecurityPreferences.storeLong(FILTER_DATE, newFilterOption)
updateUI()
}
private fun updateUI(){
viewModel.fetchBalances(mSecurityPreferences.getStoredLong(FILTER_DATE))
viewModel.getRealTimeUpdates(mSecurityPreferences.getStoredLong(FILTER_DATE))
}
}
My ViewModel:
class BalancesViewModel : ViewModel() {
private val userReference = FirebaseAuth.getInstance().currentUser!!.uid
private val dbUserReference = FirebaseDatabase.getInstance().getReference(userReference)
private val _balances = MutableLiveData<List<Balance>>()
val balances: LiveData<List<Balance>>
get() = _balances
private val _balance = MutableLiveData<Balance>()
val balance: LiveData<Balance>
get() = _balance
private val _result = MutableLiveData<Exception?>()
val result: LiveData<Exception?>
get() = _result
fun addBalance(balance: Balance) {
balance.id = dbUserReference.push().key
dbUserReference.child(NODE_BALANCES).child(balance.id!!).setValue(balance)
.addOnCompleteListener {
if (it.isSuccessful) {
_result.value = null
} else {
_result.value = it.exception
}
}
}
private val childEventListener = object : ChildEventListener {
override fun onCancelled(error: DatabaseError) {
}
override fun onChildMoved(snapshot: DataSnapshot, p1: String?) {
}
override fun onChildChanged(snapshot: DataSnapshot, p1: String?) {
val balance = snapshot.getValue(Balance::class.java)
balance?.id = snapshot.key
_balance.value = balance
}
override fun onChildAdded(snapshot: DataSnapshot, p1: String?) {
val balance = snapshot.getValue(Balance::class.java)
balance?.id = snapshot.key
_balance.value = balance
}
override fun onChildRemoved(snapshot: DataSnapshot) {
val balance = snapshot.getValue(Balance::class.java)
balance?.id = snapshot.key
balance?.isDeleted = true
_balance.value = balance
}
}
fun getRealTimeUpdates(longLimitDate: Long) {
dbUserReference.child(NODE_BALANCES).orderByChild(COLUMN_DATE_MILLI)
.startAt(longLimitDate.toDouble()).addChildEventListener(childEventListener)
}
fun fetchBalances(longLimitDate: Long) {
dbUserReference.child(NODE_BALANCES).orderByChild(COLUMN_DATE_MILLI)
.startAt(longLimitDate.toDouble())
.addListenerForSingleValueEvent(object : ValueEventListener {
override fun onCancelled(error: DatabaseError) {}
override fun onDataChange(snapshot: DataSnapshot) {
if (snapshot.exists()) {
val listBalances = mutableListOf<Balance>()
for (balanceSnapshot in (snapshot.children)) {
val balance = balanceSnapshot.getValue(Balance::class.java)
balance?.id = balanceSnapshot.key
balance?.let { listBalances.add(it) }
}
listBalances.sortByDescending { it.dateMilli }
_balances.value = listBalances
}
}
})
}
fun updateBalance(balance: Balance) {
dbUserReference.child(NODE_BALANCES).child(balance.id!!).setValue(balance)
.addOnCompleteListener {
if (it.isSuccessful) {
_result.value = null
} else {
_result.value = it.exception
}
}
}
fun deleteBalance(balance: Balance) {
dbUserReference.child(NODE_BALANCES).child(balance.id!!).setValue(null)
.addOnCompleteListener {
if (it.isSuccessful) {
_result.value = null
} else {
_result.value = it.exception
}
}
}
My Adapter:
class BalancesAdapter(private val context: Context) :
RecyclerView.Adapter<BalancesAdapter.BalanceViewModel>() {
private var balances = mutableListOf<Balance>()
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) =
BalanceViewModel(
LayoutInflater.from(parent.context)
.inflate(R.layout.item_recyclerview_balance, parent, false)
)
override fun getItemCount() = balances.size
override fun onBindViewHolder(holder: BalanceViewModel, position: Int) {
holder.view.text_view_value_balance_item.text = balances[position].value
holder.view.text_view_date_item.text = balances[position].date
}
fun setBalances(balances: List<Balance>) {
this.balances = balances as MutableList<Balance>
notifyDataSetChanged()
}
fun addBalance(balance: Balance) {
val index = balances.indexOf(balance)
if (!balances.contains(balance)) {
balances.add(balance)
notifyItemInserted(index)
} else {
if (balance.isDeleted) {
balances.removeAt(index)
notifyItemRemoved(index)
} else {
balances[index] = balance
}
}
notifyItemRangeChanged(index, itemCount)
}
class BalanceViewModel(val view: View) : RecyclerView.ViewHolder(view)
}
Tnks for your attention.
Okay, it's been 4 days since I asked this question and after feeling a little frustrated with the project I come back here on StackOverFlow to post my own answer.
The problematic issue within the code I showed is in my Adapter's addBalance method.
When I created the Balance data model, I set the isDeleted attribute to identify that it was deleted. Upon entering Firebase it receives a NULL value and therefore it ceases to exist.
Then, as I have two listeners (one defined in the addListenerForSingleValueEvent method and the other defined in the addChildEventListener method), one ends up triggering the other when there is a change in the Firebase data, but I don't want to go into detail on that issue. The fact is that I checked that my addBalance method was being called after I deleted an object, causing that object to be inserted back into the Adapter's data list, even before the removal operation ended in Firebase.
So I changed the logic of my method to make sure that my object was deleted and only included it in my Adapter list after checking the isDeleted attribute.
fun dealWithBalance(balance: Balance){
val index = balances.indexOf(balance)
if(balance.isDeleted && balances.contains(balance)){
balances.removeAt(index)
notifyItemRemoved(index)
} else if(!balance.isDeleted && !balances.contains(balance)){
balances.add(balance)
} else if(index >= 0){
balances[index] = balance
notifyItemChanged(index)
}
}
I renamed addBalance to dealWithBalance...

How to have Error Type inference for a throwing function in a protocol

Is there a way to create a throwing function with a specified Error sub type that will be thrown? Below code is an example of how I'd like it to be.
protocol ValidatorError: Error {
var somePrintableThingy: String { get }
}
protocol Validator {
associatedType T
var model: T { get set }
init(model: T)
func validate() throws where Error: ValidatorError
}
Example Use Case
class SomeModelErrorNotValidatorError: Error {
case invalidUsername
}
class SomeModelError: ValidatorError {
case invalidUsername
var somePrintableThingy: String {
switch self { case .invalidUsername: return "haha" }
}
}
class SomeModel {
var username: String = ""
init(username: String) { self.username = username }
}
class SomeModelValidator: Validator {
var model: SomeModel
init(model: SomeModel) { self.model = model }
func validate() throws {
guard self.model.username.isEmpty else {
// this line should be fine
throw SomeModelError.invalidUsername
// if i replace it with this line it should not be fine
throw SomeModelErrorNotValidatorError.invalidUsername
}
}
}
class SomeModelViewController: UIViewController {
// .. some other codes here
func buttonClicked(_ sender: Any? = nil) {
let model = SomeModel(username: self.txtUsername.text ?? "")
let validator = SomeModelValidator(model: model)
do {
try validator.validate()
} catch let error {
// since I already know that this is a `SomeModelError`
// I could just do this
print(error.somePrintableThingy)
}
}
}
PS: The possible workaround for this is to create a non throwing function with a callback but I don't want to do that
PS PS: Another possible workaround for this would be to use a linting tool, but that's too much.

How to update a global variable in Swift by reference?

My question is simple in the C language, just access the global variable using access with a pointer -
demoFunc(int *someVar) {
*someVar = 1234;
return;
}
How do you do this in Swift? For simplicity and clarity, how do you do this for the following code?
class Example {
var globalInt : Int = 0;
func someMain() {
self.modifyVar(?&globalInt?); //Q: How do you do this?
return;
}
func modifyVar(?&someVar?) { //Q: ?
someVar = 1234; //Q: ?
return;
}
}
This code:
var toto = 3
class Example {
var globalInt = 0
func someMain() {
self.modifyVar(&globalInt)
}
func modifyVar(inout someVar: Int) {
someVar = 1234
}
}
let vc = Example()
print(vc.globalInt)
vc.someMain()
print(vc.globalInt)
print(toto)
vc.modifyVar(&toto)
print(toto)
produces
0
1234
3
1234

get the type/class of a property from its name in swift

Lets say I have this class:
class Node {
var value: String
var children: [Node]?
}
If I have the name of one of its properties (for example "children") how can I get its type? (In this case [Node]?)
I imagine having a global function like below will solve my needs:
func typeOfPropertyWithName(name: String, ofClass: AnyClass) -> AnyClass? {
//???
}
// Example usage:
var arrayOfNodesClass = typeOfPropertyWithName("children", Node.self)
Swift 2 (Note: Reflection changed):
import Foundation
enum PropertyTypes:String
{
case OptionalInt = "Optional<Int>"
case Int = "Int"
case OptionalString = "Optional<String>"
case String = "String"
//...
}
extension NSObject{
//returns the property type
func getTypeOfProperty(name:String)->String?
{
let type: Mirror = Mirror(reflecting:self)
for child in type.children {
if child.label! == name
{
return String(child.value.dynamicType)
}
}
return nil
}
//Property Type Comparison
func propertyIsOfType(propertyName:String, type:PropertyTypes)->Bool
{
if getTypeOfProperty(propertyName) == type.rawValue
{
return true
}
return false
}
}
custom class:
class Person : NSObject {
var id:Int?
var name : String?
var email : String?
var password : String?
var child:Person?
}
get the type of the "child" property:
let person = Person()
let type = person.getTypeOfProperty("child")
print(type!) //-> Optional<Person>
property type checking:
print( person.propertyIsOfType("email", type: PropertyTypes.OptionalInt) ) //--> false
print( person.propertyIsOfType("email", type: PropertyTypes.OptionalString) //--> true
or
if person.propertyIsOfType("email", type: PropertyTypes.OptionalString)
{
//true -> do something
}
else
{
//false -> do something
}
Reflection is achieved in Swift using the global reflect() function. When passing an instance of some type to reflect() it returns a MirrorType, which has a range of properties allowing you to analyze your instance:
var value: Any { get }
var valueType: Any.Type { get }
var objectIdentifier: ObjectIdentifier? { get }
var count: Int { get }
var summary: String { get }
var quickLookObject: QuickLookObject? { get }
var disposition: MirrorDisposition { get }
subscript(i: Int) -> (String, MirrorType) { get }
This seems to work:
func getTypeOfVariableWithName(name: String, inInstance instance: Any) -> String? {
let mirror = reflect(instance)
var variableCollection = [String: MirrorType]()
for item in 0..<mirror.count {
variableCollection[mirror[item].0] = mirror[item].1
}
if let type = variableCollection[name] {
let longName = _stdlib_getDemangledTypeName(type.value)
let shortName = split(longName, { $0 == "."}).last
return shortName ?? longName
}
return nil
}
Here's some example code on SwiftStub.
Edit:
The result for optional values is only "Optional".
The result for arrays is only "Array".
The result for dictionaries is only "Dictionary".
I'm not sure if it is possible to extract what kind of optional/array/dictionary it is. But I guess this would also be the case for custom data structures using generics.
Building on #PeterKreinz answer I needed to be able to check types of inherited properties as well so added a little to his above code:
extension NSObject {
// Returns the property type
func getTypeOfProperty (name: String) -> String? {
var type: Mirror = Mirror(reflecting: self)
for child in type.children {
if child.label! == name {
return String(child.value.dynamicType)
}
}
while let parent = type.superclassMirror() {
for child in parent.children {
if child.label! == name {
return String(child.value.dynamicType)
}
}
type = parent
}
return nil
}
}
Hope this may help someone.
Swift 3 update:
// Extends NSObject to add a function which returns property type
extension NSObject {
// Returns the property type
func getTypeOfProperty (_ name: String) -> String? {
var type: Mirror = Mirror(reflecting: self)
for child in type.children {
if child.label! == name {
return String(describing: type(of: child.value))
}
}
while let parent = type.superclassMirror {
for child in parent.children {
if child.label! == name {
return String(describing: type(of: child.value))
}
}
type = parent
}
return nil
}
}
The solution provided by #peter-kreinz using Swift's class Mirror works beautifully when you have an instance of a class, and want to know the types of the properties. However if you want to inspect the properties of a class without having an instance of it you might be interested in my solution.
I have a solution that finds the name and type of a property given any class that inherits from NSObject.
I wrote a lengthy explanation on StackOverflow here, and my project is available here on Github,
In short you can do something like this (but really check out the code Github):
public class func getTypesOfProperties(inClass clazz: NSObject.Type) -> Dictionary<String, Any>? {
var count = UInt32()
guard let properties = class_copyPropertyList(clazz, &count) else { return nil }
var types: Dictionary<String, Any> = [:]
for i in 0..<Int(count) {
guard let property: objc_property_t = properties[i], let name = getNameOf(property: property) else { continue }
let type = getTypeOf(property: property)
types[name] = type
}
free(properties)
return types
}