DRAFT [2019-2020][ua] at 2023-01-05 17:17:43 +0200
Logo-do [errata] Profile

Програмування для мобільних пристроїв

Робота з мережею і мультимедіа. Сервіси

Конспект лекції


Робота з мережею і мультимедіа. Сервіси

 

Робота з мережею. WebView WebView

WebView представляє найпростіший елемент для рендеринга html-коду, який базується на движку WebKit. Завдяки цьому ми можемо використовувати

WebView як примітивний веб-браузер, переглядаючи через нього контент з мережі інтернет. Використання движка WebKit гарантує, що відображення

контенту буде відбуватися приблизно такжe, як і в інших браузерах, побудованих на цьому движку - Google Chrome і Safari.

Працювати з WebView дуже просто. Визначимо даний елемент в розмітці layout:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">

<WebView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/webBrowser" />

</LinearLayout>

Для отримання доступу до інтернету з програми, необхідно вказати в файлі маніфесту AndroidManifest.xml відповідний дозвіл:

<uses-permission android:name="android.permission.INTERNET"/>

Щоб завантажити певну сторінку в WebView, через метод loadUrl () треба встановити її адресу:

//....................

import android.webkit.WebView;

public class MainActivity extends ActionBarActivity {
  @Override

  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    WebView browser = (WebView) findViewById(R.id.webBrowser);
    browser.loadUrl("http://google.com");

  }

}

Замість визначення елемента в layout ми можемо створити WebView в коді Activity:

WebView browser = new WebView(this); setContentView(browser); browser.loadUrl("http://google.com");

Крім завантаження конкретної сторінки з інтернету за допомогою метод loadData ():

WebView browser=(WebView)findViewById(R.id.webBrowser); 
browser.loadData("<html><body>Hello, world!</body></html>", "text/html", "UTF-8");

Першим параметром метод приймає рядок коду html, у другому - тип вмісту, а в третьому - кодування.

За замовчуванням в WebView відключений javascript, щоб його включити треба застосувати метод setJavaScriptEnabled (true):

WebView browser=(WebView)findViewById(R.id.webBrowser);
browser.getSettings().setJavaScriptEnabled(true);

 

WebViewFragment

WebViewFragment представляє спеціальний тип фрагмента, призначений для роботи з елементом WebView. Він також успадковується від базового

класу Fragment, додаючи деяку додаткову функціональність. Фактично це звичайний WebView, обгорнутий у фрагмент. Розглянемо його роботу на

прикладі.

Створимо новий проект і визначимо у MainActivity наступний код:

package com.example.viewsapplication;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;

import android.view.LayoutInflater;
import android.view.View;

import android.view.ViewGroup;

import android.webkit.WebViewFragment;

public class MainActivity extends AppCompatActivity {
  @Override

  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    if (savedInstanceState == null) {
      getFragmentManager().beginTransaction()

        .add(R.id.container, новий CustomWebViewFragment())

        .commit();

    }

  }

  public static class CustomWebViewFragment extends WebViewFragment {

    @Override

    public void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setRetainInstance(true);

    }

    @Override

    Public View onCreateView(LayoutInflater inflater, ViewGroup container,

      Bundle savedInstanceState) {

      View result = super.onCreateView(inflater, container, savedInstanceState);
      getWebView().getSettings().setJavaScriptEnabled(true);

      // Налаштування масштабування 
      getWebView().getSettings().setSupportZoom(true); 
      getWebView().getSettings().setBuiltInZoomControls(true); 
      getWebView().loadUrl("http://stackoverflow.com"); 
      return(result);

    }

    @Override

    public void onDestroyView() {
      super.onDestroyView();

    }

  }

}

А в розмітці activity_main.xml визначимо елемент, в який буде додаватися фрагмент:

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent" />

Реалізація фрагмента WebViewFragment схожа на реалізацію будь-якого іншого фрагмента за тим винятком, що в методі onCreateView () відбувається

налаштування елемента WebView. Для отримання вбудованого в фрагмент WebView використовується метод getWebView (). І також до стандартних

методів життєвого циклу додається метод onDestroyView (), який робить недоступним подальше використання WebView і готує його до останнього

кроку - знищення в методі onDestroy ()

Перш ніж запустити додаток, також встановимо в файл маніфесту AndroidManifest.xml дозвіл на роботу з інтернетом:

<Uses-permission android: name = "android.permission.INTERNET" />

Запустимо додаток, і ми перейшли на сайт, який ми вказали для WebView:

 

 

Завантаження даних і клас HttpURLConnection

На сьогоднішній день якщо не всі, то більшість Android-пристроїв мають доступ до мережі інтернет. А велика кількість мобільних додатків так чи інакше

взаємодіють з середовищем інтернет: завантажують файли, авторизуються і отримують інформацію з зовнішніх веб-сервісів і т.д. Розглянемо, як ми

можемо використовувати в своєму додатку доступ до мережі інтернет.

Серед стандартних елементів нам доступний віджет WebView, який може завантажувати контент з певної url-адреси. Але цим можливості роботи з

мережею в Android не обмежуються. Для отримання даних з певного інтернет-ресурсу ми можемо використовувати клас HttpUrlConnection зі

стандартної бібліотеки Java. (Для роботи з протоколом https можна використовувати його двійник - клас HttpsUrlConnection)

Отже, створимо новий проект.

Насамперед для роботи з мережею нам треба встановити в файлі маніфесту AndroidManifest.xml відповідний дозвіл:

<Uses-permission android: name = "android.permission.INTERNET" />

Оскільки завантаження даних може зайняти деякий час, то для звернення до інтернету визначимо асинхронну операцію, а для організації візуального

інтерфейсу будемо використовувати фрагменти. Тому додамо в проект новий фрагмент ProgressFragment:

У файлі fragment_progress.xml, який представляє розмітку фрагмента, визначимо наступний код:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">

<Button
android:id="@+id/downloadBtn"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Завантаження" />

<WebView
android:layout_weight="1"
android:id="@+id/webView"
android:layout_width="match_parent"
android:layout_height="0dp" />

<ScrollView
android:layout_weight="1"
android:layout_width="match_parent"
android:layout_height="0dp">

<TextView
android:id="@+id/content"
android:layout_width="match_parent"
android:layout_height="match_parent" />

</ScrollView>

</LinearLayout>

Тут визначена кнопка для завантаження даних, а самі дані завантажуються у вигляді рядка в полі введення тексту в елемент WebView. Так як даних

може бути дуже багато, то текстове поле поміщено в елемент ScrollView.

У класі фрагмента ProgressFragment визначимо завантаження даних за певною адресою:

package com.example.httpapp;

import android.os.Bundle;
import android.app.Fragment;

import android.view.LayoutInflater;
import android.view.View;

import android.view.ViewGroup;
import android.os.AsyncTask;
import android.webkit.WebView;
import android.widget.Button;
import android.widget.Toast;
import android.widget.TextView;

import java.io.BufferedReader;

import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;

import javax.net.ssl.HttpsURLConnection;

public class ProgressFragment extends Fragment {
  TextView contentView;

  String contentText = null;
  WebView WebView;
  @Override

  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setRetainInstance(true);

  }

  @Override

  Public View onCreateView(LayoutInflater inflater, ViewGroup container,

    Bundle savedInstanceState) {

    View view = inflater.inflate(R.layout.fragment_progress, container, false);
    contentView = (TextView) view.findViewById(R.id.content);

    webView = (WebView) view.findViewById(R.id.webView);

    // якщо дані були завантажені раніше 
    if (contentText != null) {

      contentView.setText(contentText);

      webView.loadData(contentText, "text/html; charset=utf-8", "utf-8");

    }

    Button btnFetch = (Button) view.findViewById(R.id.downloadBtn);
    btnFetch.setOnClickListener(new View.OnClickListener() {

      @Override

      public void onClick(View v) {

        if (contentText == null) {

          contentView.setText("Завантаження...");

          new ProgressTask().execute("https://developer.android.com/index.html");

        }

      }

    });

    return view;

  }

  private class ProgressTask extends AsyncTask < String, Void, String > {
    @Override

    protected String doInBackground(String...path) {

      String content;
      try {

        content = getContent(path[0]);

      } catch (IOException ex) {
        content = ex.getMessage();

      }

      return content;

    }

    @Override

    protected void onPostExecute(String content) {

      contentText = content;
      contentView.setText(content);

      webView.loadData(content, "text/html; charset=utf-8", "utf-8");

      Toast.makeText(getActivity(), "Дані завантажені", Toast.LENGTH_SHORT)

        .show();

    }

    private String getContent(String path) throws IOException {
      BufferedReader reader = null;

      try {

        URL url = new URL(path);

        HttpsURLConnection c = (HttpsURLConnection) url.openConnection();
        c.setRequestMethod("GET");

        c.setReadTimeout(10000);
        c.connect();

        reader = New BufferedReader(New InputStreamReader(c.getInputStream()));
        StringBuilder buf = new StringBuilder();

        String line = null;

        while ((line = reader.readLine()) != null) {
          buf.append(line + "\n");

        }

        return (buf.toString());

      } finally {

        if (reader != null) {
          reader.close();

        }

      }

    }

  }

}

Як вкладений клас створюється клас ProgressTask, успадкований від AsyncTask. У методі doInBackground () він завантажує дані з певної адреси. Для

самого завантаження визначено метод getContent ().

Спочатку створюється елемент HttpsURLConnection:

HttpsURLConnection c = (HttpsURLConnection) url.openConnection ();
c.setRequestMethod ( "GET"); // установка методу отримання даних -GET
c.setReadTimeout (10000); // установка таймаута перед виконанням - 10 000 мілісекунд
c.connect (); // підключаємося до ресурсу

Після підключення відбувається зчитування з вхідного потоку:

reader = new BufferedReader (new InputStreamReader (c.getInputStream ()));

Використовуючи вхідний потік, ми можемо його зберегти в файл або вивести на екран або обробити його якимось іншим чином.

Зв'яжемо фрагмент в MainActivity. Для цього в файлі activity_main.xml додамо фрагмент:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="16dp">

<fragment android:id="@+id/contentFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:name="com.example.httpapp.ProgressFragment" />

</RelativeLayout>

Код MainActivity залишається стандартним:

package com.example.httpapp;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;

public class MainActivity extends AppCompatActivity {

  @Override

  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

  }

}

Запустимо програму і звернемося за адресою android.developer.com:

 

Звичайно, даний спосіб навряд чи підходить для перегляду інтернет-сторінок, однак таким чином, ми можемо отримувати будь-які дані (не Інтернет-

сторінки) від різних веб-сервісів, наприклад, в форматі xml або json (наприклад, різні курси валют, показники погоди), використовуючи спеціальні api, і

потім після обробки показувати їх користувачеві.

 

Робота з мультимедіа Робота з зображеннями Ресурси зображень

Одним з найбільш поширених джерел ресурсів є файли зображень. Android підтримує такі формати файлів: .png (кращий), .jpg (прийнятний), .gif

(небажаний). Для графічних файлів в проекті вже за замовчуванням створена папка res / drawable. При додаванні графічних файлів в цю папку для

кожного з них Android створює ресурс Drawable. Після цього ми можемо звернутися до ресурсу в такий спосіб в коді Java:

R.drawable.ім'я_файла

Або в коді xml:

@ [Им'я_Пакета:] drawable / им'я_файла

Отже, для роботи з зображеннями створимо новий проект. Нехай він називається ImagesApp. Як шаблон activity виберемо Empty Activity.

Після створення проекту скопіюємо в проект в папку res / drawable який-небудь файл зображення. Тут відразу варто враховувати, що файл зображення

буде додаватися в додаток, тим самим збільшуючи його розмір. Крім того, великі зображення негативно впливають на продуктивність. Тому слід

використовувати невеликі і оптимізовані (стислі) графічні файли.

При копіюванні файлу нам буде запропоновано встановити для нього нове ім'я.

Можна змінити назву файлу, а можна залишити так як є.

 

Для роботи із зображеннями в Android можна використовувати різні елементи, але безпосередньо для виведення зображень призначений ImageView.

Тому змінимо файл activity_main.xml наступним чином:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent">

<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/dubi2" />

</RelativeLayout>

В даному випадку для відображення файлу в ImageView у елемента встановлюється атрибут android: src. У його значенні вказується ім'я графічного

ресурсу, яке збігається з ім'ям файлу без розширення. І після цього вже в Preview або в режимі дизайнера в Android Studio можна буде побачити

зображення, або при запуску програми:

Якби ми створювали ImageView в коді java і з коду застосовували б ресурс, то activity могла б виглядати так:

package com.example.imagesapp;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;

import android.widget.ImageView;

public class MainActivity extends AppCompatActivity {
  @Override

  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    ImageView imageView = новий ImageView(this);

    // застосовуємо ресурс 
    imageView.setImageResource(R.drawable.dubi2);

    //setContentView(R.layout.activity_main); 
    setContentView(imageView);

  }

}

 

ImageView

У минулій темі було розглянуто, як виводити зображення за допомогою елемента ImageView.

Тепер розглянемо деякі додаткові моменти по роботі з цим елементом.

Серед його функціоналу слід зазначити можливість збільшувати або зменшувати зображення, яке задається за допомогою перерахування. Це

перерахування визначає наступні значення:

CENTER: зображення центрується по центру без масштабування

CENTER_CROP: зображення центрується по центру і масштабується зі збереженням аспектного відношення між шириною і висотою. Якщо якась

частина не поміщається в межі екрану, то вона обрізається

CENTER_INSIDE: зображення центрується по центру і масштабується зі збереженням аспектного відношення між шириною і висотою, але ширина і

висота не можуть бути більше ширини і висоти ImageView

FIT_CENTER: зображення масштабується і центрується

FIT_START: зображення масштабується і встановлюється в початок елемента (вверх при портретній орінетаціі і вліво - при альбомній)

FIT_END: зображення масштабується і встановлюється в кінець елемента (вниз при портретній орінетаціі і вправо - при альбомній)

FIT_XY: зображення масштабується без збереження аспектного відношення між шириною і висотою, заповнюючи весь простір ImageView

MATRIX: зображення масштабується з застосуванням матриці зображення

Для встановлення значень для цього поля у файлі activity_main.xml можна використовувати атрибут android: scaleType.

Наприклад, установка FIT_XY:

<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/dubi2"
android:scaleType="fitXY"/>

В результаті зображення розтягнеться по вертикалі і горизонталі:

Для створення аналогічного прикладу в коді java необхідно використовувати метод setScaleType ():

ImageView imageView = new ImageView(this);
imageView.setImageResource(R.drawable.dubi2);
imageView.setScaleType(ImageView.ScaleType.FIT_XY);

Аналогічний приклад з android: scaleType = "center":

 

 

Зображення з папки assets

У минулих темах зображення в проекті містилися в папці res / drawables в якості ресурсів і виводилися в елемент ImageView. Однак зображення

необов'язково в принципі поміщати саме в цю папку. Файли також можуть розташовуватися в папці assets. Розглянемо, як працювати з такими файлами

зображень.

Спочатку додамо в проект папку assets. Для цього перейдемо в Android Studio до повного визначення проекту та додамо в папку main нову папку, яку

назвемо assets:

Додамо в цю папку яке-небудь зображення:

 

Нехай у файлі activity_main.xml буде визначено елемент ImageView:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">

<ImageView
android:id="@+id/image"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="16dp"/>

</RelativeLayout>

Завантажимо зображення з папки assets в елемент ImageView в MainActivity:

package com.example.imagesapp;

import android.graphics.drawable.Drawable;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;

import android.widget.ImageView;

import java.io.IOException;
import java.io.InputStream;

public class MainActivity extends AppCompatActivity {
  @Override

  protected void onCreate(Bundle savedInstanceState) {

    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    ImageView imageView = (ImageView) findViewById(R.id.image);
    String filename = "dubi.png";

    InputStream inputStream = null;
    try {

      inputStream = getApplicationContext().getAssets().open(filename);
      Drawable d = Drawable.createFromStream(inputStream, null);
      imageView.setImageDrawable(d);
      imageView.setScaleType(ImageView.ScaleType.FIT_XY);

    } catch (IOException e) {
      e.printStackTrace();

    } finally {

      try {

        if (inputStream != null) inputStream.close();

      } catch (IOException ex) {
        ex.printStackTrace();

      }

    }

  }

}

Для завантаження файлу необхідно отримати потік InputStream за допомогою виразу getApplicationContext (). GetAssets (). Open (filename).

Виклик Drawable.createFromStream (inputStream, null) формує об'єкт Drawable з вхідного потоку. Метод imageView.setImageDrawable (d) завантажує

Drawable в ImageView.

  

 

Робота з відео

Для роботи з відеоматеріалами в стандартному наборі віджетів Android визначено клас VideoView, який дозволяє відтворювати відео.

Які формати відео можна використовувати? Android підтримує всі ті ж формати відео, що і HTML 5, зокрема, формат MPEG-4 H.264 (ще відомий як

WebM), який є оптимальним для Android. Але також можна використовувати поширені формати MPEG4 H.264 AVC (.mp4) і MPEG4 SP (.3gp)

VideoView може працювати як з роликами, розміщеними на мобільному пристрої, так і з відеоматеріалами з мережі. В даному випадку використовуємо

відеоролик, розміщений локально. Для цього додамо в проект будь-який відеоролик. Зазвичай відеоматеріали поміщають в проекті в папку res / raw. За

замовчуванням проект не містить подібної папки, тому додамо в каталог res підпапку raw. Для цього натиснемо на папку res правою кнопкою миші і в

меню виберемо New -> Directory: 

У відкритому після цього вікні введемо raw в якості назви для папки:

 

Після додавання папки raw скопіюємо в неї який-небудь відеофайл:

 

Тепер визначимо функціонал для його відтворення. Для цього в файлі activity_main.xml вкажемо наступний код:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">

<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">

<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Play" 
android:onClick="play"/>

<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Pause" 
android:onClick="pause"/>

<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Stop" 
android:onClick="stop"/>

</LinearLayout>

<VideoView 
android:id="@+id/videoPlayer"
android:layout_gravity="center"
android:layout_height="match_parent"
android:layout_width="match_parent"/>

</LinearLayout>

Для керування відтворенням відео тут визначені три кнопки: для запуску відео, для паузи і для його зупинки.

І також змінимо код MainActivity:

package com.example.mediaapp;

import android.net.Uri;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;

import android.view.View;
import android.widget.VideoView;

public class MainActivity extends AppCompatActivity {
  VideoView videoPlayer;

  @Override

  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    setContentView(R.layout.activity_main);

    videoPlayer = (VideoView) findViewById(R.id.videoPlayer);

    Uri myVideoUri = Uri.parse("android.resource://" + getPackageName() + "/" + R.raw.gu);
    videoPlayer.setVideoURI(myVideoUri);

  }

  public void play(View view) {
    videoPlayer.start();

  }

  public void pause(View view) {
    videoPlayer.pause();

  }

  public void stop(View view) {
    videoPlayer.stopPlayback();
    videoPlayer.resume();

  }

}

По-перше, щоб управляти потоком відтворення, нам треба отримати об'єкт VideoView:

videoPlayer = (VideoView) findViewById (R.id.videoPlayer);

Щоб вказати джерело відтворення, необхідний об'єкт Uri. В даному випадку за допомогою виразу Uri myVideoUri = Uri.parse ( "android.resource: //" +

getPackageName () + "/" + R.raw.gu); отримуємо адресу відеоролика всередині пакету додатку.

Рядок URI має ряд частин: спочатку йде Uri-схема (http: // або android.resource: //), потім назва пакета, що отримується через метод getPackageName (), і

далі безпосередньо назва ресурсу відео з папки res / raw, яке збігається з назвою файлу.

Потім цей Uri встановлюється у videoPlayer:

videoPlayer.setVideoURI (myVideoUri);

Щоб керувати відеопотоком, обробники натискання кнопки викликають відповідну дію:

public void play(View view) {
  videoPlayer.start();

}

public void pause(View view) {
  videoPlayer.pause();

}

public void stop(View view) {
  videoPlayer.stopPlayback();
  videoPlayer.resume();

}

Метод videoPlayer.pause () призупиняє відео.

Метод videoPlayer.stopPlayback () повністю зупиняє відео.

Метод videoPlayer.resume () дозволяє знову почати відтворення відео від початку до його повної зупинки.

При запуску програми ми зможемо за допомогою кнопок управляти відтворенням:

 

MediaController

За допомогою класу MediaController ми можемо додати до VideoView додатково елементи управління. Для цього змінимо код MainActivity:

package com.example.mediaapp;

import android.net.Uri;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;

import android.view.View;

import android.widget.MediaController;
import android.widget.VideoView;

public class MainActivity extends AppCompatActivity {
  VideoView videoPlayer;

  @Override

  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    videoPlayer = (VideoView) findViewById(R.id.videoPlayer);

    Uri myVideoUri = Uri.parse("android.resource://" + getPackageName() + "/" + R.raw.gu);
    videoPlayer.setVideoURI(myVideoUri);

    MediaController MediaController = новий MediaController(this);
    videoPlayer.setMediaController(mediaController);
    mediaController.setMediaPlayer(videoPlayer);

  }

  public void play(View view) {
    videoPlayer.start();

  }

  public void pause(View view) {
    videoPlayer.pause();

  }

  public void stop(View view) {
    videoPlayer.stopPlayback();
    videoPlayer.resume();

  }

}

І якщо ми запустимо додаток, то при торканні по VideoView внизу з'являться інструменти для управління відео.

 

Відтворення файлу з інтернету

VideoView підтримує відтворення файлу з інтернету. Але щоб це стало можливо, необхідно в файлі AndroidManifest.xml встановити дозвіл

android.permission.INTERNET, так як ми отримуємо дані з інтернету:

<Uses-permission android: name = "android.permission.INTERNET" />

Файл маніфесту повністю:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.mediaapp">

<uses-permission android:name="android.permission.INTERNET" />

<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true" 
android:theme="@style/AppTheme">

<activity 
android:name=".MainActivity">

<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>

</activity>
</application>

</manifest>

Далі змінимо клас MainActivity:

package com.example.mediaapp;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;

import android.view.View;
import android.widget.VideoView;

public class MainActivity extends AppCompatActivity {
  VideoView videoPlayer;

  @Override

  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    videoPlayer = (VideoView) findViewById(R.id.videoPlayer);
    videoPlayer.setVideoPath("http://video.ch9.ms/ch9/507d/71f4ef0f-3b81-4d2c-956f-c56c81f9507d/AndroidEmulatorWithMacEmulator.mp4 ");

    }

    public void play(View view) {
      videoPlayer.start();

    }

    public void pause(View view) {
      videoPlayer.pause();

    }

    public void stop(View view) {
      videoPlayer.stopPlayback();
      videoPlayer.resume();

    }

  }

Тут нам треба в метод videoPlayer.setVideoPath () передати інтернет-адресу відтвореного файлу.

 

Відтворення аудіо

Для відтворення музики та інших аудіоматеріалів Android надає клас MediaPlayer.

Щоб відтворювати аудіо, MediaPlayer повинен знати, який саме ресурс (файл) потрібно відтворити. Встановити потрібний ресурс для відтворення можна

трьома способами:

Для управління відтворенням в класі MediaPlayer визначені наступні методи:

Отже, створимо новий проект. Як і у випадку з відео, аудіофайл повинен знаходитися в папці res / raw, тому додамо в проект в Android Studio таку папку і

скопіюємо в неї який-небудь аудіофайл.

Для управління аудіопотоками визначимо в файлі activity_main.xml три кнопки:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:padding="16dp">

<Button
android:id="@+id/start"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Play" 
android:onClick="play"/>

<Button
android:id="@+id/pause"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Pause"
android:onClick="pause"/>

<Button
android:id="@+id/stop"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Stop"
android:onClick="stop"/>

</LinearLayout>

І змінимо код класу MainActivity:

package com.example.mediaapp;

import android.media.MediaPlayer;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;

import android.view.View;
import android.widget.Button;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {
  MediaPlayer mPlayer;

  Button startButton, pauseButton, stopButton;

  @Override

  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    mPlayer = MediaPlayer.create(this, R.raw.music);
    mPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {

      @Override

      public void onCompletion(MediaPlayer mp) {
        stopPlay();

      }

    });

    startButton = (Button) findViewById(R.id.start);
    pauseButton = (Button) findViewById(R.id.pause);
    stopButton = (Button) findViewById(R.id.stop);

    pauseButton.setEnabled(false);
    stopButton.setEnabled(false);

  }

  private void stopPlay() {
    mPlayer.stop();
    pauseButton.setEnabled(false);
    stopButton.setEnabled(false);
    try {

      mPlayer.prepare();
      mPlayer.seekTo(0);
      startButton.setEnabled(true);

    } catch (Throwable t) {

      Toast.makeText(this, t.getMessage(), Toast.LENGTH_SHORT).show();

    }

  }

  public void play(View view) {

    mPlayer.start();
    startButton.setEnabled(false);
    pauseButton.setEnabled(true);
    stopButton.setEnabled(true);

  }

  public void pause(View view) {

    mPlayer.pause();
    startButton.setEnabled(true);
    pauseButton.setEnabled(false);
    stopButton.setEnabled(true);

  }

  public void stop(View view) {
    stopPlay();

  }

  @Override

  public void onDestroy() {
    super.onDestroy();

    if (mPlayer.isPlaying()) {
      stopPlay();

    }

  }

}

Оброблювач кожної кнопки крім виклику певного методу у MediaPlayer також перемикає доступність кнопок.

І якщо запуск і призупинення відтворення особливих труднощів не викликає, то при обробці повної зупинки відтворення ми можемо зіткнутися з низкою

труднощів. Зокрема, коли ми виходимо з програми - повністю закриваємо його через диспетчер додатків або натискаємо на кнопку Назад, то у нас для

поточній Activity викликається метод onDestroy, activity знищується, але MediaPlayer продовжує працювати. Якщо ми повернемося до додатка, то activity

буде створена заново, але за допомогою кнопок ми не зможемо управляти відтворенням. Тому в даному випадку перевизначаємо метод onDestroy, в

якому завершуємо відтворення.

Для коректного завершення також визначено обробник OnCompletionListener, дія якого буде аналогічно натисканню на кнопку "Стоп".

Додамо до відтворення індикатор гучності. Для цього в файлі activity_main.xml визначимо SeekBar:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="16dp">

<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">

<Button
android:id="@+id/start"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Play"
android:onClick="play"/>

<Button
android:id="@+id/pause"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Pause"
android:onClick="pause"/>

<Button
android:id="@+id/stop"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Stop"
android:onClick="stop"/>

</LinearLayout>

<SeekBar
android:id="@+id/volumeControl"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="32dp"/>

<SeekBar
android:id="@+id/progressControl"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="32dp"/>

</LinearLayout>

І далі змінимо MainActivity:

package com.example.mediaapp;

import android.content.Context;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.os.Handler;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;

import android.view.View;
import android.widget.Button;
import android.widget.SeekBar;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {
  MediaPlayer mPlayer;

  Button startButton, pauseButton, stopButton;

  SeekBar volumeControl;
  AudioManager audioManager;

  @Override

  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    mPlayer = MediaPlayer.create(this, R.raw.music);
    mPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {

      @Override

      public void onCompletion(MediaPlayer mp) {
        stopPlay();

      }

    });

    startButton = (Button) findViewById(R.id.start);
    pauseButton = (Button) findViewById(R.id.pause);
    stopButton = (Button) findViewById(R.id.stop);

    audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);

    int maxVolume = audioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
    int curValue = audioManager.getStreamVolume(AudioManager.STREAM_MUSIC);

    volumeControl = (SeekBar) findViewById(R.id.volumeControl);
    volumeControl.setMax(maxVolume);
    volumeControl.setProgress(curValue);

    volumeControl.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
      @Override

      public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
        audioManager.setStreamVolume(AudioManager.STREAM_MUSIC, progress, 0);

      }

      @Override

      public void onStartTrackingTouch(SeekBar seekBar) {

      }

      @Override

      public void onStopTrackingTouch(SeekBar seekBar) {

      }

    });

    pauseButton.setEnabled(false);
    stopButton.setEnabled(false);

  }

  private void stopPlay() {
    mPlayer.stop();
    pauseButton.setEnabled(false);
    stopButton.setEnabled(false);
    try {

      mPlayer.prepare();
      mPlayer.seekTo(0);
      startButton.setEnabled(true);

    } catch (Throwable t) {

      Toast.makeText(this, t.getMessage(), Toast.LENGTH_SHORT).show();

    }

  }

  public void play(View view) {

    mPlayer.start();
    startButton.setEnabled(false);
    pauseButton.setEnabled(true);
    stopButton.setEnabled(true);

  }

  public void pause(View view) {

    mPlayer.pause();
    startButton.setEnabled(true);
    pauseButton.setEnabled(false);
    stopButton.setEnabled(true);

  }

  public void stop(View view) {
    stopPlay();

  }

  @Override

  public void onDestroy() {
    super.onDestroy();

    if (mPlayer.isPlaying()) {
      stopPlay();

    }

  }

}

Для управління гучністю звуку застосовується клас AudioManager. А за допомогою виклику audioManager.setStreamVolume

(AudioManager.STREAM_MUSIC, progress, 0); в якості другого параметра можна передати потрібне значення гучності.

 

Сервіси

Введення в сервіси Android

Сервіси являють собою особливу організацію додатку. На відміну від activity вони не вимагають наявності візуального інтерфейсу. Сервіси дозволяють

виконувати довготривалі завдання без втручання користувача.

Всі сервіси успадковуються від класу Service і проходять такі етапи життєвого циклу:

Створимо простий додаток з сервісом. Наш сервіс буде відтворювати музичний файл. І спочатку додамо в проект в каталог res папку raw і в неї

помістимо який-небудь mp3-файл. Потім додамо новий клас сервісу. Назвемо його MediaService:

package com.example.soundserviceapp;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.media.MediaPlayer;

public class MediaService extends Service {
  MediaPlayer ambientMediaPlayer;
  @Override

  public IBinder onBind(Intent intent) {

    throw new UnsupportedOperationException("Not yet implemented");

  }

  @Override

  public void onCreate() {
    ambientMediaPlayer = MediaPlayer.create(this, R.raw.zymotyx);
    ambientMediaPlayer.setLooping(true);

  }

  @Override

  public int onStartCommand(Intent intent, int flags, int startId) {
    ambientMediaPlayer.start();

    return START_STICKY;

  }

  @Override

  public void onDestroy() {
    ambientMediaPlayer.stop();

  }

}

Для відтворення музики сервіс буде використовувати компонент MediaPlayer.

У сервісі перевизначаються всі чотири методи життєвого циклу. Але по суті метод onBind () не має ніякої реалізації.

У методі onCreate () ініціалізується медіа-програвач за допомогою музичного ресурсу, який доданий в папку res / raw.

У методі onStartCommand () починається відтворення.

Метод onStartCommand () може повертати одне зі значень, яке передбачає різну поведінку в разі, якщо процес сервісу був несподівано завершено

системою:

Щоб керувати сервісом, змінимо activity. Спочатку додамо в layout пару кнопок для управління сервісом:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">

<Button
android:id="@+id/start"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Старт"
android:onClick="click"/>

<Button
android:id="@+id/stop"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Стоп"
android:onClick="click"/>

</LinearLayout>

І змінимо код activity:

package com.example.soundserviceapp;

import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;

import android.view.Menu;
import android.view.MenuItem;
import android.content.Intent;
import android.view.View;

public class MainActivity extends ActionBarActivity {

  @Override

  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

  }

  public void click(View v) {

    Intent i = new Intent(this, MediaService.class);
    if (v.getId() == R.id.start) {

      startService(i);

    } else {

      stopService(i);

    }

  }

}

Для запуску сервісу використовується об'єкт Intent:

Intent i = new Intent (this, MediaService.class);

Для запуску сервісу в класі Activity визначено метод startService (), в який передається об'єкт Intent. Цей метод буде посилати команду сервісу і

викликати його метод onStartCommand (), а також вказувати системі, що сервіс повинен продовжувати працювати до тих пір, поки не буде викликаний

метод stopService ().

Метод stopService () також визначено до класі Activity і приймає об'єкт Intent. Він зупиняє роботу сервісу, викликаючи його метод onDestroy ()

І в кінці нам треба зареєструвати сервіс в файлі маніфесту:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.soundserviceapp" >

<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >

<service
android:name=".MediaService"
android:enabled="true"
android:exported="true" >

</service>

<activity
android:name=".MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>

</manifest>

Реєстрація сервісу проводиться в вузлі application за допомогою додавання елемента

<service>. У ньому визначається атрибут android: name, який зберігає назву класу сервісу. І крім того може приймати ще ряд атрибутів:

Запустимо програму і натиснемо на кнопку запуску сервісу:

 

Після цього почнеться відтворення доданої нами в додаток мелодії.


© 2006—2023 СумДУ