Created
March 19, 2017 16:33
-
-
Save rgherta/c731ea5d102f502e0ae1dbce6f773360 to your computer and use it in GitHub Desktop.
Android Learning
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Copyright (C) 2016 The Android Open Source Project | |
* | |
* Licensed under the Apache License, Version 2.0 (the "License"); | |
* you may not use this file except in compliance with the License. | |
* You may obtain a copy of the License at | |
* | |
* http://www.apache.org/licenses/LICENSE-2.0 | |
* | |
* Unless required by applicable law or agreed to in writing, software | |
* distributed under the License is distributed on an "AS IS" BASIS, | |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
* See the License for the specific language governing permissions and | |
* limitations under the License. | |
*/ | |
package com.example.android.asynctaskloader; | |
import android.os.Bundle; | |
import android.support.v4.app.LoaderManager; | |
import android.support.v4.content.AsyncTaskLoader; | |
import android.support.v4.content.Loader; | |
import android.support.v7.app.AppCompatActivity; | |
import android.text.TextUtils; | |
import android.view.Menu; | |
import android.view.MenuItem; | |
import android.view.View; | |
import android.widget.EditText; | |
import android.widget.ProgressBar; | |
import android.widget.TextView; | |
import com.example.android.asynctaskloader.utilities.NetworkUtils; | |
import java.io.IOException; | |
import java.net.URL; | |
// COMPLETED (1) implement LoaderManager.LoaderCallbacks<String> on MainActivity | |
public class MainActivity extends AppCompatActivity implements | |
LoaderManager.LoaderCallbacks<String> { | |
/* A constant to save and restore the URL that is being displayed */ | |
private static final String SEARCH_QUERY_URL_EXTRA = "query"; | |
/* | |
* This number will uniquely identify our Loader and is chosen arbitrarily. You can change this | |
* to any number you like, as long as you use the same variable name. | |
*/ | |
private static final int GITHUB_SEARCH_LOADER = 22; | |
private EditText mSearchBoxEditText; | |
private TextView mUrlDisplayTextView; | |
private TextView mSearchResultsTextView; | |
private TextView mErrorMessageDisplay; | |
private ProgressBar mLoadingIndicator; | |
@Override | |
protected void onCreate(Bundle savedInstanceState) { | |
super.onCreate(savedInstanceState); | |
setContentView(R.layout.activity_main); | |
mSearchBoxEditText = (EditText) findViewById(R.id.et_search_box); | |
mUrlDisplayTextView = (TextView) findViewById(R.id.tv_url_display); | |
mSearchResultsTextView = (TextView) findViewById(R.id.tv_github_search_results_json); | |
mErrorMessageDisplay = (TextView) findViewById(R.id.tv_error_message_display); | |
mLoadingIndicator = (ProgressBar) findViewById(R.id.pb_loading_indicator); | |
if (savedInstanceState != null) { | |
String queryUrl = savedInstanceState.getString(SEARCH_QUERY_URL_EXTRA); | |
mUrlDisplayTextView.setText(queryUrl); | |
} | |
// COMPLETED (24) Initialize the loader with GITHUB_SEARCH_LOADER as the ID, null for the bundle, and this for the context | |
/* | |
* Initialize the loader | |
*/ | |
getSupportLoaderManager().initLoader(GITHUB_SEARCH_LOADER, null, this); | |
} | |
/** | |
* This method retrieves the search text from the EditText, constructs the | |
* URL (using {@link NetworkUtils}) for the github repository you'd like to find, displays | |
* that URL in a TextView, and finally request that an AsyncTaskLoader performs the GET request. | |
*/ | |
private void makeGithubSearchQuery() { | |
String githubQuery = mSearchBoxEditText.getText().toString(); | |
// COMPLETED (17) If no search was entered, indicate that there isn't anything to search for and return | |
/* | |
* If the user didn't enter anything, there's nothing to search for. In the case where no | |
* search text was entered but the search button was clicked, we will display a message | |
* stating that there is nothing to search for and we will not attempt to load anything. | |
* | |
* If there is text entered in the search box when the search button was clicked, we will | |
* create the URL that will return our Github search results, display that URL, and then | |
* pass that URL to the Loader. The reason we pass the URL as a String is simply a matter | |
* of convenience. There are other ways of achieving this same result, but we felt this | |
* was the simplest. | |
*/ | |
if (TextUtils.isEmpty(githubQuery)) { | |
mUrlDisplayTextView.setText("No query entered, nothing to search for."); | |
return; | |
} | |
URL githubSearchUrl = NetworkUtils.buildUrl(githubQuery); | |
mUrlDisplayTextView.setText(githubSearchUrl.toString()); | |
// COMPLETED (19) Create a bundle called queryBundle | |
Bundle queryBundle = new Bundle(); | |
// COMPLETED (20) Use putString with SEARCH_QUERY_URL_EXTRA as the key and the String value of the URL as the value | |
queryBundle.putString(SEARCH_QUERY_URL_EXTRA, githubSearchUrl.toString()); | |
/* | |
* Now that we've created our bundle that we will pass to our Loader, we need to decide | |
* if we should restart the loader (if the loader already existed) or if we need to | |
* initialize the loader (if the loader did NOT already exist). | |
* | |
* We do this by first store the support loader manager in the variable loaderManager. | |
* All things related to the Loader go through through the LoaderManager. Once we have a | |
* hold on the support loader manager, (loaderManager) we can attempt to access our | |
* githubSearchLoader. To do this, we use LoaderManager's method, "getLoader", and pass in | |
* the ID we assigned in its creation. You can think of this process similar to finding a | |
* View by ID. We give the LoaderManager an ID and it returns a loader (if one exists). If | |
* one doesn't exist, we tell the LoaderManager to create one. If one does exist, we tell | |
* the LoaderManager to restart it. | |
*/ | |
// COMPLETED (21) Call getSupportLoaderManager and store it in a LoaderManager variable | |
LoaderManager loaderManager = getSupportLoaderManager(); | |
// COMPLETED (22) Get our Loader by calling getLoader and passing the ID we specified | |
Loader<String> githubSearchLoader = loaderManager.getLoader(GITHUB_SEARCH_LOADER); | |
// COMPLETED (23) If the Loader was null, initialize it. Else, restart it. | |
if (githubSearchLoader == null) { | |
loaderManager.initLoader(GITHUB_SEARCH_LOADER, queryBundle, this); | |
} else { | |
loaderManager.restartLoader(GITHUB_SEARCH_LOADER, queryBundle, this); | |
} | |
} | |
/** | |
* This method will make the View for the JSON data visible and | |
* hide the error message. | |
* <p> | |
* Since it is okay to redundantly set the visibility of a View, we don't | |
* need to check whether each view is currently visible or invisible. | |
*/ | |
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); | |
} | |
/** | |
* This method will make the error message visible and hide the JSON | |
* View. | |
* <p> | |
* Since it is okay to redundantly set the visibility of a View, we don't | |
* need to check whether each view is currently visible or invisible. | |
*/ | |
private void showErrorMessage() { | |
/* First, hide the currently visible data */ | |
mSearchResultsTextView.setVisibility(View.INVISIBLE); | |
/* Then, show the error */ | |
mErrorMessageDisplay.setVisibility(View.VISIBLE); | |
} | |
// COMPLETED (3) Override onCreateLoader | |
@Override | |
public Loader<String> onCreateLoader(int id, final Bundle args) { | |
// COMPLETED (4) Return a new AsyncTaskLoader<String> as an anonymous inner class with this as the constructor's parameter | |
return new AsyncTaskLoader<String>(this) { | |
// COMPLETED (5) Override onStartLoading | |
@Override | |
protected void onStartLoading() { | |
// COMPLETED (6) If args is null, return. | |
/* If no arguments were passed, we don't have a query to perform. Simply return. */ | |
if (args == null) { | |
return; | |
} | |
// COMPLETED (7) Show the loading indicator | |
/* | |
* When we initially begin loading in the background, we want to display the | |
* loading indicator to the user | |
*/ | |
mLoadingIndicator.setVisibility(View.VISIBLE); | |
// COMPLETED (8) Force a load | |
forceLoad(); | |
} | |
// COMPLETED (9) Override loadInBackground | |
@Override | |
public String loadInBackground() { | |
// COMPLETED (10) Get the String for our URL from the bundle passed to onCreateLoader | |
/* Extract the search query from the args using our constant */ | |
String searchQueryUrlString = args.getString(SEARCH_QUERY_URL_EXTRA); | |
// COMPLETED (11) If the URL is null or empty, return null | |
/* If the user didn't enter anything, there's nothing to search for */ | |
if (searchQueryUrlString == null || TextUtils.isEmpty(searchQueryUrlString)) { | |
return null; | |
} | |
// COMPLETED (12) Copy the try / catch block from the AsyncTask's doInBackground method | |
/* Parse the URL from the passed in String and perform the search */ | |
try { | |
URL githubUrl = new URL(searchQueryUrlString); | |
String githubSearchResults = NetworkUtils.getResponseFromHttpUrl(githubUrl); | |
return githubSearchResults; | |
} catch (IOException e) { | |
e.printStackTrace(); | |
return null; | |
} | |
} | |
}; | |
} | |
// COMPLETED (13) Override onLoadFinished | |
@Override | |
public void onLoadFinished(Loader<String> loader, String data) { | |
// COMPLETED (14) Hide the loading indicator | |
/* When we finish loading, we want to hide the loading indicator from the user. */ | |
mLoadingIndicator.setVisibility(View.INVISIBLE); | |
// COMPLETED (15) Use the same logic used in onPostExecute to show the data or the error message | |
/* | |
* If the results are null, we assume an error has occurred. There are much more robust | |
* methods for checking errors, but we wanted to keep this particular example simple. | |
*/ | |
if (null == data) { | |
showErrorMessage(); | |
} else { | |
mSearchResultsTextView.setText(data); | |
showJsonDataView(); | |
} | |
} | |
// COMPLETED (16) Override onLoaderReset as it is part of the interface we implement, but don't do anything in this method | |
@Override | |
public void onLoaderReset(Loader<String> loader) { | |
/* | |
* We aren't using this method in our example application, but we are required to Override | |
* it to implement the LoaderCallbacks<String> interface | |
*/ | |
} | |
// COMPLETED (29) Delete the AsyncTask class | |
@Override | |
public boolean onCreateOptionsMenu(Menu menu) { | |
getMenuInflater().inflate(R.menu.main, menu); | |
return true; | |
} | |
@Override | |
public boolean onOptionsItemSelected(MenuItem item) { | |
int itemThatWasClickedId = item.getItemId(); | |
if (itemThatWasClickedId == R.id.action_search) { | |
makeGithubSearchQuery(); | |
return true; | |
} | |
return super.onOptionsItemSelected(item); | |
} | |
@Override | |
protected void onSaveInstanceState(Bundle outState) { | |
super.onSaveInstanceState(outState); | |
String queryUrl = mUrlDisplayTextView.getText().toString(); | |
outState.putString(SEARCH_QUERY_URL_EXTRA, queryUrl); | |
// COMPLETED (27) Remove the code that persists the JSON | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment