[android] 안드로이드에서 현재 전경 활동 컨텍스트를 얻는 방법?
내 방송이 실행될 때마다 포 그라운드 활동에 경고를 표시하고 싶습니다.
답변
알면 ActivityManager가 관리하는 활동을 , 그래서 우리는 정보 얻을 수 ActivityManager를 . 우리는 현재 포 그라운드에서 활동을 실행합니다.
ActivityManager am = (ActivityManager)context.getSystemService(Context.ACTIVITY_SERVICE);
ComponentName cn = am.getRunningTasks(1).get(0).topActivity;
업데이트 2018/10/03
getRunningTasks ()가 더 이상 사용되지 않습니다. 아래 솔루션을 참조하십시오.
이 메소드는 API 레벨 21에서 더 이상 사용되지 않습니다. Build.VERSION_CODES.LOLLIPOP부터이 메소드는 더 이상 써드 파티 애플리케이션에서 사용할 수 없습니다. 문서 중심의 최근 통화가 도입되면 발신자에게 개인 정보가 유출 될 수 있습니다. 이전 버전과의 호환성을 위해 최소한 발신자의 자체 작업과 민감한 것으로 알려진 집과 같은 다른 작업의 데이터의 작은 하위 집합을 반환합니다.
답변
( 참고 : API 14에 공식 API가 추가되었습니다 : https://stackoverflow.com/a/29786451/119733 참조 )
이전 (waqas716) 답변을 사용하지 마십시오.
활동에 대한 정적 참조로 인해 메모리 누수 문제가 발생합니다. 자세한 내용은 다음 링크를 참조 하십시오 http://android-developers.blogspot.fr/2009/01/avoiding-memory-leaks.html
이를 피하려면 활동 참조를 관리해야합니다. 매니페스트 파일에 응용 프로그램 이름을 추가하십시오.
<application
android:name=".MyApp"
....
</application>
응용 프로그램 클래스 :
public class MyApp extends Application {
public void onCreate() {
super.onCreate();
}
private Activity mCurrentActivity = null;
public Activity getCurrentActivity(){
return mCurrentActivity;
}
public void setCurrentActivity(Activity mCurrentActivity){
this.mCurrentActivity = mCurrentActivity;
}
}
새로운 활동 만들기 :
public class MyBaseActivity extends Activity {
protected MyApp mMyApp;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mMyApp = (MyApp)this.getApplicationContext();
}
protected void onResume() {
super.onResume();
mMyApp.setCurrentActivity(this);
}
protected void onPause() {
clearReferences();
super.onPause();
}
protected void onDestroy() {
clearReferences();
super.onDestroy();
}
private void clearReferences(){
Activity currActivity = mMyApp.getCurrentActivity();
if (this.equals(currActivity))
mMyApp.setCurrentActivity(null);
}
}
따라서 활동에 대한 활동 클래스를 확장하는 대신 MyBaseActivity를 확장하십시오. 이제 응용 프로그램 또는 다음과 같은 활동 컨텍스트에서 현재 활동을 가져올 수 있습니다.
Activity currentActivity = ((MyApp)context.getApplicationContext()).getCurrentActivity();
답변
@gezdy의 답변 맨 위로 확장합니다.
모든 활동에서 Application
수동 코딩으로 자체를 “등록”하는 대신 레벨 14 이후로 다음 API를 사용하여 수동 코딩을 줄이면서 유사한 목적을 달성 할 수 있습니다.
public void registerActivityLifecycleCallbacks (Application.ActivityLifecycleCallbacks callback)
에서 Application.ActivityLifecycleCallbacks
, Activity
“연결된”또는 “분리 된”을 얻을 수 있습니다.Application
.
그러나이 기술은 API 레벨 14 이후에만 사용 가능합니다.
답변
업데이트 2 : 공식 API가 추가되었으므로 ActivityLifecycleCallbacks를 대신 사용하십시오 .
최신 정보:
@gezdy가 지적한 것처럼, 나는 그것에 대해 감사합니다. 모든 onResume을 업데이트하는 대신 현재 활동에 대해 참조를 null로 설정하여 메모리 누수 문제를 피하기 위해 모든 onResume에서 null로 설정하십시오.
얼마 전 나는 같은 기능이 필요했으며 여기에 내가 달성 한 방법이 있습니다. 모든 활동에서 이러한 수명주기 방법을 대체하십시오.
@Override
protected void onResume() {
super.onResume();
appConstantsObj.setCurrentActivity(this);
}
@Override
protected void onPause() {
clearReferences();
super.onPause();
}
@Override
protected void onDestroy() {
clearReferences();
super.onDestroy();
}
private void clearReferences(){
Activity currActivity = appConstantsObj.getCurrentActivity();
if (this.equals(currActivity))
appConstantsObj.setCurrentActivity(null);
}
이제 방송 클래스에서 현재 활동에 액세스하여 경고를 표시 할 수 있습니다.
답변
@lockwobr 업데이트 해 주셔서 감사합니다
github에서 코드를 읽으면 Kitcurrent에서 “currentActivityThread”함수가 변경되었으므로 api 버전 16에서 100 % 작동하지 않습니다. 따라서 버전 19ish라고 말하고 싶습니다. .
전류에 접근하는 Activity
것이 매우 편리합니다. getActivity
불필요한 질문없이 현재 활동을 반환 하는 정적 메소드 를 갖는 것이 좋지 않습니까?
Activity
클래스는 매우 유용하다. 응용 프로그램의 UI 스레드, 뷰, 리소스 등에 액세스 할 수 있습니다. 수많은 메소드가 필요 Context
하지만 포인터를 얻는 방법은 무엇입니까? 몇 가지 방법이 있습니다.
- 재정의 된 수명주기 방법을 사용하여 응용 프로그램의 상태를 추적합니다. 현재 활동을 정적 변수에 저장해야하며 모든 활동의 코드에 액세스해야합니다.
- 인스 트루먼 테이션을 사용하여 애플리케이션 상태 추적 매니페스트에서 인스 트루먼 테이션을 선언하고 구현 한 후 해당 메소드를 사용하여 활동 변경 사항을 추적하십시오. 활동에 사용 된 메소드 및 클래스에 활동 포인터 전달 코드 삽입 라이브러리 중 하나를 사용하여 포인터를 주입합니다. 이러한 모든 접근 방식은 다소 불편합니다 . 운 좋게도 현재 활동을 얻는 훨씬 쉬운 방법이 있습니다.
- 위에서 언급 한 문제없이 시스템이 모든 활동에 액세스해야하는 것 같습니다. 따라서 정적 호출 만 사용하여 활동을 얻는 방법이있을 수 있습니다. grepcode.com의 Android 소스를 파고 많은 시간을 보냈으며 찾고 있던 것을 발견했습니다. 라는 클래스가 있습니다
ActivityThread
있습니다. 이 클래스는 모든 활동에 액세스 할 수 있으며 더 나은 것은 current를 얻는 정적 메소드를 가지고ActivityThread
있습니다. 한 가지 작은 문제가 있습니다. 활동 목록에는 패키지 액세스 권한이 있습니다.
리플렉션을 사용하여 쉽게 해결 :
public static Activity getActivity() {
Class activityThreadClass = Class.forName("android.app.ActivityThread");
Object activityThread = activityThreadClass.getMethod("currentActivityThread").invoke(null);
Field activitiesField = activityThreadClass.getDeclaredField("mActivities");
activitiesField.setAccessible(true);
Map<Object, Object> activities = (Map<Object, Object>) activitiesField.get(activityThread);
if (activities == null)
return null;
for (Object activityRecord : activities.values()) {
Class activityRecordClass = activityRecord.getClass();
Field pausedField = activityRecordClass.getDeclaredField("paused");
pausedField.setAccessible(true);
if (!pausedField.getBoolean(activityRecord)) {
Field activityField = activityRecordClass.getDeclaredField("activity");
activityField.setAccessible(true);
Activity activity = (Activity) activityField.get(activityRecord);
return activity;
}
}
return null;
}
이러한 방법은 앱의 어느 곳에서나 사용할 수 있으며 언급 된 모든 방법보다 훨씬 편리합니다. 또한 보이는 것만 큼 안전하지 않은 것 같습니다. 새로운 잠재적 누출이나 널 포인터를 도입하지 않습니다.
위의 코드 스 니펫에는 예외 처리가 없으며 첫 번째 실행중인 활동이 우리가 찾고있는 활동이라고 순진하게 가정합니다. 추가 검사를 추가 할 수도 있습니다.
답변
나는 Kotlin에서 다음을 수행했습니다.
- 응용 프로그램 클래스 만들기
-
다음과 같이 응용 프로그램 클래스 편집
class FTApplication: MultiDexApplication() { override fun attachBaseContext(base: Context?) { super.attachBaseContext(base) MultiDex.install(this) } init { instance = this } val mFTActivityLifecycleCallbacks = FTActivityLifecycleCallbacks() override fun onCreate() { super.onCreate() registerActivityLifecycleCallbacks(mFTActivityLifecycleCallbacks) } companion object { private var instance: FTApplication? = null fun currentActivity(): Activity? { return instance!!.mFTActivityLifecycleCallbacks.currentActivity } } }
-
ActivityLifecycleCallbacks 클래스 만들기
class FTActivityLifecycleCallbacks: Application.ActivityLifecycleCallbacks { var currentActivity: Activity? = null override fun onActivityPaused(activity: Activity?) { currentActivity = activity } override fun onActivityResumed(activity: Activity?) { currentActivity = activity } override fun onActivityStarted(activity: Activity?) { currentActivity = activity } override fun onActivityDestroyed(activity: Activity?) { } override fun onActivitySaveInstanceState(activity: Activity?, outState: Bundle?) { } override fun onActivityStopped(activity: Activity?) { } override fun onActivityCreated(activity: Activity?, savedInstanceState: Bundle?) { currentActivity = activity } }
-
이제 다음을 호출하여 모든 클래스에서 사용할 수 있습니다.
FTApplication.currentActivity()
답변
getCurrentActivity ()도 ReactContextBaseJavaModule에 있습니다.
(이 질문은 처음에 요청되었으므로 많은 Android 앱에도 ReactNative 구성 요소-하이브리드 앱이 있습니다.)
ReactNative의 ReactContext 클래스는 getCurrentActivity ()에 반환되는 mCurrentActivity를 유지하기위한 전체 로직 세트를 갖습니다.
참고 : getCurrentActivity ()가 Android Application 클래스에서 구현되기를 바랍니다.