Blog

Integrating akinaru’s speed-test-lib into Android

Background

Recently, I was looking for a speed test library that I could integrate into one of my Android projects, and I came across akinaru’s speed-test-lib on GitHub. The author of this library has written a well documented library in Java that you can use without a hassle.

Let’s have a look at how we can use this library in our own Android project.

Importing the speed test library

In order to use the speed-test-lib, we must first import it into our Android. Assuming you have created a new project (or existing one), navigate to the app level Gradle script and add the following line of code in the dependencies section.

compile 'com.github.akinaru:speedtest:1.16'

This is how it should look like.

dependencies {
    compile fileTree(include: ['*.jar'], dir: 'libs')
    testCompile 'junit:junit:4.12'
    compile 'com.android.support:appcompat-v7:23.2.0'
    compile 'com.android.support:design:23.2.0'
    compile 'com.android.support:support-v4:23.2.0'
    compile 'com.github.akinaru:speedtest:1.16'
}

Once you have added this line of code, save the script and re-sync it.

syncGradle

Add Android permissions

In order to do anything with the internet, we need to add the internet permission into our project.

This is added into the AndroidManifest.xml file.

<uses-permission android:name="android.permission.INTERNET" />

Instantiate speed test socket

Now we need to create a SpeedTestSocket and instantiate it.

public class content_home extends AppCompatActivity
        implements NavigationView.OnNavigationItemSelectedListener {

    //Instanciate SpeedTest class
    SpeedTestSocket speedTestSocket = new SpeedTestSocket();

Keeping it clean

I usually like to keep things clean in the code, so let’s make a method called initSpeedTest(SpeedTestSocket sts). This method takes a SpeedTestSocket as an argument and initializes the socket by adding a listener.

private void initTest(SpeedTestSocket sts){


}

Now add a SpeedTestListener by calling the .addSpeedTestListener(...) on the socket.

private void initTest(SpeedTestSocket sts){
    sts.addSpeedTestListener(
}

SpeedTestListener

Inside the arguments for the listener, we need to add a ISpeedTestSpeedListener.

private void initTest(SpeedTestSocket sts){
        sts.addSpeedTestListener(new ISpeedTestListener() {
            @Override
            public void onDownloadPacketsReceived(long packetSize, float transferRateBps, float transferRateOps) {
             

            }

            @Override
            public void onDownloadProgress(float percent, SpeedTestReport report) { //live data
                
            }

            @Override
            public void onDownloadError(SpeedTestError speedTestError, String errorMessage) {
               
            }

            @Override
            public void onUploadPacketsReceived(long packetSize, float transferRateBps, float transferRateOps) {
              

            }

            @Override
            public void onUploadError(SpeedTestError speedTestError, String errorMessage) {
                
            }

            @Override
            public void onUploadProgress(float percent, SpeedTestReport report) { //live data
                
            }
        });
    }

As you can see the Override methods will be implemented automatically by Android Studio.

Working with AsyncTask

If you are new to Android development, you should know that we can not execute time and resource consuming tasks on the main thread. Instead we need to use something like an AsyncTask which performs the given task in the background without interacting with other threads.

Now we need to create a class that extends AsyncTask and takes in a Character array as one of the arguments. I’m using a character as an argument as this will allow you to run a upload or download task according to the character you provide.

You should add this at the end of the file you’re working on.

public class SpeedTestTask extends AsyncTask<Character, Void, String> {

    @Override
    protected String doInBackground(Character... params) {
        char type = params[0];
        if(type=='D') {
            speedTestSocket.startDownload("1.testdebit.info", 80, "/fichiers/10Mo.dat");
        } else if (type == 'U') {
            speedTestSocket.startUpload("1.testdebit.info", 80, "/", 1000000);
        }

        return null;
    }
}

As you can see, I have chosen the character ‘D’ to start the download test and ‘U’ to start the upload test.

Now you need to create a SpeedTestTask object. Let’s add it under where we created the SpeedTestSocket.

public class content_home extends AppCompatActivity
        implements NavigationView.OnNavigationItemSelectedListener {

    //Instanciate SpeedTest class
    SpeedTestSocket speedTestSocket = new SpeedTestSocket();
    //Create speed test task
    SpeedTestTask stt;

Initialize the SpeedTestTask and call the initTest method that we created earlier. I’ve done this in the onCreate method.

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_home);
    //Instanciate speed test task
    stt = new SpeedTestTask();
    //initialize speed test
    initTest(speedTestSocket);
}

Resetting the speed test

Let’s create one more method that will reset the speed test.

private void resetSTT(){
    speedTestSocket.closeSocket();
    speedTestSocket.forceStopTask();
    stt.cancel(true); //cancel async task
    speedTestSocket = new SpeedTestSocket(); //initialize new speed test socket for next test
    initTest(speedTestSocket); //initialize new test (listeners etc) for next test
    stt = new SpeedTestTask(); //initialize new async task
}

Output the test results

Before we can execute the task, we need to output the test results onto the screen. In this tutorial, I’ll be using Android Logcat to perform this. We can do this inside the speed test listener we created earlier.

private void initTest(SpeedTestSocket sts){
        sts.addSpeedTestListener(new ISpeedTestListener() {
            @Override
            public void onDownloadPacketsReceived(long packetSize, float transferRateBps, float transferRateOps) {
            	 //reset the speed test task for the next test
                 resetSTT(); 
          //execute the upload speed straight after the download speed 
                 stt.execute('U'); //this is optional (*)

            }

            @Override
            public void onDownloadProgress(float percent, SpeedTestReport report) { //live data
                //Output to logcat
                Log.d("Downloading: ", Float.toString(report.getTransferRateBit()) + " bps");
             
            }

            @Override
            public void onDownloadError(SpeedTestError speedTestError, String errorMessage) {
               
            }

            @Override
            public void onUploadPacketsReceived(long packetSize, float transferRateBps, float transferRateOps) {
              //reset the speed test task for the next test
              resetSTT();

            }

            @Override
            public void onUploadError(SpeedTestError speedTestError, String errorMessage) {
                
            }

            @Override
            public void onUploadProgress(float percent, SpeedTestReport report) { //live data
                Log.d("Uploading: ", Float.toString(report.getTransferRateBit()) + " bps");
            }
        });
    }

(*) Notice that I execute the upload task inside onDownloadPacketsReceived. This runs the upload task after the download task is completed.

For your convenience, I have added comments to help you understand what’s going on.

Run the speed test

Now we are ready to run the speed test. Depending on how you want to run the speed test, simply call stt.execute('D') for the download test, and stt.execute('U')
for the upload test.

In my project, I have a button that executes the test.

btnTest.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        stt.execute('D');
    }
});

Please visit https://github.com/akinaru/speed-test-lib for an in depth understanding of the library.

Getting used to RecyclerView on Android

Time for a change

When I first started developing Chatto, I was using ListViews to display the data to the user. However, I was limited to use a single row data and only show text on each row. I came across RecyclerViews recently and I found it to be very useful in terms of efficiency and its design aspects.

Design aspects

By using RecyclerViews, I’m able to customize the rows by adding multiple GUI objects. Since I learned how to retrieve and post data properly through Firebase, I’ve decided to work on the Alpha version from scratch. I’ve also moved from using different Activities for different screens to using NavigationDrawer and Fragments.

FirebaseRecyclerAdapter

Firebase makes it easy to work with RecyclerViews as the Firebase UI library provides the FirebaseRecyclerAdapter. Not only it handles child events at the given database reference but it also de-serializes data into the given class type. This makes handling data easy as it does not require adding any type of listeners.

Flaws

RecyclerViews are awesome but it comes with its flaws. Out of the box, RecyclerViews does not position items on screen and other than scrolling event, it does not handle other touch events. Unlike ListViews, RecyclerViews does not have the setOnItemClickListener method. This a common issue that people come across when they want the user to be able to click on each item. If you’re using your own layout for the RecyclerView, there is one simple (maybe not) addition you can do.

Check out my tutorial on how you can allow users to click on RecyclerView rows.

How to add touch events to RecyclerView

At first, it probably seems a better choice to use RecyclerViews instead of the ordinary ListViews but one of the issues that people come across is that there are no touch events implemented in RecyclerViews.

While developing Chatto, I came up with a very logical solution for this. If you are you currently using RecyclerViews, you should be familiar with ViewHolders.

Firstly, in your model layout file for the RecyclerView (.xml file), add an id for the layout that you are using. In my layout file, I’m using a RelativeLayout.

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:minHeight="50dp"
    android:paddingBottom="5dp"
    android:id="@+id/chatroomListRelativeRow">

Now let’s take a look at a snippet from a custom ViewHolder class that I wrote for Chatto.

public class RoomViewHolder extends RecyclerView.ViewHolder{
private TextView mLblRoomName;
private TextView mLblRoomCounter;
private ImageView mImgRoomType;
private RelativeLayout chatroomListRelativeRow;
public String roomName; //fix this - dont have any publics

Notice the line private RelativeLayout chatroomListRelativeRow. As you can see, I’ve created a RelativeLayout object.

Inside the constructor of the ViewHolder class, I’ve linked the object back to the RelativeLayout in the .xml file.
chatroomListRelativeRow = RelativeLayout)v.findViewById(R.id.chatroomListRelativeRow);
Now we can use this object to add the onClickListeners and other touch events.

chatroomListRelativeRow.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //Log.d("RVH",mLblRoomName.getText().toString());
                //FragMessagesList fragMessagesList = new FragMessagesList();
                roomName = mLblRoomName.getText().toString();


                //go to messages
            }
        });

In the above code, I’ve attached a OnClickListener to the RelativeLayout. This means when the user clicks on any part of the layout (RecyclerView row), it will perform the specified action.

Now you can try this out for yourself.

As an addition, I’ve also attached a OnTouchListener to the layout. In this listener, I’m simply changing the colors when user touches the row and when the row is not touched. Now let’s see how it’s done.

In order to obtain the original color of the layout, I’ve created a Drawable and called the .getBackground() method on the layout.

final Drawable origColor = chatroomListRelativeRow.getBackground();

Now we can use this to set the color back to the original color/background when the user is not touching on the row.

chatroomListRelativeRow.setOnTouchListener(new View.OnTouchListener() {
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        if(event.getAction()==MotionEvent.ACTION_DOWN){
            chatroomListRelativeRow.setBackgroundColor(Color.parseColor("#212121"));
        }
        else{
            chatroomListRelativeRow.setBackground(origColor);
        }

        return false;
    }
});

That’s all there is to it!

Chatto

Initial Thoughts

I didn’t expect Google Firebase to be so fast at posting and retrieving data in real time but once I made a simple “my first app” by following Google Developers’s video on YouTube, I realized how quick it gets and pushes data onto the cloud. I decided to build a chatting app that let’s users to communicate with each other.

At first it seemed simple as Firebase database management system was easy to understand, however, as I was not familiar with NoSQL DBMS, I struggled in thinking of a way to structure the data. After a many number of hot swaps and patches to the code in Android Studio, I managed to get the data structure sorted as well as get more features implemented incrementally.

The Plan

I’m attempting to only use Firebase as the back end for the database system. So far the app includes Google Sign In as a method of authentication to access the database, a profile page, ability to talk to any user of the app (chatroom based), ability to talk to individuals privately, and hold private group chats. Other small features such as room participant counter and displaying users online status also have been implemented.

As I have to code along side with college work, the amount I put into the app is skewed. The application is at its very early build stages and I’m open to any suggestions and improvements.

Screenshots

This slideshow requires JavaScript.