Android Native – lazy loading Views with ViewStub

Introduction

Complex Views can use up RAM and reduce the performance of your Android apps. If a View is rarely used, you should consider delaying its rendering until it is needed by your app. One way to do that is to use the ViewStub View.

ViewStub is very cheap to inflate, so it can often be used as a stub for complex Views.

Goals

At the end of the tutorial, you would have learned:

  1. How to use ViewStub to lazily load Views.
Prerequisite Knowledge
  1. Basic Android development knowledge.
Tools Required
  1. Android Studio.
Project Setup

To follow along with the tutorial, perform the steps below:

  1. Create a new Android project with the default Empty Activity.
  2. Delete the Hello World TextView.
ViewStub Concept Overview

ViewStub is cheap to inflate because it is invisible and has zero dimensions. At development time, it references another layout file with the android:layout attribute. The XML file that it references does not necessarily have to be one of the LayoutX classes (FrameLayout, ConstraintLayout, etc). Any View would do.

When a ViewStub is inflated, the underlying layout will inherit ViewStubs layout parameters and replaces ViewStub in the parent layout. You should be careful when attempting to reference the ViewStub id after inflation because the app will throw a NullPointerException.

There are two common ways to inflate a ViewStub:

  1. Set the visibility to the constant View.VISIBLE. Use setVisibility() method if you are using Java.
  2. Call the inflate() function from the ViewStub object.

We will set visibility directly on this tutorial because it is the most readable option on Kotlin.

Create a View to stub

First, let us start with creating a View for ViewStub to reference. We will just use the Widget ProgressBar for this tutorial.

Create a progress_bar.xml file in res/layout that will only contain the ProgressBar itself.

  1. Right-click on the layout directory.
  2. New
  3. Layout Resource File.
  4. Use progress_bar as the File name.
  5. Change the root element to ProgressBar.
  6. Select OK.

progress_bar.png

The XML content of progress_bar.xml should be something like this.

<?xml version="1.0" encoding="utf-8"?>
<ProgressBar xmlns:android="http://schemas.android.com/apk/res/android"
   android:layout_width="match_parent"
   android:layout_height="match_parent">

</ProgressBar>
Create the ViewStub

Now that we have the ProgressBar View ready, let us add a ViewStub as its light-weight placeholder.

  1. Open activity_main.xml in the Design surface.

  2. Under Palette/Containers, drag a new ViewStub into ConstraintLayout.

  3. When prompted for a resource to stub, select progress_bar.

  4. Hit OK.
    viewstub.png

  5. Open activity_main.xml in Code view, and you will see an attribute called android:layout inside the ViewStub tag, as explained in the ViewStub Concept Overview section.

     <ViewStub
        android:id="@+id/viewStub"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout="@layout/progress_bar" />
  6. Switch back to the Design surface.

  7. Add the bottom, left and right constraints to ViewStub. All with zero margins. Do not forget that the ProgressBar will also inherit these constraints when it is inflated at runtime.

  8. Below is the code for the ViewStub constraints

     app:layout_constraintBottom_toBottomOf="parent"
     app:layout_constraintEnd_toEndOf="parent"
     app:layout_constraintStart_toStartOf="parent"
Add a trigger

To activate the layout inflation, let us add a simple Button to the layout.

  1. Open activity_main.xml in the Design surface.

  2. From Palette/Buttons, drag a new Button into ConstraintLayout.

  3. Constraint it to all four sides of ConstraintLayout with zero margins.

  4. Extract the hardcoded text of Button to a separate String resource.

  5. Constraint the top of ViewStub to the bottom of Button. Since ViewStub dimensions are not selectable in the Design surface, switch to the Code view and add this attribute to the ViewStub tag.

     app:layout_constraintTop_toBottomOf="@id/button"
  6. Your Button tag should now look like this.

     <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/button"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
  7. If we want our button to do something useful, then we will need to add an onClickListener to it. In MainActivity.kt, add the code below to onCreate().

     val button = findViewById<Button>(R.id.button)
     button.setOnClickListener {
        findViewById<ViewStub>(R.id.viewStub).visibility = View.VISIBLE //ViewStub is killed after this
     }

The first line attempts to find the Button by id. The second line changes the visibility of ViewStub so the ProgressBar will be inflated.

Run the app

We are now done with all prerequisites to use the ViewStub. It is time to run the app. If you also add a Profiler into the running app, then you can also see that the CPU usage increases from 0% to around 5% constantly (depending on your computer/emulator).

ViewStubAnimation.gif

This further proves that this kind of view should only be loaded when it is needed.

NullPointerException on destroyed ViewStub

Please note that if you click the button twice, then your app will crash because your onClickListener is still referencing the same ViewStub that is no longer in the view hierachy.

If you no longer need the Button or whatever trigger that your app uses, then you can just destroy the Button itself.

Another option is to simply add an elvis operator (?) to your findViewById() function call like the code below.

findViewById<ViewStub>(R.id.viewStub)?.visibility = View.VISIBLE
Solution Code

MainActivity.kt

package com.example.daniwebviewstub

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.View
import android.view.ViewStub
import android.widget.Button

class MainActivity : AppCompatActivity() {
   override fun onCreate(savedInstanceState: Bundle?) {
       super.onCreate(savedInstanceState)
       setContentView(R.layout.activity_main)

       val button = findViewById<Button>(R.id.button)
       button.setOnClickListener {
           findViewById<ViewStub>(R.id.viewStub)?.visibility = View.VISIBLE //ViewStub is killed after this
       }

   }
}

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
   xmlns:app="http://schemas.android.com/apk/res-auto"
   xmlns:tools="http://schemas.android.com/tools"
   android:layout_width="match_parent"
   android:layout_height="match_parent"
   tools:context=".MainActivity">

   <Button
       android:id="@+id/button"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:text="@string/button"
       app:layout_constraintBottom_toBottomOf="parent"
       app:layout_constraintEnd_toEndOf="parent"
       app:layout_constraintStart_toStartOf="parent"
       app:layout_constraintTop_toTopOf="parent" />

   <ViewStub
       android:id="@+id/viewStub"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:layout="@layout/progress_bar"
       app:layout_constraintBottom_toBottomOf="parent"
       app:layout_constraintEnd_toEndOf="parent"
       app:layout_constraintStart_toStartOf="parent"
       app:layout_constraintTop_toBottomOf="@id/button" />

</androidx.constraintlayout.widget.ConstraintLayout>

progress_bar.xml

<?xml version="1.0" encoding="utf-8"?>
<ProgressBar xmlns:android="http://schemas.android.com/apk/res/android"
   android:layout_width="match_parent"
   android:layout_height="match_parent">

</ProgressBar>

strings.xml

<resources>
   <string name="app_name">Daniweb ViewStub</string>
   <string name="button">Button</string>
</resources>
Summary

Congrations! You have learned how to use ViewStub on Android Native. The full project code can be found at https://github.com/dmitrilc/DaniwebViewStubAndroid/tree/main

Android Native – How to use MotionLayout

Introduction

Among all of the animation APIs on Android, MotionLayout is one of the best classes to use to create complex animations. It can animate property and motion of multiple views at the same time. Other benefits include declarative style XML and the intuitive Motion Editor built right into Android Studio.

In this tutorial, we will learn how to move a drawable resource with MotionLayout.

Goals

At the end of the tutorial, you would have learned:

  1. How to set up MotionLayout.
  2. How to use the Motion Editor in Android Studio.
Prerequisite Knowledge
  1. Basic Android development knowledge.
Tools Required
  1. Android Studio.
Project Setup

To follow along with the tutorial, perform the steps below:

  1. Create a new Android project with the default Empty Activity.

  2. Delete the Hello World TextView from activity_main.xml.

  3. Right-click on res/drawable -> New -> Vector Asset.

  4. Choose Clip Art as Asset Type.

  5. For the Name, use ic_android_black_100dp.

  6. For the Clip Art, find and select the android clip art.

  7. Set the size to 100x100.

  8. Use the default black color 000000.

  9. Opacity should be set to 100%.

  10. No need to check the TRL option.

  11. Select Next.
    Configure_Vector_Asset.png

  12. The icon path is under the default drawable directory at main/drawable/ic_android_black_100dp.xml
    confirm_icon_path.png

  13. Add a new ImageView below ConstraintView in activity_main.xml, selecting ic_android_black_100dp as the resource. If you do not want to use to the Design surface, the XML equivalence is:

     <ImageView
        android:id="@+id/imageView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:srcCompat="@drawable/ic_android_black_100dp" />
  14. Click Finish.

MotionLayout subclasses ConstraintLayout

MotionLayout is a subclass of ConstraintLayout, so it is fine to replace ConstraintLayout with MotionLayout when you need to manage animation for child Views. We can safely convert the top level ConstraintLayout in activity_main.xml to a MotionLayout. The easiest way to do that is

  1. Open activity_main.xml in the Design surface.
  2. Right-click on ConstraintLayout.
  3. Convert to MotionLayout.
    Convert_to_motionlayout.png
  4. When prompted that the action will convert your layout into a MotionLayout and create a separate MotionScene file, select Convert.
    convert_confirm.png
  5. Right-click on activity_main.xml file -> Local History -> Show History. We can see that there are a total of 2 main changes.
    a. The ConstraintLayout has been replaced by the MotionLayout.
    b. The layout file additionally references another XML file. This activity_main_scene XML file contains the animation data, which we will discuss in the next section.

history.png

MotionScene

MotionLayout manages its own layout XML, but this XML only includes information for the child Views, and not animation data. Decoupling layout and animation code improves readability for your project. The XML containing the animation data is stored inside the activity_main_scene.xml file (for this tutorial) that Android Studio created earlier for us. If we look inside activity_main_scene.xml, we can see that there are quite a few tags inside.

  1. Transition: a nested class inside MotionScene that defines how the animations are triggered, the duration of the animations, and the animation trajectory.
  2. KeyFrameSet: all animations start with the starting constraint and end with the ending constraint. KeyFrameSet contains the key frames needed to modify the path of the animation. This is optional and is out of scope for this tutorial.
  3. ConstraintSet: specifies the constraints for Views inside a ConstraintLayout. The animation will start with the starting constraint and end with the ending constraint.
Motion Editor

If we open the activity_main.xml file now in the Design/Split surface, we can see that there is a new section called the Motion Editor. This tool allows us to modify the activity_main_scene.xml file with a graphical user interface and also to preview the animation.

MotionEditor.png

The starting Constraint

We need to create a starting constraint so that MotionLayout will know where the starting position would be. To do this with the Motion Editor, perform the following steps:

  1. Select the start constraint set.
    start.png

  2. Currently the imageView is still constrained to the Select Modify constraint set.
    imageView.png

  3. Create Constraint.
    create_constraint.png

  4. You will then see that the imageView is constrained to the starting constraint (with id of start).
    start_constraint.png

  5. The ConstraintSet inside activity_main_scene.xml is also modified accordingly.

     <ConstraintSet android:id="@+id/start">
        <Constraint
            android:id="@+id/imageView"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />
     </ConstraintSet>
  6. We will want our imageView (android vector asset) to move from the bottom of the screen to the top of the screen, so add bottom, left and right constraints for it.

imageView_Constraint.png

The ending Constraint

Now that the starting point has been set, we will need to add the ending constraint. The steps are very similar to how we added the starting constraint in the previous section.

  1. Select the end ConstraintSet in the Motion Editor.
  2. Select the imageView in the Motion Editor.
  3. Select Modify constraint set.
  4. Create Constraint.
  5. Add top, left and right constraints to imageView.

ending_constraint.png

Animation Trigger

Since a Transition has already been defined for us in the activity_main_scene.xml file by Android Studio, we only need to add a trigger for our animation to start. We will use an onClick trigger for this part. To add a trigger, perform the steps below:

  1. Select the U-shaped arrow in the Motion Editor that connects the starting and ending constraint sets.
    arrow.png

  2. Select the Create click or swipe handler icon in the Motion Editor (highlited in yellow).
    clickhandler.png

  3. In View To Click, changes the value to imageView.

  4. Click Add.
    create_onclick.png

  5. Add an attribute called clickAction to the OnClick tag. The value for this attribute would be toggle. If you are confused about where this attribute came from. It is referenced here
    click_action.png

  6. The current XML definition for the OnClick tag would be:

     <OnClick motion:targetId="@+id/imageView"
        motion:clickAction="toggle" />
Preview the animation

One of the great features of Motion Editor is that you can preview the animation.

  1. Select the Transition element in Motion Editor (U-shaped arrow)
  2. When the Transition section shows up, press the Play button.

Transition_Preview.gif

Run the app

We have completed all of the steps required to animate the android icon. Go ahead and run the app. You will have to touch the icon once for the animation to start.

Android_Animation.gif

Solution Code

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.motion.widget.MotionLayout xmlns:android="http://schemas.android.com/apk/res/android"
   xmlns:app="http://schemas.android.com/apk/res-auto"
   xmlns:tools="http://schemas.android.com/tools"
   android:layout_width="match_parent"
   android:layout_height="match_parent"
   app:layoutDescription="@xml/activity_main_scene"
   tools:context=".MainActivity">

   <ImageView
       android:id="@+id/imageView"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       app:srcCompat="@drawable/ic_android_black_100dp" />
</androidx.constraintlayout.motion.widget.MotionLayout>

activity_mail_scene.xml

<?xml version="1.0" encoding="utf-8"?>
<MotionScene
   xmlns:android="http://schemas.android.com/apk/res/android"
   xmlns:motion="http://schemas.android.com/apk/res-auto">

   <Transition
       motion:constraintSetEnd="@+id/end"
       motion:constraintSetStart="@id/start"
       motion:duration="1000">
      <KeyFrameSet>
      </KeyFrameSet>
       <OnClick motion:targetId="@+id/imageView"
           motion:clickAction="toggle" />
   </Transition>

   <ConstraintSet android:id="@+id/start">
       <Constraint
           android:id="@+id/imageView"
           android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           motion:layout_constraintStart_toStartOf="parent"
           motion:layout_constraintBottom_toBottomOf="parent"
           motion:layout_constraintEnd_toEndOf="parent" />
   </ConstraintSet>

   <ConstraintSet android:id="@+id/end">
       <Constraint
           android:id="@+id/imageView"
           android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           motion:layout_constraintStart_toStartOf="parent"
           motion:layout_constraintTop_toTopOf="parent"
           motion:layout_constraintEnd_toEndOf="parent" />
   </ConstraintSet>
</MotionScene>
Summary

Congratulations, you have learned how to use MotionLayout. The full project code can be found at https://github.com/dmitrilc/DaniwebMotionLayout/tree/main

gcc find header files in current directories

I sometimes move my code around to various computers so I prefer to keep my header files in my current directory. Unfortunately it does not seem to be working.

$ gcc *.c -Wall
main.c:1:10: fatal error: mysql.h: No such file or directory
    1 | #include <mysql.h>
      |          ^~~~~~~~~
compilation terminated.

*My pygame window is black until i close it at the end

so i already posted three months ago and only reviwed my coded recently , still dotn know what is wrong . the code is quite simple however something keeps going wrong.

a possible flaw is the FPS clock which would expain why its black screen but the visible when i close t/he window.

if anyone knows what may be the problem please reply and ill send the code if neccesary , thnaks

Extract Text With AWS Textract Using AWS Step Functions

Introduction

In this post, we will look into how we can extract text from an image with AWS Textract and then generate a pdf file and upload it to the S3 bucket using AWS Step Functions. We are going to deploy a serverless stack with three lambda functions, one lambda will be triggering our AWS step functions state machine and other lambdas will be used to extract the text from the image, generate the pdf and then upload it to the S3 bucket.

Project Setup

Our project structure will look like this:

Git Clone Command vs. GitHub Backup – Best Practices

Cloning is a popular theme in science fiction movies and literature. Just to mention Star Wars and Attack of the Clones. But it’s not science fiction at all – in the real world probably everyone has heard of Dolly the sheep, the first cloned mammal. Since then, mankind has managed to clone, among others horse, pig, or dog. Wait, we are interested in the IT world, right? The world of over 87.2% programmers using the Git version control system, 60M GitHub users, 10M Bitbucket teams, and over 30M GitLab enthusiasts – so let’s focus on a very in-depth look at the git clone command topic. Do we have your attention?

What Is a Git Clone?

To work with Git, we need to have a copy of the repo on our device. In an event of failure and the lack of backups, we can restore the entire repository on the basis of such a copy. So what is a clone? This is a complete copy of the repository with an entire history of changes. But a clone is also the name of a specific function in Git that allows us to do this.