/r/learnandroid
Ask questions, help others - everything related to android programming
/r/learnandroid
I have just started professionally in the industry with an YOE of 1 and I can pretty much decently build features , fix bugs , create applications from scratch etc .
But sometimes , I still feel like I do not understand what is going underneath and some android fundamentals are a total blackbox for me.
For eg if someone asks what exactly is Context or ContextCompat or maybe what is Handler and Looper or How does networking in android work or maybe how to solve ANRs etc.
( I am just stating some examples , I know what they are but still )
I feel like I Just know how to make applications and I a lot of fundamentals feel like a blackbox to me.
Maybe this is because the way I started learning native development . I did not start by understanding the things going underneath , I started by just randomly building projects . or maybe this is normal.
This entire problem creates a huge Imposter syndrome and makes me feel superficial .
I would like to fix this and understand things from scratch but it also feels like android has reached a level of abstraction , that I do not actually need or would need to understand all of these since its APIs handle most of the stuff.
But as a Engineer , I would love to understand how things work , is there any resources which would help me with this , or maybe a process which I should go through to get a better grasp at things or am i just delusional.
I have just started professionally in the industry with an YOE of 1 and I can pretty much decently build features , fix bugs , create applications from scratch etc .
But sometimes , I still feel like I do not understand what is going underneath and some android fundamentals are a total blackbox for me.
For eg if someone asks what exactly is Context or ContextCompat or maybe what is Handler and Looper or How does networking in android work or maybe how to solve ANRs etc.
( I am just stating some examples , I know what they are but still )
I feel like I Just know how to make applications and I a lot of fundamentals feel like a blackbox to me.
Maybe this is because the way I started learning native development . I did not start by understanding the things going underneath , I started by just randomly building projects . or maybe this is normal.
This entire problem creates a huge Imposter syndrome and makes me feel superficial .
I would like to fix this and understand things from scratch but it also feels like android has reached a level of abstraction , that I do not actually need or would need to understand all of these since its APIs handle most of the stuff.
But as a Engineer , I would love to understand how things work , is there any resources which would help me with this , or maybe a process which I should go through to get a better grasp at things or am i just delusional.
I am currently following android development fundamentals from google, it is in java, but is somewhat outdated,
The reasons why i want to stick with java are as follow:
Although Java is prefered, but if there are no up to date courses in it, and you strongly advise going the Kotlin route, Then please mention a some good resource.
I know of Android basics with compose and Basics in Kotlin (which one of these to follow?? Later units of both courses have similar titles). There is also the Udacity nanodegree, but that is expensive (400$/mo Uff).
Any free or affordable course will be prefered. Maybe video ones will be better??
I cannot identify precisely what the problem is, but I know it is a problem with how a TFLite model is receiving a bitmap, as I tried sending it a different way through calling the Camera intent and it worked as intended by doing that, but I cannot call the Camera Intent as it will pull up the Camera screen, which I aim to not do.
Both versions of this code use the same tflite model, so I know it is not a model issue.
picture.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(cameraIntent, 1);
}
public void classifyImage(Bitmap image){
try {
Model model = Model.newInstance(getApplicationContext());
TensorBuffer inputFeature0 = TensorBuffer.createFixedSize(new int[]{1, 224, 224, 3}, DataType.FLOAT32);
ByteBuffer byteBuffer = ByteBuffer.allocateDirect(4 * imageSize * imageSize * 3);
byteBuffer.order(ByteOrder.nativeOrder());
int [] intValues = new int[imageSize * imageSize];
image.getPixels(intValues, 0, image.getWidth(), 0, 0, image.getWidth(), image.getHeight());
int pixel = 0;
for(int i = 0; i < imageSize; i++){
for(int j = 0; j < imageSize; j++){
int val = intValues[pixel++]; // RGB
byteBuffer.putFloat(((val >> 16) & 0xFF) * (1.f / 255.f));
byteBuffer.putFloat(((val >> 8) & 0xFF) * (1.f / 255.f));
byteBuffer.putFloat((val & 0xFF) * (1.f / 255.f));
}
}
inputFeature0.loadBuffer(byteBuffer);
Model.Outputs outputs = model.process(inputFeature0);
TensorBuffer outputFeature0 = outputs.getOutputFeature0AsTensorBuffer();
float[] confidences = outputFeature0.getFloatArray();
int maxPos = 0;
float maxConfidence = 0;
for(int i = 0; i < confidences.length; i++){
if(confidences[i] > maxConfidence){
maxConfidence = confidences[i];
maxPos = i;
}
}
String[] classes = {"Banana", "Orange", "Pen", "Sticky Notes"};
result.setText(classes[maxPos]);
String s = "";
for(int i = 0; i < classes.length; i++){
s += String.format("%s: %.1f%%\n", classes[i], confidences[i] * 100);
}
confidence.setText(s);
model.close();
}
@Override
public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
if (requestCode == 1 && resultCode == RESULT_OK) {
Bitmap image = (Bitmap) data.getExtras().get("data");
int dimension = Math.min(image.getWidth(), image.getHeight());
image = ThumbnailUtils.extractThumbnail(image, dimension, dimension);
imageView.setImageBitmap(image);
image = Bitmap.createScaledBitmap(image, imageSize, imageSize, false);
classifyImage(image);
}
super.onActivityResult(requestCode, resultCode, data);
}
}
Nonworking version:
This version will always return the same confidences (changes depending on different tflite models being used) no matter the image.
public class MainActivity extends AppCompatActivity implements ImageAnalysis.Analyzer, View.OnClickListener {
private ListenableFuture<ProcessCameraProvider> cameraProviderFuture;
PreviewView previewView;
private ImageCapture imageCapture;
private Button bCapture;
ImageView imageView;
@Override
protected void onCreate(Bundle savedInstanceState) {
cameraProviderFuture = ProcessCameraProvider.getInstance(this);
cameraProviderFuture.addListener(() -> {
try {
ProcessCameraProvider cameraProvider = cameraProviderFuture.get();
startCameraX(cameraProvider);
} catch (ExecutionException | InterruptedException e) {
e.printStackTrace();
}
}, getExecutor());
}
Executor getExecutor() {
return ContextCompat.getMainExecutor(this);
}
private void startCameraX(ProcessCameraProvider cameraProvider) {
cameraProvider.unbindAll();
CameraSelector cameraSelector = new CameraSelector.Builder()
.requireLensFacing(CameraSelector.LENS_FACING_BACK)
.build();
Preview preview = new Preview.Builder()
.build();
preview.setSurfaceProvider(previewView.getSurfaceProvider());
// Image capture use case
imageCapture = new ImageCapture.Builder()
.setCaptureMode(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY)
.build();
cameraProvider.bindToLifecycle( this, cameraSelector, preview, imageCapture);
}
@SuppressLint("RestrictedApi")
@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.bCapture:
capturePhoto();
break;
}
}
private void capturePhoto() {
ContentValues contentValues = new ContentValues();
imageCapture.takePicture(
new ImageCapture.OutputFileOptions.Builder(
getContentResolver(),
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
contentValues
).build(),
getExecutor(),
new ImageCapture.OnImageSavedCallback() {
@Override
public void onImageSaved(@NonNull ImageCapture.OutputFileResults outputFileResults) {
Toast.makeText(MainActivity.this, "Photo has been saved successfully.", Toast.LENGTH_SHORT).show();
Bitmap image = BitmapFactory.decodeFile(getLastImageId());
int dimension = Math.min(image.getWidth(), image.getHeight());
image = ThumbnailUtils.extractThumbnail(image, dimension, dimension);
image = Bitmap.createScaledBitmap(image, 224, 224, false);
imageView.setImageBitmap(image);
classifyImage(image);
}
@Override
public void onError(@NonNull ImageCaptureException exception) {
Toast.makeText(MainActivity.this, "Error saving photo: " + exception.getMessage(), Toast.LENGTH_SHORT).show();
}
}
);
}
private String getLastImageId(){
final String[] imageColumns = { MediaStore.Images.Media._ID, MediaStore.Images.Media.DATA };
final String imageOrderBy = MediaStore.Images.Media._ID+" DESC";
Cursor imageCursor = managedQuery(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, imageColumns, null, null, imageOrderBy);
if(imageCursor.moveToFirst()){
@SuppressLint("Range") String fullPath = imageCursor.getString(imageCursor.getColumnIndex(MediaStore.Images.Media.DATA));
imageCursor.close();
System.out.println(fullPath);
return fullPath;
}else{
return "";
}
}
private void classifyImage(Bitmap image) {
try {
Model model = Model.newInstance(getApplicationContext());
// Creates inputs for reference.
TensorBuffer inputFeature0 = TensorBuffer.createFixedSize(new int[]{1, 224, 224, 3}, DataType.FLOAT32);
ByteBuffer byteBuffer = ByteBuffer.allocateDirect(4*224*224*3);
byteBuffer.order(ByteOrder.nativeOrder());
int[] intValues = new int[224*224];
image.getPixels(intValues, 0, image.getWidth(), 0, 0, image.getWidth(), image.getHeight());
int pixel = 0;
for(int i = 0; i < 224; i++) {
int val = intValues[pixel++];
byteBuffer.putFloat(((val >> 16) & 0xFF) * (1.f/255.f));
byteBuffer.putFloat(((val >> 8) & 0xFF) * (1.f/255.f));
byteBuffer.putFloat(((val & 0xFF) * (1.f/255.f)));
}
inputFeature0.loadBuffer(byteBuffer);
// Runs model inference and gets result.
Model.Outputs outputs = model.process(inputFeature0);
TensorBuffer outputFeature0 = outputs.getOutputFeature0AsTensorBuffer();
float[] conifdences = outputFeature0.getFloatArray();
int maxPos = 0;
float maxConf = 0;
for(int i = 0; i < conifdences.length; i++) {
if(conifdences[i] > maxConf) {
maxConf = conifdences[i];
maxPos = i;
}
}
String[] classes = {"chicken", "apple", "things", "things"};
System.out.println(classes[maxPos]);
String s = "";
for(int i = 0; i < classes.length; i++) {
s+= String.format("%s: %.1f%%\n", classes[i], conifdences[i]*100);
}
System.out.println(s);
// Releases model resources if no longer used.
model.close();
}
}
Can you help me with this error in Android Studio?
Here is the DAO and table
@Entity(tableName = "results_table")
data class Result(
@PrimaryKey(autoGenerate = true)
var Id: Long? = 0L,
@ColumnInfo(name = "points")
val points: Int?,
@ColumnInfo(name = "time")
val lapsedTime: Long,
@ColumnInfo(name = "date")
val date: String
)
Dao:
@Query("DELETE FROM results_table")
suspend fun clear()
I would like to save the time i spent playing my game in my room database. Is there any better way to make a counter?
ViewModel:
val secondscount: MutableLiveData<Int> by lazy {
MutableLiveData<Int>()
}
fun startTimer() {
runnable = Runnable {
secondscount++ //This results as an typemismatch error
handler.postDelayed(runnable, 1000)
}
handler.postDelayed(runnable, 1000)
}
fun stopTimer() {
handler.removeCallbacks(runnable)
}
The database table
@Entity(tableName = "results_table")
data class ResultRow(
@PrimaryKey(autoGenerate = true)
var Id: Long? = 0L,
@ColumnInfo(name = "points")
val pisteet: Int,
@ColumnInfo(name = "time")
val time: Int,
)
I'm working through Udacity's "Developing Android Apps with Kotlin" class. I'm in part 6, where I'm supposed to run a test (SleepDatabaseTest
). When I originally ran it, I got an error that said
"Run Android instrumented tests using Gradle" option was ignored because this module type is not supported yet.
So I found a post on StackOverflow that said to uncheck "Run Android instrumented tests using Gradle" in the testing settings.
I did that, and the error message went away, but the test is still not running (it just says "Tests Passed 0 passed")
Can anyone help me fix this? Thanks
ETA: I also added the exclude module: "protobuf-lite"
line to my build.gradle (Module) file, but that didn't seem to make a difference (although I'm not 100% sure I did that right)
ETA^2 : found the solution: https://stackoverflow.com/questions/72130959/android-studio-test-passed-0-passed
I am taking the self learning approach, through a couple of books. i decided to refactor a Python CLI Into a GUI through Android. My question is this, in the application i set the id to a multiline text widget and create an onClick button to get everything in motion but due to my limited experience i have the on click function give me the second text output i want to spit out. Can someone point me in the best way to suspend/ or sleep the function and then clear the original output from my multiline text field and output my next desired text??
fun startSpeechBlurb(view: View) {
var intro_multiline: EditText =findViewById(R.id.intro_multiline)
if (intro_multiline.text.isEmpty()){
val hiNum: String = "Hello Friend"
val byeNum: String = "Bye Friend"
intro_multiline.setText(hiNum)
intro_multiline.setText(byeNum)
}
So i have to make this mathgame at school. Basicly the game shows two random numbers and then you have to tell what is the numbers sum.
I have two TextViwe elements and i need them to display integer type of data not string. How is this possible?
How can i make my app to start from fragment? My app currrenty starts from mainactvity. Is there a video or code example somewhere?
Fix: Go to activitymain.xml and edit <fragment>