Android 에서 Service AIDL 사용 에 대한 자세 한 설명

22203 단어 AndroidService
머리말
어떤 친구 들 은 개발 에 종사 하 는 시간 이 그리 길지 않 을 수도 있 기 때문에 Service 는 다른 두 개의 구성 요소 activity,broadcast receiver 에 비해 사용 이 특별히 많 지 않 을 수도 있다 고 생각 합 니 다.그래서 Service 에 대한 이 해 는 특별히 깊 은 것 이 아니 라 대략적인 개념 이 있 을 뿐 입 니 다.오늘 은 하나 와 함께 Service 를 가 보 겠 습 니 다.여러분 들 이 Service 에 대해 더욱 깊이 이해 하 는 데 도움 이 되 기 를 바 랍 니 다.
서비스 기본 용법-로 컬 서비스
우 리 는 서비스 가 로 컬 서비스 와 원 격 서비스 로 나 뉘 는 것 을 알 고 있 습 니 다.로 컬 서 비 스 는 시작 방식 이 다 르 기 때문에 수명 주기 도 다 릅 니 다.Service 수명 주기 에 익숙 하지 않 은 친구 들 은 스스로 바 이 두 에 가 보 세 요.자,그럼 두 가지 다른 작 동 방식 을 살 펴 보 자.
저희 가 먼저 서비스:ServiceTest.java 를 만 들 겠 습 니 다.

package com.example.administrator.servicetestaidl;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.support.annotation.IntDef;
import android.util.Log;

public class ServiceTest extends Service {


    @Override
    public void onCreate() {
        super.onCreate();
        Log.d("ServiceTest","  ----->  onCreate");
    }


    @Override
    public int onStartCommand(Intent intent,int flags, int startId) {

        Log.d("ServiceTest","  ----->  onStartCommand");

        return super.onStartCommand(intent, flags, startId);
    }


    @Override
    public void onDestroy() {
        super.onDestroy();

        Log.d("ServiceTest","  ----->  onDestroy");

    }

    @Override
    public IBinder onBind(Intent intent) {
        // TODO: Return the communication channel to the service.
        throw new UnsupportedOperationException("Not yet implemented");
    }
}
MainActivity 코드 를 보고 있 습 니 다.

package com.example.administrator.servicetestaidl;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;

public class MainActivity extends Activity {
    private Button startService, stopService;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        startService = (Button) findViewById(R.id.start_service);
        stopService = (Button) findViewById(R.id.stop_service);


        /**
         *     
         */
        startService.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent startService = new Intent(MainActivity.this,ServiceTest.class);
                startService(startService);

            }
        });


        /**
         *     
         */
        stopService.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent stopService = new Intent(MainActivity.this,ServiceTest.class);
                stopService(stopService);
            }
        });


    }
}
레이아웃 activitymain

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <Button
        android:id="@+id/start_service"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="    " />

    <Button
        android:id="@+id/stop_service"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="    " />

</LinearLayout>
프로필 AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.administrator.servicetestaidl">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <service
            android:name=".ServiceTest"
            android:enabled="true"
            android:exported="true"></service>
    </application>

</manifest>
위의 코드 는 매우 간단 하고 이해 하기 어렵 지 않 습 니 다.페이지 에 두 개의 단 추 를 추가 합 니 다.하 나 는 서 비 스 를 시작 하 는 것 이 고 하 나 는 서 비 스 를 소각 하 는 것 입 니 다.그리고 우 리 는 ServiceTest 에 있 는 몇 가지 방법 에 log 를 추가 합 니 다.그러면 우 리 는 서 비 스 를 시작 하려 면 Log 를 클릭 합 니 다.그림 과 같 습 니 다.

그리고 우 리 는 여러 번 클릭 하여 서 비 스 를 시작 합 니 다.그림 과 같 습 니 다.

우 리 는 뒤에 이 서 비 스 를 몇 번 더 켜 도 onStartCommand 방법 만 바 꾸 는 것 을 보 았 습 니 다.onCreate 방법 은 중복 호출 되 지 않 습 니 다.그것 은 우리 가 서 비 스 를 클릭 하기 때 문 입 니 다.이 서 비 스 는 이미 존재 하기 때문에 다시 만 들 지 않 기 때문에 onCreate 방법 은 한 번 만 호출 됩 니 다.
우 리 는 또한 핸드폰 의 응용 프로그램 관리 인터페이스 에 가서 Service 가 실행 되 고 있 는 지 확인 할 수 있다.아래 그림 과 같다.

그럼 서비스 정지 버튼 을 누 르 면 log 를 보 세 요.그림 과 같 습 니 다.

이 때 는 서비스 가 이미 소각 되 었 다 는 것 을 설명 했다.
어떤 친구 들 은 우리 가 방금 서 비 스 를 시작 하 는 방식 이 서 비 스 를 시작 하고 소각 하 는 것 을 제외 하고 activity 에서 서 비 스 를 통제 하기 어 려 운 것 같다 는 것 을 알 고 있 을 것 이다.무슨 뜻 일 까?예 를 들 어 제 가 지금 Service 로 무언 가 를 다운로드 하고 있다 면 저 는 지금 Service 에 이 두 가 지 를 다운로드 하 는 방법,방법 a,방법 b 가 적 혀 있 습 니 다.그러면 저 는 activity 에서 언제 방법 a 를 호출 할 지,언제 방법 b 를 호출 할 지 어떻게 제어 할 것 입 니까?만약 에 원래 의 시작 방식 대로 하면 실현 되 지 않 거나 유연성 이 떨어진다 고 할 수 있 습 니 다.그렇다면 할 수 있 는 방법 이 없 을 까?이어서 Service 의 다른 시작 방식 을 살 펴 보 자.앞에서 우 리 는 onBind 방법 을 움 직 이지 않 은 방법 이 있 습 니 다.우 리 는 이 방법 에 착안 하여 ServiceTest 코드 를 먼저 봅 니 다.

package com.example.administrator.servicetestaidl;

import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.support.annotation.IntDef;
import android.util.Log;

public class ServiceTest extends Service {


    @Override
    public void onCreate() {
        super.onCreate();
        Log.d("ServiceTest","  ----->  onCreate");
    }


    @Override
    public int onStartCommand(Intent intent,int flags, int startId) {

        Log.d("ServiceTest","  ----->  onStartCommand");

        return super.onStartCommand(intent, flags, startId);
    }


    @Override
    public void onDestroy() {
        super.onDestroy();

        Log.d("ServiceTest","  ----->  onDestroy");

    }

    @Override
    public IBinder onBind(Intent intent) {

        return new Mybind();
    }


    class Mybind extends Binder{
        public void getString(){
            Log.d("ServiceTest","  ----->  getString");
        }
    }



}
ServiceTest 에 내부 클래스 Mybind 를 추가 하고 Mybind 에 getString 방법 을 추가 하여 방법 에 log 를 인쇄 한 다음 onBind 방법 에서 Mybind 대상 을 되 돌려 줍 니 다.
메 인 액 티 비 티 코드 도 볼 게 요.

package com.example.administrator.servicetestaidl;

import android.app.Activity;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.view.View;
import android.widget.Button;

public class MainActivity extends Activity {

    private Button startService,stopService,bindService,unbindService;
    private ServiceTest.Mybind mybind;


    private ServiceConnection connection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            mybind = (ServiceTest.Mybind) service;
            mybind.getString(); //   getString  
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {

        }
    };




    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        startService = (Button) findViewById(R.id.start_service);
        stopService = (Button) findViewById(R.id.stop_service);
        bindService = (Button) findViewById(R.id.bind_service);
        unbindService = (Button) findViewById(R.id.unbind_service);


        /**
         *     
         */
        startService.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent startService = new Intent(MainActivity.this,ServiceTest.class);
                startService(startService);

            }
        });


        /**
         *     
         */
        stopService.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent stopService = new Intent(MainActivity.this,ServiceTest.class);
                stopService(stopService);
            }
        });

        /**
         *     
         */
        bindService.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent bindService = new Intent(MainActivity.this,ServiceTest.class);
                bindService(bindService,connection,BIND_AUTO_CREATE);
            }
        });

        /**
         *     
         */
        unbindService.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                unbindService(connection);
            }
        });
    }
}
홈 페이지 레이아웃:activitymain

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <Button
        android:id="@+id/start_service"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="    " />

    <Button
        android:id="@+id/stop_service"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="    " />

    <Button
        android:id="@+id/bind_service"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="    " />

    <Button
        android:id="@+id/unbind_service"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="    " />

</LinearLayout>
이 를 통 해 알 수 있 듯 이 우 리 는 먼저 ServiceConnection 의 익명 류 를 만 들 었 고 그 안에 onServiceConnected()방법 과 onServiceDisconnected()방법 을 다시 썼 다.이 두 가지 방법 은 각각 Activity 와 Service 가 관련 되 고 해 제 될 때 호출 된다.onServiceConnected()방법 에서 우 리 는 아래로 전환 을 통 해 MyBind 의 인 스 턴 스 를 얻 었 다.이 인 스 턴 스 가 있 으 면 Activity 와 Service 간 의 관 계 는 매우 밀접 해 졌 다.이제 우 리 는 Activity 에서 구체 적 인 장면 에 따라 MyBind 의 모든 Public 방법 을 호출 할 수 있다.즉,Activity 가 Service 를 지휘 하 는 대로 Service 가 하 는 기능 을 실현 했다.
저희 가 바 인 딩 서 비 스 를 클릭 할 때 결 과 는 다음 과 같 습 니 다.그림 참조.

풀 기 서 비 스 를 클릭 할 때 결 과 는 다음 과 같 습 니 다.그림 참조.

메모:Service 는 배경 에서 실행 되 고 시각 화 된 페이지 가 없습니다.저 희 는 많은 시간 이 걸 리 는 작업 을 Service 에 두 고 실 행 됩 니 다.그러나 주의 하 세 요.Service 는 메 인 스 레 드 에서 실 행 됩 니 다.서브 스 레 드 가 아니 라 Service 와 Thread 는 반 마 오 의 관계 가 없 기 때문에 Service 에서 시간 이 걸 리 는 작업 을 수행 할 때 처럼 스 레 드 를 켜 야 합 니 다.그렇지 않 으 면 ANR 을 일 으 킬 수 있 습 니 다.이것 은 구별 해 야 한다.
원 격 서비스―AIDL
AIDL(Android Interface Definition Language)은 Android 인터페이스 가 언어 를 정의 한 다 는 뜻 으로,한 Service 와 여러 애플 리 케 이 션 구성 요소 간 에 크로스 프로 세 스 통신 을 할 수 있 도록 해 여러 애플 리 케 이 션 이 같은 Service 를 공유 하 는 기능 을 수행 할 수 있다.실제로 크로스 프로 세 스 간 통신 을 실현 하 는 것 은 매우 많다.
예 를 들 어 방송,Content Provider,그러나 AIDL 의 장점 은 속도 가 빠 르 고(시스템 밑바닥 은 바로 공유 메모리)성능 이 안정 적 이 며 효율 이 높 으 며 일반 프로 세 스 간 통신 은 이 를 사용한다.
크로스 프로 세 스 인 만큼 두 가지 응용 프로그램 이 필요 합 니 다.하 나 는 service 단 이 고 하 나 는 client 단 입 니 다.그리고 클 라 이언 트 가 서버 에서 데 이 터 를 가 져 오 는 것 을 실현 합 니 다.그러면 우 리 는 서버 를 만 듭 니 다.프로젝트 구 조 는 그림 과 같 습 니 다.

서버
Google 은 서버 아래 에 MyAIDL Service.aidl 파일 을 만 듭 니 다.디 렉 터 리 구 조 는 그림 과 같 습 니 다.

그리고 MyAIDlservice 에 문자열 을 가 져 오 는 방법 을 추가 합 니 다.코드 는 다음 과 같 습 니 다.

// MyAIDLService.aidl
package aidl;

// Declare any non-default types here with import statements

interface MyAIDLService {
    //  String  
    String getString();
}
aidl 파일 을 만 든 후에 프로젝트 를 빌 드 한 다음 build->generated->source->aidl->debug 에서 aidl 파일 을 생 성 합 니 다.이것 은 AIDL 파일 이 컴 파일 되 었 음 을 설명 합 니 다.
다음 에 MyService 클래스 를 만 듭 니 다.코드 는 다음 과 같 습 니 다.

package com.example.service;

import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;

import java.util.Map;

import aidl.MyAIDLService;

public class MyService extends Service {

    @Override
    public void onCreate() {
        super.onCreate();
    }


    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        return super.onStartCommand(intent, flags, startId);
    }


    @Override
    public void onDestroy() {
        super.onDestroy();
    }

    @Override
    public IBinder onBind(Intent intent) {
        return new Mybind();
    }

    class Mybind extends MyAIDLService.Stub {

        @Override
        public String getString() throws RemoteException {
            String string = "         ";

            return string;
        }
    }
}
코드 가 익숙 해 보이 지 않 습 니까?유일 하 게 다른 것 은 원래 로 컬 서 비 스 를 할 때 내부 클래스 가 Binder 를 계승 하 는 것 입 니 다.지금 은 MyAIDL Service.Stub 를 계승 하고 있 습 니 다.우리 가 방금 만 든 adl 파일 을 계승 한 다음 에 우리 가 방금 정의 한 getString()방법 을 실현 하 는 것 입 니 다.여기 서 우 리 는'저 는 서비스 에서 돌 아 왔 습 니 다'~~~~~~~~~~~~~~~~~~~~~~~
클 라 이언 트
우선 서버 에서 생 성 된 MyAIDLRService 를 클 라 이언 트 에 그대로 복사 합 니 다.(메모:경로 가 똑 같 아야 합 니 다.이어서 클 라 이언 트 의 MainActivity 에 두 개의 단 추 를 추가 하고 서버 와 연결 합 니 다.코드 는 다음 과 같 습 니 다.
MainActivity

package com.example.administrator.servicetestaidl;

import android.app.Activity;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

import aidl.MyAIDLService;

public class MainActivity extends Activity {

    private Button bindService,unbindService;
    private TextView tvData;
    private MyAIDLService myAIDLService;


    private ServiceConnection connection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            myAIDLService = MyAIDLService.Stub.asInterface(service);
            try {
                String str =  myAIDLService.getString();
                tvData.setText(str);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            myAIDLService = null;
        }
    };




    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        bindService = (Button) findViewById(R.id.bind_service);
        unbindService = (Button) findViewById(R.id.unbind_service);
        tvData = (TextView) findViewById(R.id.tv_data);


        /**
         *     
         */
        bindService.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent();
                intent.setAction("com.example.service.MyService");
                //  Android 5.0     Intent            ,        Service        
                intent.setPackage("com.example.service");
                bindService(intent, connection, BIND_AUTO_CREATE);



            }
        });

        /**
         *     
         */
        unbindService.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                unbindService(connection);
            }
        });
    }
}
로 컬 서 비 스 를 연결 하 는 코드 와 차이 가 많 지 않 은 것 같 습 니까?맞습니다.여 기 는 두 가지 만 주의 하 셔 야 합 니 다.하 나 는 바 인 딩 서비스 일 때 Android 5.0 부터 암시 적 Intent 바 인 딩 서 비 스 를 사용 할 수 없 기 때문에 Service 가 있 는 서버 의 가방 이름 을 설정 해 야 합 니 다.
그럼 이 action 은 어떻게 왔 습 니까?서버 에 돌아 온 AndroidManifest.xml 코드 는 다음 과 같 습 니 다.

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.service">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <service
            android:name=".MyService"
           >
            <intent-filter>
                <action android:name="com.example.service.MyService" />
            </intent-filter>

        </service>
    </application>

</manifest>
또 하나 주의해 야 할 것 은 MyAIDlservice 대상 을 얻 는 것 은 MyAIDlservice.stub.asInterface(service)를 통 해 얻 는 것 이다.여기 주의 하 셔 야 합 니 다.
그러나 또 한 가지 설명 이 필요 한 것 은 서로 다른 프로 세 스 사이 에서 데 이 터 를 전달 하기 때문에 안 드 로 이 드 는 이러한 데이터 의 형식 에 대한 지원 이 매우 제한 적 이라는 것 이다.
기본적으로 자바 의 기본 데이터 형식,문자열,List 또는 Map 등 만 전달 할 수 있 습 니 다.그렇다면 내 가 사용자 정의 클래스 를 전달 하고 싶다 면 어떻게 해 야 합 니까?이 클래스 가 Parcelable 인 터 페 이 스 를 실현 하고 같은 이름 의 AIDL 파일 을 정의 해 야 합 니 다.이 부분 은 복잡 하지 않 고 Service 와 의 관계 가 크 지 않 기 때문에 더 이상 상세 하 게 설명 하지 않 겠 습 니 다.관심 이 있 는 친 구 는 스스로 관련 자 료 를 찾 아 볼 수 있 습 니 다.
메모:서버 에서 복사 한 aidl 파일 을 자바 폴 더 아래 에 직접 놓 을 수 없습니다.aidl 폴 더 를 만들어 저장 해 야 합 니 다.그렇지 않 으 면 컴 파일 이 성공 하지 못 할 것 입 니 다.
자,여기까지.기본적으로 끝 났 습 니 다.효과 도 를 한 장 동봉 합 니 다.

마지막 으로 원본 링크 를 첨부 합 니 다.
로 컬 서비스 원본:https://github.com/343661629/nativeService
원 격 서비스 원본:https://github.com/343661629/remoteService
이상 은 안 드 로 이 드 에서 서비스 AIDL 의 사용 에 대한 상세 한 내용 입 니 다.안 드 로 이 드 에서 서비스 AIDL 의 사용 에 관 한 자 료 는 저희 의 다른 관련 글 을 주목 하 세 요!

좋은 웹페이지 즐겨찾기