├── .gitignore ├── .idea ├── .name ├── compiler.xml ├── copyright │ └── profiles_settings.xml ├── encodings.xml ├── gradle.xml ├── misc.xml ├── modules.xml ├── runConfigurations.xml └── vcs.xml ├── README.md ├── RetrofitExample.iml ├── app ├── .gitignore ├── app.iml ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── psv │ │ └── apps │ │ └── java │ │ └── retrofitexample │ │ └── ApplicationTest.java │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── psv │ │ └── apps │ │ └── java │ │ └── retrofitexample │ │ ├── MainActivity.java │ │ ├── WeatherApi.java │ │ ├── WeatherApiErrorHandler.java │ │ ├── WeatherData.java │ │ └── WeatherRestAdapter.java │ └── res │ ├── layout │ └── activity_main.xml │ ├── menu │ └── menu_main.xml │ ├── mipmap-hdpi │ └── ic_launcher.png │ ├── mipmap-mdpi │ └── ic_launcher.png │ ├── mipmap-xhdpi │ └── ic_launcher.png │ ├── mipmap-xxhdpi │ └── ic_launcher.png │ ├── values-v21 │ └── styles.xml │ ├── values-w820dp │ └── dimens.xml │ └── values │ ├── colors.xml │ ├── dimens.xml │ ├── strings.xml │ └── styles.xml ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | /local.properties 3 | /.idea/workspace.xml 4 | /.idea/libraries 5 | .DS_Store 6 | /build 7 | /captures 8 | -------------------------------------------------------------------------------- /.idea/.name: -------------------------------------------------------------------------------- 1 | RetrofitExample -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 22 | -------------------------------------------------------------------------------- /.idea/copyright/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 24 | 25 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 19 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | Android Lint 39 | 40 | 41 | Groovy 42 | 43 | 44 | HTML 45 | 46 | 47 | J2ME issues 48 | 49 | 50 | Java language level issues 51 | 52 | 53 | JavaBeans issues 54 | 55 | 56 | Pattern Validation 57 | 58 | 59 | Threading issues 60 | 61 | 62 | Threading issuesGroovy 63 | 64 | 65 | XML 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 87 | 88 | 89 | 90 | 91 | 1.7 92 | 93 | 98 | 99 | 100 | 101 | 102 | 103 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # RetrofitExample 2 | 3 | This is a sample project to show how to use Square Retrofit Library in your Android Apps. 4 | 5 | 1. MainActivity: Main test activity. Preserves data and UX state on rotation of device. 6 | - Uses material design construct by having styles.xml and v21/styles.xml works with colors.xml 7 | - Handles device rotation well. 8 | - Pay attention to runOnUiThread runnable. It takes care of cases where 'runOnUiThread' 9 | may not update UX on roation as Activity may not have been recreated. 10 | 2. GetWeatherApi: The API to access weather 11 | - Async API: getWeatherFromApi, results are passed back to caller in a Callback 12 | on a different thread. 13 | - Sync API: getWeatherFromApiSync, not called from a UX thread. Blocking call, places the 14 | call from a thread. 15 | 3. GetWeatherRestAdapter: Defines the REST adapter and also a container for Weather API. 16 | 4. WeatherData: is a plain old java object that mirrors names on the JSON response. 17 | 5. Open issues: Did not check error issues. So app may crash on Retrofit errors. 18 | 6. Openweather now requires you to use their API. Set your own API key in OPEN_WEATHER_API (GetWeatherRestAdapter.java), I have kept mine in case you need to do few minor tests. 19 | 20 | ## Note for Retrofit2, use this Repo. https://github.com/opendroid/Retrofit2Example 21 | -------------------------------------------------------------------------------- /RetrofitExample.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/app.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 8 | 9 | 10 | 11 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 23 5 | buildToolsVersion "23.0.3" 6 | 7 | defaultConfig { 8 | applicationId "psv.apps.java.retrofitexample" 9 | minSdkVersion 17 10 | targetSdkVersion 23 11 | versionCode 1 12 | versionName "1.0" 13 | } 14 | buildTypes { 15 | release { 16 | minifyEnabled false 17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 18 | } 19 | } 20 | } 21 | 22 | dependencies { 23 | compile fileTree(dir: 'libs', include: ['*.jar']) 24 | compile 'com.android.support:appcompat-v7:23.3.0' 25 | compile 'com.squareup.retrofit:retrofit:1.9.0' 26 | compile 'com.google.code.gson:gson:2.4' 27 | } 28 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /Users/ajaythakur/Developer/android-sdk-macosx/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /app/src/androidTest/java/psv/apps/java/retrofitexample/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package psv.apps.java.retrofitexample; 2 | 3 | import android.app.Application; 4 | import android.test.ApplicationTestCase; 5 | 6 | /** 7 | * Testing Fundamentals 8 | */ 9 | public class ApplicationTest extends ApplicationTestCase { 10 | public ApplicationTest() { 11 | super(Application.class); 12 | } 13 | } -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 11 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /app/src/main/java/psv/apps/java/retrofitexample/MainActivity.java: -------------------------------------------------------------------------------- 1 | package psv.apps.java.retrofitexample; 2 | 3 | import android.app.Activity; 4 | import android.content.Context; 5 | import android.content.res.Resources; 6 | import android.os.Bundle; 7 | import android.os.IBinder; 8 | import android.support.v7.app.AppCompatActivity; 9 | import android.util.Log; 10 | import android.view.Menu; 11 | import android.view.MenuItem; 12 | import android.view.View; 13 | import android.view.inputmethod.InputMethodManager; 14 | import android.widget.EditText; 15 | import android.widget.ProgressBar; 16 | import android.widget.TextView; 17 | import android.widget.Toast; 18 | 19 | import java.lang.ref.WeakReference; 20 | import java.text.DateFormat; 21 | import java.text.SimpleDateFormat; 22 | import java.util.Date; 23 | import java.util.Locale; 24 | import java.util.concurrent.atomic.AtomicBoolean; 25 | 26 | import retrofit.Callback; 27 | import retrofit.RetrofitError; 28 | import retrofit.client.Response; 29 | 30 | public class MainActivity extends AppCompatActivity { 31 | protected final String TAG = getClass().getSimpleName(); 32 | private RetainedAppData mRetainedAppData; 33 | // UX handlers 34 | private ProgressBar mProgressBar; 35 | private EditText mInputCityName; 36 | private TextView mCityNameTextView; 37 | private TextView mCountryNameTextView; 38 | private TextView mCodTextView; 39 | private TextView mCoordsTextView; 40 | private TextView mTempTextView; 41 | private TextView mSunriseTextView; 42 | private TextView mSunsetTextView; 43 | 44 | @Override 45 | protected void onCreate(Bundle savedInstanceState) { 46 | super.onCreate(savedInstanceState); 47 | setContentView(R.layout.activity_main); 48 | 49 | mProgressBar = (ProgressBar) findViewById(R.id.progress_bar_id); 50 | mInputCityName = (EditText) findViewById(R.id.input_city_id); 51 | // Data saved 52 | if (savedInstanceState != null) { 53 | if (getLastCustomNonConfigurationInstance() != null) { 54 | mRetainedAppData = (RetainedAppData) getLastCustomNonConfigurationInstance(); 55 | Log.d(TAG,"onCreate(): Reusing retained data set"); 56 | } 57 | } else { 58 | mRetainedAppData = new RetainedAppData(); 59 | Log.d(TAG, "onCreate(): Creating new data set"); 60 | } 61 | 62 | // Setup activity reference 63 | // mActivityRef = new WeakReference<>(this); 64 | mRetainedAppData.setAppContext(this); 65 | 66 | if (mRetainedAppData.mData != null) { 67 | updateUXWithWeatherData(mRetainedAppData.mData); 68 | } 69 | // Setup the progress bar 70 | if (mRetainedAppData.isFetchInProgress()) { 71 | mProgressBar.setVisibility(View.VISIBLE); 72 | } else { 73 | mProgressBar.setVisibility(View.INVISIBLE); 74 | } 75 | } 76 | 77 | @Override 78 | protected void onDestroy() { 79 | super.onDestroy(); 80 | // mActivityRef = null; 81 | mRetainedAppData.setAppContext(null); 82 | Log.d(TAG,"onDestroy()"); 83 | } 84 | 85 | @Override 86 | public boolean onCreateOptionsMenu(Menu menu) { 87 | // Inflate the menu; this adds items to the action bar if it is present. 88 | getMenuInflater().inflate(R.menu.menu_main, menu); 89 | return true; 90 | } 91 | 92 | @Override 93 | public boolean onOptionsItemSelected(MenuItem item) { 94 | // Handle action bar item clicks here. The action bar will 95 | // automatically handle clicks on the Home/Up button, so long 96 | // as you specify a parent activity in AndroidManifest.xml. 97 | int id = item.getItemId(); 98 | 99 | //noinspection SimplifiableIfStatement 100 | if (id == R.id.action_settings) { 101 | return true; 102 | } 103 | 104 | return super.onOptionsItemSelected(item); 105 | } 106 | @Override 107 | public Object onRetainCustomNonConfigurationInstance() { 108 | return mRetainedAppData; 109 | } 110 | 111 | public void expandWeatherSync(View v) { 112 | hideKeyboard(MainActivity.this, mInputCityName.getWindowToken()); 113 | String city = mInputCityName.getText().toString(); 114 | if (city.isEmpty()) { 115 | Toast.makeText(getApplicationContext(),"No city specified.", 116 | Toast.LENGTH_LONG).show(); 117 | return; 118 | } 119 | mRetainedAppData.runRetrofitTestSync(city); 120 | } 121 | 122 | public void expandWeatherAsync(View v) { 123 | hideKeyboard(MainActivity.this, mInputCityName.getWindowToken()); 124 | String city = mInputCityName.getText().toString(); 125 | if (city.isEmpty()) { 126 | Toast.makeText(getApplicationContext(),"No city specified.", 127 | Toast.LENGTH_LONG).show(); 128 | return; 129 | } 130 | mRetainedAppData.runRetrofitTestAsync(city); 131 | } 132 | 133 | /** 134 | * This method is used to hide a keyboard after a user has 135 | * finished typing the url. 136 | */ 137 | public static void hideKeyboard(Activity activity, 138 | IBinder windowToken) { 139 | InputMethodManager mgr = (InputMethodManager) activity.getSystemService 140 | (Context.INPUT_METHOD_SERVICE); 141 | mgr.hideSoftInputFromWindow(windowToken, 0); 142 | } 143 | 144 | void updateUXWithWeatherData (final WeatherData data) { 145 | runOnUiThread(new Runnable() { 146 | @Override 147 | public void run() { 148 | // Setup UX handlers 149 | // Get the UX handlers every time. This is to avoid a condition 150 | // when runOnUiThread may not have updated UX handles when screen is rotated. 151 | // 'mActivityRef.get()' 152 | mProgressBar = (ProgressBar) findViewById(R.id.progress_bar_id); 153 | mInputCityName = (EditText) findViewById(R.id.input_city_id); 154 | mCityNameTextView = (TextView) findViewById(R.id.city_name_id); 155 | mCountryNameTextView = (TextView) findViewById(R.id.country_name_id); 156 | mCodTextView = (TextView) findViewById(R.id.cod_id); 157 | mCoordsTextView = (TextView) findViewById(R.id.coords_id); 158 | mTempTextView = (TextView) findViewById(R.id.temp_id); 159 | mSunriseTextView = (TextView) findViewById(R.id.sunrise_id); 160 | mSunsetTextView = (TextView) findViewById(R.id.sunset_id); 161 | 162 | // Refresh UX data 163 | if (mRetainedAppData.isFetchInProgress()) { 164 | mProgressBar.setVisibility(View.VISIBLE); 165 | } else { 166 | mProgressBar.setVisibility(View.INVISIBLE); 167 | } 168 | 169 | // Print data to Android display 170 | Resources res = getResources(); 171 | String textToPrint = res.getString(R.string.city) + data.getName(); 172 | mCityNameTextView.setText(textToPrint); 173 | textToPrint = res.getString(R.string.country) + data.getCountry(); 174 | mCountryNameTextView.setText(textToPrint); 175 | textToPrint = res.getString(R.string.coordinates) +"(" + data.getLat() + "," + data.getLon() + ")"; 176 | mCoordsTextView.setText(textToPrint); 177 | textToPrint = res.getString(R.string.cod) + data.getCod(); 178 | mCodTextView.setText(textToPrint); 179 | String tempF = String.format(Locale.UK,"Temperature: %.2f F", (data.getTemp() - 273.15) * 1.8 + 32.00); 180 | mTempTextView.setText(tempF); 181 | DateFormat dfLocalTz = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss", Locale.UK); 182 | Date sunriseTime = new Date(data.getSunrise() * 1000); 183 | Date sunsetTime = new Date(data.getSunset() * 1000); 184 | textToPrint = res.getString(R.string.sunrise) + dfLocalTz.format(sunriseTime); 185 | mSunriseTextView.setText(textToPrint); 186 | textToPrint = res.getString(R.string.sunset) + dfLocalTz.format(sunsetTime); 187 | mSunsetTextView.setText(textToPrint); 188 | } 189 | }); 190 | } 191 | 192 | /** 193 | * This is main class object that should save all data upon configuration changes. 194 | * This object is saved by the 'onRetainCustomNonConfigurationInstance' method. 195 | * 196 | * Note: In the video it is referred to as 'private class TestWeatherData' 197 | */ 198 | private static class RetainedAppData { 199 | private WeakReference mActivityRef; 200 | protected final String TAG = "RTD"; 201 | private WeatherData mData; // Weather data received 202 | private AtomicBoolean mInProgress = new AtomicBoolean(false); // Is a download in progress 203 | private WeatherRestAdapter mWeatherRestAdapter; // REST Adapter 204 | private Callback mWeatherDataCallback = new Callback() { 205 | @Override 206 | public void success(WeatherData data, Response response) { 207 | 208 | Log.d(TAG, "Async success: weatherData: Name:" + data.getName() + ", cod:" + data.getCod() 209 | + ",Coord: (" + data.getLat() + "," + data.getLon() 210 | + "), Temp:" + data.getTemp() 211 | + "\nSunset:" + data.getSunset() + ", " + data.getSunrise() 212 | + ", Country:" + data.getCountry()); 213 | mData = data; 214 | if (mActivityRef.get() != null) { 215 | mActivityRef.get().updateUXWithWeatherData(mData); 216 | mActivityRef.get().runOnUiThread(new Runnable() { 217 | @Override 218 | public void run() { 219 | mActivityRef.get().mProgressBar = (ProgressBar) mActivityRef.get(). 220 | findViewById(R.id.progress_bar_id); 221 | mActivityRef.get().mProgressBar.setVisibility(View.INVISIBLE); 222 | } 223 | }); 224 | } 225 | mInProgress.set(false); 226 | } 227 | 228 | @Override 229 | public void failure(RetrofitError error) { 230 | Log.d(TAG,"failure: " + error); 231 | mInProgress.set(false); 232 | if (mActivityRef.get() != null) { 233 | mActivityRef.get().runOnUiThread(new Runnable() { 234 | @Override 235 | public void run() { 236 | mActivityRef.get().mProgressBar = (ProgressBar) mActivityRef.get(). 237 | findViewById(R.id.progress_bar_id); 238 | mActivityRef.get().mProgressBar.setVisibility(View.INVISIBLE); 239 | } 240 | }); 241 | } 242 | } 243 | }; 244 | // Method to test Async. call 245 | public void runRetrofitTestAsync (final String city) { 246 | if ( (mActivityRef.get() != null) && (mInProgress.get())) { 247 | Toast.makeText(mActivityRef.get(),"Weather fetch in progress.", 248 | Toast.LENGTH_LONG).show(); 249 | return; 250 | } 251 | // Get the Adapter 252 | if (mWeatherRestAdapter == null) 253 | mWeatherRestAdapter = new WeatherRestAdapter(); 254 | 255 | if (mActivityRef.get() != null) { 256 | mActivityRef.get().mProgressBar.setVisibility(View.VISIBLE); 257 | } 258 | 259 | // Test delay 260 | try { 261 | mInProgress.set(true); 262 | mWeatherRestAdapter.testWeatherApi(city, mWeatherDataCallback); // Call Async API 263 | } catch (Exception e) { 264 | Log.d(TAG, "Thread sleep error" + e); 265 | } 266 | } 267 | 268 | // Method to test sync. call 269 | public void runRetrofitTestSync (final String city) { 270 | 271 | if ((mActivityRef.get() != null) && (mInProgress.get())) { 272 | Toast.makeText(mActivityRef.get(),"Weather fetch in progress.", 273 | Toast.LENGTH_LONG).show(); 274 | return; 275 | } 276 | if (mActivityRef.get() != null) { 277 | mActivityRef.get().mProgressBar.setVisibility(View.VISIBLE); 278 | } 279 | 280 | if (mWeatherRestAdapter == null) 281 | mWeatherRestAdapter = new WeatherRestAdapter(); 282 | 283 | mInProgress.set(true); 284 | 285 | // Test Sync version -- in a separate thread 286 | // Not doing this will crash the app. As Retro sync calls can not be made from 287 | // UI thread. 288 | new Thread(new Runnable() { 289 | @Override 290 | public void run() { 291 | try { 292 | // Call Async API -- always call in a try block if you dont want app to 293 | // crash. You get 'HTTP/1.1 500 Internal Server Error' more often than 294 | // you think. 295 | Thread.sleep(10000); 296 | WeatherData data = mWeatherRestAdapter.testWeatherApiSync(city); 297 | Log.d(TAG, "Sync: Data: cod:" + data.getName() + ", cod:" + data.getCod() 298 | + ",Coord: (" + data.getLat() + "," + data.getLon() 299 | + "), Temp:" + data.getTemp() 300 | + "\nSunset:" + data.getSunset() + ", " + data.getSunrise() 301 | + ", Country:" + data.getCountry()); 302 | mData = data; 303 | if (mActivityRef.get() != null) { 304 | mActivityRef.get().updateUXWithWeatherData(mData); 305 | } 306 | } catch (Exception ex) { 307 | Log.e(TAG, "Sync: exception", ex); 308 | if (mActivityRef.get() != null) { 309 | mActivityRef.get().runOnUiThread(new Runnable() { 310 | @Override 311 | public void run() { 312 | mActivityRef.get().mProgressBar = (ProgressBar) mActivityRef.get(). 313 | findViewById(R.id.progress_bar_id); 314 | mActivityRef.get().mProgressBar.setVisibility(View.INVISIBLE); 315 | } 316 | }); 317 | } 318 | } finally { 319 | mInProgress.set(false); 320 | } 321 | } 322 | }).start(); 323 | } 324 | 325 | void setAppContext (MainActivity ref) { 326 | mActivityRef = new WeakReference<>(ref); 327 | } 328 | 329 | boolean isFetchInProgress() { 330 | return mInProgress.get(); 331 | } 332 | } 333 | } 334 | -------------------------------------------------------------------------------- /app/src/main/java/psv/apps/java/retrofitexample/WeatherApi.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by ajaythakur on 6/16/15. 3 | */ 4 | package psv.apps.java.retrofitexample; 5 | 6 | import retrofit.Callback; 7 | import retrofit.http.GET; 8 | import retrofit.http.Query; 9 | 10 | public interface WeatherApi { 11 | @GET("/data/2.5/weather") 12 | void getWeatherFromApi ( 13 | @Query("q") String cityName, 14 | @Query("APPID") String appId, 15 | Callback callback); 16 | @GET("/data/2.5/weather") 17 | WeatherData getWeatherFromApiSync ( 18 | @Query("q") String cityName, 19 | @Query("APPID") String appId); 20 | } 21 | -------------------------------------------------------------------------------- /app/src/main/java/psv/apps/java/retrofitexample/WeatherApiErrorHandler.java: -------------------------------------------------------------------------------- 1 | package psv.apps.java.retrofitexample; 2 | 3 | import android.util.Log; 4 | 5 | import retrofit.ErrorHandler; 6 | import retrofit.RetrofitError; 7 | import retrofit.client.Response; 8 | 9 | /** 10 | * Created by ajaythakur on 6/16/15. 11 | */ 12 | public class WeatherApiErrorHandler implements ErrorHandler { 13 | protected final String TAG = getClass().getSimpleName(); 14 | @Override 15 | public Throwable handleError(RetrofitError cause) { 16 | Response r = cause.getResponse(); 17 | if (r != null && r.getStatus() == 401) { 18 | Log.e(TAG, "Error:", cause); 19 | } 20 | return cause; 21 | 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /app/src/main/java/psv/apps/java/retrofitexample/WeatherData.java: -------------------------------------------------------------------------------- 1 | package psv.apps.java.retrofitexample; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * Created by ajaythakur on 6/16/15. 7 | * 8 | * { 9 | * "coord":{"lon":-122.08,"lat":37.39}, 10 | * "sys":{ 11 | * "type":1,"id":451,"message":1.1091, 12 | * "country":"United States of America", 13 | * "sunrise":1434545231,"sunset":1434598293 14 | * }, 15 | * "weather":[{"id":701,"main":"Mist","description":"mist","icon":"50n"}], 16 | * "base":"stations", 17 | * "main":{"temp":288.73,"pressure":1014,"humidity":82,"temp_min":284.26,"temp_max":294.15}, 18 | * "visibility":16093, 19 | * "wind":{"speed":4.1,"deg":350}, 20 | * "clouds":{"all":20}, 21 | * "dt":1434517063, 22 | * "id":5375480, 23 | * "name":"Mountain View", 24 | * "cod":200 25 | * } 26 | */ 27 | public class WeatherData { 28 | private Coord coord; 29 | private int cod; 30 | private String base; 31 | private String name; 32 | private Main main; 33 | private List weather; 34 | private Sys sys; 35 | 36 | public WeatherData(Coord coord, int code, String base, String name, Main main) { 37 | this.coord = coord; 38 | this.cod = code; 39 | this.base = base; 40 | this.name = name; 41 | this.main = main; 42 | } 43 | 44 | public int getCod() { 45 | return cod; 46 | } 47 | 48 | public void setCod(int code) { 49 | this.cod = code; 50 | } 51 | 52 | public String getBase() { 53 | return base; 54 | } 55 | 56 | public void setBase(String base) { 57 | this.base = base; 58 | } 59 | 60 | public Coord getCoord() { 61 | return coord; 62 | } 63 | 64 | public void setCoord(Coord coord) { 65 | this.coord = coord; 66 | } 67 | 68 | public String getName() { 69 | return name; 70 | } 71 | 72 | public void setName(String name) { 73 | this.name = name; 74 | } 75 | 76 | public Main getMain() { 77 | return main; 78 | } 79 | 80 | public void setMain(Main main) { 81 | this.main = main; 82 | } 83 | 84 | class Main { 85 | double temp; 86 | double pressure; 87 | int humidity; 88 | 89 | public Main(double temp, int pressure, int humidity) { 90 | this.temp = temp; 91 | this.pressure = pressure; 92 | this.humidity = humidity; 93 | } 94 | 95 | public double getTemp() { 96 | return temp; 97 | } 98 | 99 | public void setTemp(double temp) { 100 | this.temp = temp; 101 | } 102 | 103 | public double getPressure() { 104 | return pressure; 105 | } 106 | 107 | public void setPressure(double pressure) { 108 | this.pressure = pressure; 109 | } 110 | 111 | public int getHumidity() { 112 | return humidity; 113 | } 114 | 115 | public void setHumidity(int humidity) { 116 | this.humidity = humidity; 117 | } 118 | } 119 | 120 | class Coord { 121 | double lat; 122 | double lon; 123 | 124 | public Coord(double lat, double lon) { 125 | this.lat = lat; 126 | this.lon = lon; 127 | } 128 | 129 | public double getLat() { 130 | return lat; 131 | } 132 | 133 | public void setLat(double lat) { 134 | this.lat = lat; 135 | } 136 | 137 | public double getLon() { 138 | return lon; 139 | } 140 | 141 | public void setLon(double lon) { 142 | this.lon = lon; 143 | } 144 | } 145 | 146 | class Weather { 147 | private int id; 148 | String main; 149 | String description; 150 | String icon; 151 | 152 | public Weather() { 153 | } 154 | 155 | public Weather(int id, String main, String description, String icon) { 156 | this.id = id; 157 | this.main = main; 158 | this.description = description; 159 | this.icon = icon; 160 | } 161 | 162 | public int getId() { 163 | return id; 164 | } 165 | 166 | public void setId(int id) { 167 | this.id = id; 168 | } 169 | 170 | public String getMain() { 171 | return main; 172 | } 173 | 174 | public void setMain(String main) { 175 | this.main = main; 176 | } 177 | 178 | public String getDescription() { 179 | return description; 180 | } 181 | 182 | public void setDescription(String description) { 183 | this.description = description; 184 | } 185 | 186 | public String getIcon() { 187 | return icon; 188 | } 189 | 190 | public void setIcon(String icon) { 191 | this.icon = icon; 192 | } 193 | } 194 | 195 | class Sys { 196 | int type; 197 | int id; 198 | String country; 199 | long sunrise; 200 | long sunset; 201 | 202 | public Sys() { 203 | } 204 | 205 | public Sys(int type, int id, String country, long sunrise, long sunset) { 206 | this.type = type; 207 | this.id = id; 208 | this.country = country; 209 | this.sunrise = sunrise; 210 | this.sunset = sunset; 211 | } 212 | 213 | public int getType() { 214 | return type; 215 | } 216 | 217 | public void setType(int type) { 218 | this.type = type; 219 | } 220 | 221 | public int getId() { 222 | return id; 223 | } 224 | 225 | public void setId(int id) { 226 | this.id = id; 227 | } 228 | 229 | public String getCountry() { 230 | return country; 231 | } 232 | 233 | public void setCountry(String country) { 234 | this.country = country; 235 | } 236 | 237 | public long getSunrise() { 238 | return sunrise; 239 | } 240 | 241 | public void setSunrise(long sunrise) { 242 | this.sunrise = sunrise; 243 | } 244 | 245 | public long getSunset() { 246 | return sunset; 247 | } 248 | 249 | public void setSunset(long sunset) { 250 | this.sunset = sunset; 251 | } 252 | } 253 | 254 | // Accesor methods 255 | public double getLat() { 256 | return coord.getLat(); 257 | } 258 | 259 | public double getLon() { 260 | return coord.getLon(); 261 | } 262 | 263 | public double getPressure() { 264 | return main.getPressure(); 265 | } 266 | 267 | public double getTemp() { 268 | return main.getTemp(); 269 | } 270 | 271 | public String getCountry() { 272 | return sys.getCountry(); 273 | } 274 | 275 | public long getSunrise() { 276 | return sys.getSunrise(); 277 | } 278 | 279 | public long getSunset() { 280 | return sys.getSunset(); 281 | } 282 | } 283 | -------------------------------------------------------------------------------- /app/src/main/java/psv/apps/java/retrofitexample/WeatherRestAdapter.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by ajaythakur on 6/16/15. 3 | */ 4 | package psv.apps.java.retrofitexample; 5 | 6 | import android.util.Log; 7 | 8 | import retrofit.Callback; 9 | import retrofit.RestAdapter; 10 | 11 | public class WeatherRestAdapter { 12 | protected final String TAG = getClass().getSimpleName(); 13 | protected RestAdapter mRestAdapter; 14 | protected WeatherApi mApi; 15 | static final String WEATHER_URL="http://api.openweathermap.org"; 16 | static final String OPEN_WEATHER_API = "51337ba29f38cb7a5664cda04d84f4cd"; 17 | 18 | public WeatherRestAdapter() { 19 | mRestAdapter = new RestAdapter.Builder() 20 | .setLogLevel(RestAdapter.LogLevel.FULL) 21 | .setEndpoint(WEATHER_URL) 22 | .setErrorHandler(new WeatherApiErrorHandler()) 23 | .build(); 24 | mApi = mRestAdapter.create(WeatherApi.class); // create the interface 25 | Log.d(TAG, "WeatherRestAdapter -- created"); 26 | } 27 | 28 | public void testWeatherApi(String city, Callback callback){ 29 | Log.d(TAG, "testWeatherApi: for city:" + city); 30 | mApi.getWeatherFromApi(city, OPEN_WEATHER_API, callback); 31 | } 32 | 33 | public WeatherData testWeatherApiSync(String city) { 34 | WeatherData result; 35 | Log.d(TAG, "testWeatherApi: for city:" + city); 36 | result = mApi.getWeatherFromApiSync(city,OPEN_WEATHER_API); 37 | return result; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 10 | 11 | 17 | 18 | 19 | 20 | 27 |