AndroidStudio and Kotlin: What is Error Expecting Member Declaration - android-studio

I'm learning myself some android programming (beginning level) and following a tutorial. I'm getting an error when I run/build the project. Expecting member declaration. I've checked the code for typos and syntax errors. I've googled this, but I'm just not sure what it means or what to look for to fix it.
Are other classes used in the project automatically seen by the MainActivity class?
Code in part:
MainActivity.kt:
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
val friendlyDestroyer = Destroyer("Invincible")
val friendlyCarrier = Carrier("Indomitable")
val enemyDestroyer = Destroyer("Grey Death")
val enemyCarrier = Carrier("Big Grey Death")
val friendlyShipyard = ShipYard()
friendlyDestroyer.takeDamage(enemyDestroyer.shootShell())
friendlyDestroyer.takeDamage(enemyCarrier.launchAerialAttack())
// Fight back
enemyCarrier.takeDamage(friendlyCarrier.launchAerialAttack())
enemyCarrier.takeDamage(friendlyDestroyer.shootShell())
...
Any line that has an instance to a class with a function call shows the red squiggly line and the error.
In the line: friendlyDestroyer.takeDamage(enemyDestroyer.shootShell()), it shows the expecting member declaration error at just about every part of the line.
This happens on every instance of a class making a call to a class.
I'm not seeing any errors for the other classes/files.
Destroyer.kt:
package com.johndcowan.basicclasses
class Destroyer(name: String) {
// what is the name of the ship
var name: String = ""
private set
// what type of ship is it
// alwys a destroyer
val type = "Destroyer"
// how much the ship can take before sinking
private var hullIntegrity = 200
// how many shots left in the arsenal
var ammo = 1
// cannot be directly set externally
private set
// no external access whatsoever
private var shotPower = 60
// has the ship been sunk
private var sunk = false
// this code runs as the instance is being initialized
init {
// so we can use the name parameter
this.name = "$type $name"
}
fun takeDamage(damageTaken: Int) {
if (!sunk) {
hullIntegrity -= damageTaken
println("$name hull integrity = $hullIntegrity")
if (hullIntegrity <= 0){
println("Destroyer $name has been sunk")
sunk = true
}
} else {
// Already sunk
println("Error Ship does not exist")
}
}
fun shootShell():Int {
// let the calling code know how much damage to do
return if (ammo > 0) {
ammo--
shotPower
}else{
0
}
}
...
What am I missing or not seeing?
Thanks for any tips.

Related

What changes are required to make this class scan Barcode in any direction. It works only for QR codes

I am developing a Qr Code and Barcode Scanner App, using CameraX and Zxing but the following class only works for Qr Code. I want to scan barcodes as well from any orientation on an android device
Code Scanning class:
public class QRCodeImageAnalyzer implements ImageAnalysis.Analyzer {
private QRCodeFoundListener listener;
public QRCodeImageAnalyzer(QRCodeFoundListener listener) {
this.listener = listener;
}
#SuppressLint("UnsafeOptInUsageError")
#Override
public void analyze(#NonNull ImageProxy imageProxy) {
Image image = imageProxy.getImage();
if (image.getFormat() == YUV_420_888 || image.getFormat() == YUV_422_888 || image.getFormat() == YUV_444_888) {
ByteBuffer byteBuffer = image.getPlanes()[0].getBuffer();
byte[] imageData = new byte[byteBuffer.capacity()];
byteBuffer.get(imageData);
PlanarYUVLuminanceSource source = new PlanarYUVLuminanceSource(
imageData,
image.getWidth(), image.getHeight(),
0, 0,
image.getWidth(), image.getHeight(),
false
);
BinaryBitmap binaryBitmap = new BinaryBitmap(new HybridBinarizer(source));
try {
Result result = new QRCodeMultiReader().decode(binaryBitmap);
listener.onQRCodeFound(result.getText());
} catch (FormatException | ChecksumException | NotFoundException e) {
listener.qrCodeNotFound();
}
}
imageProxy.close();
}
}
I also tried this class CameraX with MLKit: I tried the sample from the official docs of MLKit provided in the first answer but it scan nothing neither QR Code nor Barcode. Please take a look if I put things the wrong way.
import android.annotation.SuppressLint
import android.util.Log
import androidx.camera.core.ExperimentalGetImage
import androidx.camera.core.ImageAnalysis
import androidx.camera.core.ImageProxy
import com.google.mlkit.vision.barcode.Barcode
import com.google.mlkit.vision.barcode.BarcodeScannerOptions
import com.google.mlkit.vision.barcode.BarcodeScanning
import com.google.mlkit.vision.common.InputImage
#UseExperimental(markerClass = [ExperimentalGetImage::class])
class QrCodeAnalyzer(
private val onQrCodesDetected: (qrCodes: List<Barcode>?) -> Unit
) : ImageAnalysis.Analyzer {
private val TAG: String = "Kamran"
private fun rotationDegreesToFirebaseRotation(rotationDegrees: Int): Int {
return when (rotationDegrees) {
0 -> 0
90 -> 1
180 -> 2
270 -> 3
else -> throw IllegalArgumentException("Not supported")
}
}
#SuppressLint("UnsafeOptInUsageError")
override fun analyze(image: ImageProxy) {
val rotation = rotationDegreesToFirebaseRotation(image.imageInfo.rotationDegrees)
image.image?.let{
val optionss = BarcodeScannerOptions.Builder()
.setBarcodeFormats(
Barcode.FORMAT_QR_CODE,
Barcode.FORMAT_EAN_8,
Barcode.FORMAT_EAN_13)
.build()
val imageValue = InputImage.fromMediaImage(it, image.imageInfo.rotationDegrees)
//val options = BarcodeScannerOptions.Builder().setBarcodeFormats(Barcode.FORMAT_QR_CODE).build()
val scanner = BarcodeScanning.getClient(optionss)
scanner.process(imageValue)
.addOnCompleteListener { barcodes ->
barcodes.result?.forEach { barcode ->
val bounds = barcode.boundingBox
val corners = barcode.cornerPoints
val rawValue = barcode.rawValue
}
onQrCodesDetected(barcodes.result)
image.image?.close()
image.close()
Log.d(TAG, "Successfully got inside onCompleteListener")
}
.addOnFailureListener { failure ->
failure.printStackTrace()
image.image?.close()
image.close()
}
}
}
}
I am not sure If using ZXing android library is a requirement (afaik it is no longer developed). If it is not a hard requirement, I would suggest you to give it a try for MLKit Barcode Scanner. It scans QR as well.
Also, you would probably find it easier to implement with CameraX as they already have multiple examples and sample code.
For example check this guide for step by step instructions.
Particularly this part.
You can configire the scanner first:
val options = BarcodeScannerOptions.Builder()
.setBarcodeFormats(
Barcode.FORMAT_QR_CODE,
Barcode.FORMAT_EAN_8,
Barcode.FORMAT_EAN_13)
.build()
then;
private class YourImageAnalyzer : ImageAnalysis.Analyzer {
override fun analyze(imageProxy: ImageProxy) {
val mediaImage = imageProxy.image
if (mediaImage != null) {
val image = InputImage.fromMediaImage(mediaImage, imageProxy.imageInfo.rotationDegrees)
// Pass image to an ML Kit Vision API
// ...
}
}
}
finally this is how you get it decoded:
val result = scanner.process(image)
.addOnSuccessListener { barcodes ->
// Task completed successfully
// ...
}
.addOnFailureListener {
// Task failed with an exception
// ...
}

Android Jetpack Passing Data Between Composables

I'm trying to pass a constantly updating variable "message" across my Jetpack Composables. I have a draggable box that tracks the coordinates of the box but I'm trying to send the real-time data through a TCP connection. However, I noticed that the current coordinate of the draggable box isn't passing through to the other Composable or the socket -only the same value is passed despite message changing continuously due to me dragging the box. Also, the moment dataSendButton() is pressed, the createDragImage() and its draggable box stops animating/running.
var message = "" // global Android send message
class MainActivity : ComponentActivity() {
private var textView: TextView? = null
dataSendButton()
createDragImage()
...
}
}
}
#Composable
fun createDragImage(){
val context = LocalContext.current
...
Box() {
var offsetX by remember { mutableStateOf(0f) }
var offsetY by remember { mutableStateOf(0f) }
Box(
Modifier
.offset { IntOffset(offsetX.roundToInt(), offsetY.roundToInt()) }
.background(Color.Transparent)
.size(150.dp)
.border(BorderStroke(4.dp, SolidColor(Color.Red)))
.pointerInput(Unit) {
detectDragGestures { change, dragAmount ->
change.consumeAllChanges()
offsetX = someConstantX
offsetY += dragAmount.y
message = offsetY.toString()
...
#Composable
fun dataSendButton() {
val context = LocalContext.current
...
Button(
onClick = {
// **ISSUE: message in this composable is not getting updated with message value from createDragImage()
val b1 = MainActivity.TCPconnector_client(context, message)
b1.execute()
},
{
Text(text = "Send Data", color = Color.White, fontSize = 20.sp)
}
}
}
}
}
It is because that is not how you store state in Compose.
Change the declaration of the variable.
var message by mutableStateOf(...)
Then the changes to it will trigger a recomposition, and so the rest of the code should remain the same. It is always recommended to store the state holders in a viewmodel, and pass the viewmodel around instead.
This is a working code with viewmodel
class MainActivity : ComponentActivity() {
private var textView: TextView? = null
val vm by viewmodels<MViewModel>()
dataSendButton(vm.message, vm:: onMessageChange)
createDragImage(vm.message)
...
}
}
}
#Composable
fun createDragImage(message: String, onMessageChange: (String) -> Unit){
val context = LocalContext.current
...
Box() {
var offsetX by remember { mutableStateOf(0f) }
var offsetY by remember { mutableStateOf(0f) }
Box(
Modifier
.offset { IntOffset(offsetX.roundToInt(), offsetY.roundToInt()) }
.background(Color.Transparent)
.size(150.dp)
.border(BorderStroke(4.dp, SolidColor(Color.Red)))
.pointerInput(Unit) {
detectDragGestures { change, dragAmount ->
change.consumeAllChanges()
offsetX = someConstantX
offsetY += dragAmount.y
onMessageChange (offsetY.toString())
...
#Composable
fun dataSendButton(message: String) {
val context = LocalContext.current
...
Button(
onClick = {
// **ISSUE: message in this composable is not getting updated with message value from createDragImage() // This seems to be an error. Calling a Composable from onClick?
val b1 = MainActivity.TCPconnector_client(context, message)
b1.execute()
},
{
Text(text = "Send Data", color = Color.White, fontSize = 20.sp)
}
}
}
}
}
class MViewModel: ViewModel(){
var message by mutableStateOf("")
private set //do not allow external modifications to ensure consistency
fun onMessageChange (newMessage: String){
message = newMessage
}
}
Note this is the ideal way of doing such implementation. However, for your specific case, if you do not need to access it anywhere else, only changing the declaration as described in the second line of the answer should do
Thanks

Why does zoomRatio display the error Unresolved reference when I use camerax "1.0.0-alpha06"?

I have read the artical. https://proandroiddev.com/android-camerax-tap-to-focus-pinch-to-zoom-zoom-slider-eb88f3aa6fc6
I add Code A to the office camerx sample. https://github.com/android/camera-samples/tree/master/CameraXBasic
The sample code use camerax "1.0.0-alpha06"
I get the error Unresolved reference for zoomRatio, you can see Image 1, how can I fix it?
Code A
private fun setUpPinchToZoom() {
val cameraControl = CameraX.getCameraControl(lensFacing)
val cameraInfo = CameraX.getCameraInfo(lensFacing)
val listener = object : ScaleGestureDetector.SimpleOnScaleGestureListener() {
override fun onScale(detector: ScaleGestureDetector): Boolean {
val currentZoomRatio: Float = cameraInfo.zoomRatio.value ?: 0F
val delta = detector.scaleFactor
cameraControl.setZoomRatio(currentZoomRatio * delta)
return true
}
}
val scaleGestureDetector = ScaleGestureDetector(context, listener)
viewFinder.setOnTouchListener { _, event ->
scaleGestureDetector.onTouchEvent(event)
return#setOnTouchListener true
}
}
Image 1
Zoom controls have been added on version 1.0.0-alpha07. You need to update your code to use at least camera-Core version 1.0.0-alpha07: https://developer.android.com/jetpack/androidx/releases/camera

Kotlin how to combine different receivers via with clause without repeating it

I have Parent-Search-Child system as below:
class Room
class Building {
fun find(by: By) = Room()
}
sealed class By {
abstract fun search(): Room
class ById(id: String) : By() {
override fun search(): Room = Room() // epic search method
}
class ByName(name: String) : By() {
override fun search(): Room = Room() // epic search method
}
class Byurpose(purpose: String) : By() {
override fun search(): Room = Room() // epic search method
}
companion object {
fun id(id: String) = ById(id)
fun name(name: String) = ByName(name)
fun purpose(purpose: String) = Byurpose(purpose)
}
}
Which can be used as follows:
val building = Building()
val room = building.find(By.name("Toilet"))
However, I am not very satisfied with the current syntax, which could be much less verbose in Kotlin. In addition, building.find can appear thousands times in the code. I could implement it differently, but actually I don't own Room, Building or By classes, so I can't. Thus this was my approach:
I implemented context class that stores Building reference, and use it internally as source for search methods:
class BuildingContext(private val building: Building) {
fun String.findById() = building.find(By.id(this))
fun String.findByName() = building.find(By.name(this))
fun String.findByPurpose() = building.find(By.purpose(this))
}
It can be used as below:
with(BuildingContext(building)) {
val room2 = "Toilet".findByName()
}
After that I noticed that I only use one search method in 99% cases, so (for sake of even shorter syntax!) I implemented following classes:
object AlwaysSearchById {
fun String.find(building: Building) = building.find(By.id(this))
}
object AlwaysSearchByName {
fun String.find(building: Building) = building.find(By.name(this))
}
object AlwaysSearchByPurpose {
fun String.find(building: Building) = building.find(By.purpose(this))
}
Which can be used this way:
with(AlwaysSearchByName) {
val room3 = "Toilet".find(building)
}
Unfortunately, building reference appears again. The ideal syntax would be "Toilet".find(). I could fix it re-implementing Always~ classes as follows:
class AlwaysSearchByNameV2(private val building: Building) {
fun String.find() = building.find(By.name(this))
}
And it would be used as below:
with(AlwaysSearchByNameV2(building)) {
val room = "Toilet".find()
}
But it some cases, I would like to access BuildingContext methods as well, so So I have to write:
with(BuildingContext(building)) {
with(AlwaysSearchByNameV2(building)) {
val toilet = "Toilet".find()
val randomRoom = "123".findById()
}
}
The question is - How I reduce multiple with clauses in this case?
In the example above there are only 2 with clauses, but it's only basic example. In real world there could be dozens of them, and writing with(with(with(with(with... would surely be a pain.
On the side note this doesn't work:
with(BuildingContext(building), AlwaysSearchByNameV2(building)) {
val toilet = "Toilet".find()
val randomRoom = "123".findById()
}
nor this
with(*arrayOf(BuildingContext(building), BuildingContext(building))) {
val toilet = "Toilet".find()
val randomRoom = "123".findById()
}
You can write custom scoping functions instead of relying on with all the time. For example you can add an extension function that will run a block of code in scope of AlwaysSearchByNameV2 object:
inline fun BuildingContext.byName(f : AlwaysSearchByNameV2.() -> Unit) = AlwaysSearchByNameV2(building).apply(f)
And use it:
with(BuildingContext(building)) { // this: BuildingContext
byName { // this: AlwaysSearchByNameV2
val toilet = "Toilet".find()
val randomRoom = "123".findById() // can still refer to BuildingContext
}
// back to this: BuildingContext
}

AST Transformation to wrap entire method body in a closure

I'm trying to do something rather simple. I would like to wrap the whole method code into an additional closure block that would measure the execution time. Right now I'm getting a really not helpful error message:
Error:Groovyc: NPE while processing Test.groovy
Annotation:
#Retention(RetentionPolicy.SOURCE)
#Target([ElementType.METHOD])
#GroovyASTTransformationClass(["WithTimingASTTransformation"])
public #interface WithTiming {
}
My wrapping closure:
class Benchmark {
static def measureTime(Closure cl) {
def start = System.currentTimeMillis()
def result = cl()
def time = System.currentTimeMillis() - start
println "it took $time"
result
}
}
My Transformation:
#GroovyASTTransformation(phase = CompilePhase.SEMANTIC_ANALYSIS)
class WithTimingASTTransformation implements ASTTransformation {
#Override
void visit(ASTNode[] astNodes, SourceUnit sourceUnit) {
MethodNode method = astNodes[1]
method.code = wrap(method)
}
private Statement wrap(MethodNode method) {
def newBlock = new BlockStatement()
newBlock.addStatement(
new ExpressionStatement(
new StaticMethodCallExpression(
new ClassNode(Benchmark),
'measureTime',
new ArgumentListExpression(
new ClosureExpression(new Parameter[0], method.code)
))))
newBlock
}
}
I'm really stuck here and don't know how can I debug the problem.
There is an answer on a similar topic (wrapping whole method body into a try/catch block here). This works fine but my case is slightly different.
In my case similar NPE was coming from:
java.lang.NullPointerException
at org.codehaus.groovy.classgen.asm.ClosureWriter.createClosureClass(ClosureWriter.java:194)
at org.codehaus.groovy.classgen.asm.ClosureWriter.getOrAddClosureClass(ClosureWriter.java:159)
at org.codehaus.groovy.classgen.asm.ClosureWriter.writeClosure(ClosureWriter.java:90)
at org.codehaus.groovy.classgen.AsmClassGenerator.visitClosureExpression(AsmClassGenerator.java:673)
Whereas:
if (parameters == null || expression.getVariableScope() == null) {
parameters = Parameter.EMPTY_ARRAY;
} else if (parameters.length == 0) {
// let's create a default 'it' parameter
Parameter it = new Parameter(ClassHelper.OBJECT_TYPE, "it", ConstantExpression.NULL);
parameters = new Parameter[]{it};
Variable ref = expression.getVariableScope().getDeclaredVariable("it");
if (ref != null) it.setClosureSharedVariable(ref.isClosureSharedVariable());
}
and line 194 (as of https://github.com/groovy/groovy-core/commit/a52d0d3c5dd1cbb342992d36235171718a563c8b) is:
Variable ref = expression.getVariableScope().getDeclaredVariable("it");
Thus you need to define a VariableScope for your ClosureExpression. I had to add tracing into org.codehaus.groovy.ast.ClosureWriter to find this, because there is an issue with exception display on stage of Class Generation - both in IntelliJ Idea and in Groovy Console - it does not show proper lines of code.
Furthermore, I think that either ClosureWriter or ClosureExpression constructor can be fixed to work aligned by default - without this NPE. I will possibly submit an issue to Groovy Jira for this.
Now I am able to inject closure expression in my code. But struggling to call this closure.
Getting:
groovy.lang.MissingMethodException: No signature of method: com.a9ae0b01f0ffc.VSMSGEN.implementation.T_visa_recon_generator$_convert_vts_log_to_ctf_closure2.call() is applicable for argument types: () values: []
Long story short, after some iterations my method-wrapping AST looks like this:
BlockStatement bs = new BlockStatement()
ClosureExpression closureExp = new ClosureExpression( methodNode.parameters, methodNode.code )
closureExp.variableScope = new VariableScope() // <- this does the trick!
bs.addStatement new ExpressionStatement( new StaticMethodCallExpression( new ClassNode( TransactionUtil ), 'wrap', new ArgumentListExpression( closureExp ) ) )
methodNode.code = bs
The line closureExp.variableScope = new VariableScope() avoids the NPE in ClosureWriter.java:194 and the whole thing runs like a charm!
Hope it helps someone...

Resources