В этом посте описывается, как создать навигационный ящик со средством выбора учетной записи . Панель навигации — это новый шаблон пользовательского интерфейса, представленный в последнем вводе / выводе. Для этого я буду использовать новый Google Service API с Drive SDK, смешивая их для достижения этой цели. Есть много документов, объясняющих, как создать навигационный ящик, но я хочу объяснить, как добавить к нему средство выбора учетной записи . Если вы посмотрите на Google Drive App, то заметите, что вы можете выбрать свою учетную запись прямо из левого ящика, а не выбирать ее в настройках. В этом посте я покажу, как мы можем получить папку в нашей учетной записи Google Drive, выбрав ее в левом навигационном ящике.
Настройка макета навигационного ящика
Я не буду вдаваться в подробности, как использовать навигационный ящик, потому что об этом уже слишком много документов, поэтому в этом посте предполагается, что вы уже знакомы с этим шаблоном. Если вы хотите узнать больше, вы можете взглянуть на « Навигационный ящик ». Давайте сначала настроим наш макет, нам нужно:
- Спиннер, чтобы выбрать наш аккаунт
- Элементы навигационного ящика
Как мы уже знаем, ящик должен быть первым элементом в нашем макете, поэтому мы имеем
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
|
<android.support.v4.widget.DrawerLayout android:id="@+id/drawer_layout" android:layout_width="match_parent" android:layout_height="match_parent"> <FrameLayout android:id="@+id/content_frame" android:layout_width="match_parent" android:layout_height="match_parent"/> <LinearLayout android:layout_height="match_parent" android:orientation="vertical" android:id="@+id/menu" android:layout_gravity="start" android:layout_width="240dp"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Accounts" style="?android:attr/textAppearanceMedium" /> <Spinner android:id="@+id/spinnerAccount" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentLeft="true" android:layout_alignParentTop="true" android:layout_gravity="start" /> <ListView android:id="@+id/left_drawer" android:layout_height="match_parent" android:choiceMode="singleChoice" android:divider="@android:color/transparent" android:dividerHeight="0dp" android:background="#AA111000" android:layout_gravity="start" android:layout_width="match_parent" /> </LinearLayout></android.support.v4.widget.DrawerLayout> |
В строке 7 мы вводим FrameLayout для динамической обработки содержимого пользовательского интерфейса. Вместо использования ListView непосредственно после FrameLayout (как в официальном документе), мы вводим линейный макет (строка 12) для удерживания счетчика (строка 25) и пунктов меню.
Заполните счетчик счетами
Следующим шагом является заполнение счетчика активной учетной записью, настроенной на смартфоне. Для этого мы можем использовать AccountManager и получить список учетных записей следующим образом:
|
01
02
03
04
05
06
07
08
09
10
11
|
AccountManager accMgr = AccountManager.get(this);Account[] accountList = accMgr.getAccounts();final String[] accountNames = new String[accountList.length + 1];int i=1;accountNames[0] = getResources().getString(R.string.infospinner);for (Account account : accountList) { String name = account.name; accountNames[i++] = name;} |
Когда у нас есть список учетных записей, нам нужно просто определить новый адаптер, чтобы можно было заполнить счетчик.
|
1
2
|
ArrayAdapter<String> adp = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item, accountNames);spinner.setAdapter(adp); |
Выбор учетной записи пользователя
Мы должны обработать выбор учетной записи пользователя, чтобы мы могли настроить правильный процесс, требующий авторизацию, если это необходимо, и правильно настроить Drive API. Тогда мы имеем:
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
|
@Overridepublic void onItemSelected(AdapterView<?> parent, View view, int position, long id) { System.out.println("Pos ["+position+"]"); if (position == 0) return ; String currentAccount = accountNames[position]; credential = GoogleAccountCredential.usingOAuth2(MainActivity.this, DriveScopes.DRIVE); credential.setSelectedAccountName(currentAccount); service = getDriveService(credential); AsyncAuth auth = new AsyncAuth(); auth.execute("");}....}); |
В строке 8 мы выбираем выбранную учетную запись. Затем мы сохраняем выбранную пользователем учетную информацию (строка 9) и запускаем асинхронный процесс для извлечения пользовательской папки (строка 12,13).
Авторизация и доступ к Google Диску
Теперь мы хотим получить доступ к данным Google Drive и получить все папки в корневом каталоге. Мы знаем, что для этого нам необходимо пройти аутентификацию и авторизацию, и этот процесс состоит из двух разных этапов:
- Выберите аккаунт
- Авторизовать аккаунт
Первый шаг уже сделан, когда мы выбираем нашу учетную запись с помощью счетчика (см. Выше), поэтому мы должны сосредоточиться на втором шаге (авторизация). Первое, что мы должны сделать, это попытаться получить доступ к данным диска, чтобы мы могли знать, авторизованы ли мы уже или нам нужна авторизация. Процесс для доступа к данным удаленного диска использует HTTP-соединение, поэтому мы не можем обработать его в нашем главном потоке, поэтому нам нужно создать асинхронный процесс с использованием AsyncTask .
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
|
private class AsyncAuth extends AsyncTask<String, Void, List<File>> { @Override protected List<File> doInBackground(String... params) { List<File> fileList = new ArrayList<File>(); try { Files.List request = service.files().list().setQ("mimeType = '" + MIME_FOLDER + "'"); FileList files = request.execute(); fileList = files.getItems(); } catch(UserRecoverableAuthIOException e) { startActivityForResult(e.getIntent(), REQUEST_AUTHORIZATION); } catch (IOException e1) { e1.printStackTrace(); } return fileList; }} |
Как мы видим, мы просто пытаемся извлечь пользовательскую папку (строка 7-10) и перехватываем UserRecoverableAuthIOException (строка 13), чтобы получить информацию о необходимости авторизации. Если нам нужно авторизоваться, мы начинаем новую операцию (строка 14), запрашивая у пользователя запрос авторизации.
Теперь мы должны обработать результат запроса авторизации, поэтому мы реализуем onActivityResult в нашей основной деятельности следующим образом:
|
01
02
03
04
05
06
07
08
09
10
11
12
|
@Overrideprotected void onActivityResult(int requestCode, int resultCode, Intent data) { switch (requestCode) { case REQUEST_AUTHORIZATION: System.out.println("Auth request"); if (resultCode == Activity.RESULT_OK) { AsyncAuth auth = new AsyncAuth(); auth.execute(""); } }} |
В строке 6, если у нас есть положительный результат (RESULT_OK), мы снова запускаем асинхронный процесс для получения пользовательских папок.
Украсить код
К настоящему времени мы еще не использовали FrameLayout, поэтому пришло время его использовать. Как мы уже говорили в начале, этот кадр используется для отображения некоторого контента в пользовательском интерфейсе. Мы можем динамически изменять этот контент, используя фрагменты. Мы хотим показать информацию «ожидания», пока мы обращаемся к учетной записи диска пользователя, а затем к папке, которая была извлечена. Для этого нам понадобятся два простых фрагмента:
- WaitFragment, который показывает символ ожидания при доступе к диску
- ListFragment, который показывает список папок
Я не буду вдаваться в подробности, потому что они очень просто, я хочу подчеркнуть, как изменить содержимое в FrameLayout. Если мы вернемся к нашему AsyncAuth, то заметим, что он реализован только методом doBackgroud. У нас есть два других метода для использования таким образом:
|
1
2
3
4
5
6
7
8
9
|
@Overrideprotected void onPreExecute() { WaitFragment wf = new WaitFragment(); FragmentManager manager = MainActivity.this.getFragmentManager(); FragmentTransaction trans = manager.beginTransaction(); trans.replace(R.id.content_frame, wf); trans.commit();} |
Этот фрагмент показан в начале, информируя пользователя о необходимости ожидания, а второй:
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
|
@Overrideprotected void onPostExecute(List<File> result) { FragmentManager manager = MainActivity.this.getFragmentManager(); FragmentTransaction trans = manager.beginTransaction(); ListFragment lf = new ListFragment(); List<String> itemList = new ArrayList<String>(); for (File f : result) { itemList.add(f.getTitle()); } lf.setItemList(itemList); trans.replace(R.id.content_frame, lf); trans.commit();} |
В строке мы просто заполняем адаптер просмотра списка именами папок.
Исходный код скоро будет доступен.


