Android 멀티스레드(IntentService 편)

[제천의 블로그] 전재는 출처를 밝혀 주십시오(대단히 감사합니다!):https://blog.csdn.net/qijinglai/article/details/80747150
관련 기사: 안드로이드 다중 스레드(Handler 편) 안드로이드 다중 스레드(AsyncTask 편) 안드로이드 다중 스레드(Handler Thread 편) 안드로이드 다중 스레드(Intent Service 편)
전언
예를 들어 업로드와 다운로드 등 작업은 원칙적으로 가능한 한 서비스에 맡겨야 한다. 업로드 등 과정에서 사용자가 백엔드에 응용할 수 있기 때문에 이때 Activity가 죽을 가능성이 높다.서비스가 죽을까 봐 걱정되면 startForeground를 통해 우선순위를 높일 수 있습니다.그러나 서비스에서 라인을 켜야 시간이 걸리기 때문에 스스로 서비스와 라인을 관리하는 것은 우아한 방법처럼 들리지 않는다. 이때 안드로이드가 제공하는 종류인 Intent Service를 사용할 수 있다.전편에서는HandlerThread를 언급했고,HandlerThread의 실례는 바로 오늘 쓴 Intent Service이다.
사용
단계
  • My Intent Service 상속 Intent Service를 만들고 onHandl Intent()에서 시간 소모 작업
  • 을 실행합니다
  • Activity 등록 및 브로드캐스트 수신을 시작하려면 UI 업데이트
  • 와 같은 많은 시간이 소요되는 작업 완료 이벤트가 발생합니다.
  • Activity에서 MyIntentService를 시작하는 예제 코드는 다음과 같습니다.
  • public class MyIntentService extends IntentService {
        private static final String ACTION_UPLOAD_IMG = "com.qit.action.UPLOAD_IMAGE";
        public static final String EXTRA_IMG_PATH = "com.qit.extra.IMG_PATH";
    
        public static void startUploadImg(Context context, String path) {
            Intent intent = new Intent(context, MyIntentService.class);
            intent.setAction(ACTION_UPLOAD_IMG);
            intent.putExtra(EXTRA_IMG_PATH, path);
            context.startService(intent);
        }
    
    
        public MyIntentService() {
            super("MyIntentService");
        }
    
        @Override
        protected void onHandleIntent(Intent intent) {
            if (intent != null) {
                final String action = intent.getAction();
                if (ACTION_UPLOAD_IMG.equals(action)) {
                    final String path = intent.getStringExtra(EXTRA_IMG_PATH);
                    handleUploadImg(path);
                }
            }
        }
    
        private void handleUploadImg(String path) {
            try {
                //      
                Thread.sleep(((long) (Math.random() * 3000)));
    
                Intent intent = new Intent(MainActivity.UPLOAD_RESULT);
                intent.putExtra(EXTRA_IMG_PATH, path);
                sendBroadcast(intent);
    
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    public class MainActivity extends AppCompatActivity {
        public static final String UPLOAD_RESULT = "com.qit.UPLOAD_RESULT";
    
        private LinearLayout ll;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            ll = (LinearLayout) findViewById(R.id.ll);
            findViewById(R.id.btn).setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    addTask();
                }
            });
            IntentFilter filter = new IntentFilter();
            filter.addAction(UPLOAD_RESULT);
            registerReceiver(uploadImgReceiver, filter);
        }
    
        private BroadcastReceiver uploadImgReceiver = new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                if (intent.getAction() == UPLOAD_RESULT) {
                    String path = intent.getStringExtra(MyIntentService.EXTRA_IMG_PATH);
    
                    handleResult(path);
    
                }
    
            }
        };
    
        private void handleResult(String path) {
            TextView tv = (TextView) ll.findViewWithTag(path);
            tv.setText(path + " upload success ~~~ ");
        }
    
        int i = 0;
    
        public void addTask() {
            //    
            String path = "/sdcard/imgs/" + (++i) + ".png";
            MyIntentService.startUploadImg(this, path);
    
            TextView tv = new TextView(this);
            ll.addView(tv);
            tv.setText(path + " is uploading ...");
            tv.setTag(path);
        }
    
    
        @Override
        protected void onDestroy() {
            super.onDestroy();
            unregisterReceiver(uploadImgReceiver);
        }
    }
    
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:id="@+id/ll"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">
    
        <Button
            android:id="@+id/btn"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text=" " />
    
    LinearLayout>

    IntentService도 Service가 등록되어 있는 걸로 알고 있습니다.
    원리 분석
    원본이 많지 않으니까 다 가져와 봐.
    public abstract class IntentService extends Service {
        private volatile Looper mServiceLooper;
        private volatile ServiceHandler mServiceHandler;
        private String mName;
        private boolean mRedelivery;
    
        private final class ServiceHandler extends Handler {
            public ServiceHandler(Looper looper) {
                super(looper);
            }
    
            @Override
            public void handleMessage(Message msg) {
                onHandleIntent((Intent)msg.obj);
                stopSelf(msg.arg1);
            }
        }
    
        /**
         * Creates an IntentService.  Invoked by your subclass's constructor.
         *
         * @param name Used to name the worker thread, important only for debugging.
         */
        public IntentService(String name) {
            super();
            mName = name;
        }
    
        /**
         * Sets intent redelivery preferences.  Usually called from the constructor
         * with your preferred semantics.
         *
         * 

    If enabled is true, * {@link #onStartCommand(Intent, int, int)} will return * {@link Service#START_REDELIVER_INTENT}, so if this process dies before * {@link #onHandleIntent(Intent)} returns, the process will be restarted * and the intent redelivered. If multiple Intents have been sent, only * the most recent one is guaranteed to be redelivered. * *

    If enabled is false (the default), * {@link #onStartCommand(Intent, int, int)} will return * {@link Service#START_NOT_STICKY}, and if the process dies, the Intent * dies along with it. */

    public void setIntentRedelivery(boolean enabled) { mRedelivery = enabled; } @Override public void onCreate() { // TODO: It would be nice to have an option to hold a partial wakelock // during processing, and to have a static startService(Context, Intent) // method that would launch the service & hand off a wakelock. super.onCreate(); HandlerThread thread = new HandlerThread("IntentService[" + mName + "]"); thread.start(); mServiceLooper = thread.getLooper(); mServiceHandler = new ServiceHandler(mServiceLooper); } @Override public void onStart(@Nullable Intent intent, int startId) { Message msg = mServiceHandler.obtainMessage(); msg.arg1 = startId; msg.obj = intent; mServiceHandler.sendMessage(msg); } /** * You should not override this method for your IntentService. Instead, * override {@link #onHandleIntent}, which the system calls when the IntentService * receives a start request. * @see android.app.Service#onStartCommand */ @Override public int onStartCommand(@Nullable Intent intent, int flags, int startId) { onStart(intent, startId); return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY; } @Override public void onDestroy() { mServiceLooper.quit(); } /** * Unless you provide binding for your service, you don't need to implement this * method, because the default implementation returns null. * @see android.app.Service#onBind */ @Override @Nullable public IBinder onBind(Intent intent) { return null; } /** * This method is invoked on the worker thread with a request to process. * Only one Intent is processed at a time, but the processing happens on a * worker thread that runs independently from other application logic. * So, if this code takes a long time, it will hold up other requests to * the same IntentService, but it will not hold up anything else. * When all requests have been handled, the IntentService stops itself, * so you should not call {@link #stopSelf}. * * @param intent The value passed to {@link * android.content.Context#startService(Intent)}. * This may be null if the service is being restarted after * its process has gone away; see * {@link android.app.Service#onStartCommand} * for details. */ @WorkerThread protected abstract void onHandleIntent(@Nullable Intent intent); }
  • onCreate:안에는HandlerThread가 초기화되어 있습니다.HandlerThread에 관해서는 저의 이전 글인 안드로이드 멀티스레드(HandlerThread편)를 보실 수 있습니다
  • onStart Command: 온Start
  • onStart에서 mServiceHandler를 통해 이handler의handleMessage에 메시지를 보냅니다.
  • handle Message (): 온Handle Intent (intent) 를 리셋한 후 stopSelf (msg.arg1) 를 리셋합니다. 이 msg를 주의하십시오.arg1은 int값으로 요청의 유일한 표식에 해당합니다.요청을 보낼 때마다 유일한 표식을 생성하고 요청을 대기열에 넣습니다. (마지막 요청도 getLastStartId = = startId) 또는 현재 보낸 표식이 최근에 보낸 것 (getLastStartId = = startId) 이면 저희 서비스를 삭제합니다.들어오는 것이 -1이면 바로 소각한다.
  • 작업이 완료되면 Service 리셋 onDestory를 삭제하면 onDestroy에서 우리의 Looper:mServiceLooper를 방출하는 것을 볼 수 있습니다.quit().

  • end.

    좋은 웹페이지 즐겨찾기