В этом посте описывается, как создать навигационный ящик со средством выбора учетной записи . Панель навигации — это новый шаблон пользовательского интерфейса, представленный в последнем вводе / выводе. Для этого я буду использовать новый 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
|
@Override public 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
|
@Override protected 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
|
@Override protected 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
|
@Override protected 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(); } |
В строке мы просто заполняем адаптер просмотра списка именами папок.
Исходный код скоро будет доступен.