programing

안드로이드에서 현재 전경 활동 컨텍스트를 얻는 방법은 무엇입니까?

linuxpc 2023. 8. 29. 20:11
반응형

안드로이드에서 현재 전경 활동 컨텍스트를 얻는 방법은 무엇입니까?

내 방송이 실행될 때마다 전경 활동에 대한 경고를 표시하고 싶습니다.

(참고: 공식 API는 API 14에 추가되었습니다: 이 답변을 참조하십시오. 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);
    }
}

이제 활동에 대한 활동 클래스를 확장하는 대신 내 기본 활동을 확장하십시오.이제 애플리케이션 또는 활동 컨텍스트에서 다음과 같은 현재 활동을 가져올 수 있습니다.

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 이후에만 사용할 수 있습니다.

업데이트 3: 이를 위한 공식 API가 추가되었습니다. 대신 ActivityLifeCycleCallback을 사용하십시오.

활동 관리자가 활동을 관리하므로 활동 관리자로부터 정보를 얻을 수 있습니다.현재 진행 중인 활동을 다음과 같이 가져옵니다.

ActivityManager am = (ActivityManager)context.getSystemService(Context.ACTIVITY_SERVICE);
ComponentName cn = am.getRunningTasks(1).get(0).topActivity;

201803 2018/10/03 입니다.
getRunningTasks()는 더 이상 사용되지 않습니다. 아래 솔루션을 참조하십시오.

이 방법은 API 레벨 21에서 더 이상 사용되지 않습니다.빌드 기준.버전_코드.롤리팝, 이 방법은 더 이상 타사 응용 프로그램에서 사용할 수 없습니다. 문서 중심 최근의 도입은 발신자에게 개인 정보를 유출할 수 있음을 의미합니다.이전 버전과의 호환성을 위해 최소한 호출자 자신의 작업 및 민감하지 않은 것으로 알려진 집과 같은 일부 다른 작업과 같은 데이터의 하위 집합을 여전히 반환합니다.

코틀린에서 다음을 수행했습니다.

  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. ActivityLifecycleCallback 클래스를 만듭니다.

    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에 .
제기된 구성 요소 - 앱이

ReactNative의 클래스 ReactContext에는 getCurrentActivity()에서 반환되는 mCurrentActivity를 유지하기 위한 전체 논리 집합이 있습니다.

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

이전 버전과의 호환성:

ComponentName cn;
ActivityManager am = (ActivityManager) getApplicationContext().getSystemService(Context.ACTIVITY_SERVICE);
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
    cn = am.getAppTasks().get(0).getTaskInfo().topActivity;
} else {
    //noinspection deprecation
    cn = am.getRunningTasks(1).get(0).topActivity;
}

저는 우리 팀이 만족할 만한 해결책을 찾지 못해서 각자 해결책을 제시했습니다.우리는 사용합니다.ActivityLifecycleCallbacks현재 활동을 추적한 다음 서비스를 통해 노출합니다.자세한 내용은 여기에서 확인하십시오. https://stackoverflow.com/a/38650587/10793

코드의 이 부분을 사용하면 앱이 백그라운드/포그라운드로 이동할 때 탐지하고 현재 활동 이름과 컨텍스트에 액세스할 수 있습니다.

제 대답은 다음 기사를 기반으로 합니다: Android: 앱이 백그라운드/포그라운드로 이동할 때 탐지하는 방법

먼저, 다음을 확장하는 클래스를 만듭니다.android.app.Application을 구현합니다.ActivityLifecycleCallbacks인터페이스에서Application.onCreate()콜백을 등록합니다.

public class App extends Application implements ActivityLifecycleCallbacks
@Override
public void onCreate() {
    super.onCreate();
    registerActivityLifecycleCallbacks(this);
}

아래와 같이 매니페스트에 "App" 클래스를 등록합니다.

<application
    android:name=".App"

ActivityLifeCycleCallbacks 인터페이스는 다음과 같습니다.

public interface ActivityLifecycleCallbacks {
    void onActivityCreated(Activity activity, Bundle savedInstanceState);
    void onActivityStarted(Activity activity);
    void onActivityResumed(Activity activity);
    void onActivityPaused(Activity activity);
    void onActivityStopped(Activity activity);
    void onActivitySaveInstanceState(Activity activity, Bundle outState);
    void onActivityDestroyed(Activity activity);
}

따라서 라이브러리에서 작성하거나 포함한 활동(사용자가 작성한 활동)이 위에서 언급한 라이프사이클 방법 중 하나를 거치면 이러한 콜백이 호출됩니다.앱이 포그라운드에 있을 때 시작된 상태에 하나 이상의 활동이 있고 앱이 백그라운드에 있을 때 시작된 상태에 있는 활동이 없습니다."App" 클래스에서 아래와 같이 변수 2개를 선언합니다.

private int activityReferences = 0;
private boolean isActivityChangingConfigurations = false;

활동 참조는 시작된 상태의 활동 수를 유지합니다.isActivityChangingConfigurations는 현재 활동이 방향 전환과 같은 구성 변경을 겪고 있는지 여부를 나타내는 플래그입니다.다음 코드를 사용하여 앱이 전경인지 감지할 수 있습니다.

@Override
public void onActivityStarted(Activity activity) {
    if (++activityReferences == 1 && !isActivityChangingConfigurations) {
        // App enters foreground
    }
}

다음과 같은 방법으로 컨텍스트에 액세스할 수 있습니다.

activity.getBaseContext()

앱이 백그라운드로 실행되는지 탐지하는 방법입니다.

Override
public void onActivityStopped(Activity activity) {

    isActivityChangingConfigurations = activity.isChangingConfigurations();
    if (--activityReferences == 0 && !isActivityChangingConfigurations) {
        // App enters background
    }
}

이제 현재 전경 활동 이름과 컨텍스트에 액세스할 수 있습니다.

개인적으로 저는 "척옌청"이 말한 대로 했지만, 저는 제 모든 활동에 대한 "백스택"을 갖기 위해 "리스트"를 사용했습니다.

현재 활동을 선택하려면 목록의 마지막 활동 클래스를 가져오면 됩니다.

"응용프로그램"을 확장하는 응용프로그램을 만들고 다음 작업을 수행합니다.

public class MyApplication extends Application implements Application.ActivityLifecycleCallbacks,
EndSyncReceiver.IEndSyncCallback {

private List<Class> mActivitiesBackStack;
private EndSyncReceiver mReceiver;
    private Merlin mMerlin;
    private boolean isMerlinBound;
    private boolean isReceiverRegistered;

@Override
    public void onCreate() {
        super.onCreate();
        [....]
RealmHelper.initInstance();
        initMyMerlin();
        bindMerlin();
        initEndSyncReceiver();
        mActivitiesBackStack = new ArrayList<>();
    }

/* START Override ActivityLifecycleCallbacks Methods */
    @Override
    public void onActivityCreated(Activity activity, Bundle bundle) {
        mActivitiesBackStack.add(activity.getClass());
    }

    @Override
    public void onActivityStarted(Activity activity) {
        if(!isMerlinBound){
            bindMerlin();
        }
        if(!isReceiverRegistered){
            registerEndSyncReceiver();
        }
    }

    @Override
    public void onActivityResumed(Activity activity) {

    }

    @Override
    public void onActivityPaused(Activity activity) {

    }

    @Override
    public void onActivityStopped(Activity activity) {
        if(!AppUtils.isAppOnForeground(this)){
            if(isMerlinBound) {
                unbindMerlin();
            }
            if(isReceiverRegistered){
                unregisterReceiver(mReceiver);
            }
            if(RealmHelper.getInstance() != null){
                RealmHelper.getInstance().close();
                RealmHelper.getInstance().logRealmInstanceCount("AppInBackground");
                RealmHelper.setMyInstance(null);
            }
        }
    }

    @Override
    public void onActivitySaveInstanceState(Activity activity, Bundle bundle) {

    }

    @Override
    public void onActivityDestroyed(Activity activity) {
        if(mActivitiesBackStack.contains(activity.getClass())){
            mActivitiesBackStack.remove(activity.getClass());
        }
    }
    /* END Override ActivityLifecycleCallbacks Methods */

/* START Override IEndSyncCallback Methods */
    @Override
    public void onEndSync(Intent intent) {
        Constants.SyncType syncType = null;
        if(intent.hasExtra(Constants.INTENT_DATA_SYNC_TYPE)){
            syncType = (Constants.SyncType) intent.getSerializableExtra(Constants.INTENT_DATA_SYNC_TYPE);
        }
        if(syncType != null){
            checkSyncType(syncType);
        }
    }
    /* END IEndSyncCallback Methods */

private void checkSyncType(Constants.SyncType){
    [...]
    if( mActivitiesBackStack.contains(ActivityClass.class) ){
         doOperation()     }
}

}

제 경우에는 "애플리케이션"을 사용했습니다.활동 라이프사이클 콜백" 목적:

  • Merlin 인스턴스 바인딩/바인딩 해제(예: 모바일 데이터를 닫거나 열 때 앱이 연결을 잃거나 연결이 끊어질 때 이벤트를 가져오는 데 사용됨).이 기능은 "OnConnectivityChanged" 의도 작업이 비활성화된 후에 유용합니다.MERLIN에 대한 자세한 내용은 MERLIN INFO LINK를 참조하십시오.

  • 응용프로그램이 닫힐 때 마지막 영역 인스턴스를 닫습니다. 다른 모든 활동에서 확장되고 개인 영역이 있는 기본 활동 내에서 해당 영역 인스턴스를 시작합니다.도우미 인스턴스입니다.RREAL에 대한 자세한 내용은 RREAL INFO LINK를 참조하십시오. 예를 들어, 저는 정적인 "REALM"을 가지고 있습니다.내 "레임" 내 "헬퍼" 인스턴스내 응용프로그램 "생성 시" 내부에서 인스턴스화되는 "도움말" 클래스입니다.새로운 "레름"을 생성하는 동기화 서비스가 있습니다.영역이 "스레드 연결"이고 영역 인스턴스가 다른 스레드 내에서 작동할 수 없기 때문에 도우미"입니다.따라서 Realm Documentation "시스템 리소스 유출을 방지하기 위해 열려 있는 모든 Realm 인스턴스를 닫아야 합니다"를 따르기 위해 "응용 프로그램"을 사용했습니다.위에 표시된 것처럼 활동 라이프사이클 콜백"을 선택합니다.

  • 마지막으로, 내가 내 애플리케이션 동기화를 완료할 때 트리거되는 수신기가 있습니다.그런 다음 동기화가 종료되면 "IEndSyncCallback" 메서드를 "onEndSync" 메서드로 호출합니다. 동기화가 해당 작업을 업데이트한 경우 보기의 데이터를 업데이트해야 하고 앱 동기화 후 다른 작업을 수행해야 할 수 있기 때문입니다.

그게 전부입니다. 이게 도움이 되길 바랍니다.다음에 봐요 :)

지금까지 최고의 솔루션 앱에 클래스 이름 ActivityManager 생성(자바)

public class ActivityManager implements Application.ActivityLifecycleCallbacks {

    private Activity activity;


    public ActivityManager(App myApplication) {
        myApplication.registerActivityLifecycleCallbacks(this);
    }

    public Activity getActivity(){
        return activity;
    }
    @Override
    public void onActivityCreated(@NonNull Activity activity, @Nullable Bundle bundle) {
        this. activity = activity;

    }

    @Override
    public void onActivityStarted(@NonNull Activity activity) {
       this. activity = activity;
    }

    @Override
    public void onActivityResumed(@NonNull Activity activity) {
        this. activity = activity;

    }

    @Override
    public void onActivityPaused(@NonNull Activity activity) {

    }

    @Override
    public void onActivityStopped(@NonNull Activity activity) {

    }

    @Override
    public void onActivitySaveInstanceState(@NonNull Activity activity, @NonNull Bundle bundle) {

    }

    @Override
    public void onActivityDestroyed(@NonNull Activity activity) {

    }
}

그런 다음 애플리케이션(kotlin)에서 초기화합니다.

class App : Application() {

    override fun onCreate() {
     
        appOpenManager =  AppOpenManager(this);
    }
  companion object {
        lateinit var appOpenManager: AppOpenManager
    }
}

그러면 다음과 같이 사용합니다.

App.activityManager.getActivity()

유연한 라이프사이클 처리를 위해 이 클래스를 사용할 수 있습니다.

용도:

    //Initialization
    val lifeCycleHandler = ActivityLifeCycleHandler<Activity>()

    //Detect only a specific type of activities
    val lifeCycleHandler = ActivityLifeCycleHandler<MainActivity>()

    //Get current activity
    val instance = lifeCycleHandler.currentReference

    //Get current activity state
    val state = lifeCycleHandler.currentState

    //Use listeners
    lifeCycleHandler.addStateChangeListener { newState ->
        //TODO: handle new state
    }

    lifeCycleHandler.addSpecificStateChangeListener(ActivityLifeCycleHandler.ActivityState.STARTED) {
        //TODO: handle new state
    }

    //Removable listeners
    val listener = { newState: Int ->

    }

    lifeCycleHandler.addStateChangeListener(listener)
    lifeCycleHandler.removeStateChageListener(listener)


    //Start listening
    App.app.registerActivityLifecycleCallbacks(lifeCycleHandler)

    //Stop listening
    lifeCycleHandler.releaseListeners()
    App.app.unregisterActivityLifecycleCallbacks(lifeCycleHandler)

코틀린을 사용하는 경우 현재 활동 이름을 가져오는 데 도움이 될 수 있습니다.그러나 getRecentTasks() 메서드는 Java에서 더 이상 사용되지 않습니다.

 val am: ActivityManager = applicationContext.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
 val activityName: String = am.getRecentTasks(1, 0).get(0).topActivity.toString()

waqas716의 답은 좋습니다.코드와 유지보수를 덜 요구하는 특정 사례에 대한 해결 방법을 만들었습니다.

저는 정적 방법을 사용하여 전경에 있는 것으로 의심되는 활동에서 보기를 가져와 특정 작업을 해결했습니다.모든 활동을 반복하고 활동 이름이 마틴의 답변에서 나오는지 여부를 확인할 수 있습니다.

ActivityManager am = (ActivityManager)context.getSystemService(Context.ACTIVITY_SERVICE);
ComponentName cn = am.getRunningTasks(1).get(0).topActivity; 

그런 다음 보기가 null이 아닌지 확인하고 getContext()를 통해 컨텍스트를 가져옵니다.

View v = SuspectedActivity.get_view();

if(v != null)
{
    // an example for using this context for something not 
    // permissible in global application context. 
    v.getContext().startActivity(new Intent("rubberduck.com.activities.SomeOtherActivity"));
}

을 합니다.is연산자 또는 그 부정형!is개체가 지정된 형식을 준수하는지 여부를 식별하는 런타임 검사를 수행합니다.

if (this !is OneActivity) {
// do something
} else if (this !is TwoActivity) {
// do something 2
}

저는 다른 어떤 대답도 좋아하지 않습니다.활동 관리자는 현재 활동을 가져오는 데 사용되지 않습니다.슈퍼클래싱과 디스트로이에 의존하는 것 또한 깨지기 쉽고 최고의 디자인은 아닙니다.

솔직히, 지금까지 생각해낸 것 중 가장 좋은 것은 활동이 작성될 때 설정되는 응용프로그램에 열거형을 유지하는 것입니다.

다른 권장 사항은 가능하면 여러 활동을 사용하는 것을 피하는 것입니다.이 작업은 조각을 사용하거나 기본 설정 사용자 정의 보기에서 수행할 수 있습니다.

좀 더 간단한 해결책은 하나 이상의 활동 또는 앱 전체에서 액세스할 수 있는 모든 활동에 대한 참조를 저장할 수 있는 싱글톤 관리자 클래스를 만드는 것입니다.

UberManager.getInstance().setMainActivity( activity );Create의 주요 활동에 있습니다.

UberManager.getInstance().getMainActivity();사용자의 앱 어디에서나 검색할 수 있습니다. (UI 스레드가 아닌 다른 스레드에서 토스트를 사용할 수 있도록 이 기능을 사용합니다.)

다에통화추합니다에 전화를 .UberManager.getInstance().cleanup();사용자의 앱이 파괴될 수 있습니다.

import android.app.Activity;

public class UberManager
{
    private static UberManager instance = new UberManager();

    private Activity mainActivity = null;

    private UberManager()
    {

    }

    public static UberManager getInstance()
    {
        return instance;
    }

    public void setMainActivity( Activity mainActivity )
    {
        this.mainActivity = mainActivity;
    }

    public Activity getMainActivity()
    {
        return mainActivity;
    }

    public void cleanup()
    {
        mainActivity = null;
    }
}

저는 3년 정도 늦었지만, 저처럼 누군가가 이것을 발견할 경우를 대비해 어쨌든 대답하겠습니다.

이 문제는 다음과 같이 간단히 해결되었습니다.

    if (getIntent().toString().contains("MainActivity")) {
        // Do stuff if the current activity is MainActivity
    }

"getIntent().toString()"에는 패키지 이름 및 활동에 대한 모든 의도 필터와 같은 다른 텍스트가 포함됩니다.기술적으로는 활동이 아닌 현재의 의도를 확인하고 있지만 결과는 같습니다.모든 텍스트를 보려면 Log.d("test", getIntent().toString() 등을 사용하십시오.이 솔루션은 약간 구식이지만 코드가 훨씬 깔끔하고 기능도 동일합니다.

언급URL : https://stackoverflow.com/questions/11411395/how-to-get-current-foreground-activity-context-in-android

반응형