Приложение вылетает при получении местоположения через ForegroundService - PullRequest
0 голосов
/ 28 марта 2020

Я реализовал точно такой же пример службы LocationUpdateForeground, как и в этих местоположениях-образцах . Проблема в том, что когда я запускаю предоставленный проект, он запускается, но, поскольку я работаю с Kotlin, а эти проекты находятся в Java, мое приложение падает и выдает исключение нулевого указателя на mService!!.removeLocationUpdates(), но я попытался скопировать его то же самое без каких-либо изменений, и он все еще падает.

Я застрял на получении фонового местоположения, так как большинство из них не работают, и этот работает точно даже в Android Q.

Ошибка возникает из-за того, что onServiceConnected() никогда не вызывается при инициализации mService.

Манифест. xml

    <service
       android:name="com.app.writer.LocationUpdatesService"
       android:enabled="true"
       android:exported="true"
       android:foregroundServiceType="location"
       android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE">
       <intent-filter>
           <action android:name="android.accessibilityservice.AccessibilityService" />
       </intent-filter>
    </service>

MainActivity

class MainActivity : AppCompatActivity(), SharedPreferences.OnSharedPreferenceChangeListener {
var prevMenuItem: MenuItem? = null
private lateinit var tinyDB: TinyDB
private lateinit var myApi: INodeJS
private lateinit var mySnackbar: Snackbar
private var compositeDisposable = CompositeDisposable()
private var mServiceBinder: LocationUpdatesService.LocalBinder? = null    
private val TAG = MainActivity::class.java.simpleName
// Used in checking for runtime permissions.
private val REQUEST_PERMISSIONS_REQUEST_CODE = 34
// The BroadcastReceiver used to listen from broadcasts from the service.
private var myReceiver: MainActivity.MyReceiver? =
    null



// A reference to the service used to get location updates.
private var mService: LocationUpdatesService? = null

// Tracks the bound state of the service.
private var mBound = false

private val mServiceConnection: ServiceConnection = object :
    ServiceConnection {
    override fun onServiceConnected(name: ComponentName, service: IBinder) {
        mServiceBinder = service as LocationUpdatesService.LocalBinder
        mService = mServiceBinder!!.service
        mBound = true
    }

    override fun onServiceDisconnected(name: ComponentName) {
        mService = null
        mBound = false
    }
  }

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)
    window.decorView.systemUiVisibility = (
            View.SYSTEM_UI_FLAG_LAYOUT_STABLE
                    or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN)
    tinyDB = TinyDB(this) //Easy way to save data in SharedPreferences
    myReceiver = MyReceiver()
    // Check that the user hasn't revoked permissions by going to Settings.
    if (Utils.requestingLocationUpdates(this)) {
        if (!checkPermissions()) {
            requestPermissions()
        }
    }
}

override fun onDestroy() {
    super.onDestroy()
}

override fun onStop() {
    if (mBound) {
        // Unbind from the service. This signals to the service that this activity is no longer
        // in the foreground, and the service can respond by promoting itself to a foreground
        // service.
        unbindService(mServiceConnection)
        mBound = false
    }
    PreferenceManager.getDefaultSharedPreferences(this)
        .unregisterOnSharedPreferenceChangeListener(this)
    super.onStop()
}

override fun onStart() {
    super.onStart()
    PreferenceManager.getDefaultSharedPreferences(this)
        .registerOnSharedPreferenceChangeListener(this)
    Writer.setOnClickListener{
        if (!checkPermissions()) {
            requestPermissions()
        } else {
            if (tinyDB.getBoolean("Writer")) {
                mySnackbar.setText("Kavach Disabled!!!").show()
            } else {
                mService!!.requestLocationUpdates()
            }

        }
    }

    // Restore the state of the buttons when the activity (re)launches.
    setButtonsState(Utils.requestingLocationUpdates(this))

    // Bind to the service. If the service is in foreground mode, this signals to the service
    // that since this activity is in the foreground, the service can exit foreground mode.
    applicationContext.bindService(
        Intent(this, LocationUpdatesService::class.java), mServiceConnection,
        Context.BIND_AUTO_CREATE
    )
}

override fun onResume() {
    super.onResume()
    LocalBroadcastManager.getInstance(this).registerReceiver(
        myReceiver!!,
        IntentFilter(LocationUpdatesService.ACTION_BROADCAST)
    )
}

override fun onPause() {
    LocalBroadcastManager.getInstance(this).unregisterReceiver(myReceiver!!)
    super.onPause()
}

/**
 * Returns the current state of the permissions needed.
 */
private fun checkPermissions(): Boolean {
    return PackageManager.PERMISSION_GRANTED == ActivityCompat.checkSelfPermission(
        this,
        Manifest.permission.ACCESS_FINE_LOCATION
    )
}

private fun requestPermissions() {
    val shouldProvideRationale =
        ActivityCompat.shouldShowRequestPermissionRationale(
            this,
            Manifest.permission.ACCESS_FINE_LOCATION
        )

    // Provide an additional rationale to the user. This would happen if the user denied the
    // request previously, but didn't check the "Don't ask again" checkbox.
    if (shouldProvideRationale) {
        Log.i(
            TAG,
            "Displaying permission rationale to provide additional context."
        )
        mySnackbar.setText("Location permission is needed for core functionality")
            .setAction("Ok", View.OnClickListener { // Request permission
                ActivityCompat.requestPermissions(
                    this@MainActivity,
                    arrayOf(Manifest.permission.ACCESS_FINE_LOCATION),
                    REQUEST_PERMISSIONS_REQUEST_CODE
                )
            })
            .show()
    } else {
        Log.i(TAG, "Requesting permission")
        // Request permission. It's possible this can be auto answered if device policy
        // sets the permission in a given state or the user denied the permission
        // previously and checked "Never ask again".
        ActivityCompat.requestPermissions(
            this@MainActivity,
            arrayOf(Manifest.permission.ACCESS_FINE_LOCATION),
            REQUEST_PERMISSIONS_REQUEST_CODE
        )
    }
}

/**
 * Callback received when a permissions request has been completed.
 */
override fun onRequestPermissionsResult(
    requestCode: Int, permissions: Array<String?>,
    grantResults: IntArray
) {
    Log.i(TAG, "onRequestPermissionResult")
    if (requestCode == REQUEST_PERMISSIONS_REQUEST_CODE) {
        if (grantResults.isEmpty()) {
            // If user interaction was interrupted, the permission request is cancelled and you
            // receive empty arrays.
            Log.i(TAG, "User interaction was cancelled.")
        } else if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            // Permission was granted.
            mService!!.requestLocationUpdates()
        } else {
            // Permission denied.
            setButtonsState(false)
            mySnackbar.setText("Permission Denied, can't work without it")
                .setAction(
                    R.string.settings
                ) { // Build intent that displays the App settings screen.
                    val intent = Intent()
                    intent.action =
                        android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS
                    val uri = Uri.fromParts(
                        "package",
                        BuildConfig.APPLICATION_ID, null
                    )
                    intent.data = uri
                    intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
                    startActivity(intent)
                }
                .show()
        }
    }
}

/**
 * Receiver for broadcasts sent by [LocationUpdatesService].
 */
private class MyReceiver : BroadcastReceiver() {
    override fun onReceive(
        context: Context,
        intent: Intent
    ) {
        val location =
            intent.getParcelableExtra<Location>(LocationUpdatesService.EXTRA_LOCATION)
        if (location != null) {
            Toast.makeText(
                context, Utils.getLocationText(location),
                Toast.LENGTH_SHORT
            ).show()
        }
    }
}

override fun onSharedPreferenceChanged(
    sharedPreferences: SharedPreferences,
    s: String
) {
    // Update the buttons state depending on whether location updates are being requested.
    if (s == Utils.KEY_REQUESTING_LOCATION_UPDATES) {
        setButtonsState(
            sharedPreferences.getBoolean(
                Utils.KEY_REQUESTING_LOCATION_UPDATES,
                false
            )
        )
    }
}

private fun setButtonsState(requestingLocationUpdates: Boolean) {
    if (!requestingLocationUpdates) {
        mService!!.removeLocationUpdates()
    } else {
        mService!!.requestLocationUpdates()
    }
}
}

Я знаю, что такое исключение nullpointer, но здесь я застрял, а также, это происходит из-за onStart.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...