Android APT 컨트롤 주입 프레임 워 크 SqInject 구현 예제
안녕하세요,저 는 작은 흠 이 라 고 합 니 다.크레용 작은 흠 이 라 고 불 러 도 됩 니 다.😊;
저 는 17 년 동안 중 산 대학 교 를 졸 업 했 고 2018 년 7 월 에 37 모 바 일 게임 안 드 로 이 드 팀 에 가 입 했 으 며 구 방 디지털 에서 안 드 로 이 드 개발 엔지니어 로 일 했 습 니 다.
현재 37 모 바 일 게임 안 드 로 이 드 팀 의 해외 책임자 로 관련 업무 개발 을 맡 고 있다.동시에 일부 기초 건설 관련 업 무 를 동시에 고려 하 다.
배경
게임 발행 에 있어 서 가방 을 자 르 는 경우 가 많 습 니 다.R.id.xxx 를 직접 사용 하면 컴 파일 할 때 resources.arsc 가 다시 컴 파일 되 기 때문에 R 류 의 id 값 과 resources.arsc 의 대응 관계 가 이상 하여 프로그램 이 이상 합 니 다.우 리 는 두 가지 해결 방법 이 있다.
하 나 는 패 킷 을 자 르 는 과정 에서 R 류 의 값 을 바로 잡 는 것 으로 실현 방안 에 대한 구체 적 인 소 개 는 볼 수 있다.
게임 에서 패키지 자원 인덱스 충돌 해결 방안 을 발행 합 니 다.링크 는 다음 과 같 습 니 다.
//www.jb51.net/article/207579.htm
또 다른 솔 루 션 은 getIdentifier 를 사용 하여 자원 ID 를 가 져 오고 R 류 를 사용 하 는 것 을 포기 하 는 것 입 니 다.이런 방식 으로 인 코딩 이 번 거 롭 고 getIdentifier 에 문자열 을 써 야 하기 때문에 잘못 쓰기 쉽 고 컴 파일 과정 에서 발견 할 수 없습니다.이러한 상황 을 바탕 으로 getIdentifier 기반 컨트롤 주입 프레임 워 크 를 개 발 했 습 니 다.
1.APT 기술 소개
1.APT 정의
APT(Annotation Processing Tool)는 주 해 를 처리 하 는 도구 입 니 다.정확히 말 하면 자바 c 의 도구 입 니 다.컴 파일 할 때 주 해 를 스 캔 하고 처리 하 는 데 사 용 됩 니 다.주해 처리 기 는 자바 코드 를 입력 하여 자바 파일 을 출력 으로 생 성 합 니 다.
2.주해 정의
1.주 해 는 자바 코드 에 추 가 될 수 있 는 메타 데이터 로 클래스,방법,변수,파라미터 와 가방 은 모두 주해 로 수식 할 수 있 습 니 다.
2.주 해 는 수 정 된 코드 에 직접적인 영향 을 주지 않 습 니 다.
3.APT 원리 소개
Annotation processing 은 컴 파일 단계 에서 실 행 됩 니 다.그 원 리 는 자바 소스 코드 를 읽 고 주 해 를 해석 한 다음 에 새로운 자바 코드 를 생 성 하 는 것 입 니 다.새로 생 성 된 자바 코드 는 마지막 으로 자바 바이트 코드 로 컴 파일 되 었 으 며,주석 해석 기(Annotation Processor)는 읽 은 자바 클래스 를 변경 할 수 없습니다.예 를 들 어 자바 방법 을 추가 하거나 삭제 할 수 없습니다.
2.APT 실전 사용
1.SqInject 프레임 워 크 원본
모 바 일 게임 발행 에 있어 서 가방 을 자 르 고 게임 을 SDK 1 의 가방 을 받 으 며 역 컴 파일 을 통 해 smali 파일 과 다른 자원 파일 을 교체 하 는 방식 으로 채널 SDK 2 의 채널 가방 으로 교체 해 야 합 니 다.이 역 컴 파일 과정 에서 자원 색인 ID(즉 R 류 와 resources.arsc 의 ID 맵 관계)가 충돌 하여 프로그램 에 이상 이 생 길 수 있 습 니 다.즉,특수 처 리 를 하지 않 으 면 채널 SDK 및 SDK 발행 은 R 류 를 직접 사용 할 수 없습니다.getIdentifier 를 사용 하여 자원 ID 를 가 져 와 야 합 니 다.
프로그램 에서 getIdentifier 를 사용 하도록 요구 하 는 것 은 개발 과정 에서 비교적 번 거 로 운 일이 다.이러한 조건 하에 서 우 리 는 butterknife 와 같은 프레임 워 크 를 사용 할 수 없다.따라서 우 리 는 butterknife 를 모방 하여 getIdentifier 기반 컨트롤 주입 프레임 워 크 SqInject 를 개발 했다.다음은 SqInject 의 실현 을 소개 합 니 다.먼저 간단하게 사용 해 보 겠 습 니 다.
public class MainActivity extends AppCompatActivity {
// ID
@BindView(SqR.id.tv)
TextView hello;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
SqInject.bind(this);
Log.e("SqInject", hello.getText().toString());
}
//
@OnClick(SqR.id.tv)
public void click(View view) {
Intent intent = new Intent(MainActivity.this, TestActivity.class);
startActivity(intent);
}
}
2.SqInject 의 실현 원리2.1 주해 프로세서 모듈 실현
위 에서 말 한 APT 는 코드 생 성 에 자주 사 용 됩 니 다.SqInject 에서 APT 주해 처리 부분 에서 절 차 는 다음 그림 과 같 습 니 다.
컴 파일 과정 에서 주 해 를 스 캔 하여 자바 코드 를 생 성 한 후 다시 컴 파일 합 니 다.
SqInject 코드 에서 다음 과 같이 실 현 됩 니 다.
@AutoService(Processor.class)
@SupportedSourceVersion(SourceVersion.RELEASE_7)
public class SqInjectProcessor extends AbstractProcessor {
...
//
@Override
public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
// ,ResChecker id , " +$ViewBinder ,
BindViewBuilder bindViewBuilder = new BindViewBuilder(roundEnvironment, mResChecker, mElementUtils, mTypeUtils, mFiler, mMessager);
bindViewBuilder.build();
//id ,ResChecker id , " +$IdBinder ",
BindIdsBuilder bindIdsBuilder = new BindIdsBuilder(roundEnvironment, mResChecker, mElementUtils, mTypeUtils, mFiler, mMessager);
bindIdsBuilder.build();
return false;
}
}
컨트롤 이 관련 코드 를 주입 하기 전에 프레임 워 크 에서 자원 id 의 합 법성 을 먼저 검 측 합 니 다.이 프레임 워 크 에서 주 해 를 사용 할 때 문자열 이 들 어 옵 니 다.자원 이름 은 대응 하 는 자원 이 존재 하지 않 을 수 있 으 며 프레임 워 크 는 해당 하 는 검 측 을 할 수 있 습 니 다.2.2 자원 검 측
Android 가 자원 을 컴 파일 하 는 과정 에서 R 류 가 생 성 됩 니 다.즉,R 류 에 존재 하 는 경우 에 만 getIdentifier 로 얻 을 수 있 습 니 다.그러면 우 리 는 R 류 로 들 어 오 는 매개 변수 가 합 리 적 인지 확인 할 수 있 습 니 다.코드 는 다음 과 같 습 니 다.
/**
* id R
* @param name
* @param type
* @return
*/
public boolean isIdValid(String name, String type) {
String RClassName = mPackageNeme + ".R." + type;
TypeElement RClassType = mElementUtils.getTypeElement(RClassName);
if (RClassType == null) {
mMessager.printMessage(Diagnostic.Kind.ERROR, RClassName + " , , ");
} else {
//
for (Element element : RClassType.getEnclosedElements()) {
String fieldName = element.getSimpleName().toString();
if (name.equals(fieldName)) {
return true;
}
}
}
return false;
}
2.3 주석 해석,코드 생 성BindView 를 예 로 들 면 코드 는 다음 과 같 습 니 다.
/**
* BindView
* @return
*/
private Map<TypeElement, List<VariableElement>> parseBindView(){
Set<Element> elements = (Set<Element>) mRoundEnvironment.getElementsAnnotatedWith(BindView.class);
if (!Utils.isEmpty(elements)) {
Map<TypeElement, List<VariableElement>> map = new HashMap<>();
for (Element element : elements) {
if (element instanceof VariableElement) {
//
TypeElement targetElement = (TypeElement) element.getEnclosingElement();
mTargetSet.add(targetElement);
if (map.get(targetElement) == null) {
List<VariableElement> targetStringLists = new ArrayList<>();
targetStringLists.add((VariableElement) element);
map.put(targetElement, targetStringLists);
} else {
map.get(targetElement).add((VariableElement) element);
}
}
}
return map;
}
return null;
}
BindView 주 해 를 분석 한 후 자바 poet 을 사용 하여 코드 를 생 성 합 니 다.편폭 이 제한 되 어 있 습 니 다.다음은 매개 변수 와 생 성 코드 의 일부분 만 보 여 줍 니 다.
if (mBindViewIdTargetMap != null && mBindViewIdTargetMap.get(targetElement) != null) {
List<VariableElement> viewElements = mBindViewIdTargetMap.get(targetElement);
//
for (VariableElement viewElement : viewElements) {
//
String fieldName = viewElement.getSimpleName().toString();
//
TypeMirror typeMirror = viewElement.asType();
TypeElement fieldClassElement = (TypeElement) mTypeUtils.asElement(typeMirror);
mMessager.printMessage(Diagnostic.Kind.NOTE, " : " + fieldClassElement.getQualifiedName().toString());
TypeElement fieldType = mElementUtils.getTypeElement(fieldClassElement.getQualifiedName());
ClassName fieldClassName = ClassName.get(fieldType);
// @BindView ,
String name = viewElement.getAnnotation(BindView.class).value();
//
if(!mResChecker.isIdValid(name, "id")){
mMessager.printMessage(Diagnostic.Kind.ERROR, "R id " + name + " ");
}
methodBuilder.addStatement("target.$N = $T.findRequiredViewAsType(source, $S, $S, $T.class)", fieldName, JptConstants.UTILS, name, "field " + fieldName,fieldClassName);
}
}
요약 하면 주해 프로세서 에서 가장 중요 한 두 부분 중 하 나 는 주 해 를 해석 하고 파 라 메 터 를 얻 은 다음 자바 poet 프레임 워 크 를 이용 하여 코드 를 만 드 는 것 입 니 다.생 성 된 코드 를 보 겠 습 니 다.
public class MainActivity$ViewBinder implements ViewBinder<MainActivity> {
@Override
public void bindView(final MainActivity target, final View source) {
//
target.hello = ViewUtils.findRequiredViewAsType(source, "tv", "field hello", TextView.class);
IdUtils.findViewByName("tv", source).setOnClickListener(new DebouncingOnClickListener() {
public void doClick(View v) {
target.click(v);
}
} );
}
}
여기까지 APT 생 성 코드 를 소 개 했 습 니 다.본 논문 에서 언급 한 프레임 워 크 SqInject 는 우리 가 일상 업무 에서 사용 할 수 있 는 SqInject 프레임 워 크 입 니 다.이 프레임 워 크 는 오픈 소스 입 니 다.주 소 는github.com/37sy/SqInje…관심 있 는 환영 스타 입 니 다.이상 은 안 드 로 이 드 APT 구현 컨트롤 주입 프레임 워 크 SqInject 의 예제 에 대한 상세 한 내용 입 니 다.안 드 로 이 드 APT 컨트롤 주입 프레임 워 크 SqInject 에 관 한 자 료 는 다른 관련 글 을 주목 하 십시오!
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Bitrise에서 배포 어플리케이션 설정 테스트하기이 글은 Bitrise 광고 달력의 23일째 글입니다. 자체 또는 당사 등에서 Bitrise 구축 서비스를 사용합니다. 그나저나 며칠 전 Bitrise User Group Meetup #3에서 아래 슬라이드를 발표했...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.