Indonesian (Bahasa Indonesia) translation by ⚡ Rova Rindrata (you can also view the original English article)

Banyak aplikasi cuaca populer di Google Play penuh dengan iklan, memerlukan terlalu banyak izin, atau menyertakan fitur yang kebanyakan tidak pernah kita gunakan. Bukankah lebih bagus lagi jika Anda bisa membuat aplikasi cuaca Anda sendiri dari awal?
Dalam tutorial ini, saya akan menunjukkan caranya. Aplikasi kita akan memiliki antarmuka pengguna yang sederhana dan minimalis, menunjukkan kepada pengguna apa yang perlu diketahui tentang kondisi cuaca saat ini. Mari kita mulai.
1. Prasyarat
Sebelum melanjutkan, periksa kembali apakah Anda sudah menyiapkannya:
- Eclipse ADT Bundle: Anda dapat mengunduhnya di situs pengembang Android.
- Kunci API OpenWeatherMap: Ini tidak diperlukan untuk menyelesaikan tutorial, tapi gratis. Anda bisa mendapatkannya dengan mendaftar di situs OpenWeatherMap.
- Ikon: Saya sarankan Anda mengunduh font ikon cuaca yang dibuat oleh Erik Flowers. Anda perlu mengunduh file TTF, karena kami akan menggunakannya di aplikasi asli. Kita akan menggunakan font untuk me-render berbagai ikon tergantung pada kondisi cuaca.
2. Membuat Sebuah Proyek Baru
Saya akan memanggil aplikasi ini SimpleWeather, tapi jangan ragu untuk memberikan nama yang Anda suka. Masukkan nama paket yang unik, setel SDK minimum yang diperlukan ke Android 2.2, dan tetapkan target SDK ke Android 4.4. Anda bisa meninggalkan tema di Holo Dark.

Aplikasi ini hanya akan memiliki satu Activity
dan akan didasarkan pada template Blank Activity seperti yang ditunjukkan di bawah ini.

Namakan Activity
tersebut WeatherActivity. Kita akan menggunakan Fragment
di dalam Activity
ini. Layout yang terkait dengan Activity
adalah activity_weather.xml. Layout yang terkait dengan Fragment
adalah fragment_weather.xml.

3. Menambahkan Font Kustom
Salin weathericons-regular-webfont.ttf ke direktori assets/fonts proyek Anda dan ubah namanya menjadi weather.ttf.
4. Edit Manifest-nya
Satu-satunya izin yang dibutuhkan aplikasi ini adalah android.permission.INTERNET
.
<uses-permission android:name="android.permission.INTERNET"/>
Agar tutorial ini tetap sederhana, kami hanya akan mendukung mode portrait. Node activity
dari manifest harus terlihat seperti ini:
<activity android:name="ah.hathi.simpleweather.WeatherActivity" android:label="@string/app_name" android:screenOrientation="portrait" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity>
5. Edit Layout Activity
Tidak banyak perubahan dalam activity_weather.xml. Seharusnya sudah memiliki FrameLayout
. Tambahkan properti tambahan untuk mengubah warna background
menjadi #FF0099CC
.
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/container" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="ah.hathi.simpleweather.WeatherActivity" tools:ignore="MergeRootFrame" android:background="#FF0099CC" />
6. Edit Layout Fragment
Edit fragment_weather.xml dengan menambahkan lima tag TextView
untuk menampilkan informasi berikut:
- kota dan negara
- suhu saat ini
- sebuah ikon yang menunjukkan kondisi cuaca saat ini
- sebuah cap waktu yang memberitahu pengguna saat informasi cuaca terakhir diperbarui
- informasi lebih rinci tentang cuaca saat ini, seperti deskripsi dan kelembaban
Gunakan RelativeLayout
untuk mengatur tampilan teks. Anda bisa mengatur textSize
agar sesuai dengan berbagai perangkat.
<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:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context="ah.hathi.simpleweather.WeatherActivity$PlaceholderFragment" > <TextView android:id="@+id/city_field" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentTop="true" android:layout_centerHorizontal="true" android:textAppearance="?android:attr/textAppearanceLarge" /> <TextView android:id="@+id/updated_field" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@+id/city_field" android:layout_centerHorizontal="true" android:textAppearance="?android:attr/textAppearanceMedium" android:textSize="13sp" /> <TextView android:id="@+id/weather_icon" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerVertical="true" android:layout_centerHorizontal="true" android:textAppearance="?android:attr/textAppearanceLarge" android:textSize="70sp" /> <TextView android:id="@+id/current_temperature_field" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:layout_centerHorizontal="true" android:textAppearance="?android:attr/textAppearanceLarge" android:textSize="40sp" /> <TextView android:id="@+id/details_field" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@+id/weather_icon" android:layout_centerHorizontal="true" android:textAppearance="?android:attr/textAppearanceMedium" /> </RelativeLayout>
7. Edit strings.xml
File ini berisi string yang digunakan di aplikasi kita serta kode karakter Unicode yang akan kita gunakan untuk me-render ikon cuaca. Aplikasi ini akan mampu menampilkan delapan jenis kondisi cuaca. Jika Anda ingin menangani lebih banyak, maka lihatlah lembar contekan ini. Tambahkan yang berikut ini ke values/strings.xml:
<?xml version="1.0" encoding="utf-8"?> <resources> <string name="app_name">Simple Weather</string> <string name="change_city">Change city</string> <!-- Put your own APP ID here --> <string name="open_weather_maps_app_id">11111</string> <string name="weather_sunny"></string> <string name="weather_clear_night"></string> <string name="weather_foggy"></string> <string name="weather_cloudy"></string> <string name="weather_rainy"></string> <string name="weather_snowy"></string> <string name="weather_thunder"></string> <string name="weather_drizzle"></string> <string name="place_not_found">Sorry, no weather data found.</string> </resources>
8. Menambahkan Item Menu
Pengguna akan bisa memilih kota yang ingin mereka lihat. Edit menu/weather.xml dan tambahkan item untuk pilihan ini.
<menu xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" tools:context="ah.hathi.simpleweather.WeatherActivity" > <item android:id="@+id/change_city" android:orderInCategory="1" android:title="@string/change_city" app:showAsAction="never"/> </menu>
Sekarang semua file XML siap digunakan, mari kita lanjutkan dan melakukan kueri API OpenWeatherMap untuk mengambil data cuaca.
9. Mengambil Data dari OpenWeatherMap
Kita bisa mendapatkan rincian cuaca terkini dari setiap kota yang diformat sebagai JSON menggunakan API OpenWeatherMap. Dalam string kueri, kita meneruskan nama kota dan sistem metrik yang seharusnya masuk ke dalamnya.
Misalnya, untuk mendapatkan informasi cuaca saat ini untuk Canberra, dengan menggunakan sistem metrik, kita mengirim permintaan ke http://api.openweathermap.org/data/2.5/weather?q=Canberra&units=metric
Tanggapan yang kita dapatkan dari API terlihat seperti ini:
{ "base": "cmc stations", "clouds": { "all": 90 }, "cod": 200, "coord": { "lat": -35.28, "lon": 149.13 }, "dt": 1404390600, "id": 2172517, "main": { "humidity": 100, "pressure": 1023, "temp": -1, "temp_max": -1, "temp_min": -1 }, "name": "Canberra", "sys": { "country": "AU", "message": 0.313, "sunrise": 1404335563, "sunset": 1404370965 }, "weather": [ { "description": "overcast clouds", "icon": "04n", "id": 804, "main": "Clouds" } ], "wind": { "deg": 305.004, "speed": 1.07 } }
Buat kelas Java baru dan beri nama RemoteFetch.java. Kelas ini bertanggung jawab untuk mengambil data cuaca dari API OpenWeatherMap.
Kami menggunakan kelas HttpURLConnection
untuk melakukan permintaan jarak jauh. API OpenWeatherMap mengharapkan kunci API di header HTTP bernama x-api-key
. Ini ditentukan dalam permintaan kami dengan menggunakan metode setRequestProperty
.
Kami menggunakan BufferedReader
untuk membaca respons API ke StringBuffer
. Bila kita memiliki respon yang lengkap, kita mengubahnya menjadi objek JSONObject
.
Seperti yang dapat Anda lihat dalam respon di atas, data JSON berisi field bernama cod
. Nilainya 200
jika permintaan itu berhasil. Kami menggunakan nilai ini untuk memeriksa apakah respon JSON memiliki informasi cuaca saat ini atau tidak.
Kelas RemoteFetch.java akan terlihat seperti ini:
package ah.hathi.simpleweather; import java.io.BufferedReader; import java.io.InputStreamReader; import java.net.HttpURLConnection; import java.net.URL; import org.json.JSONObject; import android.content.Context; import android.util.Log; public class RemoteFetch { private static final String OPEN_WEATHER_MAP_API = "http://api.openweathermap.org/data/2.5/weather?q=%s&units=metric"; public static JSONObject getJSON(Context context, String city){ try { URL url = new URL(String.format(OPEN_WEATHER_MAP_API, city)); HttpURLConnection connection = (HttpURLConnection)url.openConnection(); connection.addRequestProperty("x-api-key", context.getString(R.string.open_weather_maps_app_id)); BufferedReader reader = new BufferedReader( new InputStreamReader(connection.getInputStream())); StringBuffer json = new StringBuffer(1024); String tmp=""; while((tmp=reader.readLine())!=null) json.append(tmp).append("\n"); reader.close(); JSONObject data = new JSONObject(json.toString()); // This value will be 404 if the request was not // successful if(data.getInt("cod") != 200){ return null; } return data; }catch(Exception e){ return null; } } }
10. Menyimpan Kota sebagai Preferensi
Pengguna tidak perlu menentukan nama kota setiap kali mereka ingin menggunakan aplikasi. Aplikasi ini akan mengingat kota terakhir yang diminati pengguna. Kami melakukan ini dengan memanfaatkan SharedPreferences
. Namun, alih-alih mengakses preferensi ini secara langsung dari kelas Activity
kami, lebih baik membuat kelas terpisah untuk tujuan ini.
Buat kelas Java baru dan beri nama CityPreference.java. Untuk menyimpan dan mengambil nama kota, buat dua metode setCity
dan getCity
. Objek SharedPreferences
diinisialisasi dalam constructor. Kelas CityPreference.java akan terlihat seperti ini:
package ah.hathi.simpleweather; import android.app.Activity; import android.content.SharedPreferences; public class CityPreference { SharedPreferences prefs; public CityPreference(Activity activity){ prefs = activity.getPreferences(Activity.MODE_PRIVATE); } // If the user has not chosen a city yet, return // Sydney as the default city String getCity(){ return prefs.getString("city", "Sydney, AU"); } void setCity(String city){ prefs.edit().putString("city", city).commit(); } }
11. Membuat Fragment
Buat kelas Java baru dan beri nama WeatherFragment.java. Fragment ini menggunakan fragment_weather.xml sebagai layout-nya. Deklarasikan lima objek TextView
dan menginisialisasi mereka dalam metode onCreateView
. Deklarasikan objek Typeface
baru bernama weatherFont
. Objek TypeFace
akan menunjuk ke font web yang Anda unduh dan disimpan di folder assets/fonts.
Kita akan menggunakan Thread
terpisah untuk secara asinkron mengambil data dari API OpenWeatherMap. Kita tidak dapat memperbarui antarmuka pengguna dari thread latar belakang tersebut. Karena itu kita membutuhkan objek Handler
, yang kita inisialisasi pada constructor dari kelas WeatherFragment
.
public class WeatherFragment extends Fragment { Typeface weatherFont; TextView cityField; TextView updatedField; TextView detailsField; TextView currentTemperatureField; TextView weatherIcon; Handler handler; public WeatherFragment(){ handler = new Handler(); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View rootView = inflater.inflate(R.layout.fragment_weather, container, false); cityField = (TextView)rootView.findViewById(R.id.city_field); updatedField = (TextView)rootView.findViewById(R.id.updated_field); detailsField = (TextView)rootView.findViewById(R.id.details_field); currentTemperatureField = (TextView)rootView.findViewById(R.id.current_temperature_field); weatherIcon = (TextView)rootView.findViewById(R.id.weather_icon); weatherIcon.setTypeface(weatherFont); return rootView; } }
Inisialisasi objek WeatherFont
dengan memanggil createFromAsset
pada kelas Typeface
. Kita juga meminta metode updateWeatherData
di onCreate
.
@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); weatherFont = Typeface.createFromAsset(getActivity().getAssets(), "fonts/weather.ttf"); updateWeatherData(new CityPreference(getActivity()).getCity()); }
Di updateWeatherData
, kita memulai thread baru dan memanggil getJSON
di kelas RemoteFetch
. Jika nilai yang dikembalikan oleh getJSON
adalah null
, kita menampilkan pesan kesalahan kepada pengguna. Jika tidak, kita memanggil metode renderWeather
.
Hanya Thread
utama yang diizinkan memperbarui antarmuka pengguna aplikasi Android. Memanggil Toast
atau renderWeather
langsung dari thread latar belakang akan menyebabkan kesalahan runtime. Itulah sebabnya kita memanggil metode ini menggunakan metode post
dari handler
.
private void updateWeatherData(final String city){ new Thread(){ public void run(){ final JSONObject json = RemoteFetch.getJSON(getActivity(), city); if(json == null){ handler.post(new Runnable(){ public void run(){ Toast.makeText(getActivity(), getActivity().getString(R.string.place_not_found), Toast.LENGTH_LONG).show(); } }); } else { handler.post(new Runnable(){ public void run(){ renderWeather(json); } }); } } }.start(); }
Metode renderWeather
menggunakan data JSON untuk memperbarui objek TextView
. Node weather
dari respon JSON adalah array data. Dalam tutorial ini, kita hanya akan menggunakan elemen pertama dari array data cuaca.
private void renderWeather(JSONObject json){ try { cityField.setText(json.getString("name").toUpperCase(Locale.US) + ", " + json.getJSONObject("sys").getString("country")); JSONObject details = json.getJSONArray("weather").getJSONObject(0); JSONObject main = json.getJSONObject("main"); detailsField.setText( details.getString("description").toUpperCase(Locale.US) + "\n" + "Humidity: " + main.getString("humidity") + "%" + "\n" + "Pressure: " + main.getString("pressure") + " hPa"); currentTemperatureField.setText( String.format("%.2f", main.getDouble("temp"))+ " ℃"); DateFormat df = DateFormat.getDateTimeInstance(); String updatedOn = df.format(new Date(json.getLong("dt")*1000)); updatedField.setText("Last update: " + updatedOn); setWeatherIcon(details.getInt("id"), json.getJSONObject("sys").getLong("sunrise") * 1000, json.getJSONObject("sys").getLong("sunset") * 1000); }catch(Exception e){ Log.e("SimpleWeather", "One or more fields not found in the JSON data"); } }
Pada akhir metode renderWeather
, kita meminta setWeatherIcon
dengan id
dari cuaca saat ini dan juga saat matahari terbit dan terbenam. Menetapkan ikon cuaca sedikit rumit, karena API OpenWeatherMap mendukung lebih banyak kondisi cuaca daripada yang bisa kita dukung dengan font web yang kita gunakan. Untungnya, id cuaca mengikuti pola, yang bisa Anda baca lebih lanjut di situs OpenWeatherMap.
Ini adalah bagaimana kita memetakan id cuaca ke ikon:
- kode cuaca di kisaran 200 terkait dengan badai petir, yang berarti kita dapat menggunakan
R.string.weather_thunder
untuk ini - kode cuaca di kisaran 300 terkait dengan gerimis dan kami menggunakan
R.string.weather_drizzle
untuk ini - kode cuaca di kisaran 500 menandakan hujan dan kita menggunakan
R.string.weather_rain
untuk mereka - dan seterusnya ...
Kita menggunakan waktu matahari terbit dan terbenam untuk menampilkan matahari atau bulan, tergantung pada waktu saat ini dan hanya jika cuaca cerah.
private void setWeatherIcon(int actualId, long sunrise, long sunset){ int id = actualId / 100; String icon = ""; if(actualId == 800){ long currentTime = new Date().getTime(); if(currentTime>=sunrise && currentTime<sunset) { icon = getActivity().getString(R.string.weather_sunny); } else { icon = getActivity().getString(R.string.weather_clear_night); } } else { switch(id) { case 2 : icon = getActivity().getString(R.string.weather_thunder); break; case 3 : icon = getActivity().getString(R.string.weather_drizzle); break; case 7 : icon = getActivity().getString(R.string.weather_foggy); break; case 8 : icon = getActivity().getString(R.string.weather_cloudy); break; case 6 : icon = getActivity().getString(R.string.weather_snowy); break; case 5 : icon = getActivity().getString(R.string.weather_rainy); break; } } weatherIcon.setText(icon); }
Tentu saja, Anda dapat menangani lebih banyak kondisi cuaca dengan menambahkan lebih banyak pernyataan case
ke pernyataan switch
dari metode setWeatherIcon
.
Akhirnya, tambahkan metode changeCity
ke fragment agar pengguna memperbarui kota saat ini. Metode changeCity
hanya akan dipanggil dari class Activity
utama.
public void changeCity(String city){ updateWeatherData(city); }
12. Mengedit Activity
Selama penyiapan proyek, Eclipse mengisi WeatherActivity.java dengan beberapa kode boilerplate. Ganti implementasi default metode onCreate
dengan yang di bawah ini dimana kita menggunakan WeatherFragment
. Metode onCreate
akan terlihat seperti ini:
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_weather); if (savedInstanceState == null) { getSupportFragmentManager().beginTransaction() .add(R.id.container, new WeatherFragment()) .commit(); } }
Selanjutnya, edit metode onOptionsItemSelected
dan atur satu-satunya pilihan menu yang kita miliki. Yang harus Anda lakukan di sini adalah memanggil metode showInputDialog
.
Dalam metode showInputDialog
, kita menggunakan AlertDialog.Builder
untuk membuat objek Dialog
yang meminta pengguna untuk memasukkan nama sebuah kota. Informasi ini diteruskan ke metode changeCity
, yang menyimpan nama kota menggunakan kelas CityPreference
dan memanggil metode ChangeCity
dari Fragment
.
@Override public boolean onOptionsItemSelected(MenuItem item) { if(item.getItemId() == R.id.change_city){ showInputDialog(); } return false; } private void showInputDialog(){ AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setTitle("Change city"); final EditText input = new EditText(this); input.setInputType(InputType.TYPE_CLASS_TEXT); builder.setView(input); builder.setPositiveButton("Go", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { changeCity(input.getText().toString()); } }); builder.show(); } public void changeCity(String city){ WeatherFragment wf = (WeatherFragment)getSupportFragmentManager() .findFragmentById(R.id.container); wf.changeCity(city); new CityPreference(this).setCity(city); }
Aplikasi cuaca Anda sekarang sudah siap. Build proyeknya dan kirimkan ke perangkat Android untuk pengujian.

Kesimpulan
Anda sekarang memiliki aplikasi cuaca yang berfungsi penuh. Jangan ragu untuk mengeksplorasi API OpenWeatherMap untuk lebih meningkatkan aplikasi Anda. Anda mungkin juga ingin menggunakan lebih banyak ikon cuaca, karena saat ini kami hanya menggunakan sebagian kecil dari mereka.
Subscribe below and we’ll send you a weekly email summary of all new Code tutorials. Never miss out on learning about the next big thing.
Update me weeklyEnvato Tuts+ tutorials are translated into other languages by our community members—you can be involved too!
Translate this post