I'm facing following Errors/Exceptions when receiving data from one App to another App in Kotlin (Android):
Class Not Found When Unmarshalling: com.example.Parcelable.User
mExtras=Bundle[{)}]
mParcelledData=null
mMap=size 0
Also, In MainActivtiy: if(intent.hasExtra("USER")) statement giving error and displaying Toast message written in Else statement.
Please help me how I can resolve these exceptions ? Thanks a Lot!
(SendingApp File) -> MainActivity.kt
btnSendData1.setOnClickListener {
val intent = Intent(Intent.ACTION_SEND).setType("text/plain")
intent.component =
ComponentName.unflattenFromString("com.example.receive")
val args = Bundle()
args.putParcelable(USER_KEY, User("Ahmer", "28"))
intent.putExtras(args)
Log.d("Ahmer", args.toString())
startActivity(Intent.createChooser(intent, "Share to..."))
}
(ReceivingApp File) -> MainActivity.kt
class MainActivity : AppCompatActivity() {
private lateinit var textView: TextView
#SuppressLint("SetTextI18n")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
textView = findViewById(R.id.tv_username)
when (intent?.action) {
Intent.ACTION_SEND -> {
if ("text/plain" == intent.type) {
handleSendText(intent)
} else {
Toast.makeText(this, "No Text", Toast.LENGTH_SHORT).show()
}
}
}
}
#SuppressLint("SetTextI18n")
private fun handleSendText(intent: Intent) {
if (intent.extras != null) {
if (intent.hasExtra("USER")) {
Log.d("Intent", intent.toString())
val bundle = intent.extras
val user = bundle?.getParcelable<User>("USER") as User
textView.text = "${user.name}${user.age}"
} else {
Toast.makeText(this, "Has Extras Null", Toast.LENGTH_SHORT).show()
}
} else {
Toast.makeText(this, "Extras Null", Toast.LENGTH_SHORT).show()
}
}
}
(ReceivingApp File) -> User.kt
package com.example.receive
import android.os.Parcelable
import kotlinx.android.parcel.Parcelize
#Parcelize
data class User(
var name: String,
var age: String
) : Parcelable
Related
Android 12 Location updates not working when app is on background. and work fine when app is on forground.
I also "allow all time" permission for for location. Acc to docs after this location updates start work on background. but in my case it stop updates when app is on foreground.
locationUpdatePendingIntent
private val locationUpdatePendingIntent: PendingIntent by lazy {
val intent = Intent(context, LocationUpdatesBroadcastReceiver::class.java)
intent.action = LocationUpdatesBroadcastReceiver.ACTION_PROCESS_UPDATES
PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_MUTABLE)
}
Firstly I use Location Request. inside Automatic Workmanager
val mLocationRequest = LocationRequest.Builder(Priority.PRIORITY_HIGH_ACCURACY, 0L)
.setWaitForAccurateLocation(false)
.build()
if (ActivityCompat.checkSelfPermission(
context.applicationContext,
Manifest.permission.ACCESS_FINE_LOCATION
) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(
context,
Manifest.permission.ACCESS_COARSE_LOCATION
) != PackageManager.PERMISSION_GRANTED
) {
return Result.success();
}
fusedLocationProviderClient?.requestLocationUpdates(
mLocationRequest,
locationUpdatePendingIntent
)
then listen to location updates used inside Automatic Workmanager
override fun onLocationUpdate(location: Location) {
val executor: ExecutorService = Executors.newSingleThreadExecutor()
executor.execute {
lastLocation = location
updateLocation()
}
}
Location update broadcast (in this location update)
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.location.Location
import android.util.Log
import com.google.android.gms.location.LocationAvailability
import com.google.android.gms.location.LocationResult
class LocationUpdatesBroadcastReceiver: BroadcastReceiver() {
private val TAG = "LocationUpdatesBroadcas";
override fun onReceive(context: Context?, intent: Intent?) {
Log.d(TAG, "onReceive() context:$context, intent:$intent")
if (intent?.action == ACTION_PROCESS_UPDATES) {
// Checks for location availability changes.
LocationAvailability.extractLocationAvailability(intent)?.let { locationAvailability ->
if (!locationAvailability.isLocationAvailable) {
Log.d(TAG, "Location services are no longer available!")
}
}
LocationResult.extractResult(intent)?.let { locationResult ->
Log.e(TAG, "onReceive: lastLocation ${locationResult.locations.size}", )
if(locationResult.lastLocation != null){
ShareLocationToAutomaticWorker.INSTANCE?.reciveLocation(locationResult.lastLocation!!)
}
}
}
}
companion object {
const val ACTION_PROCESS_UPDATES =
"action." +
"PROCESS_UPDATES"
}
interface UpdatedLocation{
fun onLocationUpdate(location: Location)
}
}
class ShareLocationToAutomaticWorker(var updateLocation: LocationUpdatesBroadcastReceiver.UpdatedLocation){
private val TAG = "LocationUpdatesBroadcas"
fun reciveLocation( location:Location){
Log.e(TAG, "reciveLocation:--- ${location} " )
updateLocation.onLocationUpdate(location)
}
companion object {
var INSTANCE: ShareLocationToAutomaticWorker? = null
fun getInstance(updateLocation: LocationUpdatesBroadcastReceiver.UpdatedLocation): ShareLocationToAutomaticWorker {
return INSTANCE ?: synchronized(this) {
INSTANCE ?: ShareLocationToAutomaticWorker(
updateLocation )
.also { INSTANCE = it }
}
}
}
}
I fixed this issue by changing "AutomaticLocationWorker" to "AutomaticLocationBackgroundService:LifecycleService()" or change worker to lifecycleService.
private var fusedLocationProviderClient: FusedLocationProviderClient? = null
private val locationUpdatePendingIntent: PendingIntent by lazy {
val intent = Intent(this, LocationUpdatesBroadcastReceiver::class.java)
intent.action = LocationUpdatesBroadcastReceiver.ACTION_PROCESS_UPDATES
PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_MUTABLE)
}
fusedLocationProviderClient?.requestLocationUpdates(
mLocationRequest,
locationUpdatePendingIntent
)
LocationUpdatesBroadcastReceiver
class LocationUpdatesBroadcastReceiver: BroadcastReceiver() {
private val TAG = "LocationUpdatesBroadcas";
override fun onReceive(context: Context?, intent: Intent?) {
Log.d(TAG, "onReceive() context:$context, intent:$intent")
if (intent?.action == ACTION_PROCESS_UPDATES) {
// Checks for location availability changes.
LocationAvailability.extractLocationAvailability(intent)?.let { locationAvailability ->
if (!locationAvailability.isLocationAvailable) {
Log.d(TAG, "Location services are no longer available!")
}
}
LocationResult.extractResult(intent)?.let { locationResult ->
Log.e(TAG, "onReceive: lastLocation ${locationResult.locations.size}", )
if(locationResult.lastLocation != null){
ShareLocationToAutomaticWorker.INSTANCE?.reciveLocation(locationResult.lastLocation!!)
}
}
}
}
companion object {
const val ACTION_PROCESS_UPDATES =
"com.commuteoptm.bcos.background_services.action." +
"PROCESS_UPDATES"
}
interface UpdatedLocation{
fun onLocationUpdate(location: Location)
}
}
ShareLocationToAutomaticWorker
class ShareLocationToAutomaticWorker(var updateLocation: LocationUpdatesBroadcastReceiver.UpdatedLocation){
private val TAG = "LocationUpdatesBroadcas"
fun reciveLocation( location:Location){
Log.e(TAG, "reciveLocation:--- ${location} " )
updateLocation.onLocationUpdate(location)
}
companion object {
var INSTANCE: ShareLocationToAutomaticWorker? = null
fun getInstance(updateLocation: LocationUpdatesBroadcastReceiver.UpdatedLocation): ShareLocationToAutomaticWorker {
return INSTANCE ?: synchronized(this) {
INSTANCE ?: ShareLocationToAutomaticWorker(
updateLocation )
.also { INSTANCE = it }
}
}
}
}
How to scan barcode lines with VARCHAR Chars For example OfficeEqp35023U11 In android Kotlin
Struggling to scan this asset image
Struggling to scan this asset image
class BarcodeScannerActivity : AppCompatActivity(), ZXingScannerView.ResultHandler {
private var mScannerView: ZXingScannerView? = null
lateinit var apiInterface: APIInterface
public override fun onCreate(state: Bundle?) {
super.onCreate(state)
setContentView(R.layout.activity_barcode_scanner)
ssoId = intent.getStringExtra("initiator")
val contentFrame = findViewById<View>(R.id.content_frame) as ViewGroup
mScannerView = ZXingScannerView(this)
contentFrame.addView(mScannerView)
}
public override fun onResume() {
super.onResume()
mScannerView!!.setResultHandler(this)
mScannerView!!.startCamera()
}
public override fun onPause() {
super.onPause()
mScannerView!!.stopCamera()
}
override fun handleResult(rawResult: Result) {
Toast.makeText(
this, "Contents = " + rawResult.text +
", Format = " + rawResult.barcodeFormat.toString(), Toast.LENGTH_SHORT
).show()
var result = rawResult.text
if (result.isDigitsOnly()) {
assetTag = result.filter { it.isLetterOrDigit() }
mScannerView!!.stopCamera()
apiInterface = APIClient.client!!.create(APIInterface::class.java)
val call: Call<Verifiedd> =
apiInterface.saveVerification(assetTag, ssoId, ssoId, "Verified", "Verified")
call.enqueue(object : Callback<Verifiedd> {
override fun onResponse(call: Call<Verifiedd>, response: Response<Verifiedd>) {
if (response.body() != null) {
lovelyProgressDialog?.dismiss()
Log.d("TAG", response.code().toString() + "")
var displayResponse = ""
val resource: Verifiedd = response.body()!!
responseCode = resource.responseCode
responseMessage = resource.responseMessage
if (responseMessage == "Data persisted successfully " || responseMessage.equals(
"Data persisted successfully "
)
) {
Toasty.normal(
this#BarcodeScannerActivity,
"",
Toasty.LENGTH_LONG
).show()
} else if (responseMessage == "" || responseMessage.equals(
""
)
) {
Toasty.normal(
this#BarcodeScannerActivity,
"Invalid Asset Verification status values",
Toasty.LENGTH_LONG
).show()
val intent =
Intent(this#BarcodeScannerActivity, BranchItemsActivity::class.java)
intent.flags =
Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
intent.putExtra(
"initiator", ssoId
)
startActivity(intent)
}
}
}
override fun onFailure(call: Call<Verifiedd>, t: Throwable) {
Toasty.normal(
this#BarcodeScannerActivity,
"Server Error",
Toasty.LENGTH_LONG
).show()
}
})
I'm assigning a value to lateinit varable in my first function and I want to access same value in my second function but gives me an error UninitializedPropertyAccessException. I know it is because of variable scope. My question is how can i access this value?
Here is my lateinit variables
lateinit var area:String
lateinit var zipcode:String
Here is my first function
fun showSearchDialog(view: View) {
val dialog = context?.let { Dialog(it) }
dialog?.requestWindowFeature(Window.FEATURE_NO_TITLE)
dialog?.setCancelable(true)
dialog?.setContentView(R.layout.alertdialog_search_layout)
//Initializing the views of the dialog.
val postalCode: TextInputEditText? = dialog?.findViewById(R.id.et_zip_code)
val sliderArea: Slider? = dialog?.findViewById(R.id.slider_area)
val searchButton: Button? = dialog?.findViewById(R.id.search_btn)
searchButton?.setOnClickListener {
if (sliderArea != null) {
area = sliderArea.value.toString()
}
zipcode = postalCode?.text.toString()
val postCodeUpperCase = postalCode?.text.toString().toUpperCase(Locale.ROOT)
if (zipcode.isEmpty()) {
postalCode?.error = "Please enter your post code"
postalCode?.requestFocus()
} else if (isValidZipCode(postCodeUpperCase)) {
postalCode?.error = "Please enter valid post code"
postalCode?.requestFocus()
} else {
if (isNetworkAvailable(requireContext())) {
viewModel.getSkipFilterList(zipcode, area)
Toast.makeText(context, "Valid postal code is = $zipcode", Toast.LENGTH_LONG).show()
}
else {
showAlertDialog(getString(R.string.no_internet))
}
}
//dialog.dismiss()
}
dialog?.show()
Here is my second Function
override fun inOnCreateView(mRootView: ViewGroup, savedInstanceState: Bundle?) {
val homeActivity = activity as HomeNavHostActivity
homeActivity.toolbar_id?.visibility = View.VISIBLE
homeActivity.toolbar_search_icon_id.visibility = View.VISIBLE
homeActivity.toolbar_add_icon_id.visibility = View.GONE
homeActivity.home_view_layout?.visibility = View.VISIBLE
homeActivity.bottom_layout?.visibility = View.VISIBLE
homeActivity.toolbar_title_tv.text = "Home"
homeActivity.toolbar_search_icon_id.setOnClickListener() {
showSearchDialog(mRootView)
}
homeActivity.cancel_text.setOnClickListener() {
homeActivity.search_layout.visibility = View.GONE
homeActivity.toolbar_title_tv.visibility = View.VISIBLE
homeActivity.search_view?.setQuery("", false)
homeActivity.search_view?.clearFocus()
}
val dialogHelper by inject<MaterialDialogHelper>()
setupProgressDialog(viewModel.showHideProgressDialog, dialogHelper)
if (isNetworkAvailable(requireContext())) {
viewModel.getSkipFilterList(zipcode, area)
// viewModel.getSkipHomeData()
} else {
showAlertDialog(getString(R.string.no_internet))
}
attachViewModel()
}
In the Adapter method. i am able to print list elements in updateUsers(newUsers: List)
that means I am getting dataset in the Adapter, but none of the Adapter methods are getting called.
I have set the layout manager too.
I have breakpoints for All adapter methods onCreateViewHolder, onBindViewHolder. but control is not entering code block.
class MainActivity : AppCompatActivity() {
lateinit var viewModel: ListViewModel
private val usersAdapter = UserListAdapter(arrayListOf(),this)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
viewModel = ViewModelProviders.of(this).get(ListViewModel::class.java)
viewModel.refresh()
usersList.apply {
layoutManager = LinearLayoutManager(this.context)
adapter = usersAdapter
}
usersList.adapter = usersAdapter
observeViewModel()
}
fun observeViewModel() {
viewModel.users.observe(this, Observer {
it?.let {
it.forEach {
Log.d("Each Item", it.toString());
}
loading_view.visibility = View.VISIBLE
usersAdapter.updateUsers(it)
}
})
viewModel.userLoadError.observe(this, Observer {
it?.let {
list_error.visibility = if (it) View.VISIBLE else View.GONE
}
})
viewModel.loading.observe(this, Observer {
it?.let {
loading_view.visibility = if (it) View.VISIBLE else View.GONE
if (it) {
list_error.visibility = View.GONE
usersList.visibility = View.GONE
}
}
})
}
}
class UserListAdapter(private var users: ArrayList<User>, private val context : Context) : RecyclerView.Adapter<UserListAdapter.UserViewHolder>() {
fun updateUsers(newUsers: List<User>) {
newUsers.forEach() {
Log.d("updateUsers", it.firstName)
}
users.clear()
users.addAll(newUsers)
notifyDataSetChanged()
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) : UserViewHolder{
val layoutInflator = LayoutInflater.from(parent.context)
val view = layoutInflator.inflate(R.layout.item_layout,parent,false)
return UserViewHolder(view)
}
override fun getItemCount():Int {
return users.size
}
override fun onBindViewHolder(holder: UserViewHolder, position: Int) {
holder.bind(users[position])
}
class UserViewHolder(view: View) : RecyclerView.ViewHolder(view) {
private val imageView = view.imageView
private val userName = view.name
private val userEmail = view.email
fun bind(country: User) {
userName.text = country.firstName + " " + country.lastName
userEmail.text = country.email
imageView.loadImage(country.avatar)
}
}
}
I am not exactly sure why your code is not working, here I have implemented using your code and it's working.
MainActivity
class MainActivity : AppCompatActivity() {
private lateinit var viewModel: ListViewModel
private val usersAdapter = UserListAdapter(arrayListOf(), this)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
viewModel = ViewModelProviders.of(this).get(ListViewModel::class.java)
viewModel.refresh()
usersList.apply {
layoutManager = LinearLayoutManager(this.context,
RecyclerView.VERTICAL, false)
adapter = usersAdapter
}
// usersList.adapter = usersAdapter // Don't need, you already set the
// adapter above.
observeViewModel()
}
private fun observeViewModel() {
viewModel.users.observe(this, Observer {
it?.let {
it.forEach {
Log.d("Each Item", it.toString());
}
//loading_view.visibility = View.VISIBLE
usersAdapter.updateUsers(it)
}
})
// commented for simplicity
//viewModel.userLoadError.observe(this, Observer {
// it?.let {
//list_error.visibility = if (it) View.VISIBLE else View.GONE
// }
//})
// viewModel.loading.observe(this, Observer {
// it?.let {
// loading_view.visibility = if (it) View.VISIBLE else View.GONE
// if (it) {
// list_error.visibility = View.GONE
// usersList.visibility = View.GONE
// }
//
// }
// })
}
}
UserListAdapter
class UserListAdapter(private var users: ArrayList<User>, private val context : Context) : RecyclerView.Adapter<UserListAdapter.UserViewHolder>() {
fun updateUsers(newUsers: List<User>) {
newUsers.forEach() {
Log.d("updateUsers", it.firstName)
}
users.clear()
users.addAll(newUsers)
notifyDataSetChanged()
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) : UserViewHolder {
val inflater = LayoutInflater.from(parent.context)
val view = inflater.inflate(R.layout.item_layout,parent,false)
return UserViewHolder(view)
}
override fun getItemCount():Int {
return users.size
}
override fun onBindViewHolder(holder: UserViewHolder, position: Int) {
holder.bind(users[position])
}
class UserViewHolder(view: View) : RecyclerView.ViewHolder(view) {
private val imageView = view.imageView
private val userName = view.name
private val userEmail = view.email
fun bind(country: User) {
userName.text = country.firstName + " " + country.lastName
userEmail.text = country.email
//imageView.loadImage(country.avatar)
}
}
}
ListViewModel
class ListViewModel: ViewModel() {
val users : MutableLiveData<List<User>> = MutableLiveData()
fun refresh() {
val userList = mutableListOf<User>()
userList.add(User(
"User1 First Name",
"User1 last Name",
"example#gmail.com"
))
userList.add(User(
"User2 First Name",
"User2 First Name",
"example#gmail.com"
))
userList.add(User(
"User3 First Name",
"User3 First Name",
"example#gmail.com"
))
userList.add(User(
"User4 First Name",
"User4 First Name",
"example#gmail.com"
))
userList.add(User(
"User5 First Name",
"User5 First Name",
"example#gmail.com"
))
userList.add(User(
"User6 First Name",
"User6 First Name",
"example#gmail.com"
))
users.value = userList
}
}
Hope this helps.
I am trying to run an application that I rewrote in Kotlin from the following link:
https://www.androidhive.info/RxJava/android-rxjava-networking-with-retrofit-gson-notes-app/
The example was originally code base was coded in Java. I am getting the following error upon running the application.
2018-11-16 12:12:38.173 11843-11843/com.touchsides.rxjavanetworking E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.touchsides.rxjavanetworking, PID: 11843
java.lang.RuntimeException: Unable to instantiate activity ComponentInfo{com.touchsides.rxjavanetworking/com.touchsides.rxjavanetworking.view.MainActivity}: java.lang.InstantiationException: java.lang.Class<com.touchsides.rxjavanetworking.view.MainActivity> cannot be instantiated
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2843)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3048)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1808)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:6669)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
Caused by: java.lang.InstantiationException: java.lang.Class<com.touchsides.rxjavanetworking.view.MainActivity> cannot be instantiated
at java.lang.Class.newInstance(Native Method)
at android.app.AppComponentFactory.instantiateActivity(AppComponentFactory.java:69)
at android.support.v4.app.CoreComponentFactory.instantiateActivity(CoreComponentFactory.java:43)
at android.app.Instrumentation.newActivity(Instrumentation.java:1215)
The MainActivity code is as follows:
abstract class MainActivity : AppCompatActivity()
{
lateinit var apiService: ApiService
var disposable = CompositeDisposable()
lateinit var mAdapter: NotesAdapter
var noteList = ArrayList<Note>()
companion object
{
val TAG = MainActivity::class.java.simpleName;
}
#BindView(R.id.coordinator_layout) var coordinatorLayout: CoordinatorLayout? = null
#BindView(R.id.recycler_view) var recyclerView: RecyclerView? = null
#BindView(R.id.txt_empty_notes_view) var noNotesView: TextView? = null
override fun onCreate(savedInstanceState: Bundle?)
{
super.onCreate(savedInstanceState)
getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
setContentView(R.layout.activity_main);
ButterKnife.bind(this);
val toolbar = findViewById<Toolbar>(R.id.toolbar)
toolbar.setTitle(getString(R.string.activity_title_home))
setSupportActionBar(toolbar)
fab.setOnClickListener { view ->
showNoteDialog(false, null, -1);
}
}
override fun onCreateOptionsMenu(menu: Menu): Boolean
{
// Inflate the menu; this adds items to the action bar if it is present.
menuInflater.inflate(R.menu.menu_main, menu)
return true
}
override fun onOptionsItemSelected(item: MenuItem): Boolean
{
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
return when (item.itemId)
{
R.id.action_settings -> true
else -> super.onOptionsItemSelected(item)
}
}
/**
* Registering new user
* sending unique id as device identification
* https://developer.android.com/training/articles/user-data-ids.html
*/
private fun registerUser()
{
// unique id to identify the device
val uniqueId = UUID.randomUUID().toString()
disposable.add(apiService.register(uniqueId).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribeWith(
object : DisposableSingleObserver<User>()
{
override fun onSuccess(user: User)
{
// Storing user API Key in preferences
user.apiKey?.let { PrefUtils.storeApiKey(applicationContext, it) }
Toast.makeText(applicationContext,
"Device is registered successfully! ApiKey: " + PrefUtils.getApiKey(applicationContext),
Toast.LENGTH_LONG).show()
}
override fun onError(e: Throwable)
{
Log.e(TAG, "onError: " + e.message)
showError(e)
}
}))
}
/**
* Creating new note
*/
private fun createNote(note: String)
{
disposable.add(apiService.createNote(note).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribeWith(
object : DisposableSingleObserver<Note>()
{
override fun onSuccess(note: Note)
{
if (!TextUtils.isEmpty(note.error))
{
Toast.makeText(applicationContext, note.error, Toast.LENGTH_LONG).show()
return
}
Log.d(TAG, "new note created: " + note.id + ", " + note.note + ", " + note.timestamp)
// Add new item and notify adapter
noteList.add(0, note)
mAdapter.notifyItemInserted(0)
toggleEmptyNotes()
}
override fun onError(e: Throwable)
{
Log.e(TAG, "onError: " + e.message)
showError(e)
}
}))
}
/**
* Updating a note
*/
private fun updateNote(noteId: Int, note: String, position: Int)
{
disposable.add(apiService.updateNote(noteId,
note).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribeWith(object :
DisposableCompletableObserver()
{
override fun onComplete()
{
Log.d(TAG, "Note updated!")
val n = noteList.get(position)
n.note = (note)
// Update item and notify adapter
noteList.set(position, n)
mAdapter.notifyItemChanged(position)
}
override fun onError(e: Throwable)
{
Log.e(TAG, "onError: " + e.message)
showError(e)
}
}))
}
/**
* Deleting a note
*/
private fun deleteNote(noteId: Int, position: Int)
{
Log.e(TAG, "deleteNote: $noteId, $position")
disposable.add(apiService.deleteNote(noteId).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribeWith(
object : DisposableCompletableObserver()
{
override fun onComplete()
{
Log.d(TAG, "Note deleted! $noteId")
// Remove and notify adapter about item deletion
noteList.removeAt(position)
mAdapter.notifyItemRemoved(position)
Toast.makeText(this#MainActivity, "Note deleted!", Toast.LENGTH_SHORT).show()
toggleEmptyNotes()
}
override fun onError(e: Throwable)
{
Log.e(TAG, "onError: " + e.message)
showError(e)
}
}))
}
/**
* Shows alert dialog with EditText options to enter / edit
* a note.
* when shouldUpdate=true, it automatically displays old note and changes the
* button text to UPDATE
*/
private fun showNoteDialog(shouldUpdate: Boolean, note: Note?, position: Int)
{
val layoutInflaterAndroid = LayoutInflater.from(applicationContext)
val view = layoutInflaterAndroid.inflate(R.layout.note_dialog, null)
val alertDialogBuilderUserInput = AlertDialog.Builder(this#MainActivity)
alertDialogBuilderUserInput.setView(view)
val inputNote = view.findViewById<EditText>(R.id.note)
val dialogTitle = view.findViewById<TextView>(R.id.dialog_title)
dialogTitle.setText(if (!shouldUpdate) getString(R.string.lbl_new_note_title) else getString(R.string.lbl_edit_note_title))
if (shouldUpdate && note != null)
{
inputNote.setText(note.note)
}
alertDialogBuilderUserInput.setCancelable(false).setPositiveButton(if (shouldUpdate) "update" else "save",
DialogInterface.OnClickListener { dialogBox, id -> })
.setNegativeButton("cancel", DialogInterface.OnClickListener { dialogBox, id -> dialogBox.cancel() })
val alertDialog = alertDialogBuilderUserInput.create()
alertDialog.show()
alertDialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener(View.OnClickListener {
// Show toast message when no text is entered
if (TextUtils.isEmpty(inputNote.text.toString()))
{
Toast.makeText(this#MainActivity, "Enter note!", Toast.LENGTH_SHORT).show()
return#OnClickListener
} else
{
alertDialog.dismiss()
}
// check if user updating note
if (shouldUpdate && note != null)
{
// update note by it's id
updateNote(note.id, inputNote.text.toString(), position)
} else
{
// create new note
createNote(inputNote.text.toString())
}
})
}
/**
* Opens dialog with Edit - Delete options
* Edit - 0
* Delete - 0
*/
private fun showActionsDialog(position: Int)
{
val colors = arrayOf<CharSequence>("Edit", "Delete")
val builder = AlertDialog.Builder(this)
builder.setTitle("Choose option")
builder.setItems(colors) { dialog, which ->
if (which == 0)
{
showNoteDialog(true, noteList.get(position), position)
} else
{
deleteNote(noteList.get(position).id, position)
}
}
builder.show()
}
private fun toggleEmptyNotes()
{
if (noteList.size > 0)
{
noNotesView?.setVisibility(View.GONE)
} else
{
noNotesView?.setVisibility(View.VISIBLE)
}
}
/**
* Showing a Snackbar with error message
* The error body will be in json format
* {"error": "Error message!"}
*/
fun showError(e: Throwable)
{
var message = ""
try
{
if (e is IOException)
{
message = "No internet connection!"
}
else (e is HttpException)
{
var error = e as HttpException
var errorBody = error.response().errorBody().toString()
val jObj = JSONObject(errorBody)
message = jObj.getString("error")
}
}
catch (e1: IOException)
{
e1.printStackTrace()
}
catch (e1: JSONException)
{
e1.printStackTrace()
}
catch (e1: Exception)
{
e1.printStackTrace()
}
if (TextUtils.isEmpty(message))
{
message = "Unknown error occurred! Check LogCat.";
}
val snackbar = coordinatorLayout?.let { Snackbar.make(it, message, Snackbar.LENGTH_LONG) }
val sbView = snackbar?.getView()
val textView = sbView?.findViewById<TextView>(android.support.design.R.id.snackbar_text)
textView?.setTextColor(Color.YELLOW)
snackbar?.show()
}
fun whiteNotificationBar(view: View)
{
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
{
var flags = view.getSystemUiVisibility();
flags = View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
view.setSystemUiVisibility(flags);
getWindow().setStatusBarColor(Color.WHITE);
}
}
override fun onDestroy()
{
super.onDestroy()
disposable.dispose()
}
}
I found out what the issue was. It seems by using the code complete option it ended up making the MainActivity class abstract
abstract class MainActivity : AppCompatActivity()
{
/// code base
}
instead of
class MainActivity : AppCompatActivity()
{
// code base
}