Skip to content
This repository has been archived by the owner on Jun 23, 2022. It is now read-only.

2.07 build url with params #310

Open
wants to merge 15 commits into
base: 1.01_hello_world
Choose a base branch
from
3 changes: 3 additions & 0 deletions app/build.gradle
Expand Up @@ -17,6 +17,9 @@ android {
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
buildTypes.each {
it.buildConfigField 'String', 'OPEN_WEATHER_MAP_API_KEY', MyOpenWeatherMapApiKey
}
}

dependencies {
Expand Down
3 changes: 3 additions & 0 deletions app/src/main/AndroidManifest.xml
Expand Up @@ -2,6 +2,9 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.android.sunshine.app" >

<!-- This permission is necessary in order for Sunshine to perform network access. -->
<uses-permission android:name="android.permission.INTERNET" />

<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
Expand Down
@@ -0,0 +1,208 @@
/*
* Copyright (C) 2014 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.sunshine.app;

import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ListView;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
* Encapsulates fetching the forecast and displaying it as a {@link ListView} layout.
*/
public class ForecastFragment extends Fragment {

private ArrayAdapter<String> mForecastAdapter;

public ForecastFragment() {
}

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Add this line in order for this fragment to handle menu events.
setHasOptionsMenu(true);
}

@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.forecastfragment, menu);
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == R.id.action_refresh) {
FetchWeatherTask weatherTask = new FetchWeatherTask();
weatherTask.execute("94043");
return true;
}
return super.onOptionsItemSelected(item);
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {

// Create some dummy data for the ListView. Here's a sample weekly forecast
String[] data = {
"Mon 6/23 - Sunny - 31/17",
"Tue 6/24 - Foggy - 21/8",
"Wed 6/25 - Cloudy - 22/17",
"Thurs 6/26 - Rainy - 18/11",
"Fri 6/27 - Foggy - 21/10",
"Sat 6/28 - TRAPPED IN WEATHERSTATION - 23/18",
"Sun 6/29 - Sunny - 20/7"
};
List<String> weekForecast = new ArrayList<String>(Arrays.asList(data));

// Now that we have some dummy forecast data, create an ArrayAdapter.
// The ArrayAdapter will take data from a source (like our dummy forecast) and
// use it to populate the ListView it's attached to.
mForecastAdapter =
new ArrayAdapter<String>(
getActivity(), // The current context (this activity)
R.layout.list_item_forecast, // The name of the layout ID.
R.id.list_item_forecast_textview, // The ID of the textview to populate.
weekForecast);

View rootView = inflater.inflate(R.layout.fragment_main, container, false);

// Get a reference to the ListView, and attach this adapter to it.
ListView listView = (ListView) rootView.findViewById(R.id.listview_forecast);
listView.setAdapter(mForecastAdapter);

return rootView;
}

public class FetchWeatherTask extends AsyncTask<String, Void, Void> {

private final String LOG_TAG = FetchWeatherTask.class.getSimpleName();

@Override
protected Void doInBackground(String... params) {

// If there's no zip code, there's nothing to look up. Verify size of params.
if (params.length == 0) {
return null;
}

// These two need to be declared outside the try/catch
// so that they can be closed in the finally block.
HttpURLConnection urlConnection = null;
BufferedReader reader = null;

// Will contain the raw JSON response as a string.
String forecastJsonStr = null;

String format = "json";
String units = "metric";
int numDays = 7;

try {
// Construct the URL for the OpenWeatherMap query
// Possible parameters are avaiable at OWM's forecast API page, at
// http://openweathermap.org/API#forecast
final String FORECAST_BASE_URL =
"http://api.openweathermap.org/data/2.5/forecast/daily?";
final String QUERY_PARAM = "q";
final String FORMAT_PARAM = "mode";
final String UNITS_PARAM = "units";
final String DAYS_PARAM = "cnt";
final String APPID_PARAM = "APPID";

Uri builtUri = Uri.parse(FORECAST_BASE_URL).buildUpon()
.appendQueryParameter(QUERY_PARAM, params[0])
.appendQueryParameter(FORMAT_PARAM, format)
.appendQueryParameter(UNITS_PARAM, units)
.appendQueryParameter(DAYS_PARAM, Integer.toString(numDays))
.appendQueryParameter(APPID_PARAM, BuildConfig.OPEN_WEATHER_MAP_API_KEY)
.build();

URL url = new URL(builtUri.toString());

Log.v(LOG_TAG, "Built URI " + builtUri.toString());

// Create the request to OpenWeatherMap, and open the connection
urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.setRequestMethod("GET");
urlConnection.connect();

// Read the input stream into a String
InputStream inputStream = urlConnection.getInputStream();
StringBuffer buffer = new StringBuffer();
if (inputStream == null) {
// Nothing to do.
return null;
}
reader = new BufferedReader(new InputStreamReader(inputStream));

String line;
while ((line = reader.readLine()) != null) {
// Since it's JSON, adding a newline isn't necessary (it won't affect parsing)
// But it does make debugging a *lot* easier if you print out the completed
// buffer for debugging.
buffer.append(line + "\n");
}

if (buffer.length() == 0) {
// Stream was empty. No point in parsing.
return null;
}
forecastJsonStr = buffer.toString();
} catch (IOException e) {
Log.e(LOG_TAG, "Error ", e);
// If the code didn't successfully get the weather data, there's no point in attemping
// to parse it.
return null;
} finally {
if (urlConnection != null) {
urlConnection.disconnect();
}
if (reader != null) {
try {
reader.close();
} catch (final IOException e) {
Log.e(LOG_TAG, "Error closing stream", e);
}
}
}
return null;
}
}
}
@@ -1,14 +1,24 @@
/*
* Copyright (C) 2014 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.sunshine.app;

import android.support.v7.app.ActionBarActivity;
import android.support.v4.app.Fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.support.v7.app.ActionBarActivity;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;


public class MainActivity extends ActionBarActivity {

Expand All @@ -18,7 +28,7 @@ protected void onCreate(Bundle savedInstanceState) {
setContentView(R.layout.activity_main);
if (savedInstanceState == null) {
getSupportFragmentManager().beginTransaction()
.add(R.id.container, new PlaceholderFragment())
.add(R.id.container, new ForecastFragment())
.commit();
}
}
Expand All @@ -44,20 +54,4 @@ public boolean onOptionsItemSelected(MenuItem item) {

return super.onOptionsItemSelected(item);
}

/**
* A placeholder fragment containing a simple view.
*/
public static class PlaceholderFragment extends Fragment {

public PlaceholderFragment() {
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_main, container, false);
return rootView;
}
}
}
19 changes: 12 additions & 7 deletions app/src/main/res/layout/fragment_main.xml
@@ -1,12 +1,17 @@
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin"
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="@dimen/activity_horizontal_margin"

android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:paddingBottom="@dimen/activity_vertical_margin"
tools:context=".MainActivity$PlaceholderFragment">
tools:context=".MainActivity$ForecastFragment">

<TextView android:text="@string/hello_world" android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<ListView
android:id="@+id/listview_forecast"
android:layout_width="match_parent"
android:layout_height="match_parent" />

</RelativeLayout>
</FrameLayout>
8 changes: 8 additions & 0 deletions app/src/main/res/layout/list_item_forecast.xml
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>

<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?android:attr/listPreferredItemHeight"
android:gravity="center_vertical"
android:id="@+id/list_item_forecast_textview" />
8 changes: 8 additions & 0 deletions app/src/main/res/menu/forecastfragment.xml
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>

<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item android:id="@+id/action_refresh"
android:title="@string/action_refresh"
app:showAsAction="never" />
</menu>
15 changes: 14 additions & 1 deletion app/src/main/res/values/strings.xml
@@ -1,8 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>

<!--
Used in Action Bar, and in AndroidManifest to tell the device the name of this app.
It's to keep this short, so your launcher icon isn't displayed with "The greatest Wea"
or something similar.
-->
<string name="app_name">Sunshine</string>
<string name="hello_world">Hello world!</string>

<!--
By convention, "action" denotes that this String will be used as the label for an Action,
typically from the action bar. The ActionBar is limited real estate, so shorter is better.
-->
<string name="action_settings">Settings</string>

<!-- Menu label to fetch updated weather info from the server -->
<string name="action_refresh" translatable="false">Refresh</string>
<string name="hello_world">Hello world!</string>

</resources>