개발하는 두더지

[Android/안드로이드] InputStream, OutputStream을 활용한 동영상 다운로드 및 재생 본문

Java,Android

[Android/안드로이드] InputStream, OutputStream을 활용한 동영상 다운로드 및 재생

덜지 2016. 7. 22. 01:40

목차

1. InputStream, OutputStream에 대해 알아보기

2. AsyncTask 동작 방법에 대해 알아보기


결과물

1. 소켓 통신으로 서버와 클라이언트 간 데이터 통신에 이해

2. AsyncTask 비 동기식 Thread의 사용 방법과 이해



InputStream

Most clients will use input streams that read data from the file system (FileInputStream), the network (getInputStream()/getInputStream()), or from an in-memory byte array (ByteArrayInputStream).

Most clients should wrap their input stream with BufferedInputStream


public int read (byte[] buffer, int byteOffset, int byteCount)

Reads up to byteCount bytes from this stream and stores them in the byte array buffer starting at byteOffset


// URL 객체를 생성

URL url = new URL(UrlString);


// URL에 연결된 객체를 생성

HttpURLConnection conn = (HttpURLConnection)url.openConnection();


// 연결된 URL 에서 데이터를 얻어와서 버퍼스트림에 넣어줌

BufferedInputStream br = new BufferedInputStream( conn.getInputStream() );


// 바이트 배열 생성

byte[] data = new byte[4096];


// 스트림에서 바이트 배열 크기만큼 데이터를 읽어서 byte 객체에 저장. 데이터를 끝까지 받을 때 까지 이 과정을 반복

while( (bytesRead = br.read(data, 0, data.length)) >= 0)



OutputStream

Most clients will use output streams that write data to the file system (FileOutputStream), the network (getOutputStream()/getOutputStream()), or to an in-memory byte array (ByteArrayOutputStream).
Most clients should wrap their output stream with BufferedOutputStream

public void write (byte[] buffer, int offset, int count)

Writes count bytes from the byte array buffer starting at position offset to this stream


// 파일을 생성해주고 데이터를 쓸 수 있는 아웃풋스트림 객체 생성

String FullPath = "/sdcard/Sample1/test.mp4";

OutputStream output = new FileOutputStream(FullPath);


// 0 위치부터 bytesRead 크기 만큼 data에서 데이터를 빼와서 output이 가리키고 있는 대상에 데이터를 써줌. 

// 지금 예제에서는 mp4 파일에 데이터를 써준다.

output.write(data, 0, bytesRead);



AsyncTask

AsyncTask enables proper and easy use of the UI thread. This class allows to perform background operations and publish results on the UI thread without having to manipulate threads and/or handlers.

AsyncTask must be subclassed to be used. The subclass will override at least one method (doInBackground(Params...)), and most often will override a second one (onPostExecute(Result).)
 
// Sample
AsyncTask<Params, Progress, Result>
Params : AsyncTask 를 execute 하면서 넘어온 인자
Progress : AsyncTask 가 진행될때 사용
Result : 최종 결과 값을 받을 인자, doInBackground 의 return 값

private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> {
     
protected Long doInBackground(URL... urls) {
         
int count = urls.length;
         
long totalSize = 0;
         
for (int i = 0; i < count; i++) {
             totalSize
+= Downloader.downloadFile(urls[i]);
             publishProgress
((int) ((i / (float) count) * 100));
             
// Escape early if cancel() is called
             
if (isCancelled()) break;
         
}
         
return totalSize;
     
}

     
protected void onProgressUpdate(Integer... progress) {
         setProgressPercent
(progress[0]);
     
}

     
protected void onPostExecute(Long result) {
         showDialog
("Downloaded " + result + " bytes");
     
}
 
}

// MainActivity에서 구동 방법
 new DownloadFilesTask().execute(url1, url2, url3);



  1. onPreExecute(), invoked on the UI thread before the task is executed
  2. doInBackground(Params...), invoked on the background thread immediately after onPreExecute() finishes executing. 
  3. onProgressUpdate(Progress...), invoked on the UI thread after a call to publishProgress(Progress...).
  4. onPostExecute(Result), invoked on the UI thread after the background computation finishes


Threading rules


There are a few threading rules that must be followed for this class to work properly:

Memory observability


AsyncTask guarantees that all callback calls are synchronized in such a way that the following operations are safe without explicit synchronizations.





Example)

// 현재 Activity의 Context와 doInBackground 에서 쓸 String 객체 execute
new DownLoad(MainActivity.this).execute(url);

// 가장 먼저 onPreExecute() 실행 되는데 이때 ProgressDialog 객체 만들어주고 값을 설정 한 뒤 show
@Override
protected void onPreExecute()
{
super.onPreExecute();
lodingBar = new ProgressDialog(mContext);
lodingBar.setMessage("다운로드 중 ...");
lodingBar.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
lodingBar.setMax(100);
lodingBar.show();
}

// doInBackground 가 Thread와 Runnable의 Run() 과 같은 역할을 한다.
// URL 에 접근하여 데이터를 받아오면서 파일에 데이터를 쓰는 역할
// publishProgress 를 이용하여 UI Thread에도 접근 가능
@Override
protected Integer doInBackground(String... params)
{
if( params != null && params.length > 0) 
{
String UrlString = params[0];
try
{
URL url = new URL(UrlString);
HttpURLConnection conn = (HttpURLConnection)url.openConnection();
if( conn != null)
{
conn.setRequestMethod("GET");
conn.setDoInput(true);
conn.setDoOutput(false);

int responseCode = conn.getResponseCode();
if( responseCode == HttpURLConnection.HTTP_OK)
{
int result = readContent(conn.getInputStream());
return result;
}
}
}
catch (Exception e)
{
e.printStackTrace();
}
}
return null;
}

public int readContent(InputStream is)
{
BufferedInputStream br = new BufferedInputStream(is);
OutputStream output = null;
try
{
output = new FileOutputStream(FullPath);
}
catch (FileNotFoundException e1)
{
e1.printStackTrace();
return 1;
}
byte[] data = new byte[4096];
int bytesRead = 0, totalRead = 0;
try
{
while( (bytesRead = br.read(data, 0, data.length)) >= 0)
{
output.write(data, 0, bytesRead);
totalRead += bytesRead;
int totalReadInKB = totalRead / ( Size / 100 );
publishProgress(totalReadInKB);
}
output.flush();
}
catch (IOException e)
{
e.printStackTrace();
return 2;
}
finally
{
try
{
output.flush();
output.close();
br.close();
is.close();
}
catch (IOException e)
{
e.printStackTrace();
return 3;
}
}
return 0;
}

// publishProgress 에서 넘어온 값이 values에 저장되어 있음.
// 그 값을 꺼내어 프로그래스 바 값을 세팅 해준다.
@Override
protected void onProgressUpdate(Integer... values)
{
super.onProgressUpdate(values[0]);
lodingBar.setProgress(values[0]);
}

// doInBackground 가 return 되면 그 값이 onPostExecute의 인자인 result 에 저장이 된다. 그리고 밑에 코드를 실행
@Override
protected void onPostExecute(Integer result)
{
super.onPostExecute(result);

lodingBar.dismiss();
if ( result == 0)
{
Toast.makeText(mContext, "Success" , Toast.LENGTH_SHORT).show();
}
else
{
Toast.makeText(mContext, "Null" , Toast.LENGTH_SHORT).show();
}
}



Comments