Category Archives: Android

How to add a select element in React Native

TL;DR: The React Native Picker component is the equivalent of the HTML select element.

In my last post, I used fetch to download a list of movie titles. However, I only displayed the list by using a debugging tool. My app user will want to see this list, and even better, may want to select something off the list. The commonly used web widget which does this is the HTML <select> element. In React Native, the corresponding widget is a Picker.

You can add a Picker to your render method very easily, like this:

import { Picker } from 'react-native';
...
render() {
    return <View>
        <Picker>
        </Picker>
    </View>;
}

That’s a start, but it doesn’t display my data, and it doesn’t look very interesting. We’ve got a picker with no functionality which looks like this:

Notice the little upside-down triangle in the upper right corner, which indicates the Picker has loaded.

In order to populate the Picker with data, we need to get access to the list of movies inside the render method. Fortunately, I already used setState to make the movie data persist in my app’s state (see previous post). That means I can use it in render, like this:

render() {
    let items = [];
    var length = this.state.dataSource.length;
    for (var i = 0; i < length; i++) {
        var item = this.state.dataSource[i];
        // Really, really important to not put quotes around these braces:
        items.push(<Picker.Item label={item.title} value={item.title} key={item.id} />);
    }
    return <View>
        <Picker>
        </Picker>
    </View>;
}

Uh oh, wait, as soon as I added this code, I saw the red screen of death in the emulator. The error message read “TypeError: null is not an object (evaluating ‘this.state.dataSource’). This error is located at: in HelloWorldApp (at renderApplication.js:40)…”

The problem is that I tried to reference this.state.dataSource before it had been set. The render method might be called before fetch runs. We don’t know when our fetch statement will be called, or even if it is successful. We need to add code in render which handles the case where this data is not yet available.

Here’s the new render code which skips doing anything with dataSource if it is not found:

render() {
    if (this.state && !this.state.isLoading) {
        let items = [];
        var length = this.state.dataSource.length;
        for (var i = 0; i < length; i++) {
            var item = this.state.dataSource[i];
            items.push(<Picker.Item label={item.title} value={item.title} key={item.id} />);
        }
        return <View>
            <Picker>
            </Picker>
        </View>;
    } else {
        return ( <View></View>);
    }
}

That fixes the error, but the Picker is still empty. But in anticipation of needing a list of movies, I’ve already got a list of Picker.Item objects loaded into an array using JSX (items.push(<Picker.Item....). It turns out to be very easy to add these to the Picker. Just add items in braces inside the Picker tags, like this:

<Picker>
{items}
</Picker>

As soon as this is done, like magic, the Picker reflects the changes. A dropdown appears with the text Star Wars selected by default.

Now you can click the dropdown, and try to select a different movie, but what you’ll find is that the dropdown is stuck at Star Wars – you can’t select anything else!

For a finishing touch, let’s make it possible for the user to select a different movie. The Picker documentation tells us how to do this by adding the selectedValue attribute and the onValueChange methods like this:

selectedValue={this.state.movie}
onValueChange={(itemValue, itemIndex) =>
    this.setState({ movie: itemValue })
}

After adding this I can select any movie, and that movie stays selected! Here’s my final code:

import React, { Component } from 'react';
import { View, Picker } from 'react-native';

export default class HelloWorldApp extends Component {
    componentDidMount() {
        return fetch('https://facebook.github.io/react-native/movies.json')
            .then((response) => response.json())
            .then((responseJson) => {
                console.log(responseJson);
                this.setState({
                    isLoading: false,
                    dataSource: responseJson.movies,
                }, function () {

                });

            })
            .catch((error) => {
                console.error(error);
            });
    }

    render() {
        if (this.state && !this.state.isLoading) {
            let items = [];
            var length = this.state.dataSource.length;
            for (var i = 0; i < length; i++) {
                var item = this.state.dataSource[i];
                // Really, really important to not put quotes around these braces:
                items.push(<Picker.Item label={item.title} value={item.title} key={item.id} />);
            }
            return <View>
                <Picker selectedValue={this.state.movie}
                    onValueChange={(itemValue, itemIndex) =>
                        this.setState({ movie: itemValue })
                    }>
                    {items}
                </Picker>
            </View>;
        } else {
            return (<View></View>);
        }
    }
}

If you found this interesting, click the subscribe button below! I write a new post about once a week.

Simple debugging tool in React Native

TL;DR: If you want to debug React Native code really quickly, console.log and console.warn can help.

In my previous post, I described how I ported the React Clock app to React Native. This is the code for my simple app:

import React, { Component } from 'react';
import { Text, View, Button } from 'react-native';
import Clock from './Clock';

export default class HelloWorldApp extends Component {
    render() {
        return (
            <View style={{ flex: 1, justifyContent: "center", alignItems: "center" }}>
                <Text style={{ fontWeight: 'bold', padding: 10 }}>Hello, world!</Text>
                {/* padding does not work with Button!! */}
                <Button style={{ fontWeight: 'bold', padding: 40 }} title="Click me" >Click Me!</Button>
                {/* Since padding does not work with Button, we add an empty text area */}
                <Text>{""}</Text>
                <Clock />
            </View>
        );
    }
}

For my next project, I decided to do something more realistic. I wanted to figure out how to fetch data from a REST API.

I already had the Android emulator started (see previous post). A quick look at the React-Native networking documentation told me that doing a fetch should be a piece of cake. Because I didn’t want to copy their entire sample app, but just reuse their fetch call, I copied the componentDidMount method, and pasted it into my application above the render method:

componentDidMount(){
return fetch('https://facebook.github.io/react-native/movies.json')
    .then((response) => response.json())
    .then((responseJson) => {

    this.setState({
        isLoading: false,
        dataSource: responseJson.movies,
    }, function(){

    });

    })
    .catch((error) =>{
    console.error(error);
    });
}

(The componentDidMount method may be familiar to you from React.js development.)

I didn’t see any errors when I did this, but I also couldn’t tell whether the fetch method had worked! If I had been building this app using JavaScript in a web browser, I could have quickly checked the results by adding a console.log statement to print out responseJson. I tried this, in fact, but nothing noticeable happened onscreen when I made my change. It took a little while, but I finally noticed that my statements were being logged in the terminal window that was running the Metro server (where I’d run the npm start command)! It took me a while before I noticed this because I’m not usually looking at the terminal unless I’m trying to debug a problem.

A quick search also told me that I could use console.warn to display text on the emulator’s screen. I added console.warn(responseJson); just above the setState call, and I could see that the method had succeeded, and I could also see part of the responseJson content in the YellowBox which appeared. Clicking on this YellowBox warning gave me a fullscreen view of the JSON.

Probably it’s a bad idea to display debug messages using console.warn, but if I were debugging on a device without the help of Metro server, I think console.warn would come in handy.

If you found this interesting, click the subscribe button below! I write a new post about once a week.

Invariant violation: Text strings must be rendered within a Text component

TL;DR: To display text in React Native, you must always use a Text tag. This is different from React.js, where text can be displayed in html tags like <div> or <h1>.

For my next mini React Native project, I’m porting the React Clock app to React Native. FYI I’m doing this work on Ubuntu 16.04.

I have to start up my Android emulator first. I list the available ones like this:

emulator -list-avds
Galaxy_Nexus_API_23
Galaxy_Nexus_API_28
Samsung_S4_mIni_API_17

I pick one, and start it:

emulator -avd Galaxy_Nexus_API_28

I didn’t want to have to fire up Android Studio every time I worked on a React Native project, so running the emulator from the command line is super useful. Note the emulator has nothing to do with React Native, per se, and it’s just running in a standalone mode. I can run my emulator commands from any directory; I just open a terminal and do it.

I had already gotten started with React Native. I had a folder called AwesomeProject with a directory structure like this:

...
ios/
android/
App.js

I step into this directory and run the commands npx react-native run-android followed by npm start. I see my project load into the emulator.

I’m using VS Code as my IDE for React Native development. I have no trouble making a small change or two to my App.js file, and I see these changes immediately loaded into the emulator.

Next, I add a file called Clock.js in the same directory as my App.js class.

import React from 'react';
export default class Clock extends React.Component {
  constructor(props) {
    super(props);
    this.state = {date: new Date()};
  }

  componentDidMount() {
    this.timerID = setInterval(
      () => this.tick(),
      1000
    );
  }

  componentWillUnmount() {
    clearInterval(this.timerID);
  }

  tick() {
    this.setState({
      date: new Date()
    });
  }

  render() {
    return (
      <div>
        <h1>Hello, world!</h1>
        <h2>It is {this.state.date.toLocaleTimeString()}.</h2>
      </div>
    );
  }
}

This is almost the same as the Clock.js code in the React.js state and lifecycle demo. I’ve removed the ReactDOM.render method because I don’t want the clock rendering immediately. Also, I’ve exported the class so it can be used by other components.

Now I add the Clock to my App. There’s just one line to import it:

import Clock from './Clock';

And a tag to add it:

<Clock/>

This is what my App.js file looks like:

import React, { Component } from 'react';
import { Text, View, Button } from 'react-native';
import Clock from './Clock';

export default class HelloWorldApp extends Component {
    render() {
        return (
            <View style={{ flex: 1, justifyContent: "center", alignItems: "center" }}>
            <Text style={{ fontWeight: 'bold', padding: 10 }}>Hello, world!</Text>
            {/* padding does not work with Button!! */}
            <Button style={{ fontWeight: 'bold', padding: 40 }} title="Click me" >Click Me!</Button>
            {/* Since padding does not work with Button, we add an empty text area */}
            <Text>{""}</Text>
            <Clock/>
            </View>
        );
    }
}

As soon as I did this, I saw an error message in my emulator:

The error message reads “Invariant violation: Text strings must be rendered within a component. This error is located at: in h1 (at Clock.js:28) in dev (at Clock.js:27)…”

Since the location of the error is very nicely displayed, I can quickly find the problem. The render method of my React.js Clock class is

  render() {
    return (
      <div>
        <h1>Hello, world!</h1>
        <h2>It is {this.state.date.toLocaleTimeString()}.</h2>
      </div>
    );

and the complaint is about the text “Hello, world!” within the <h1> tags. It didn’t take long before I discovered the problem in the React Native documentation for the Text component: “In React Native, we are more strict about it: you must wrap all the text nodes inside of a component. You cannot have a text node directly under a <View>.”

Let me just try using a Text tag instead of h1 and h2 tags. First I add the import statement:

import { Text } from 'react-native';

And then I swap out <h1> and <h2> for <Text>. That seems to work, but now I have a new error: “Invariant violation: View config not found for name div. Make sure to start component names with a capital letter.”

I already know the complaint is about the div tag in Clock.js. Whoops, divs do not live in native apps. I’ll just change my div tag to a Text tag and see what happens. Here’s my render code:

  render() {
    return (
        <Text>
            <Text>Hello, world!</Text>
            <Text>It is {this.state.date.toLocaleTimeString()}.</Text>
        </Text>
    );
  }

And here’s my running clock!

If you found this interesting, click the subscribe button below! I write a new post about once a week.

Unable to load script. Make sure you’re either running a Metro server…

TL;DR: run npm start in your project root to avoid this error! I’m using Ubuntu 16.04 and Android, YMMV.

In teaching myself React, I’ve been pleasantly surprised by the documentation provided by Facebook. It’s very clear, I’ve been following along easily, and I never hit a speed bump. I was expecting something similar when I started on React Native.

Unfortunately, the React Native docs are a little less polished than those for React.

I started at the appropriately named Getting Started page. I’m running Ubuntu 16.04, and I’ve done Android development, so I followed the “React Native CLI Quickstart” choose-your-own-adventure path, clicking on “Development OS: Linux” and “Target OS: Android”.

I followed the instructions to the letter, except for a few things. I already had Android Studio installed, for example, so I didn’t have to do that. However, I initialized a fresh new React Native project using their installer, just as they said, even using the same project name: npx react-native init AwesomeProject.

I got down to the section entitled “Running your React Native application”, and did as instructed:

cd AwesomeProject
npx react-native run-android

This is what I saw in the Emulator: a message with white letters on a red background saying "Unable to load script. Make sure you're either running a Metro server (run 'react-native start') or that your bundle 'index.android.bundle' is packaged correctly for release."

This was not one of those cases where I immediately knew what was wrong. Why are they talking about “Metro server”? How would I know if my bundle is packaged correctly for release??

I tried doing as the error message suggests:

~/AwesomeProject$ react-native start
react-native: command not found

No.

I went down one rabbit hole after another trying to fix the problem: First, I switched to USB debugging on an Android mobile device, because I thought the most obvious solution would be a problem with the Android Emulator (quite often, that is the problem). I got the same message there. (At this point, I started calling this page the “red screen of death”).

Finally, I got the app working in my mobile device by doing a release build:

~/AwesomeProject$ npx react-native run-android --variant=release

That worked! The app looked like this in my mobile device:

That was confidence inspiring because at least something worked. But it wasn’t useful; I wanted to be able to do hot reloading of my changes, and the install process of the release build was taking two to three minutes. No way was I going to spend 2 minutes waiting to see my changes.

Long story short, I finally figured out what was wrong (thank you, Stack Overflow).

The solution is to run npm start in the root of the project, like this:

~/AwesomeProject$ npm start

NOT react-native start, which was suggested in the error message, as I mentioned above. That was a total fail.

When I ran npm start in the command line, I saw this:

~/AwesomeProject$ npm start

> AwesomeProject@0.0.1 start /home/fullstackdev/AwesomeProject
> react-native start

┌──────────────────────────────────────────────────────────────────────────────┐
│                                                                              │
│  Running Metro Bundler on port 8081.                                         │
│                                                                              │
│  Keep Metro running while developing on any JS projects. Feel free to        │
│  close this tab and run your own Metro instance if you prefer.               │
│                                                                              │
│  https://github.com/facebook/react-native                                    │
│                                                                              │
└──────────────────────────────────────────────────────────────────────────────┘

Looking for JS files in
   /home/fullstackdev/AwesomeProject 

Loading dependency graph, done.

 BUNDLE  [android, dev] ./index.js ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ 100.0% (449/449), done.

 LOG  Running "AwesomeProject" with {"rootTag":1}

Notice the important message: “Keep Metro running while developing on any JS projects“. Doh! Thanks for telling me that.. now that it’s started, lol!

But now I’ve got my “Hello World” app running, and I can proceed working on something more interesting.

If you found this interesting, click the subscribe button below! I write a new post about once a week.

How to access an AWS RDS using JDBC in your Android app – Part II

In my last post, I described a quick way to set up an Amazon MySQL RDS (Relational Database Service).

In this post, I’m going to build an Android app which uses JDBC to search that database, and list results.

Caveat: As I mentioned in my previous post, this is a “quick and dirty” way of doing things, and it’s not recommended to do things exactly this way. However, this method is fine when you’re building a proof of concept or a demo and you need to get things done quickly. It took me an afternoon to throw together a working demo using this method!

To get started on your app, fire up Android Studio and create a “New Project” with an “Empty Activity”. Accept all the defaults, but make sure your app is for Java (unless you want to work with Kotlin).

We just want to add a few simple items for the user interface: a text input for searching on a term, a button to submit the search term, and a scrollview that can be used to display results. Let’s do that now.

When I created my empty activity, a new layout file was added called activity_main.xml. I opened that up in the design view, and added the widgets that I wanted. Eventually, I finished the layout by customizing it in the text view. Here’s the final layout:

<?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">
    <EditText
        android:id="@+id/editText"
        android:layout_width="357dp"
        android:layout_height="48dp"
        android:ems="10"
        android:hint="Enter Search term and hit button for results"
        android:inputType="text"
        app:layout_constraintTop_toTopOf="parent"
        android:layout_marginTop="8dp"
        android:layout_marginBottom="8dp"
        android:layout_marginRight="8dp"
        app:layout_constraintRight_toRightOf="parent"
        android:layout_marginLeft="8dp"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintHorizontal_bias="0.513"
        android:layout_marginStart="8dp"
        android:layout_marginEnd="8dp"/>
    <Button
        android:id="@+id/btnSearch"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Search"
        android:layout_marginRight="8dp"
        app:layout_constraintRight_toRightOf="parent"
        android:layout_marginLeft="8dp"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintHorizontal_bias="0.502"
        app:layout_constraintTop_toBottomOf="@+id/editText"
        android:layout_marginStart="8dp"
        android:layout_marginEnd="8dp"
        android:layout_marginTop="8dp"/>

    <ScrollView
        android:id="@+id/scrollview"
        android:layout_width="wrap_content"
        android:layout_height="0dp"
        android:layout_margin="8dp"
        app:layout_constraintBottom_toTopOf="@+id/textView"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/btnSearch">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical">

            <TextView
                android:id="@+id/tvResults"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:text=""></TextView>
        </LinearLayout>
    </ScrollView>

    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="8dp"
        android:text="Type in text, click a button to search"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

It looks like a lot, but it isn’t. Android layout files are quite verbose! One comment: notice that the ScrollView has a layout height of 0dp. It took me a few minutes of searching to figure out that this was necessary. Prior to doing that, the ScrollView results overlapped the search button and instructional text.

Notice that I’ve set Android @+ids for the parts that I need to access programmatically. I need to be able to click the search Button (@+id/btnSearch), get text from the input EditText (@+id/editText), and display text in the ScrollView‘s TextView (@+id/tvResults).

Next, I opened the MainActivity class, and added the methods needed to click the button, get results, and display them – like this:

package com.fullstackoasis.myapplication;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.text.Editable;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity implements AsyncResponse {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Button b = (Button)this.findViewById(R.id.btnSearch);
        b.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                searchByName();
            }
        });
    }

    protected void searchByName() {
        EditText et = (EditText)findViewById(R.id.editText);
        Editable editable = et.getText();
        String s = editable.toString();
        Log.d("MainActivity", "searchByName " + s);
        if (s.length() > 2) {
            MySQLAsyncTask mySQLAsyncTask = new MySQLAsyncTask();
            mySQLAsyncTask.setDelegate(this);
            mySQLAsyncTask.execute(s);
        } else {
            displayResults("Please type in at least 3 letters, for example 'Italian'");
        }
    }

    public void processFinish(String result) {
        if (result.length() > 502) {
            Log.d("MainActivity:", "processFinish " + result.substring(0, 500));
        } else {
            Log.d("MainActivity:", "processFinish " + result);
        }
        displayResults(result);
    }

    private void displayResults(String res) {
        TextView tvResults = (TextView)findViewById(R.id.tvResults);
        tvResults.setText(res);
    }
}

Now I only needed one more crucial bit, the Java class which contacts the Amazon RDS. I added a new Java class by clicking the menu item File > New > Java Class, and chose the name MySQLAsyncTask. I had it extend AsyncTask. The source for that class is shown next. If you copy this code for your own working demo, you will have to edit the url string to use your own RDS endpoint. Also, notice the big warnings about checking in files into source control if they contain hard-coded strings that would make your credentials publicly available! I’m not going to go into how to handle that here, but just don’t do it.

package com.fullstackoasis.myapplication;

import android.os.AsyncTask;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.PreparedStatement;

final class MySQLAsyncTask extends AsyncTask<String, Void, String> {
    private static final String url = "jdbc:mysql://healthdata-1.c84gpzpanfrn.us-east-1.rds.amazonaws.com:3306/food_inspections";
    private static final String user = "MY_WONDERFUL_USER_NAME"; // WARNING! DO NOT CHECK IN YOUR CREDENTIALS INTO PUBLIC SOURCE CONTROL
    private static final String pass = "MY_WONDERFUL_PASSWORD"; // WARNING! DO NOT CHECK IN YOUR CREDENTIALS INTO PUBLIC SOURCE CONTROL
    private static String res;
    private AsyncResponse delegate = null;

    void setDelegate(AsyncResponse d) {
        delegate = d;
    }

    @Override
    protected void onPreExecute() {
        super.onPreExecute();
    }
    @Override
    protected String doInBackground(String... params) {
        try {
            Class.forName("com.mysql.jdbc.Driver").newInstance();
            Connection con = DriverManager.getConnection(url, user, pass);
            System.out.println("Database Connection success "  + params);

            String result = "Database Connection Successful\n";
            // Let's search by dba_name and / or aka name.
            // Limit results by to top 10 results, and let user scroll

            PreparedStatement ps = con.prepareStatement("SELECT * FROM health_reports" +
                    " WHERE " +
                    "dba_name LIKE ? OR aka_name LIKE ? LIMIT 10");
            String searchPartial = params[0] + "%"; // LIKE 'Blah%'
            ps.setString(1, searchPartial);
            ps.setString(2, searchPartial);

            ResultSet rs = ps.executeQuery();
            ResultSetMetaData rsmd = rs.getMetaData();

            String sep = " | ";

            while (rs.next()) {
                result += rs.getInt(1) + sep + // id
                        rs.getInt(2) + sep + // inspection_id
                        rs.getString(3) + sep + // dba_name
                        rs.getString(4) + sep + // aka_name
                        rs.getInt(5) + sep + // license_num
                        rs.getString(6) + sep + // facility_type
                        rs.getString(7) + sep + // risk
                        rs.getString(8) + sep + // address
                        rs.getString(9) + sep + // city
                        rs.getString(10) + sep + // state
                        rs.getString(11) + sep; // zip
                try {
                    result += rs.getString(12).toString() + sep; // inspection_date
                } catch (Exception e) {
                    // e.printStackTrace();
                }
                result += rs.getString(13) + sep + // inspection_type
                        rs.getString(14) + sep + // results
                        rs.getString(15) + sep + // violations
                        rs.getString(16) + sep // location
                        ;
                result += System.lineSeparator();
                result += "------------";
                result += System.lineSeparator();
            }
            res = result;
            if (res.length() > 502) {
                Log.d("Task:", "Database Result success " + result.substring(0, 500));
            } else {
                Log.d("Task:", "Database Result success " + result);
            }
        } catch (Exception e) {
            e.printStackTrace();
            res = e.toString();
        }
        return res;
    }
    @Override
    protected void onPostExecute(String result) {
        Log.d("Task:", "onPostExecute");
        this.res = result;
        delegate.processFinish(result);
    }
}

This class uses the MySQL JDBC driver. You have to add the MySQL database connector as a module to your project. The instructions to do that are in StackOverflow – click that link and follow the instructions, which were pretty easy, at least with Android Studio 3.5.

For test purposes, I ran this demo in the Android Emulator. I typed in ‘Italian’ for the search term, and got back a bunch of results. It took a short while, because I never added any indexes to my database table, but that’s something to fine-tune later.

As a finishing touch, I built the Android APK, and loaded it onto my phone. Here’s a screenshot of the result:

Now, as mentioned earlier, you shouldn’t use a direct connection to the database in production code. A hacker might crack open your app, find the user name and password to your database, and do bad things! Ideally, you’ll want to connect to your database using some middleware which fields requests to the database, and makes sure that things like access permissions are enforced. That’s why this little Android app is just for demonstration purposes. The good part is that it can be built quickly, so you don’t have to waste time building middleware until you’re 100% sure you’re going to need it in a publicly available app!

If you found this interesting, click the subscribe button below! I write a new post about once a week.

How to access an AWS RDS using JDBC in your Android app – Part I

You’ve got a huge spreadsheet that has a lot of data in it, and you’ve built an Android app which works like a search engine on the data. Nice! But there’s a problem: when you build your app with all of that data in it, the APK is huge! You want to reduce the size of the app. And you also want to offload the search functionality onto a relational database, which is probably going to provide a more efficient search. How do you start?

This blog post explores one way to do it. It’s “quick and dirty”, and it’s not recommended to do things exactly this way. I’ll talk about why in Part II. But this method will give you a start.

Here’s a quick sketch of the idea: You put your data in the cloud using the Amazon Relational Database Service (RDS). Then you add JDBC calls to your app to access the cloud. It’s pretty quick. Here are the steps, using a simple example that I tried for myself.

Technical Details: My development environment runs Ubuntu 16.04, and I have a MySQL client and the MySQL database already installed on my local machine. I use Android Studio 3.5 IDE for building Android apps. Also, I have an Amazon AWS account set up already. You can follow this tutorial if you don’t have any of that, but then specific steps will differ for you.

Get Your Data Source Ready

For my data source, I downloaded some food inspection data from healthdata.gov in a csv (“comma-separated values”) format. I opened the csv file in a spreadsheet, selected some of the columns that I wanted, and exported them to another file, also in csv format. You can use the csv file that I generated by starting with this small, truncated version of the data. Later, you can use or create your own, very large data source for experiments.

Create an Amazon RDS MySQL Database

Visit the Amazon MySQL RDS page and click “Get Started”. If you don’t have an AWS account, you will need to sign up for one, first. Check out the pricing, if you are worried. There’s a free tier, great!

If you’re already signed in, another way to get started is to visit the AWS Management Console, search for “RDS”, and click the result for “Managed Relational Database Service”.

At this point, you’ll see a “Create Database” button. Choose “MySQL”, and click the “free tier”. Type in healthdata-1 for the name. Choose a username when requested. I’m using fullstackdev. Pick a secure password. The other parts of the form are straightforward. You can think about using IAM based authentication later. For this proof-of-concept piece of work, let’s keep it simple, and use password based authentication. For the rest, accept all defaults.

At this point, a page opens which says the database is being created.

AWS RDS creating database

Click the “modify” button. You’ll see that you can modify various things about the database later, if you want. Just be aware of this. For right now, you’ll need to “modify” the RDS so that it can be accessed from external sources – so choose “Public accessibility” and set it to Yes, and make sure to click the “Continue” button at the bottom of the page to save your changes. You need to do this so that you can create a database, load data into it, and access it via JDBC.

Now we’ve got an RDS in the cloud, and it’s accessible from our home environment. Next, we need to create a database.

Create Your Database and Manage Access

If you click the DB identifier in your RDS console, you will see an area called “Connectivity & security”. That area tells you what your endpoint is, and what your port is. The port defaults to 3306. Your endpoint will be something like healthdata-1.c84gpzpanfrn.us-east-1.rds.amazonaws.com. This is a URL you can use to access the database from another machine.

In the ‘Security’ pane, at the right, you will see your VPC (Virtual Private Cloud) security groups with a link to the default. Click that. It will take you to your Security Groups area. The default VPC security group should be preselected. Look at the bottom panel, where you should see the “Description”, “Inbound”, “Outbound”, and “Tags” tabs. Click “Inbound” and hit the “Edit” button. Click the “Add Rule” button, select MySQL/Aurora, make sure that the protocol is set to TCP/IP and the port to 3306, thne choose “MyIP” as the source. Your IP address will be set when doing this. Then hit the “Save” button.

Remember that you’ve added this rule just for your own IP address! You’re doing this for test purposes. Later, if you want, you can make different inbound rules, but this setup is good for a proof-of-concept.

Now the RDS is accessible. I am comfortable using the command line for MySQL client, so I used this to step into the cloud, and create my database. You can use whatever tool you want to do this.

First, I connected via this command:

mysql -u fullstackdev -P 3306 -p -h healthdata-1.c84gpzpanfrn.us-east-1.rds.amazonaws.com healthdata-1

The -p option tells the client to ask for a password interactively. I gave the password that I had set up earlier, and immediately, I was connected. This is what I saw:

Type: MySQL/Aurora,
Protocol: TCP
Port Range: 3306
Source: MyIP
Description: MySQL client

show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| innodb             |
| mysql              |
| performance_schema |
| sys                |
+--------------------+
5 rows in set (0.03 sec)

It’s the usual default MySQL database setup.

I had already designed a database around the food inspection data that I had decided to import. I created my own database like this:

CREATE DATABASE food_inspections;
USE food_inspections;
DROP TABLE health_reports;
CREATE TABLE health_reports (
    id INT AUTO_INCREMENT PRIMARY KEY,
	inspection_id INT,
	dba_name TEXT,
	aka_name TEXT,
	license_num INT,
	facility_type TEXT,
	risk TEXT, address TEXT,
	city TEXT, state TEXT,
	zip TEXT, inspection_date DATE,
	inspection_type TEXT, results TEXT,
	violations TEXT, location TEXT
);

I didn’t add any indexes for the columns other than the primary key. That can all be added later, when performance tuning.

Push Your Data to Amazon RDS MySQL Database

AWS provides instructions for pushing data to a MySQL RDS in the cloud. Since we have a new RDS which is already set up, we can skip straight to step 5, “Load the Data”.

They tell you to use the mysqlimport command, and you can do that if you want. There are other tools that can be used to import data, too. However, since I was already in the MySQL client, I used the LOAD DATA command, like so:

LOAD DATA LOCAL INFILE 'Food_Inspections_small.csv' INTO TABLE health_reports
	FIELDS TERMINATED BY ',' ENCLOSED BY '"'
    LINES TERMINATED BY '\n' (@inspection_id, @dba_name, @aka_name,
		@license_num, @facility_type, @risk, @address, @city, @state, @zip,
		@inspection_date, @inspection_type, @results, @violations, @location)
	SET inspection_id = @inspection_id, dba_name = @dba_name, aka_name = @aka_name,
		license_num = @license_num, facility_type = @facility_type, risk = @risk,
		address = @address, city = @city, state = @state, zip = @zip,
		inspection_date = @inspection_date, inspection_type = @inspection_type,
		results = @results, violations = @violations, location = @location;

Keep in mind that you may need to modify this command for your own purposes. I had launched the MySQL client from within the same directory where my Food_Inspections_small.csv was located, , so this command worked for me straightaway.

Now, my RDS is all set up, complete with data! That is half the battle. In my next blog post, I’ll cover how to access the RDS using an Android app.

If you found this interesting, click the subscribe button below! I write a new post about once a week.

How to build your Android app without opening the IDE

When developing Android apps, I’m almost always working in the Android Studio development environment (IDE).

I have a pretty solid dev computer, but even so, it just takes a little while for Android Studio to start up. There are times when I have to make a teeny tiny change to the source code, and it’s just a chore to open the IDE, change the code, and rebuild my app.

For example, suppose my client has requested a change to a string that’s displayed in a TextView. I’d much rather open my strings.xml file using a text editor like vi, edit the string as requested, and rebuild the app without ever touching Studio.

In fact, it’s possible to do this. Open a terminal, and go to your Android Studio project root. For me, this is in my home directory under ~/StudioProjects/. After editing the strings file (e.g. ./app/src/main/res/values/strings.xml), run ./gradlew build. You’ll see a bunch of output like this:

./gradlew build
:buildSrc:compileJava UP-TO-DATE
:buildSrc:compileGroovy UP-TO-DATE
...
:app:test UP-TO-DATE
:app:check
:app:build

BUILD SUCCESSFUL

Total time: 4.855 secs

Your new apk will be in the default location for your project. If you don’t recall where that is, you can find it quickly by running find . -name "*.apk".

Note: this demo was done using Ubuntu 16.04 OS with Android Studio 2.3. I’m not sure if it will work for Android Studio 3, but I think it will.

If you found this interesting, click the subscribe button below! I write a new post about once a week.

How to create a keystore file for Android development using the command line environment

TL;DR: Run keytool -genkey -alias MyReleaseKeyAlias1 -keystore mykeystore.pfx -storetype PKCS12 -keyalg RSA -validity 1095 -keysize 2048 and respond to the prompts to generate a keystore file which is good for 1095 days (3 years).

Even the long answer is pretty straightforward 🙂 I am using a Linux environment, Ubuntu 18.04.

You may need to install the JDK. Make sure that JDK version 8 is installed (if the JDK is already installed, this command will not do any harm, so you need not be afraid to run it):

sudo apt-get install openjdk-8-jdk

Next, create a directory for your keystore, and go into it. For example,

mkdir ~/AndroidKeystores
cd ~/AndroidKeystores/

(The tilde ~/ is a shorthand for your home directory, for example /home/fullstackdev.)

Finally, generate the keystore by using keytool

keytool -genkey -v -keystore my.keystore -alias MyReleaseKeyAlias1 -keyalg RSA -keysize 2048 -validity 1095

You will have to answer a few, fairly straightforward, questions. In my example, below, I just made up some silly answers; you should use your own information instead. But you can also make up anything – as long as you are just using the keystore for development work, it doesn’t matter what you use.

keytool -genkey -v -keystore my.keystore -alias MyReleaseKeyAlias1 -keyalg RSA -keysize 2048 -validity 1095
Enter keystore password:  
Re-enter new password: 
What is your first and last name?
  [Unknown]:  Full Stack Dev
What is the name of your organizational unit?
  [Unknown]:  Full Stack Oasis
What is the name of your organization?
  [Unknown]:  
What is the name of your City or Locality?
  [Unknown]:  Whitehorse Ledge
What is the name of your State or Province?
  [Unknown]:  New Hampshire
What is the two-letter country code for this unit?
  [Unknown]:  US
Is CN=Full Stack Dev, OU=Full Stack Oasis, O=Unknown, L=Whitehorse Ledge, ST=New Hampshire, C=US correct?
    [no]:  yes
Generating 2,048 bit RSA key pair and self-signed certificate (SHA256withRSA) with a validity of 1,095 days
	for: CN=Full Stack Dev, OU=Full Stack Oasis, O=Unknown, L=Whitehorse Ledge, ST=New Hampshire, C=US
Enter key password for <MyReleaseKeyAlias1>
	(RETURN if same as keystore password):  
Re-enter new password: 
[Storing my.keystore]

Warning:
The JKS keystore uses a proprietary format. It is recommended to migrate to PKCS12 which is an industry standard format using "keytool -importkeystore -srckeystore my.keystore -destkeystore my.keystore -deststoretype pkcs12".

Now, notice that the output tells me that JKS is proprietary. So let’s use the recommended solution:

keytool -importkeystore -srckeystore my.keystore -destkeystore my.keystore -deststoretype pkcs12

Here’s the output:

Enter source keystore password:  
Entry for alias myreleasekeyalias1 successfully imported.
Import command completed:  1 entries successfully imported, 0 entries failed or cancelled

Warning:
Migrated "my.keystore" to Non JKS/JCEKS. The JKS keystore is backed up as "my.keystore.old".

Since I migrated the key to PKCS12, I might as well have created the key that way, too. Here’s how that’s done:

keytool -genkey -alias MyReleaseKeyAlias1 -keystore mykeystore.pfx -storetype PKCS12 -keyalg RSA -validity 1095 -keysize 2048
Enter keystore password:  
Re-enter new password: 
What is your first and last name?
  [Unknown]:  Full Stack Dev
What is the name of your organizational unit?
  [Unknown]:  Full Stack Oasis
What is the name of your organization?
  [Unknown]:  
What is the name of your City or Locality?
  [Unknown]:  Whitehorse Ledge
What is the name of your State or Province?
  [Unknown]:  NH
What is the two-letter country code for this unit?
  [Unknown]:  US
Is CN=Full Stack Dev, OU=Full Stack Oasis, O=Unknown, L=Whitehorse Ledge, ST=NH, C=US correct?
    [no]:  yes

I did the same thing this time as I did before. But now I’ve generated a PKCS12 keystore, and got no complaints from keytool. Now I can use the output keystore file, mykeystore.pfx, for signing Android apps. Task complete!

Here’s one last hint. If you build your Android APK using gradlew, make sure that you delete your release build APK prior to rebuilding, if the only thing you’ve changed is the keystore file. Gradle will only build your APK if it sees a change in the source, and your keystore file is not in your source code. So Gradle won’t rebuild when you’ve only changed the keystore, unless the APK is gone. You may be fooled into thinking that the APK was built, until you notice that the timestamp on your APK is old. This happened to me 🙂

If you found this interesting, click the subscribe button below! I write a new post about once a week.

What’s a PWA?

What’s a progressive web app (PWA)?

A progressive web app is a special type of web application (a software application that you use in a web browser). It maintains some functionality even when you’re offline. It can also be installed, like an app, on your cell phone.

Why take the trouble to develop a technology that makes it possible to use a web app offline, and make it act like an installed app on your cell phone? This may not seem useful, at first glance. Many web applications, like gmail, started out at home in a web browser, being used on a desktop computer. On desktops, you’re usually working online, so why take the extra effort to deal with the rare Internet outage at home?

Well, more and more people are using web apps on mobile devices. Even if you live in a heavily populated area, you may find that once in a while you get no Internet service on your cell phone. For most applications, that puts a hard stop to many of the uses for your phone. It’s frustrating for users. In some cases, a web app doesn’t really need a constant Internet connection to be useful. For example, you may want to visit your email client in a web browser to write an email even if you’re offline. You can queue up the draft to be emailed later, when you enter an area where data service is available.

This is where Progressive Web Apps (PWAs) enter the picture. If you run a web application that could be useful to people even when it’s offline, it can make sense to turn your app into a PWA.

Why Not Build a Native App?

If you’ve already built a web application, you could also build a native app for your users (an Android app, for example). From the provider’s viewpoint, this can be a big project – building a native app requires an entirely different set of development skills from web development, and it’s an additional cost. Aside from that, there’s a hurdle for users to install a native app, even if you’ve taken the trouble to build one. They have to go to the Google Play store, search for the app, wait for it to download, and then they might find that it’s not used very often or it’s just taking up space on their phone, so they wind up uninstalling it.

What if it were possible to download a “light” version of an app directly from the web app’s website? That’s what you can do if you build a PWA.

Properties of a PWA

According to Google’s Developers site, my PWA must fulfill some requirements:

  1. It must run in a web browser and as an app in mobile devices.
  2. It must be “fast and reliable” (even native apps aren’t always fast and reliable, so this requirement is a bit funny!). This just means it loads really fast, and does something useful even if you aren’t connected to the Internet. No “ERR_INTERNET_DISCONNECTED” errors like you’d get when your browser is offline, please.
  3. It must be installable. When installed, it appears in Android’s “Apps drawer” (where all apps are listed), and you can add a shortcut to it on your home screen (or desktop on a PC). When running on a mobile device, it’s a top-level app in the task switcher.

What you want, more than anything, is just to make sure that the web app does something useful when the user is offline. Instead of seeing a blank page with an error message, you get some functionality. You also want it to be easily accessible (hence installable) for people who will want to use it frequently.

How to Build a PWA

I’ve written a page which explains how to build a PWA, step by step. Take a look there if you’d like to follow the tutorial.

If you found this interesting, click the subscribe button below! I write a new post about once a week.

20 web dev portfolio project ideas to make your resume shine

If you don’t have much web development experience, and you’ll be looking for a job soon, you want to do everything you can to make yourself an attractive candidate for the positions that you’re interested in. That means polishing up the resume.

Want your resume to shine? Think about adding a “side project” to it.

A side project can be any software that demonstrates your skill. It doesn’t have to be super complicated, like the next Facebook or whatever. It’s just there to give hiring managers help in evaluating what you can do.

Unless you’re a masochist, you should focus on a side project in an area that interests you. If you create a project that builds a robot buggy using the raspberry pi, that’s definitely pretty cool… but if you’re going to be applying for web developer positions, you may lose out to someone else whose portfolio demonstrates web programming experience. So don’t go for something that’s got a million bells and whistles if it doesn’t interest you. Work on a project that you like. That way, it will be easier to work on it, and get it finished. And it will be more likely to lead to a job that you like.

If you’re having trouble coming up with ideas for side projects, here is a list of 20 different ones to help you get started, including links to example sites:

(1) A to-do list. Examples: https://todoist.com/ or https://www.rememberthemilk.com/

(2) A slugify tool: https://blog.tersmitten.nl/slugify/

(3) An online stopwatch, timer, or alarm clock. For example: https://www.online-stopwatch.com/

(4) A web shop which displays images from Amazon: https://docs.aws.amazon.com/AWSECommerceService/latest/DG/EX_RetrievingImages.htmlAmazon has a lot of APIs and SDKs – pick one that interests you and build something!

(5) A tic-tac-toe game https://playtictactoe.org/

(6) A simple login page which uses the Google login or Facebook login API

(7) A tip calculator e.g. https://www.calculator.net/tip-calculator.html or http://www.itipping.com/tip-calculator.htm

(8) A URL encoder or decoder https://meyerweb.com/eric/tools/dencoder/

(9) A histogram generator which plots a histogram from some input, e.g. https://www.socscistatistics.com/descriptive/histograms/ and bonus points for taking input from a Google Drive spreadsheet.

(10) A MadLibs game site, for example http://www.madlibs.com/

(11) A hangman game site https://en.wikipedia.org/wiki/Hangman(game)

(12) A web scraper https://www.webscraper.io/

(13) A site which consumes the MediaWiki API e.g. https://www.mediawiki.org/wiki/API:Picture_of_the_day_viewer

(14) Build an “echo” chat bot https://www.codersbistro.com/blog/chat-bot-microsoft-bot-framework/

(15) A word counter service https://wordcounter.net/

(16) Something like MindMapper https://www.mindmapper.com/

(17) Build a REST API that takes a zip code as input and returns the average income for that zip code using https://catalog.data.gov/dataset/zip-code-data

(18) A word cloud generator https://www.jasondavies.com/wordcloud/

(19) A URL shortener https://bitly.com/

(20) A bookmark (URL) manager https://pinboard.in/

As you develop your side project, think about the following things:

(1) Use version control from the get-go. Having a git commit history with informative comments demonstrates that you care about code maintenance.

(2) Plan things. Create a README and if possible draw some wireframes.

(3) Write unit tests.

(4) Maybe add documentation using a wiki.

(5) Include code documentation such as Javadoc.

(6) Keep a consistent naming convention.

(7) Use consistent tabbing/whitespace/source code formatting.

(8) Avoid code duplication. Copy/paste is lazy and leads to unmaintainable code – refactor!

(9) Think to yourself – is the code maintainable, organized, and easy to understand? If not, refactor.

(10) If possible, use a continuous integration (CI) system for deploying to a hosting service.

(11) Use tools to compute code coverage and code complexity.

(12) Validate user inputs and handle exceptions nicely.

(13) Do not ignore security! Have you avoided SQL injection and cross site scripting attacks? If this is a web app, make sure it’s secure by using HTTPS.

(14) Work together with someone else, if possible, to show you can work on a team.

(15) Be able to demo your software live during an interview.

(16) Be able to talk about it comfortably and answer questions about your design and coding choices.

(17) Avoid surprise bugs during the demo – make sure you have performed QA on your application.

Once you finish one project, you will probably want to start on another one. Over time, you’ll be able to show prospective employers a portfolio of working projects. This won’t guarantee you a job, but it will probably give you an edge over other candidates.

If you want some real world experience, I’ll be honest and tell you that I never had a portfolio of projects that helped me get a job. I came to software development as a STEM graduate (not computer science), and I relied on that background to help “ease” my way into dev work. In fact, it was not easy! I found that some computer science majors are very skeptical of people who make lateral moves into software. They assume the worst about your coding style and competency. When I look back, I wish someone had suggested to me that I build some small projects that would have helped to demonstrate my abilities, especially when finding my first job. I think my job searches would have been easier.

If you found this interesting, click the subscribe button below! I write a new post about once a week.