जब भी मेरे प्रसारण को निष्पादित किया जाता है तो मैं अग्रभूमि गतिविधि के प्रति सतर्क दिखाना चाहता हूं।
जब भी मेरे प्रसारण को निष्पादित किया जाता है तो मैं अग्रभूमि गतिविधि के प्रति सतर्क दिखाना चाहता हूं।
जवाबों:
यह जानते हुए कि ActivityManager का प्रबंधन करता है गतिविधि है, तो हम से जानकारी हासिल कर सकते हैं ActivityManager । हमें वर्तमान अग्रभूमि चल गतिविधि मिलती है
ActivityManager am = (ActivityManager)context.getSystemService(Context.ACTIVITY_SERVICE);
ComponentName cn = am.getRunningTasks(1).get(0).topActivity;
UPDATE 2018/10/03
getRunningTasks () का मूल्यांकन किया गया है। नीचे दिए गए समाधान देखें।
इस विधि को एपीआई स्तर 21 में पदावनत किया गया था। बिल्ड.VERSION_CODES.LOLLIPOP के रूप में, यह विधि अब तीसरे पक्ष के अनुप्रयोगों के लिए उपलब्ध नहीं है: दस्तावेज़-केंद्रित पुनरावृत्तियों की शुरूआत का अर्थ है कि यह व्यक्ति की जानकारी कॉलर को लीक कर सकता है। पीछे की संगतता के लिए, यह अभी भी अपने डेटा का एक छोटा सबसेट लौटाएगा: कम से कम कॉलर के स्वयं के कार्य, और संभवतः घर जैसे कुछ अन्य कार्य जो संवेदनशील नहीं होने के लिए जाने जाते हैं।
( नोट: एपीआई 14 में एक आधिकारिक एपीआई जोड़ा गया था: इस उत्तर को देखें https://stackoverflow.com/a/29786451/11973333 )
जवाब का उपयोग न करें (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();
WeakReferences
एंड्रॉइड में उपयोग करने के लिए कभी भी पुनर्संयोजन नहीं होगा जीसी उन्हें तेजी से इकट्ठा करता है फिर आप सोचते हैं।
WeakReference
कैशिंग के लिए करने की सलाह नहीं दी जाती है, यह कैशिंग नहीं है, यह mCurrentActivity
इच्छाशक्ति का केवल तभी संदर्भ होगा जब यह जीवित हो इसलिए शीर्ष पर WeakReference
रहते हुए कभी भी एकत्र नहीं किया जाएगा Activity
। हालाँकि जो @NachoColoma का सुझाव गलत है, क्योंकि WeakReference
यदि अभी तक वेरिएबल क्लियर नहीं किया गया है, तो एक गैर- रेज़्यूमे (जीवित / शीर्ष पर नहीं) गतिविधि को संदर्भित कर सकता है!
Application .ActivityLifecycleCallbacks
, जो अधिक केंद्रीय होगा और आपको अपनी सभी गतिविधियों में कोई प्रबंधन कोड नहीं जोड़ना होगा। इसके अलावा developer.android.com/reference/android/app/…
मैं @ जेज़्डी के उत्तर के शीर्ष पर विस्तार करता हूं।
प्रत्येक गतिविधियों में, Application
मैनुअल कोडिंग के साथ खुद को "पंजीकृत" करने के बजाय , हम निम्न एपीआई का उपयोग 14 के स्तर से कर सकते हैं, जिससे हमें कम मैनुअल कोडिंग के साथ समान उद्देश्य प्राप्त करने में मदद मिल सके।
public void registerActivityLifecycleCallbacks (Application.ActivityLifecycleCallbacks callback)
में Application.ActivityLifecycleCallbacks
, आप इसे Activity
"संलग्न" या "अलग" कर सकते हैं Application
।
हालाँकि, यह तकनीक केवल एपीआई स्तर 14 के बाद से उपलब्ध है।
implements Application.ActivityLifecycleCallbacks
, और इसे लागू करने के तरीके जोड़ते हैं। फिर उस वर्ग के कंस्ट्रक्टर (या onCreate या init या अन्य विधि जो कि उस समय चलती है जब उदाहरण सक्रिय / तैयार हो रहा है), getApplication().registerActivityLifecycleCallbacks(this);
अंतिम पंक्ति के रूप में रखा जाता है।
अपडेट 2 : इसके लिए एक आधिकारिक एपि जोड़ा गया है, कृपया इसके बजाय एक्टिविटी लाइफ़साइकल कॉलबैक का उपयोग करें ।
अपडेट करें:
जैसा कि @gezdy ने बताया है, और मैं इसके लिए आभारी हूं। वर्तमान गतिविधि के लिए भी अशक्त करने के लिए संदर्भ सेट करें , केवल हर onResume को अपडेट करने के बजाय इसे मेमोरी लीक समस्या से बचने के लिए प्रत्येक गतिविधि के onDestroy पर शून्य करने के लिए सेट करें।
कुछ समय पहले मुझे उसी कार्यक्षमता की आवश्यकता थी और यहाँ विधि है कि मैंने इसे कैसे प्राप्त किया। आपकी हर गतिविधि में इन जीवन चक्र विधियों को ओवरराइड किया जाता है।
@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);
}
अब अपने प्रसारण वर्ग में आप इस पर सतर्कता दिखाने के लिए वर्तमान गतिविधि तक पहुँच सकते हैं।
Application
केवल एक बार बनाया जाता है और कचरा कभी भी स्थिर चर की तरह एकत्र नहीं किया जाता है।
clearReferences()
जाए (this.equals(currActivity))
।
@lockwobr अपडेट के लिए धन्यवाद
यह एपीआई संस्करण 16 में समय का 100% काम नहीं करता है, यदि आप जीथब पर कोड पढ़ते हैं तो फ़ंक्शन "currentActivityThread" किटकैट में बदल गया था, इसलिए मैं संस्करण 19ish कहना चाहता हूं, गिटब में रिलीज के लिए एपीआई संस्करण से मिलान करने के लिए कठिन प्रकार ।
करंट तक पहुंच Activity
बहुत आसान है। क्या यह अच्छा होगा कि getActivity
कोई अनावश्यक प्रश्नों के साथ वर्तमान गतिविधि को वापस करने वाली एक स्थिर पद्धति हो?
Activity
वर्ग बहुत उपयोगी है। यह एप्लिकेशन के UI थ्रेड, व्यूज़, रिसोर्सेज और कई अन्य चीजों तक पहुंच देता है। कई तरीकों की आवश्यकता होती है Context
, लेकिन पॉइंटर कैसे प्राप्त करें? यहाँ कुछ तरीके हैं:
ActivityThread
। इस वर्ग की सभी गतिविधियों तक पहुँच है और, क्या बेहतर है, वर्तमान प्राप्त करने के लिए एक स्थिर तरीका है 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;
}
इस तरह की विधि का उपयोग ऐप में कहीं भी किया जा सकता है और यह सभी उल्लिखित दृष्टिकोणों की तुलना में बहुत अधिक सुविधाजनक है। इसके अलावा, ऐसा लगता है जैसे यह असुरक्षित नहीं है क्योंकि यह दिखता है। यह किसी भी नए संभावित लीक या अशक्त संकेत का परिचय नहीं देता है।
उपरोक्त कोड स्निपेट में अपवाद हैंडलिंग की कमी है और भोलेपन से माना जाता है कि पहली चलने वाली गतिविधि वह है जिसे हम खोज रहे हैं। आप कुछ अतिरिक्त चेक जोड़ना चाह सकते हैं।
Map
इसके बजाय इंटरफ़ेस का उपयोग करना चाहिए HashMap
या ArrayMap
। मैंने @AZ_ उत्तर संपादित किया है।
मैंने कोटलिन में फॉलो किया
निम्नानुसार एप्लिकेशन क्लास संपादित करें
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 में है।
(चूंकि यह सवाल शुरू में पूछा गया था, कई एंड्रॉइड ऐप में रिएक्टनवेटिव घटक भी है - हाइब्रिड ऐप।)
ReactNative में class ReactContext में mCurrentActivity को बनाए रखने के लिए तर्क का पूरा सेट है जो getCurrentActivity () में वापस आ जाता है।
नोट: मेरी इच्छा है कि एंड्रॉइड एप्लिकेशन क्लास में getCurrentActivity () लागू हो।
मुझे कोई समाधान नहीं मिला कि हमारी टीम खुश हो जाए इसलिए हमने अपना रोल किया। हम ActivityLifecycleCallbacks
वर्तमान गतिविधि का ट्रैक रखने के लिए उपयोग करते हैं और फिर एक सेवा के माध्यम से इसे उजागर करते हैं। अधिक विवरण यहां: https://stackoverflow.com/a/38650587/10793
पीछे की संगतता के लिए:
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;
}
WeakReference
से एक संभाल कर रख सकता है Application
- जबकि यह ComponentName
निर्धारित करना आवश्यक है कि क्या Activity
चल रहे कार्य सूची में शीर्ष पर है। और अगर यह पूरी तरह से सवाल का जवाब नहीं देता है, तो स्वीकृत जवाब या तो नहीं है।
topActivity
केवल Android Q
व्यक्तिगत रूप से मैंने "चेओक यान चेंग" के रूप में किया था, लेकिन मैंने अपनी सभी गतिविधियों का "बैकस्टैक" करने के लिए एक "सूची" का उपयोग किया।
यदि आप जांचना चाहते हैं कि वर्तमान गतिविधि कौन सी है तो आपको सूची में अंतिम गतिविधि वर्ग प्राप्त करना होगा।
एक एप्लिकेशन बनाएं जो "एप्लिकेशन" का विस्तार करता है और यह करें:
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() }
}
}
मेरे मामले में मैंने "Application.ActivityLifecycleCallbacks" का उपयोग किया:
Bind / Unbind मर्लिन इंस्टेंस (ऐप खो जाने या कनेक्शन प्राप्त होने पर ईवेंट प्राप्त करने के लिए उपयोग किया जाता है, उदाहरण के लिए जब आप मोबाइल डेटा बंद करते हैं या जब आप इसे खोलते हैं)। "OnConnectivityChanged" इरादे कार्रवाई अक्षम होने के बाद यह उपयोगी है। मर्लिन के बारे में अधिक जानकारी के लिए देखें: मर्लिन जानकारी लिंक
जब एप्लिकेशन बंद हो जाए तो मेरा अंतिम क्षेत्र बंद करें; मैं इसे एक बेसएक्टिविटी विच के अंदर डालूंगा जो अन्य सभी गतिविधियों से बढ़ा है और जिसमें एक निजी रियलमहेलर इंस्टेंस है। REALM के बारे में अधिक जानकारी के लिए देखें: REALM INFO LINK उदाहरण के लिए मेरे पास मेरे "RealmHelper" वर्ग के अंदर एक स्थिर "RealmHelper" उदाहरण है, जो कि मेरे आवेदन "onCreate" के अंदर त्वरित है। मेरे पास एक सिंक्रनाइज़ेशन सेवा है, जिसमें मैं नया "RealmHelper" बनाता हूं क्योंकि Realm "थ्रेड-लिंक्ड" है और एक Realm इंस्टेंस एक अलग थ्रेड के अंदर काम नहीं कर सकता है। तो रियलम डॉक्युमेंटेशन का अनुसरण करने के लिए "आपको सिस्टम रिसोर्स लीक्स से बचने के लिए सभी ओपन रियलिटी इंस्टेंस को बंद करने की आवश्यकता है", इस चीज को पूरा करने के लिए मैंने "Application.ActivityLifecycleCallbacks" का उपयोग किया जैसा कि आप देख सकते हैं।
अंत में मेरे पास एक रिसीवर विच होता है जब मैं अपने एप्लिकेशन को सिंक्रनाइज़ करने के लिए समाप्त हो जाता हूं, तो जब सिंक अंत यह "IEndSyncCallback" "onEndSync" विधि को कॉल करेगा, जिसमें मुझे लगता है कि क्या मुझे अपने एक्टिविटीबैकस्टैक लिस्ट के अंदर एक विशिष्ट गतिविधि है क्योंकि मुझे इसकी आवश्यकता है यदि सिंक सिंक ने उन्हें अपडेट किया है, तो डेटा को अपडेट करने के लिए और मुझे ऐप सिंक के बाद दूसरों के ऑपरेशन करने की आवश्यकता हो सकती है।
बस, उम्मीद है कि यह मददगार होगा। फिर मिलते हैं :)
वकास 716 द्वारा जवाब अच्छा है। मैंने कम कोड और रखरखाव की मांग के लिए एक विशिष्ट मामले के लिए एक वैकल्पिक हल बनाया।
मुझे एक विशिष्ट काम मिला जिसमें एक स्थिर विधि द्वारा अग्रभूमि में होने वाली संदिग्ध गतिविधि से एक दृश्य प्राप्त किया गया। आप सभी गतिविधियों के माध्यम से पुनरावृत्ति कर सकते हैं और जांच सकते हैं कि क्या आप मार्टिन के उत्तर से गतिविधि का नाम चाहते हैं या प्राप्त कर सकते हैं
ActivityManager am = (ActivityManager)context.getSystemService(Context.ACTIVITY_SERVICE);
ComponentName cn = am.getRunningTasks(1).get(0).topActivity;
मैं तब जांचता हूं कि क्या दृश्य अशक्त नहीं है और 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"));
}
getRunningTasks
: डेवलपर."Note: this method is only intended for debugging and presenting task management user interfaces. This should never be used for core logic in an application, ..."
मुझे कोई अन्य उत्तर पसंद नहीं है। एक्टिविटी मैनजर का उपयोग वर्तमान गतिविधि को प्राप्त करने के लिए किया जाना नहीं है। सुपर क्लासिंग और ऑनडेस्ट्रॉय पर निर्भर करता है भी नाजुक और सबसे अच्छा डिजाइन नहीं है।
ईमानदारी से, मैं अब तक का सबसे अच्छा काम कर रहा हूं, बस अपने एप्लिकेशन में एक एनम को बनाए रख रहा हूं, जो एक गतिविधि बनने पर सेट हो जाता है।
एक और सिफारिश यदि संभव हो तो कई गतिविधियों का उपयोग करने से दूर रहना चाहिए। यह या तो टुकड़ों का उपयोग करके किया जा सकता है, या मेरी प्राथमिकता में कस्टम दृश्य।
एक सरल समाधान एक एकल प्रबंधक वर्ग बनाना है, जिसमें आप एक या एक से अधिक गतिविधियों के संदर्भ में स्टोर कर सकते हैं, या कुछ और जिसे आप पूरे ऐप तक पहुंच चाहते हैं।
कॉल UberManager.getInstance().setMainActivity( activity );
मुख्य गतिविधि के ऑनक्रीट में ।
कॉल UberManager.getInstance().getMainActivity();
इसे पुनः प्राप्त करने के लिए अपने ऐप में कहीं भी । (मैं इसका उपयोग गैर यूआई थ्रेड से टोस्ट का उपयोग करने में सक्षम होने के लिए कर रहा हूं।)
सुनिश्चित करें कि 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 () .String ()" में आपके पैकेज का नाम और आपकी गतिविधि के किसी भी इरादे वाले फ़िल्टर जैसे अन्य पाठ का एक समूह शामिल है। तकनीकी रूप से हम वर्तमान इरादे की जाँच कर रहे हैं, गतिविधि की नहीं, बल्कि परिणाम वही है। जैसे कि Log.d ("test", getIntent () .String ()) का उपयोग करें; यदि आप सभी पाठ देखना चाहते हैं। यह सॉल्यूशन थोड़ा हैकी है, लेकिन यह आपके कोड में बहुत क्लीनर है और कार्यक्षमता समान है।