Северный (Арктический) федеральный университет им. М.В. Ломоносова
Опубликован: 10.04.2014 | Доступ: свободный | Студентов: 6837 / 1233 | Длительность: 14:18:00
Специальности: Программист
Самостоятельная работа 7:

Многооконное приложение

12.6 Настройка интерфейса и реализация логики главной активности приложения

Настроим интерфейс главной активности приложения. Эта активность содержит три кнопки (Image Button):

bCamera - для вызова активности, предоставляющей возможности работы с камерой;
bGallery - для вызова активности, предоставляющей возможности просмотра изображений;
bMusic - для вызова активности, предоставляющей возможности воспроизведения аудио и видео.

Предлагаем настроить интерфейс самостоятельно. В нашем случае активность выглядит так, как показано на рис. 12.4. Но это, разумеется, не единственно возможный вариант.

Интерфейс главной активности приложения

увеличить изображение
Рис. 12.4. Интерфейс главной активности приложения

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

  • Создадим переменную btnClick, как реализацию интерфейса-слушателя OnClickListener:
    OnClickListener btnClick=new OnClickListener() {
        @Override
        public void onClick(View v) {
            Click(v.getId());
        }
    };
          
  • Добавим слушателя события нажатия к каждой кнопке активности:
    ((ImageButton)findViewById(R.id.bMusic)).setOnClickListener(btnClick);
    ((ImageButton)findViewById(R.id.bCamera)).setOnClickListener(btnClick);
    ((ImageButton)findViewById(R.id.bGallery)).setOnClickListener(btnClick);
          
  • В методе onClick() слушателя вызываем метод Click(), в котором выполняется запуск соответствующей активности:
    protected void Click(int view){
        Intent intent=null;
        switch (view){
            case R.id.bMusic: intent=new Intent(this,mediaPlayer.class); break;
            case R.id.bGallery: intent=new Intent(this,GalleryActivity.class); break;
            case R.id.bCamera: intent=new Intent(this,CameraActivity.class); break;
            default: break;
        }
        if(intent!=null){
            startActivity(intent);
        }
    }
          

В листинге 12.4 представлен код главной активности.

package com.example.lab5_4_media;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import android.hardware.Camera;
import android.hardware.Camera.Size;
import android.os.Bundle;
import android.app.Activity;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.view.ViewGroup.LayoutParams;

public class CameraActivity extends Activity {
  
  private Camera camera;
  private SurfaceHolder surfaceHolder;
  private SurfaceView preview;
  private View shotBtn;

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

    // если хотим, чтобы приложение постоянно имело портретную ориентацию
    setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);

    // если хотим, чтобы приложение было полноэкранным
    getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);

    // и без заголовка
    requestWindowFeature(Window.FEATURE_NO_TITLE);

    setContentView(R.layout.activity_camera);
        
    preview = (SurfaceView) findViewById(R.id.surfaceCamera);
    surfaceHolder = preview.getHolder();
    surfaceHolder.addCallback(new MyCallback(this));
    surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
        
    shotBtn = findViewById(R.id.bCameraShot);
    shotBtn.setOnClickListener(new MyViewListener());
  }
    
  @Override
  protected void onResume() {
    super.onResume();
    camera = Camera.open();
  }
    
  @Override
  protected void onPause(){
    super.onPause();
    if (camera != null){
      camera.setPreviewCallback(null);
      camera.stopPreview();
      camera.release();
      camera = null;
    }
  }
    
  class MyCallback implements SurfaceHolder.Callback{
      
    Activity host;
      
    MyCallback(Activity act){
      host=act;
    }
      
    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, 
    int height){}
    @Override
    public void surfaceCreated(SurfaceHolder holder){
      try {
        camera.setPreviewDisplay(holder);
        camera.setPreviewCallback(new MyPreviewCallback());
      }
      catch (IOException e){
        Log.d("myLogs","Ошибка камеры");
        e.printStackTrace();
      }
      Size previewSize = camera.getParameters().getPreviewSize();
      float aspect = (float) previewSize.width / previewSize.height;

      int previewSurfaceWidth = preview.getWidth();
      int previewSurfaceHeight = preview.getHeight();

      LayoutParams lp = preview.getLayoutParams();

      // здесь корректируем размер отображаемого preview, чтобы не было искажений

      if (host.getResources().getConfiguration().orientation != 
              Configuration.ORIENTATION_LANDSCAPE){
        // портретный вид
        camera.setDisplayOrientation(90);
        lp.height = previewSurfaceHeight;
        lp.width = (int) (previewSurfaceHeight / aspect);
      }
      else {
        // ландшафтный
        camera.setDisplayOrientation(0);
        lp.width = previewSurfaceWidth;
        lp.height = (int) (previewSurfaceWidth / aspect);
      }
      preview.setLayoutParams(lp);
      camera.startPreview();
    }
      
    @Override
    public void surfaceDestroyed(SurfaceHolder holder){}     
  }
    
  class MyViewListener implements View.OnClickListener{
    
    @Override
    public void onClick(View v) {
      if (v == shotBtn) {        
        // либо делаем снимок непосредственно здесь
        // либо включаем обработчик автофокуса

        //camera.takePicture(null, null, null, this);
        camera.autoFocus(new MyAutoFocusCallback());
      }
    }
  }
    
  class MyAutoFocusCallback implements Camera.AutoFocusCallback{

    @Override
    public void onAutoFocus(boolean paramBoolean, Camera paramCamera){
      if (paramBoolean){
        // если удалось сфокусироваться, делаем снимок
        paramCamera.takePicture(null, null, null, new MyPictureCallback());
      }
    }
  }
    
  class MyPictureCallback implements Camera.PictureCallback{

    @Override
    public void onPictureTaken(byte[] paramArrayOfByte, Camera paramCamera){
      // сохраняем полученные jpg в папке /sdcard/CameraExample/
      // имя файла - System.currentTimeMillis()
      try {
        File saveDir = new File("/sdcard/CameraExample/");
        if (!saveDir.exists()) {
          saveDir.mkdirs();
        }

        FileOutputStream os = new FileOutputStream(String.format("/sdcard/CameraExample/%d.jpg", System.currentTimeMillis()));
        os.write(paramArrayOfByte);
        os.close();
      }
      catch (Exception e) {}

      // после того, как снимок сделан, показ превью отключается. 
      // Необходимо включить его
      paramCamera.startPreview();
    }
  }
    
  class MyPreviewCallback implements Camera.PreviewCallback{
      
    @Override
    public void onPreviewFrame(byte[] paramArrayOfByte, Camera paramCamera) {
      // здесь можно обрабатывать изображение, показываемое в preview
    }
  }
}
    
Листинг 12.1. Класс CameraActivity для работы с камерой
Марат Нуриджанян
Марат Нуриджанян

Пример: Скачать среду можно с сайта для разработчиков Android (http://developer.android.com/sdk/index.html).

Там скачать можно только Android Studio

Владимир Каункин
Владимир Каункин

В самостоятельной работе 2 в примере решения задания некорректно загадывается число (в двух местах), выбирая случайное целое число из диапазона [0, 99] вместо [1, 100], как того требует условие. Кроме того, загадывание числа всё таки лучше вынести в отдельный метод, как мне кажется.