Mostrando postagens com marcador Galeria. Mostrar todas as postagens
Mostrando postagens com marcador Galeria. Mostrar todas as postagens

terça-feira, 7 de junho de 2016

Carregando imagens da galeria do Android

Olá povo,

Nesse post rápido vou mostrar como carregar imagens da galeria de mídia do Android. O único detalhe a observar nesse post é que estamos carregando imagens tanto locais quando as que estão em algum serviço da nuvem como DropBox e Google Photos. Por isso, para começar coloque as permissões necessárias no AndroidManifest.xml.
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.INTERNET"/>
Lembrando que para o Android 6 (API Level 23) você deve checar essas permissões em tempo de execução.

Em seguida, inicie uma nova activity utilizando a ação ACTION_GET_CONTENT.
private static final int IMAGE_GALLERY_REQUEST = 1;
...
public void selectImageClick(View view) {
    if (ActivityCompat.checkSelfPermission(this, 
            Manifest.permission.READ_EXTERNAL_STORAGE) ==
            PackageManager.PERMISSION_GRANTED) {
        Intent intent = new Intent();
        intent.setType("image/*");
        intent.setAction(Intent.ACTION_GET_CONTENT);
        startActivityForResult(
                Intent.createChooser(
                        intent,
                        getString(R.string.select_picture_title)),
                IMAGE_GALLERY_REQUEST);
    } else {
        ActivityCompat.requestPermissions(this,
                new String[]{ Manifest.permission.READ_EXTERNAL_STORAGE },
                IMAGE_GALLERY_REQUEST);
    }
}
Ao selecionarmos uma imagem, o método onActivityResult será chamado.
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);

    if (requestCode == IMAGE_GALLERY_REQUEST && resultCode == RESULT_OK){
        new LoadImageTask(this).execute(data.getData());
    }
}

Como falamos anteriormente, carregaremos as imagens do sistema de arquivos ou da web. Por isso, devemos realizar essa operação fora da UI thread, então definimos a classe LoadImageTask.
class LoadImageTask extends AsyncTask<Uri, Void, Bitmap> {

    WeakReference<PickImageActivity> mActivity;

    public LoadImageTask(PickImageActivity activity) {
        this.mActivity = new WeakReference<>(activity);
    }

    public PickImageActivity getActivity() {
        return mActivity.get();
    }

    @Override
    protected Bitmap doInBackground(Uri... params) {
        if (getActivity() != null) {
            try {
                return BitmapFactory.decodeStream(
                        getActivity().getContentResolver().openInputStream(params[0]));
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            }
        }
        return null;
    }

    @Override
    protected void onPostExecute(Bitmap bitmap) {
        super.onPostExecute(bitmap);
        if (getActivity() != null){
            getActivity().showImage(bitmap);
        }
    }
}
Temos algumas coisas interessantes aqui. A primeira é essa classe não deve ser uma inner class da Activity/Fragment, pois uma inner class sempre contém uma referência para sua outer class. Uma vez que ela não é uma inner class, devemos passar a referência da activity/fragment para essa classe. Estamos utilizando uma WeakReference para armazenar a instância da activity, o motivo disso é evitar o leak de memória, já que se o usuário sair da tela antes da imagem ser baixada aquela memória ficará alocada desnecessariamente durante algum tempo.
Outra coisa interessante é que estamos utilizando o método openInputStream() da classe ContentResolver para obter a imagem propriamente dita.
A imagem retornada terá o seu tamanho original, se você preferir, pode utilizar a técnica de redimensionamento de imagem que eu mostrei nesse post.
Por fim, no onPostExecute, invocamos o método showImage da Activity.
public void showImage(Bitmap bitmap) {
    ImageView imageView = (ImageView)findViewById(R.id.imageView);
    if (imageView != null){
        imageView.setImageBitmap(bitmap);
    }
}
Qualquer dúvida, deixe seu comentário ;)

 4br4ç05,
nglauber

segunda-feira, 1 de outubro de 2012

Upload de arquivos no Android

Olá povo,

Esse post tava há um bom tempo como rascunho no blog e só agora consegui terminar para postar aqui. Vou mostrar como fazer uma aplicação Android que faz upload de arquivos para um servidor web.
public class UploadActivity extends Activity {

  private TextView txtArquivo;
 
  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_upload);

    txtArquivo = (TextView)
      findViewById(R.id.txtArquivo);
  }
 
  // Ao selecionar o arquivo, preenchemos o 
  // TextView com o caminho real do arquivo
  @Override
  protected void onActivityResult(int requestCode, 
    int resultCode, Intent data) {
    super.onActivityResult(requestCode, 
      resultCode, data);

    if (resultCode == RESULT_OK) {
      if (requestCode == 0) {
        Uri selectedImageUri = data.getData();
        txtArquivo.setText(getPath(selectedImageUri));
      }
    }  
  }

  // Botão que abre a galeria de mídia para 
  // selecionar um arquivo
  public void selecionarArquivo(View v){
    Intent intent = new Intent();
    intent.setType("image/*");
    intent.setAction(Intent.ACTION_GET_CONTENT);
    startActivityForResult(Intent.createChooser(
      intent,"Selecione uma imagem"), 0);
  }
 
  // Botão que envia o arquivo selecionado
  public void enviarArquivo(View v){
    try {
      new Thread(){
        public void run(){
          executeMultipartPost();
        }
      }.start();
    } catch (Exception e) {
      Log.e("NGVL", e.getMessage());
    }  
  }
 
  // Obtém o caminho real do arquivo 
  // através do ContentProvider
  public String getPath(Uri uri) {
    String[] projection = { 
      MediaStore.Images.Media.DATA };

    Cursor cursor = getContentResolver().query(
      uri, projection, null, null, null);

    int column_index = cursor.getColumnIndexOrThrow(
      MediaStore.Images.Media.DATA);

    cursor.moveToFirst();
    return cursor.getString(column_index);
  }
 
  // Método que realmente envia o arquivo
  public void executeMultipartPost() 
    throws Exception {

    String caminhoDoArquivoNoDispositivo = 
      txtArquivo.getText().toString();

    String urlDoServidor = 
      "http://url_servidor/pagina_que_trata_upload";
    String lineEnd = "\r\n";
    String twoHyphens = "--";
    String boundary = "*****"; // Delimitador

    byte[] buffer;
    int bytesRead, bytesAvailable, bufferSize;
    int maxBufferSize = 1 * 1024 * 1024; // 1MB

    try {
      // Criando conexão com o servidor
      URL url = new URL(urlDoServidor);
      HttpURLConnection connection = 
        (HttpURLConnection) url.openConnection();

      // Conexão vai ler e escrever dados
      connection.setDoInput(true);
      connection.setDoOutput(true);
      connection.setUseCaches(false);

      // Setando método POST
      connection.setRequestMethod("POST");

      // Adicionando cabeçalhos
      connection.setRequestProperty(
        "Connection", "Keep-Alive");
      connection.setRequestProperty(
        "Content-Type",
        "multipart/form-data;boundary=" + boundary);
      connection.connect();
   
      // Escrevendo payload da requisição
      DataOutputStream outputStream = 
        new DataOutputStream(
          connection.getOutputStream());
      outputStream.writeBytes(
        twoHyphens + boundary + lineEnd);
      outputStream.writeBytes(
        "Content-Disposition: form-data; "+
        "name=\"uploadedfile\";filename=\""+ 
        caminhoDoArquivoNoDispositivo + "\"" +
        lineEnd);
      outputStream.writeBytes(lineEnd);

      // Stream para ler o arquivo
      FileInputStream fileInputStream = 
        new FileInputStream(new File(
          caminhoDoArquivoNoDispositivo));
   
      // Preparando para escrever arquivo
      bytesAvailable = fileInputStream.available();
      bufferSize = Math.min(
        bytesAvailable, maxBufferSize);
      buffer = new byte[bufferSize];

      // Lendo arquivo e escrevendo na conexão
      bytesRead = fileInputStream.read(
        buffer, 0, bufferSize);

      while (bytesRead > 0) {
        outputStream.write(buffer, 0, bufferSize);
        bytesAvailable = fileInputStream.available();
        bufferSize = Math.min(
          bytesAvailable, maxBufferSize);
        bytesRead = fileInputStream.read(
          buffer, 0, bufferSize);
      }
      outputStream.writeBytes(lineEnd);
      outputStream.writeBytes(
        twoHyphens + boundary + 
        twoHyphens + lineEnd);

      // Obtendo o código e a mensagem
      // de resposta do servidor
      int serverResponseCode = 
        connection.getResponseCode();
      String serverResponseMessage = 
        connection.getResponseMessage();

      Log.d("NGVL", serverResponseCode +" = "+ 
        serverResponseMessage);
   
      fileInputStream.close();
      outputStream.flush();
      outputStream.close();
   
    } catch (Exception ex) {
      // Exception handling
    }
  }
}
O código acima está todo comentado, então vou mostrar o arquivo de layout da aplicação. O único detalhe que eu quero ressaltar, é que utilizei uma Thread apenas pra facilitar o código, mas deveríamos utilizar uma AsyncTask ou até um Service.
<LinearLayout 
  xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:tools="http://schemas.android.com/tools"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:orientation="vertical" >

  <TextView
    android:id="@+id/txtArquivo"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Arquivo a ser enviado" />

  <Button
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Selecionar arquivo" 
    android:onClick="selecionarArquivo"/>

  <Button
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Enviar" 
    android:onClick="enviarArquivo"/>

</LinearLayout>
A última coisa a fazer é adicionar a permissão de INTERNET no AndroidManifest.xml.
<uses-permission 
  android:name="android.permission.INTERNET"/>
A figura abaixo mostra a aplicação em execução:

Qualquer dúvida, deixem seus comentários.

4br4ç05,
nglauber

domingo, 21 de agosto de 2011

Galeria de mídia do Android

Olá povo,

Neste post vou mostrar como tirar uma foto com a aplicação de câmera, salvar a imagem em um diretório temporário e em seguida adiciona-la à galeria de mídia do aparelho. E por último, vou mostrar como carregar uma imagem da galeria.
Vamos iniciar mostrando como chamar a aplicação de câmera.
public void tirarFotoClick(View v) {
  String nomeFoto = DateFormat.format(
    "yyyy-MM-dd_hhmmss", new Date()).toString();

  caminhoFoto = new File(
    Environment.getExternalStoragePublicDirectory(
      Environment.DIRECTORY_PICTURES),
    nomeFoto);

  Intent it = new Intent(
    MediaStore.ACTION_IMAGE_CAPTURE);  
  it.putExtra(MediaStore.EXTRA_OUTPUT, 
    Uri.fromFile(caminhoFoto));
  startActivityForResult(it, 0);
}
A aplicação de câmera é chamada através da ação ACTION_IMAGE_CAPTURE passado no construtor da Intent. Um detalhe interessante aqui é o parâmetro EXTRA_OUTPUT, ele serve para indicar um caminho para a foto ser salva. Sem ele, a imagem será salva com tamanho e qualidade inferior a que a câmera realmente tirou.

caminhoFoto é um atributo do tipo File.
A chamada do método startActivityForResult indica que queremos tratar o resultado da activity que estamos chamando. Esse tratamento é feito no método onActivityResult.
protected void onActivityResult(
  int requestCode, int resultCode, Intent data) {
  super.onActivityResult(
    requestCode, resultCode, data);

  if (resultCode == RESULT_OK && requestCode == 0) {
    ImageView img = (ImageView)
      findViewById(R.id.imageView1);
   
    // Obtém o tamanho da ImageView
    int targetW = img.getWidth();
    int targetH = img.getHeight();
    
    // Obtém a largura e altura da foto
    BitmapFactory.Options bmOptions =
      new BitmapFactory.Options();
    bmOptions.inJustDecodeBounds = true;
    BitmapFactory.decodeFile(
      caminhoFoto.getAbsolutePath(), bmOptions);

    int photoW = bmOptions.outWidth;
    int photoH = bmOptions.outHeight;
    
    // Determina o fator de redimensionamento
    int scaleFactor = Math.min(
      photoW/targetW, photoH/targetH);
    
    // Decodifica o arquivo de imagem em 
    // um Bitmap que preencherá a ImageView
    bmOptions.inJustDecodeBounds = false;
    bmOptions.inSampleSize = scaleFactor;
    bmOptions.inPurgeable = true;
    
    Bitmap bitmap = BitmapFactory.decodeFile(
      caminhoFoto.getAbsolutePath(), bmOptions);
    img.setImageBitmap(bitmap);
  }
}
Quando chamamos a câmera, no startActivityForResult, passamos o valor 1 como segundo parâmetro, esse valor representa o código da requisição (requestCode). Esse valor é retornado no método onActivityResult para saber se o resultado que estamos tratando é daquela requisição. No if que fizemos, além do requestCode, checamos o resultCode. O resultCode descreve o resultado da operação, que neste caso é tirar a foto. Se o resultado for RESULT_OK, é porque uma foto foi tirada.
[EDITADO em 12/05/2013] 
A foto que é tirada com as câmeras atuais requer muita memória para ser alocada. Sendo assim, verificamos o tamanho da ImageView para carregar a imagem deste tamanho.
O atributo caminhoFoto que foi atribuído no método tirarFotoClick é utilizado para carregar a imagem e atribuir em um ImageView. Agora vamos ver como salvar essa imagem na galeria de mídia.
public void salvarFotoClick(View v) {
  if (caminhoFoto != null && caminhoFoto.exists()) {
    MediaStore.Images.Media.insertImage(
      getContentResolver(), 
      caminhoFoto.getAbsolutePath(), 
      caminhoFoto.getName(), "");

    Toast.makeText(this, 
      "Imagem adicionada a galeria.",
      Toast.LENGTH_SHORT).show();
  }
}
A classe MediaStore.Images.Media tem um "método mágico" que permite que possamos inserir um Bitmap na galeria. Essa operação é feita graças a um ContentProvider disponibilizado pela aplicação de galeria. O próximo passo será como abrir a galeria de mídia para selecionarmos uma imagem.
public void galleryButtonClick(View v) {

  Intent intent = new Intent(
    Intent.ACTION_GET_CONTENT);
  intent.setType("image/*");
  startActivityForResult(intent, 2);
}
O código acima abrirá a aplicação de galeria. Notem que agora passamos o valor 2 para o startActivityForResult. Da mesma forma que fizemos para tirar foto, usaremos o método onActivityResult para tratar a imagem selecionada.
// adicione esse código no onActivityResult
if (resultCode == RESULT_OK && requestCode == 2) {
  Uri selectedImage = data.getData();
  String[] filePathColumn = { 
    MediaStore.Images.Media.DATA };

  Cursor cursor = getContentResolver().query(
    selectedImage, filePathColumn, null, null, null);
  cursor.moveToFirst();

  int columnIndex = cursor.getColumnIndex(
    filePathColumn[0]);
  String filePath = cursor.getString(columnIndex); 
  cursor.close();

  Bitmap yourSelectedImage = 
    BitmapFactory.decodeFile(filePath);

  imageView1.setImageBitmap(yourSelectedImage);
}
A galeria retorna o endereço da imagem selecionada através de um objeto Uri que é obtido em data.getData(). Com essa informação podemos acessar o ContentProvider da galeria para obter o caminho da imagem. Com esse caminho passamos para a classe BitmapFactory que retornará um objeto Bitmap para preencher a imageView.

Qualquer dúvida, deixem seus comentários.

4br4ç05,
nglauber