일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
- 안드로이드 숏컷
- 노티피케이션 익스텐션
- 플러터 뷰 컨트롤러
- 푸시 데이터 저장
- Flutter NativeView
- FlutterView MethodChannel
- silent push
- NotificationService Extension
- 앱 꺼졌을 때 푸시 데이터 저장
- swift sms
- 스위프트 UserDefaults
- 안드로이드 에러
- Flutter UIKitView MethodChannel
- flutter 회전
- swift autolayout
- native flutter view
- 스위프트 푸시
- 안드로이드 앨범
- Swift flutterview
- 앱 백그라운드 푸시 데이터 저장
- swift 문자
- 스위프트 앨범
- flutter rotate
- 안드로이드 바로가기
- 스위프트 테이블 뷰 셀
- 스위프트
- 안드로이드 FCM
- Swift flutterviewcontroller
- 스위프트 카메라
- 스위프트 웹뷰
- Today
- Total
Things take time
[Android] Async 비동기를 위한 기본적인 사용법 본문
[AsyncTask]
흔히 쓰레드와 핸들러를 묶어서 해놓은 클래스라 생각하면 된다.
메인쓰레드의 경우에만 UI접근 및 수정이 가능하고, 이 메인쓰레드에게 개발자가원하는 UI를 변경하려면 핸들러를 사용해야한다.
그리고 네트워크나 비트맵같은 작업들은 메인쓰레드 하나에서 돌리기엔 프레임을 너무 잡아먹어 성능 저하의 원인이 되기 때문에 별도의 쓰레드를 만들어서, 각 쓰레드를 실행해야 한다. 이것들을 하나로 묶어서 편리하게 이용할 수 있는 개념이다.
[예제]
상황 : 앨범 파일의 경로 리스트를 받아와서 해당 사진들을 저화질로 만든다. 만드는 과정에는 프로그레스바를 통해 진행상황을 표기할 수 있도록 한다.
public class CreateLowBitmap extends AsyncTask<Void, Integer, List>{ List<String> imageList = new ArrayList<>(); ProgressDialog mProgressDialog; // 진행 상태 다이얼로그 String funcName = ""; public CreateLowBitmap(List<String> imagePathList, String funcName) { this.imageList = imagePathList; this.funcName = funcName; } @Override protected void onPreExecute() { mProgressDialog = new ProgressDialog(mContext); mProgressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); mProgressDialog.setMax(imageList.size()); mProgressDialog.setTitle("파일 변환중입니다."); mProgressDialog.setCanceledOnTouchOutside(false); mProgressDialog.show(); } @Override protected List<String> doInBackground(Void... params) { List<String> returnList = new ArrayList<>(); for(int i=0; i<imageList.size(); i++) { final String path = imageList.get(i); BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; Bitmap calculateBitmap = BitmapFactory.decodeFile(path, options); options.inSampleSize = calculateInSampleSize(options, 1024, 1024); options.inJustDecodeBounds = false; Bitmap bitmap = BitmapFactory.decodeFile(path, options); Random random = new Random(); String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date()); String imageFileName = timeStamp + "_" + random.nextInt(10000) + ".jpg"; File fileCacheItem = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/test/" + imageFileName); if (fileCacheItem.exists()) { Log.i("fileCacheItem 존재", fileCacheItem.getAbsolutePath()); } else { try { Log.i("fileCacheItem 없음", "파일 상위 디렉토리 생성"); fileCacheItem.getParentFile().createNewFile(); } catch (Exception e) { Log.e("path.mkdirs", e.toString()); } } OutputStream out = null; try { fileCacheItem.createNewFile(); out = new FileOutputStream(fileCacheItem); bitmap.compress(Bitmap.CompressFormat.JPEG, 100, out); } catch (Exception e) { sendLogMsgPHP("createLowBitmapPath : " + e.toString()); } finally { try { out.close(); } catch (IOException e) { sendLogMsgPHP("createLowBitmapPath : " + e.toString()); } } Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE); Uri contentUri = Uri.fromFile(fileCacheItem); mediaScanIntent.setData(contentUri); mContext.sendBroadcast(mediaScanIntent); publishProgress(i); returnList.add(fileCacheItem.getAbsolutePath()); } return returnList; } @Override protected void onProgressUpdate(Integer... values) { mProgressDialog.setProgress(values[0]); } @Override protected void onPostExecute(List<String> strings) { if(mProgressDialog.isShowing()){ mProgressDialog.dismiss(); } UploadMultiFile uploadMultiFile = new UploadMultiFile(mContext, webView, funcName); uploadMultiFile.setInit(strings, "ImageFile"); String url = baseDomain + "UploadFile4Multi.php"; uploadMultiFile.execute(url); } }
[설명]
1) extends Async<Void, Integer, List<String>
- 첫 번째 파라미터는 이 UploadFile클래스 객체를 선언한 변수가 execute를 실행할때 전달되는 매개변수로, doInBackground에서 받아와 사용하는 매개 변수이다.
- 두 번째 파라미터는 onProgressUpdate의 매개변수이며, doInBackground에서 publishProgress()의 ()안에 들어갈 데이터 타입과 일치한다.
- 세 번째 파라미터는 doInBackground의 리턴 값이면서 onPostExecute의 매개변수이다.
2)
- doInBackground : AsyncTask 클래스를 사용하는 목적은, 메인 쓰레드(UI THREAD)이외의 개인 쓰레드를 사용하면서 다른 작업들(네트워크, 파일 저장 등)을 하기 위함이었는데, 이 작업을 하기 위한 공간이다. 즉, 사용자 지정 쓰레드와 같은 개념이면서.. 이 UploadFile이란 클래스를 객체로 만들어 사용할 변수의 execute()메소드로 호출되면, 그 execute()의 ()안 매개 변수 값이 전달된다. 내 예제에서는 서버에 올릴 것이므로 서버 URL을 전달받을 것이다. 이 함수에서는 UI접근이 불가능하다.
- onPreExecute : execute()함수를 통해 호출된 doInBackground보다 이전에 호출되는 메소드이다. 이 메소드에서는 UI에 대한 접근이 가능하다. 즉, doInBackground는 사용자 지정쓰레드이기에 메인쓰레드처럼 UI접근이 안되나, onPreExecute안에 UI접근 내용을 작성하면 메인쓰레드에서 이 부분에 있는 것을 인식하고, UI 작업을 가능하게 한다.
- onPostExecute : Post가 들어간 것으로 보니, execute 이후에 작업이 호출된다는 뜻이다. 이 곳은 doInBackground 메소드가 종료된 후 호출되는데, 만약 doInBackground가 정상적이지 않게 종료된 경우, 이 파라미터로 null 값이 전달된다. 그러므로 null이 들어왔을 때 처리하는 구문 등을 활용하면, 오류 예외 처리가 가능하다. 이 곳도 UI접근이 가능하다.
- onProgressUpdate : Async는 쓰레드기능과 핸들러기능을 동시에 수행할 수 있다고 했다. 근데 onPreExecute와 onPostExecute는 doInBackground 이 전, 이 후에만 UI접근이 가능한 것인데.. 만약 doInBackground 중간에 UI를 편집하고 싶다면 어떻게 해야할까. 그 작업을 이 메소드에서 수행한다. 이 메소드를 호출하려면 doInBackground 메소드내에 publishProgress(progress)를 호출하면 이 곳으로 온다! 이 곳도 UI접근이 가능하다.
'Android(기능)' 카테고리의 다른 글
[Android] Webview 쿠키, 캐시, 히스토리 등 웹데이터 삭제 (0) | 2017.12.20 |
---|---|
[Android] 오레오(8.0) 업데이트 및 노티피케이션 채널(Notification Channel) (0) | 2017.12.01 |
[Android] 외부 라이브러리 제거하기 (Gradle아닌 Module로 Import한 경우) (0) | 2017.08.31 |
[Android] 카메라 사진 찍기 및 앨범에서 사진 가져오기, 크롭(Crop)하기, 프로바이더 설정하기, 이미지뷰에 띄우기 (81) | 2017.08.28 |
[Android] 위험 권한, 권한 전용 팝업 만들기 (3) | 2017.08.28 |