diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9c4de58 --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +.gradle +/local.properties +/.idea/workspace.xml +/.idea/libraries +.DS_Store +/build +/captures diff --git a/.idea/.name b/.idea/.name new file mode 100644 index 0000000..c78db89 --- /dev/null +++ b/.idea/.name @@ -0,0 +1 @@ +homework5-master \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..96cc43e --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/copyright/profiles_settings.xml b/.idea/copyright/profiles_settings.xml new file mode 100644 index 0000000..e7bedf3 --- /dev/null +++ b/.idea/copyright/profiles_settings.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml new file mode 100644 index 0000000..bd4202c --- /dev/null +++ b/.idea/gradle.xml @@ -0,0 +1,19 @@ + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..fbb6828 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..aa89085 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/runConfigurations.xml b/.idea/runConfigurations.xml new file mode 100644 index 0000000..7f68460 --- /dev/null +++ b/.idea/runConfigurations.xml @@ -0,0 +1,12 @@ + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/.gitignore b/app/.gitignore new file mode 100644 index 0000000..796b96d --- /dev/null +++ b/app/.gitignore @@ -0,0 +1 @@ +/build diff --git a/app/app.iml b/app/app.iml new file mode 100644 index 0000000..aef896b --- /dev/null +++ b/app/app.iml @@ -0,0 +1,97 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 34fb554..5e9ae22 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -11,7 +11,7 @@ android:label="@string/app_name" android:supportsRtl="true" android:theme="@style/AppTheme" > - + @@ -20,4 +20,4 @@ - + \ No newline at end of file diff --git a/app/src/main/java/ru/ifmo/android_2015/homework5/DownloadService.java b/app/src/main/java/ru/ifmo/android_2015/homework5/DownloadService.java new file mode 100644 index 0000000..692ce31 --- /dev/null +++ b/app/src/main/java/ru/ifmo/android_2015/homework5/DownloadService.java @@ -0,0 +1,50 @@ +package ru.ifmo.android_2015.homework5; + +import android.app.IntentService; +import android.content.Intent; +import android.util.Log; + +import java.io.IOException; + +public class DownloadService extends IntentService { + + + public DownloadService(String name) { + super(name); + } + + public DownloadService() { + super("DownloadService"); + } + + + @Override + protected void onHandleIntent(Intent intent) { + if (intent != null) { + final String action = intent.getAction(); + if (action.equals("DOWNLOAD")) { + try { + InitSplashActivity.downloadFile(this, new ProgressCallback() { + @Override + public void onProgressChanged(int progress) { + sendProgress(InitSplashActivity.DownloadState.DOWNLOADING, progress); + } + }); + } catch (Exception e) { + sendProgress(InitSplashActivity.DownloadState.ERROR, 100); + return; + } + sendProgress(InitSplashActivity.DownloadState.DONE, 100); + } + } + } + + private void sendProgress(InitSplashActivity.DownloadState downloadState, int progress) { + Intent intent = new Intent(String.valueOf(R.string.action)); + intent.putExtra("download_state", downloadState); + intent.putExtra("progress", progress); + + sendBroadcast(intent); + } + +} \ No newline at end of file diff --git a/app/src/main/java/ru/ifmo/android_2015/homework5/InitSplashActivity.java b/app/src/main/java/ru/ifmo/android_2015/homework5/InitSplashActivity.java index 8810d30..266e9a4 100644 --- a/app/src/main/java/ru/ifmo/android_2015/homework5/InitSplashActivity.java +++ b/app/src/main/java/ru/ifmo/android_2015/homework5/InitSplashActivity.java @@ -1,8 +1,10 @@ package ru.ifmo.android_2015.homework5; import android.app.Activity; +import android.content.BroadcastReceiver; import android.content.Context; -import android.os.AsyncTask; +import android.content.Intent; +import android.content.IntentFilter; import android.os.Bundle; import android.util.Log; import android.widget.ProgressBar; @@ -11,24 +13,16 @@ import java.io.File; import java.io.IOException; -/** - * Экран, выполняющий инициализацию при первом запуске приложения. В процессе инициализации - * скачивается файл с данными, нужными для работы приложения. Пока идет инициализация, показывается - * сплэш-скрин с индикатором прогресса. - */ + public class InitSplashActivity extends Activity { - // Урл для скачивания файла с данными, нужными для инициализации приложения при первом запуске. - // GZIP-архив, содержащий список городов в формате JSON. private static final String CITIES_GZ_URL = "https://www.dropbox.com/s/d99ky6aac6upc73/city_array.json.gz?dl=1"; - // Индикатор прогресса private ProgressBar progressBarView; - // Заголовок + private DownloadState downloadState; private TextView titleTextView; - // Выполняющийся таск загрузки файла - private DownloadFileTask downloadTask; + private BroadcastReceiver broadcastReceiver; @Override @SuppressWarnings("deprecation") @@ -42,38 +36,79 @@ protected void onCreate(Bundle savedInstanceState) { progressBarView.setMax(100); + + if (savedInstanceState == null) { + downloadState = DownloadState.DOWNLOADING; + startReceiver(); + Intent intent = new Intent(this, DownloadService.class); + intent.setAction("DOWNLOAD"); + startService(intent); + } + } + @Override + protected void onDestroy() { + Log.d(TAG, "onDestroy"); + super.onDestroy(); + } + + protected void onSaveInstanceState(Bundle outState) { + Log.d(TAG, "onRestore"); + outState.putSerializable("download_state", downloadState); + outState.putInt("progress", progressBarView.getProgress()); + super.onSaveInstanceState(outState); + } + + protected void onRestoreInstanceState(Bundle savedInstanceState) { + Log.d(TAG, "onRestore"); + super.onRestoreInstanceState(savedInstanceState); if (savedInstanceState != null) { - // Пытаемся получить ранее запущенный таск - downloadTask = (DownloadFileTask) getLastNonConfigurationInstance(); + downloadState = (DownloadState) savedInstanceState.getSerializable("download_state"); + updateView(downloadState, savedInstanceState.getInt("progress")); + startReceiver(); } - if (downloadTask == null) { - // Создаем новый таск, только если не было ранее запущенного таска - downloadTask = new DownloadFileTask(this); - downloadTask.execute(); + } + + private void startReceiver() { + if (downloadState == DownloadState.DOWNLOADING ) { + broadcastReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + downloadState = (DownloadState) intent.getSerializableExtra("download_state"); + int progress = intent.getIntExtra("progress", 0); + if (downloadState == DownloadState.DONE || downloadState == DownloadState.ERROR) { + unregisterReceiver(broadcastReceiver); + } + updateView(downloadState, progress); + } + }; + + IntentFilter intFilt = new IntentFilter(String.valueOf(R.string.action)); + registerReceiver(broadcastReceiver, intFilt); + } + } + + void updateView(DownloadState state, int progress) { + if (state.titleResId == R.string.downloading) { + titleTextView.setText("Загрузка..." + " " + progress + "%"); } else { - // Передаем в ранее запущенный таск текущий объект Activity - downloadTask.attachActivity(this); + titleTextView.setText(state.titleResId); } + progressBarView.setProgress(progress); } + @Override @SuppressWarnings("deprecation") public Object onRetainNonConfigurationInstance() { - // Этот метод вызывается при смене конфигурации, когда текущий объект - // Activity уничтожается. Объект, который мы вернем, не будет уничтожен, - // и его можно будет использовать в новом объекте Activity - return downloadTask; + return broadcastReceiver; } - /** - * Состояние загрузки в DownloadFileTask - */ + enum DownloadState { DOWNLOADING(R.string.downloading), DONE(R.string.done), ERROR(R.string.error); - // ID строкового ресурса для заголовка окна прогресса final int titleResId; DownloadState(int titleResId) { @@ -81,106 +116,6 @@ enum DownloadState { } } - /** - * Таск, выполняющий скачивание файла в фоновом потоке. - */ - static class DownloadFileTask extends AsyncTask - implements ProgressCallback { - - // Context приложения (Не Activity!) для доступа к файлам - private Context appContext; - // Текущий объект Activity, храним для обновления отображения - private InitSplashActivity activity; - - // Текущее состояние загрузки - private DownloadState state = DownloadState.DOWNLOADING; - // Прогресс загрузки от 0 до 100 - private int progress; - - DownloadFileTask(InitSplashActivity activity) { - this.appContext = activity.getApplicationContext(); - this.activity = activity; - } - - /** - * Этот метод вызывается, когда новый объект Activity подключается к - * данному таску после смены конфигурации. - * - * @param activity новый объект Activity - */ - void attachActivity(InitSplashActivity activity) { - this.activity = activity; - updateView(); - } - - /** - * Вызываем на UI потоке для обновления отображения прогресса и - * состояния в текущей активности. - */ - void updateView() { - if (activity != null) { - activity.titleTextView.setText(state.titleResId); - activity.progressBarView.setProgress(progress); - } - } - - /** - * Вызывается в UI потоке из execute() до начала выполнения таска. - */ - @Override - protected void onPreExecute() { - updateView(); - } - - /** - * Скачивание файла в фоновом потоке. Возвращает результат: - * 0 -- если файл успешно скачался - * 1 -- если произошла ошибка - */ - @Override - protected DownloadState doInBackground(Void... ignore) { - try { - downloadFile(appContext, this /*progressCallback*/); - state = DownloadState.DONE; - - } catch (Exception e) { - Log.e(TAG, "Error downloading file: " + e, e); - state = DownloadState.ERROR; - } - return state; - } - - // Метод ProgressCallback, вызывается в фоновом потоке из downloadFile - @Override - public void onProgressChanged(int progress) { - publishProgress(progress); - } - - // Метод AsyncTask, вызывается в UI потоке в результате вызова publishProgress - @Override - protected void onProgressUpdate(Integer... values) { - if (values.length > 0) { - int progress = values[values.length - 1]; - this.progress = progress; - updateView(); - } - } - - @Override - protected void onPostExecute(DownloadState state) { - // Проверяем код, который вернул doInBackground и показываем текст в зависимости - // от результата - this.state = state; - if (state == DownloadState.DONE) { - progress = 100; - } - updateView(); - } - } - - /** - * Скачивает список городов во временный файл. - */ static void downloadFile(Context context, ProgressCallback progressCallback) throws IOException { File destFile = FileUtils.createTempExternalFile(context, "gz"); @@ -188,4 +123,4 @@ static void downloadFile(Context context, } private static final String TAG = "InitSplash"; -} +} \ No newline at end of file diff --git a/app/src/main/java/ru/ifmo/android_2015/homework5/ProgressCallback.java b/app/src/main/java/ru/ifmo/android_2015/homework5/ProgressCallback.java index 0d26c5c..bbf6092 100644 --- a/app/src/main/java/ru/ifmo/android_2015/homework5/ProgressCallback.java +++ b/app/src/main/java/ru/ifmo/android_2015/homework5/ProgressCallback.java @@ -1,7 +1,7 @@ package ru.ifmo.android_2015.homework5; /** - * Callback интерфейс для получения уведомления о прогрессе. + * ProgressCallback интерфейс для получения уведомления о прогрессе. */ public interface ProgressCallback { @@ -10,4 +10,5 @@ public interface ProgressCallback { * @param progress новое значение прогресса от 0 до 100. */ void onProgressChanged(int progress); + } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index f501861..f6cebfe 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1,6 +1,8 @@ - Example 2.4 + Downloading Загрузка… Ошибка Готово + ru.ifmo.android_2015.homework5 + diff --git a/homework5-master.iml b/homework5-master.iml new file mode 100644 index 0000000..7a5b5ba --- /dev/null +++ b/homework5-master.iml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file