Android App ep.102

My Network Reporter v.2

For this project we are going to be recreating the network reporter application in Kotlin to look at the advantages and uniqueness Kotlin can provide.

Previous application utilizing java: Android App ep.101

Application Purpose:

This will remain the same as the last application….

We want to discern if transmitting a file of a size A across a network with a speed B gives us a reasonable time in seconds.

Our size of the file size is measured in MiB and our network speed is measured in Mbps.

We know that 1 B = 8 b; 1 MiB = 220 B; 1 Mbps = 106 bps.

Video to view in action: https://youtu.be/JUkxk5NhutM

activity_main.xml  Layout


This will remain the same as well since we just want to look at the benefits of Kotlin to Java.

Screen Shot 2018-10-15 at 8.44.27 AM

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal">

    <TextView
        android:id="@+id/textView"
        android:layout_width="96dp"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:paddingHorizontal="10dp"
        android:text="@string/file_size_label"
        android:textAlignment="center"
        android:textAllCaps="false"
        android:textSize="14sp" />

    <EditText
        android:id="@+id/fileSizeInput"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="@string/file_input_hint"
        android:inputType="number" />

</LinearLayout>

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal">

    <TextView
        android:id="@+id/networkSpeedLabel"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:text="@string/network_label"
        android:textAlignment="center"
        android:textSize="14sp" />

    <EditText
        android:id="@+id/networkSpeedInput"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="@string/network_hint"
        android:inputType="number" />
</LinearLayout>

<TextView
    android:id="@+id/resultDisplay"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:text="Input is needed for both File Size and Network Speed to estimate time"
    android:textAlignment="center"
    android:textColor="@android:color/black"
    android:textSize="18sp" />

On our Kotlin side…


package com.amsuarez.mynetworkreporter

import android.app.Activity
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.text.Editable
import android.text.TextWatcher
import android.widget.EditText
import kotlinx.android.synthetic.main.activity_main.*

class MainActivity : AppCompatActivity() {

    fun EditText.changed() {
       this.addTextChangedListener(object: TextWatcher {
            override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {}
            override fun onTextChanged(charSequence: CharSequence, i: Int, i1: Int, i2: Int) {
                if (fileSizeInput.text.toString() == "" || networkSpeedInput.text.toString() == "") {
                    resultDisplay.text = "Input is needed for both File Size and Network Speed to estimate time"
                } else {
                    val myb = Integer.parseInt(fileSizeInput.text.toString()).toDouble() * Math.pow(2.0, 20.0) * 8.0
                    val mybps = Integer.parseInt(networkSpeedInput.text.toString()) * Math.pow(10.0, 6.0)
                    resultDisplay.setText(String.format("%.1f", myb / mybps) + " seconds")
                }
            }
            override fun afterTextChanged(s: Editable) {}
        })
    }

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

        fileSizeInput.changed()
        networkSpeedInput.changed()
    }
}

Here we utilized some really cool features that Kotlin provides us with.

Extension Functions:

We utilized these to extend upon the EditText class to allow us to run a text watcher object in any EditText. This gives us a very clean call in our onCreate fun increasing readability.

Where are the findViewByIds? 👀

Kotlin provides a feature that allows us to reference straight out of our activities.

It is done by importing:

 import kotlinx.android.synthetic.main.activity_main.*

This allows us to no longer need to call findViewById and instead we can reference directly into our activities.

Objects? 🤔

Here we use object as an anonymous class that inherits TextWatcher allowing us to override the TextWatcher without having to “formally declare a new class”.

For more on Objects: https://kotlinlang.org/docs/reference/object-declarations.html

 

Android App ep.101

 

My Network Reporter

For this project we are going to be creating a simple application using TextFields, EditText, and a TextWatcher.

This tutorial assumes you know basic information about widgets and Java programming

Application Purpose:

We want to discern if transmitting a file of a size A across a network with a speed B gives us a reasonable time in seconds.

Our size of the file size is measured in MiB and our network speed is measured in Mbps.

We know that 1 B = 8 b; 1 MiB = 220 B; 1 Mbps = 106 bps.

Video to view in action: https://youtu.be/JUkxk5NhutM

activity_main.xml  Layout


Screen Shot 2018-10-15 at 8.44.27 AM.png

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal">

    <TextView
        android:id="@+id/textView"
        android:layout_width="96dp"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:paddingHorizontal="10dp"
        android:text="@string/file_size_label"
        android:textAlignment="center"
        android:textAllCaps="false"
        android:textSize="14sp" />

    <EditText
        android:id="@+id/fileSizeInput"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="@string/file_input_hint"
        android:inputType="number" />

</LinearLayout>

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal">

    <TextView
        android:id="@+id/networkSpeedLabel"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:text="@string/network_label"
        android:textAlignment="center"
        android:textSize="14sp" />

    <EditText
        android:id="@+id/networkSpeedInput"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="@string/network_hint"
        android:inputType="number" />
</LinearLayout>

<TextView
    android:id="@+id/resultDisplay"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:text="Input is needed for both File Size and Network Speed to estimate time"
    android:textAlignment="center"
    android:textColor="@android:color/black"
    android:textSize="18sp" />

Here we kept it as simple as possible using two linear layouts to block each input and label and a separate TextView to display a result.

 

On our Java side…


public class MainActivity extends AppCompatActivity {
    EditText fileSize;
    EditText networkSpeed;
    TextView result;

     // Here we use a TextWatcher to see if there are any changes.
    TextWatcher watchChange = new TextWatcher() {
        @Override
        public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {}

        @Override
        public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
            if(fileSize.getText().toString().equals("") || networkSpeed.getText().toString().equals("")){
                result.setText("Input is needed for both File Size and Network Speed to estimate time");
            }
            else {
               // this section calculates the time to send.
                Double myb = Integer.parseInt(fileSize.getText().toString()) * Math.pow(2, 20) * 8;
                Double mybps = Integer.parseInt(networkSpeed.getText().toString()) * Math.pow(10, 6);
                result.setText(String.format("%.1f", myb / mybps) + " seconds");
            }
        }
        @Override
        public void afterTextChanged(Editable editable) {}
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

         // this section assigns our java code to the xml android widgets
        fileSize        = (EditText) findViewById(R.id.fileSizeInput);
        networkSpeed    = (EditText) findViewById(R.id.networkSpeedInput);
        result          = (TextView) findViewById(R.id.resultDisplay);
        
        //this assigns the TextWatcher to both entry fields
        fileSize.addTextChangedListener(watchChange);
        networkSpeed.addTextChangedListener(watchChange);
    }
}

For more on TextWatchers visit Android documentation here : https://developer.android.com/reference/android/text/TextWatcher

Medium: Article: https://medium.com/@austinmsuarez/android-app-ep-101-83e0f0af8aa0

Simple StopWatch

StopWatch by Developer Austin.

Screen Shot 2018-01-17 at 3.35.50 PM.png

This was my first actual published application for the Android Play Store and I loved the process! My goal for this project was to create a simple application and to try to learn as much as possible.

I used Android O to create and release so it is not available to everyone.

Download Page: https://play.google.com/store/apps/details?id=com.amsuarez.stopwatch

Application Design

Layout

Screen Shot 2018-01-17 at 3.38.32 PM.png
For this application, I used the constraint layout, Chronometer, ListView, and two Buttons. I went with a listview since it is easy to set constraints regardless of the device size. The chronometer seemed like a logical choice over Date since it had methods for starting and stopping. The start and stop buttons I placed at the bottom and placed colors so that it is easy to discern the differences at a glance.

Code

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.Chronometer;
import android.os.SystemClock;
import android.widget.ListView;
import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity {
   private Chronometer stopwatch;
   private List<String> timeList;
   private ListView timeElapsedList;
   private boolean timerStart = false;
   private ArrayAdapter<String> listAdapter;
   private int lapCount = 0;
    @Override
    protected void onCreate(Bundle savedInstanceState) {

        //sets up layout
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // setting stopwatch to chronometer
        stopwatch = findViewById(R.id.timeElapsed);

        //setting up listview
        timeList = new ArrayList<String>();
        timeElapsedList = (ListView) findViewById(R.id.timeListView);
        listAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, timeList);
        // DataBind ListView with items from ArrayAdapter
        timeElapsedList.setAdapter(listAdapter);
    }

    public void startButton(View view) {
        // resets the start time
        stopwatch.setBase(SystemClock.elapsedRealtime());
        // starts the chronometer
        stopwatch.start();
        timerStart = true;
    }

    public void stopButton(View view) {
        stopwatch.stop();
        // if the start was pressed prior then stop process begins
        if (timerStart) {
            lapCount++;
            timeList.add("Lap " + lapCount + ": " +stopwatch.getText().toString());
            listAdapter.notifyDataSetChanged();
            stopwatch.setBase(SystemClock.elapsedRealtime());
            timerStart = false;
        }
    }

This was the first time I used the chronometer, I was originally going to use a Date variable but soon ran into some trouble. Using a Date variable I could measure the exact time elapsed; however, creating a visual transition of the time elapsed on the UI was difficult. I then picked the chronometer and my code was able to slim down since the methods the widget had been just what I needed.

Porting to the Store:

This was fairly easy to launch to the market since it did not use location or any other information from the user. In the future, I would like dive deeper into the Beta and Alpha testing processes in the Play Console.

Conclusion:

It was a fun simple project and I am definitely excited to do more projects like this!

If you are reading this and have any suggestions please message or comment. 😀