The Github Repo Search app searches for a GitHub repository by name. The URL you'll use to get search information will be something like the URL below, which searches for repositories containing the word android and sorts by the number of stars the repo has:

https://api.github.com/search/repositories?q=android&sort=stars

Which returns information in JSON. We'll be going over how to make sense of this returned JSON, parse it and display it in your app during this lesson. We'll also cover how to connect to the internet and download data. Let's get started!

The code for this app can be found in the Lesson02-GitHub-Repo-Search folder of the Toy App Repository.

Exercise Code:

T02.01-Exercise-CreateLayout

Exercise:

  1. Convert the ConstraintLayout to a LinearLayout
  2. Add the EditText for the query
  3. Add a TextView to display the URL
  4. Add a scrolling TextView (TextView in a ScrollView) to display the query result
  5. Create and populate the MainActivity member variables for the Search Box EditText, the URLDisplay TextView, and the SearchResults TextView
  6. Remove the unneeded reference to the ConstraintLayout library
  7. Migrate to Androidx and update dependencies

Exercise Code:

T02.02-Exercise-AddMenu

Exercise:

  1. Create the Menu Resource main.xml
<menu xmlns:android="http://schemas.android.com/apk/res/android"
      xmlns:app="http://schemas.android.com/apk/res-auto">

<!-- TO DO -->

</menu>
  1. Add the menu item for Search to the Menu Resource, setting it to showAsAction ifRoom
<item
        android:id="@+id/action_search"
        android:orderInCategory="1"
        app:showAsAction="ifRoom"
        android:title="@string/search"/>
  1. Inflate the menu in onCreateOptionsMenu
@Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.main, menu);
        // Return true to display your menu
        return true;
    }
  1. Display a toast in onOptionsItemSelected when Search is selected
@Override
    public boolean onOptionsItemSelected(MenuItem item) {
        int itemThatWasClickedId = item.getItemId();
        if (itemThatWasClickedId == R.id.action_search) {
            Context context = MainActivity.this;
            String textToShow = "Search clicked";
            Toast.makeText(context, textToShow, Toast.LENGTH_SHORT).show();
            return true;
        }
        return super.onOptionsItemSelected(item);
    }

Build the Url that will be used to query Github and display it when the Search button is pressed.

Exercise Code:

T02.03-Exercise-DisplayUrl

Exercise:

  1. Fill in the buildUrl method from NetworkUtils using Uri.Builder and the URL constructor
public static URL buildUrl(String githubSearchQuery) {
        Uri builtUri = Uri.parse(GITHUB_BASE_URL).buildUpon()
                .appendQueryParameter(PARAM_QUERY, githubSearchQuery)
                .appendQueryParameter(PARAM_SORT, sortBy)
                .build();

        URL url = null;
        try {
            url = new URL(builtUri.toString());
        } catch (MalformedURLException e) {
            e.printStackTrace();
        }

        return url;
    }
  1. Implement the makeGithubSearchQuery method
private void makeGithubSearchQuery() {
        String githubQuery = mSearchBoxEditText.getText().toString();
        URL githubSearchUrl = NetworkUtils.buildUrl(githubQuery);
        mUrlDisplayTextView.setText(githubSearchUrl.toString());
    }
  1. Call the makeGithubSearchQuery method when Search is selected

Follow the TODOS. But it will crash when you run it.

Exercise Code:

T02.04-Exercise-ConnectingToTheInternet

Exercise:

  1. Add the Internet permission
<uses-permission android:name="android.permission.INTERNET" />
  1. Change the makeGithubSearchQuery to call NetworkUtils.getResponseFromHttpUrl
String githubSearchResults = null;
        try {
            githubSearchResults = NetworkUtils.getResponseFromHttpUrl(githubSearchUrl);
            
        } catch (IOException e) {
            e.printStackTrace();
        }
  1. Set the results in our searchResultsTextView
mSearchResultsTextView.setText(githubSearchResults);

Thread Basics

"When an application component starts and the application does not have any other components running, the Android system starts a new Linux process for the application with a single thread of execution. By default, all components of the same application run in the same process and thread (called the "main" thread). If an application component starts and there already exists a process for that application (because another component from the application exists), then the component is started within that process and uses the same thread of execution. However, you can arrange for different components in your application to run in separate processes, and you can create additional threads for any process."

Check Processes and threads overview for more details how the processes works.

AsyncTask

Android AsyncTask going to do background operation on background thread and update on main thread. In android we can't directly touch background thread to main thread in android development. asynctask helps us to make communication between background thread to main thread.

Methods of AsyncTask

Generic Types in Async Task

Exercise Code:

T02.05-Exercise-CreateAsyncTask

Exercise:

  1. Create GithubQueryTask as an inner class of MainActivity, with the types URL, Void, and String.
public class GithubQueryTask extends AsyncTask<URL, Void, String> {

}
  1. Override doInBackground to query Github and return a string
@Override
        protected String doInBackground(URL... params) {
            URL searchUrl = params[0];
            String githubSearchResults = null;
            try {
                githubSearchResults = NetworkUtils.getResponseFromHttpUrl(searchUrl);
            } catch (IOException e) {
                e.printStackTrace();
            }
            return githubSearchResults;
        }
  1. Override onPostExecute to set our searchResultsTextView with the GitHub query search results
@Override
        protected void onPostExecute(String githubSearchResults) {
            if (githubSearchResults != null && !githubSearchResults.equals("")) {
                mSearchResultsTextView.setText(githubSearchResults);
            }
        }
  1. Instantiate and call GithubQueryTask in the makeGithubSearchQuery function
new GithubQueryTask().execute(githubSearchUrl);

Comment out the

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

statement in the AndroidManifest.xml and then run the app. Make a search in the app, and then look in the Android Monitor logcat.

QUESTION

In the Android Monitor logcat, what error do you see when the app tries to connect to the Internet?

Exercise Code:

T02.06-Exercise-AddPolish

Exercise:

  1. Add error text string
<string name="error_message">
        Failed to get results. Please try again.
    </string>
  1. Wrap the ScrollView with a FrameLayout
<FrameLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">
</FrameLayout>
  1. Insert an error TextView into the FrameLayout set to our new text string
<TextView
            android:id="@+id/tv_error_message_display"
            android:textSize="22sp"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:padding="16dp"
            android:text="@string/error_message"
            android:visibility="invisible" />
  1. Add helper functions in MainActivity to swap the visibility of JsonData and the ErrorView.
private void showJsonDataView() {
        // First, make sure the error is invisible
        mErrorMessageDisplay.setVisibility(View.INVISIBLE);
        // Then, make sure the JSON data is visible
        mSearchResultsTextView.setVisibility(View.VISIBLE);
    }
private void showErrorMessage() {
        // First, hide the currently visible data
        mSearchResultsTextView.setVisibility(View.INVISIBLE);
        // Then, show the error
        mErrorMessageDisplay.setVisibility(View.VISIBLE);
    }
  1. Call the error view on null or empty data.
  2. Add a progressBar to the FrameLayout
<ProgressBar
            android:id="@+id/pb_loading_indicator"
            android:layout_height="42dp"
            android:layout_width="42dp"
            android:layout_gravity="center"
            android:visibility="invisible" />
  1. Show the progressBar during loading and hide it afterwards

JSON stands for JavaScript Object Notation.It is an independent data exchange format and is the best alternative for XML. This chapter explains how to parse the JSON file and extract necessary information from it.

Android provides four different classes to manipulate JSON data. These classes are JSONArray, JSONObject, JSONStringer and JSONTokenizer.

  1. Networking

Exercise Code:

S02.01-Exercise-Networking

In this Exercise, you will get to apply what you've learned on Sunshine to add an async task and permissions to load weather data.

  1. Fill in buildUrl in NetworkUtils.java
  2. Add the Internet Permission
  3. Delete the dummy data-related code
  4. Create a FetchWeatherTask AsyncTask to perform the network requests
  5. Override the doInBackground and onPostExecute methods to get and display the results of the network request
  6. Create a loadWeatherData function to get the preferredWeatherLocation from SunshinePreferences and execute the FetchWeatherTask
  7. Call loadWeatherData from onCreate
  1. Add a menu to Sunshine

Exercise Code:

S02.02-Exercise-Menus

Look at your TODOs. This is going to look a lot like what we did to add that menu to the Github query app earlier.

  1. Add a "Refresh" string named action_refresh
  2. Create a new "forecast" menu with a single "Refresh" menu item
  3. Inflate the menu on onCreateOptionsMenu
  4. Handle the menu action in onOptionsItemSelected by clearing the weatherTextView and calling loadWeatherData
  1. Add Loading Polish and Error Messages to Sunshine

Exercise Code:

S02.03-Exercise-Polish

In this Exercise, you will get to apply what you've learned about adding polish to Sunshine.

Add code and views to display an error message for a failed data retrieval, and loading indicators for loading data.

  1. Add a string resource for an error message, should loading data fail.
  2. Add a TextView that you will show the user if there is an error loading content.
  3. Add a ProgressBar to show the user content is loading.
  4. In onPostExecute, show the error message, progress bar, or data views as appropriate.
  5. Override the method onPreExecute and show the loading indicator.