[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)

http://developer.android.com/reference/android/app/Application.html#registerActivityLifecycleCallbacks%28android.app.Application.ActivityLifecycleCallbacks%29

에서 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에서 다음을 수행했습니다.

  1. 응용 프로그램 클래스 만들기
  2. 다음과 같이 응용 프로그램 클래스 편집

    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
        }
    }
    
     }
  3. 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
    }
    
    }
  4. 이제 다음을 호출하여 모든 클래스에서 사용할 수 있습니다. FTApplication.currentActivity()


답변

getCurrentActivity ()도 ReactContextBaseJavaModule에 있습니다.
(이 질문은 처음에 요청되었으므로 많은 Android 앱에도 ReactNative 구성 요소-하이브리드 앱이 있습니다.)

ReactNative의 ReactContext 클래스는 getCurrentActivity ()에 반환되는 mCurrentActivity를 유지하기위한 전체 로직 세트를 갖습니다.

참고 : getCurrentActivity ()가 Android Application 클래스에서 구현되기를 바랍니다.