[Android]임의의 시간 에 하위 스 레 드 에서 주 스 레 드 로 전환 합 니 다.
17404 단어 Android
끌어들이다
안 드 로 이 드 개발 에 서 는 네트워크 요청,데이터베이스 데이터 준비 등 시간 이 걸 리 는 작업 이 자주 발생 합 니 다.이 작업 들 은 메 인 스 레 드 에서 진행 할 수 없습니다.메 인 스 레 드 를 막 아 프로그램 이 응답 하지 않 기 때문이다.
그래서 다른 키 스 레 드 에서 만 시간 이 걸 리 는 작업 을 하고 완성 한 후에 화면 에 표시 할 수 있 습 니 다.알다 시 피 인터페이스 등 컨트롤 작업 은 메 인 스 레 드 에서 만 이 루어 집 니 다.그래서 불가피 하 게 하위 스 레 드 에서 주 스 레 드 로 전환 해 야 합 니 다.
방법.
이런 경우 Android 에서 흔히 볼 수 있 는 것 은 AsynTask 클래스 를 사용 하거나... Handler 가 스 레 드 전환 하기;그 중에서 AsynTask 는 공식 적 으로 포 장 된 유형 으로 비교적 간단 하고 효율 도 비교적 좋 지만 모든 상황 에 적합 하지 않다.적어도 나 는 한두 번 사용 한 후에 다 시 는 사용 하지 않 았 다.쓰다 Handler 는 가장 만능 적 인 방식 이 라 고 할 수 있 는데 그 원 리 는 메시지 순환 이다.메 인 스 레 드 에 Handler 변 수 를 만 들 때 Handler 메시지 순환 을 시작 하고 메시지 대기 열 에 있 는 작업 을 하나씩 처리 하 는 것 이다.하지만 까다 로 울 때 도 있다.그 까다 로 운 점 은 번 거 로 움 이다.
매번 하 나 를 만들어 야 돼 요. Handler 클래스,그리고 voidhandleMessage(Messagemsg)를 사용 합 니 다. 방법 은 정 보 를 꺼 내 서 인터페이스 조작 을 하 는데 그 중에서 매개 변수의 전달 등 문제 에 부 딪 혀 서 말하자면 정말 번거롭다.
생각.
이렇게 많은 문제 가 있 지만 또 그 장점 이 있 는데,우 리 는 왜 스스로 한 번 포장 하지 않 습 니까?
여기 서 나 는 생각 을 정리 했다.
4.567917.역시 사용 Handler 스 레 드 전환4.567917.서브 스 레 드 에서 간단 한 호출 을 통 해 메 인 스 레 드 로 전환 하여 작업 을 할 수 있 습 니 다4.567917.서브 스 레 드 가 메 인 스 레 드 로 전환 할 때 서브 스 레 드 는 메 인 스 레 드 가 실 행 될 때 까지 차단 에 들 어 갑 니 다(왜 이런 수요 가 있 는 지 아 세 요?)
4.567917.반드시 그 효율 을 확보 해 야 한다.
4.567917.메 인 스 레 드 의 집행 은 시간 제한 이 있어 야 하고 너무 오래 실행 하면 메 인 스 레 드 가 막 히 지 않 습 니 다내 가 생각 할 수 있 는 것 은 바로 이것 이다.시청자 여러분 어때요?더 필요 하 십 니까?
한다 면 한다,실현 방법 을 정리 하 다
Handler 사용 실현,그렇다면 주 된 방법 은 당연히 상속 Handler 를 사용 하 는 것 이다. 실현
4.567917.간단 하면 서도 수시로 들 어 갈 수 있 는 방법 이 있어 야 한다.그러면 대외 적 으로 정태 적 인 방법 을 사용 하 는 것 이 좋 은 선택 이다효율 성 을 확보 하려 면 Handler 를 메시지 대기 열 이 너무 많 지만 수시로 호출 할 수 있다 는 것 을 만족 시 키 려 면 외부 로 Queue
4.567917.더욱 상황 이 막 히 거나 막 히 지 않 는 서브 스 레 드 두 가지 상황 이 있 으 면 두 개 를 사용한다. Queue 야,헤어져4.567917.메 인 스 레 드 에서 오래 실행 되 지 않도록 해 야 합 니 다.그러면 대기 열의 실행 에 시간 제한 이 있어 야 합 니 다.시간 변 수 를 추가 하 세 요
CodeTime
우선 우 리 는 ToolKit 클래스 를 만 듭 니 다.
public class ToolKit {
/**
* Asynchronously
*
* @param runnable Runnable Interface
*/
public static void runOnMainThreadAsync(Runnable runnable) {
}
/**
* Synchronously
*
* @param runnable Runnable Interface
*/
public static void runOnMainThreadSync(Runnable runnable) {
}
}
두 가지 대외 적 인 방법 은 쉽게 말 하면 이렇다.하지만 그 기능 이 실현 되 려 면 계승 핸들 러 를 사용 해 야 한다.
클래스 Handler Poster 를 만 들 고 Handler 에서 계승 합 니 다:
final class HandlerPoster extends Handler {
private final int ASYNC = 0x1;
private final int SYNC = 0x2;
private final Queue asyncPool;
private final Queue syncPool;
private final int maxMillisInsideHandleMessage;
private boolean asyncActive;
private boolean syncActive;
HandlerPoster(Looper looper, int maxMillisInsideHandleMessage) {
super(looper);
this.maxMillisInsideHandleMessage = maxMillisInsideHandleMessage;
asyncPool = new LinkedList<>();
syncPool = new LinkedList<>();
}
void dispose() {
this.removeCallbacksAndMessages(null);
this.asyncPool.clear();
this.syncPool.clear();
}
void async(Runnable runnable) {
synchronized (asyncPool) {
asyncPool.offer(runnable);
if (!asyncActive) {
asyncActive = true;
if (!sendMessage(obtainMessage(ASYNC))) {
throw new GeniusException("Could not send handler message");
}
}
}
}
void sync(SyncPost post) {
synchronized (syncPool) {
syncPool.offer(post);
if (!syncActive) {
syncActive = true;
if (!sendMessage(obtainMessage(SYNC))) {
throw new GeniusException("Could not send handler message");
}
}
}
}
@Override
public void handleMessage(Message msg) {
if (msg.what == ASYNC) {
boolean rescheduled = false;
try {
long started = SystemClock.uptimeMillis();
while (true) {
Runnable runnable = asyncPool.poll();
if (runnable == null) {
synchronized (asyncPool) {
// Check again, this time in synchronized
runnable = asyncPool.poll();
if (runnable == null) {
asyncActive = false;
return;
}
}
}
runnable.run();
long timeInMethod = SystemClock.uptimeMillis() - started;
if (timeInMethod >= maxMillisInsideHandleMessage) {
if (!sendMessage(obtainMessage(ASYNC))) {
throw new GeniusException("Could not send handler message");
}
rescheduled = true;
return;
}
}
} finally {
asyncActive = rescheduled;
}
} else if (msg.what == SYNC) {
boolean rescheduled = false;
try {
long started = SystemClock.uptimeMillis();
while (true) {
SyncPost post = syncPool.poll();
if (post == null) {
synchronized (syncPool) {
// Check again, this time in synchronized
post = syncPool.poll();
if (post == null) {
syncActive = false;
return;
}
}
}
post.run();
long timeInMethod = SystemClock.uptimeMillis() - started;
if (timeInMethod >= maxMillisInsideHandleMessage) {
if (!sendMessage(obtainMessage(SYNC))) {
throw new GeniusException("Could not send handler message");
}
rescheduled = true;
return;
}
}
} finally {
syncActive = rescheduled;
}
} else super.handleMessage(msg);
}
}
다음은 제 가 시간 이 많이 걸 려 서 만 든 종 류 를 말씀 드 리 겠 습 니 다.
클래스 의 변수 부분:
두 개의 표지,두 개의 대기 열,두 개의 실행 상태,한 개의 시간 제한;잘 이해 하 시 죠?표 지 는 그 대기 열 을 처리 하기 위해 사용 합 니 다.대열 은 당연히 임 무 를 담 고 있 지.실행 상 태 는 메 시 지 를 반복 해서 보 내 는 것 을 피하 기 위해 메시지 대기 열 이 너무 많 습 니 다.시간 제한 은 이해 하 는 게 좋 을 거 야.
다음은 방법 부분 을 말씀 드 리 겠 습 니 다.
구조 함수 HandlerPoster(Looperlooper,int_maxMillisInsideHandleMessage):
두 개의 매개 변 수 를 입력 합 니 다.각각 Looper 입 니 다.메 인 스 레 드 로 초기 화 하 는 데 사 용 됩 니 다.그 다음은 시간 제한 입 니 다.그리고 두 대기 열 을 초기 화 했 습 니 다.
폐기 함수 voiddispose():처리 되 지 않 은 메 시 지 를 먼저 제거 한 다음 대기 열 을 비 웁 니 다.
비동기 실행 방법 추가 voidasync(Runnable_runnable):
void async(Runnable runnable) {
synchronized (asyncPool) {
asyncPool.offer(runnable);
if (!asyncActive) {
asyncActive = true;
if (!sendMessage(obtainMessage(ASYNC))) {
throw new GeniusException("Could not send handler message");
}
}
}
}
진입 방법 을 볼 수 있 습 니 다.첫 번 째 일 은 동기 화 상태 에 들 어간 다음 에 asyncPool.offer(runnable)를 호출 하 는 것 입 니 다.작업 을 대기 열 에 기록 하 다.
그 다음 에 현재 비동기 작업 수행 여 부 를 판단 합 니 다.그렇지 않 으 면 즉시 상 태 를 바 꾸 고 현재 Handler 에 메 시 지 를 보 냅 니 다.물론 표지 에 들 어 가 는 것 을 잊 지 마 세 요.
물론 효율 적 인 메 시 지 를 위 한 구조 도 obtainMessage(ASYNC)방법 을 통 해 이 루어 집 니 다.새로운 Message 를 만 들 고 현재 대기 열 에 남 은 메 시 지 를 사용 하기 위해 서 입 니 다.
동기 화 실행 방법 추가 voidsync(SyncPost_post):
void sync(SyncPost post) {
synchronized (syncPool) {
syncPool.offer(post);
if (!syncActive) {
syncActive = true;
if (!sendMessage(obtainMessage(SYNC))) {
throw new GeniusException("Could not send handler message");
}
}
}
}
여기 서 들 어 오 는 것 은 Runnable 이 아니 라 SyncPost 입 니 다.이 는 동기 화 를 위해 Runnable 을 한 번 패키지 한 클래스 입 니 다.소개
마찬가지 로 동기 화,추가,판단,메 시 지 를 보 냅 니 다.
퀘 스 트 수행 자@Overridevoid_handleMessage(Message_msg):
이것 은 복사 한 Handler 의 메시지 처리 방법 입 니 다.현재 Handler 메시지 대기 열 에 메시지 가 있 을 때 순서대로 이 방법 을 호출 합 니 다.
단계별 로 보면:
if (msg.what == ASYNC) {
boolean rescheduled = false;
try {
long started = SystemClock.uptimeMillis();
while (true) {
Runnable runnable = asyncPool.poll();
if (runnable == null) {
synchronized (asyncPool) {
// Check again, this time in synchronized
runnable = asyncPool.poll();
if (runnable == null) {
asyncActive = false;
return;
}
}
}
runnable.run();
long timeInMethod = SystemClock.uptimeMillis() - started;
if (timeInMethod >= maxMillisInsideHandleMessage) {
if (!sendMessage(obtainMessage(ASYNC))) {
throw new GeniusException("Could not send handler message");
}
rescheduled = true;
return;
}
}
} finally {
asyncActive = rescheduled;
}
}
들 어가 면 우선 비동기 처리 소식 인지,그렇다면 이 자리 에 들어간다.
들 어 와 서 저희 가 try 를 했 어 요.finally 변수 logstarted 는 시작 시간 을 표시 하 는 데 사 용 됩 니 다.
한 작업 을 수행 한 후 한 번 판단 합 니 다.주 스 레 드 를 사용 할 때마다 시간 제한 을 초과 하면 대기 열 에 있 는 작업 이 수행 되 든 안 되 든 종료 하고 Handler 순환 대기 열 에 새로운 메 시 지 를 보 냅 니 다.
while 부분 에서 우 리 는 대기 열 에서 임 무 를 꺼 내 폴 방법 을 사용 합 니 다.비어 있 는 지 여 부 를 판단 합 니 다.비어 있 는 대기 열 동기 화 블록 에 들 어가 면;그리고 다시 한 번 취하 여 다시 판단 한다.
공교롭게도 동기 화 대기 열 에 들 어가 기 전에 새로운 작업 이 왔 다 면 두 번 째 로 얻 은 것 은 당연히 NULL 이 아니 라 계속 실 행 될 것 이다.반대로 비어 있다 면;현재 대기 열의 상 태 를 false 로 초기 화하 고 순환 을 동시에 뛰 어 넘 습 니 다.
다음은 두 번 째 부분 을 살 펴 보 겠 습 니 다.
else if (msg.what == SYNC) {
boolean rescheduled = false;
try {
long started = SystemClock.uptimeMillis();
while (true) {
SyncPost post = syncPool.poll();
if (post == null) {
synchronized (syncPool) {
// Check again, this time in synchronized
post = syncPool.poll();
if (post == null) {
syncActive = false;
return;
}
}
}
post.run();
long timeInMethod = SystemClock.uptimeMillis() - started;
if (timeInMethod >= maxMillisInsideHandleMessage) {
if (!sendMessage(obtainMessage(SYNC))) {
throw new GeniusException("Could not send handler message");
}
rescheduled = true;
return;
}
}
} finally {
syncActive = rescheduled;
}
} else super.handleMessage(msg);
우선 동기 화 작업 메시지 가 들 어 오 는 지 판단 합 니 다.그렇지 않 으 면 슈퍼 handleMessage(msg)만 호출 합 니 다.됐어.
위의 처리 부분 에서 알 수 있 듯 이 그 처리 과정 은 첫 번 째 부분 과 완전히 같다 고 할 수 있다.
서로 다른 대기 열 에서 서로 다른 종류의 SyncPost 를 꺼 내 서 실행 을 판단 하고 서로 다른 표지 의 메 시 지 를 보 내 는 것 에 불과 합 니 다.첫 부분 을 알 게 되면 이 부분 은 영양 이 없다 고 할 수 있다.
여기 서 문제 가 있 습 니 다.방법 조작 절차 가 같은 이상 동기 화 와 비동기 화 는 어디서 구분 합 니까?
여기 SyncPost 를 봐 야 겠 어 요.
final class SyncPost {
boolean end = false;
Runnable runnable;
SyncPost(Runnable runnable) {
this.runnable = runnable;
}
public void run() {
synchronized (this) {
runnable.run();
end = true;
try {
this.notifyAll();
} catch (Exception e) {
e.printStackTrace();
}
}
}
public void waitRun() {
if (!end) {
synchronized (this) {
if (!end) {
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
}
먼저 SyncPost 의 구조 함 수 를 보십시오.
Runnable 인터페이스 로 들 어 가 는 거 아니 야?그 러 니까 Runnable 에 대한 간단 한 패키지.
그 public 를 볼 수 있 습 니 다.void_run()방법:
이 방법 에서 우 리 는 동기 블록 에 들 어간 후에 Runnable 인터페이스의 run 방법 을 호출 했다.동시에 실행 완료 후 상태 변 수 를 boolean 변경 하 였 습 니 다.end=true;
그리고 this.notifyAll()을 호출 합 니 다.기다 리 는 부분 은 계속 할 수 있 습 니 다.물론 이런 상황 이 있 습 니 다.이 동기 블록 에 들 어 갈 때 하위 스 레 드 가 this.wait()에 실행 되 지 않 았 다 면;부분 은 요?그래서 우 리 는 이 를 위해 end 와 try 를 준비 했다.
그리고 publicvoid_waitRun()방법:
이 중에서 우 리 는 먼저 상 태 를 판단 합 니 다.만약 상태 가 이미 변 했다 면 하위 스 레 드 가 여기까지 실 행 했 을 때 메 인 스 레 드 와 void 를 실 행 했 음 을 증명 합 니 다.run()。
그 러 니까 동기 블록 에 들 어가 서 기다 리 지 않 아 도 돼.그렇지 않 으 면 죽 을 때 까지 기다 릴 거 야?반대로 메 인 스 레 드 가 this.notifyAll()을 호출 할 때 까지 대기 합 니 다.
격정 부분
곧 완성 부분 에 들 어가 구성 이 완 선 됐 으 니 마지막 조립 을 해 야 한다.
클래스 classToolKit 로 돌아 가기
public class ToolKit {
private static HandlerPoster mainPoster = null;
private static HandlerPoster getMainPoster() {
if (mainPoster == null) {
synchronized (ToolKit.class) {
if (mainPoster == null) {
mainPoster = new HandlerPoster(Looper.getMainLooper(), 20);
}
}
}
return mainPoster;
}
/**
* Asynchronously
* The child thread asynchronous run relative to the main thread,
* not blocking the child thread
*
* @param runnable Runnable Interface
*/
public static void runOnMainThreadAsync(Runnable runnable) {
if (Looper.myLooper() == Looper.getMainLooper()) {
runnable.run();
return;
}
getMainPoster().async(runnable);
}
/**
* Synchronously
* The child thread relative thread synchronization operation,
* blocking the child thread,
* thread for the main thread to complete
*
* @param runnable Runnable Interface
*/
public static void runOnMainThreadSync(Runnable runnable) {
if (Looper.myLooper() == Looper.getMainLooper()) {
runnable.run();
return;
}
SyncPost poster = new SyncPost(runnable);
getMainPoster().sync(poster);
poster.waitRun();
}
public static void dispose() {
if (mainPoster != null) {
mainPoster.dispose();
mainPoster = null;
}
}
}
정적 변수 중 하나 입 니 다.Handler Poster
그리고 초기 화 부분 Handler PostergetMainPoster()는 다 중 스 레 드 동시 호출 상황 에 적응 하기 위해 동기 화 방식 으로 초기 화 합 니 다.물론 초기 화 할 때 저희 가 들 어 왔 죠.
mainPoster=newHandlerPoster(Looper.getMainLooper(),20); 메 인 스 레 드 에서 실행 되 는 HandlerPoster 를 결정 하 는 동시에 메 인 스 레 드 의 단일 실행 시간 을 20 밀리초 로 지정 합 니 다.
방법 voidrunOnMainThreadAsync(Runnable_runnable)중:
우선 이 방법 을 호출 하 는 것 이 메 인 스 레 드 인지 아 닌 지 를 판단 합 니 다.그렇다면 대열 에서 무엇 을 수행 하 시 겠 습 니까?직접 집행 하 라 고?하위 스 레 드 라면 getMainPoster().async(runnable)를 호출 합 니 다.대기 열 에 추가 하여 실행 합 니 다.
방법 voidrunOnMainThreadSync(Runnable_runnable)중:
public static void runOnMainThreadSync(Runnable runnable) {
if (Looper.myLooper() == Looper.getMainLooper()) {
runnable.run();
return;
}
SyncPost poster = new SyncPost(runnable);
getMainPoster().sync(poster);
poster.waitRun();
}
같은 스 레 드 판단 을 한 다음 에 패 키 징 을 한 다음 에 대기 열 에 던 져 서 실행 을 기다 리 고 이 방법 에서 poster.wait Run()을 호출 합 니 다.대기 하기;주 스 레 드 가 SyncPost 류 의 run 방법 을 실행 할 때 까지마지막 으로 당연히 소각 방법 을 남 겼 다.엄 마 는 쓰레기 를 남기 지 않 고 치 우 는 법 을 배 워 야 한다 고 말씀 하 셨 다.voiddispose()
OK,완 성 했 습 니 다.
// "Runnable" "run()"
// "run()" ,
// ,
ToolKit.runOnMainThreadSync(Runnable runnable);
// ,
ToolKit.runOnMainThreadAsync(Runnable runnable);
대외 적 으로 는 이렇게 두 가지 방법 이 있 습 니 다.간단 하고 편리 합 니 다.모두 해 보 세 요.한 글자 시원 하 다!
코드:코드 가 변경 되 어 이름 이 바 뀌 었 습 니 다.
UIKit.java
UIKitHandlerPoster.java
UIKitSyncPost.java
오픈 소스 항목:
Genius-Android
새로운 문장
[Android]임의의 시간 에 하위 스 레 드 에서 주 스 레 드 로 전환 하 는 실현 원리 및 강화 판
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 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에 따라 라이센스가 부여됩니다.