ব্যাকগ্রাউন্ডে, আমি বলতে চাইছি অ্যাপ্লিকেশনটির কোনওটিই বর্তমানে ব্যবহারকারীর কাছে দৃশ্যমান নয়?
ব্যাকগ্রাউন্ডে, আমি বলতে চাইছি অ্যাপ্লিকেশনটির কোনওটিই বর্তমানে ব্যবহারকারীর কাছে দৃশ্যমান নয়?
উত্তর:
আপনার অ্যাপ্লিকেশনটি ব্যাকগ্রাউন্ডে চলছে কিনা তা সনাক্ত করার কয়েকটি উপায় রয়েছে তবে তাদের মধ্যে কেবল একটিই সম্পূর্ণ নির্ভরযোগ্য:
সঠিক সমাধান (ক্রেডিট যেতে ড্যান , CommonsWare এবং NeTeInStEiN )
নিজের দ্বারা আপনার অ্যাপ্লিকেশন ব্যবহার করে ট্র্যাক দৃশ্যমানতা Activity.onPause
, Activity.onResume
পদ্ধতি। অন্য কিছু শ্রেণিতে "দৃশ্যমানতা" স্থিতি সঞ্চয় করুন। ভাল পছন্দগুলি আপনার নিজের প্রয়োগ Application
বা একটি Service
( আপনি যদি পরিষেবা থেকে ক্রিয়াকলাপের দৃশ্যমানতা পরীক্ষা করতে চান তবে এই সমাধানের কয়েকটি ভিন্নতাও রয়েছে)।
উদাহরণ
কাস্টম Application
ক্লাস প্রয়োগ করুন ( isActivityVisible()
স্থির পদ্ধতিটি নোট করুন ):
public class MyApplication extends Application {
public static boolean isActivityVisible() {
return activityVisible;
}
public static void activityResumed() {
activityVisible = true;
}
public static void activityPaused() {
activityVisible = false;
}
private static boolean activityVisible;
}
আপনার অ্যাপ্লিকেশন ক্লাসটি এখানে নিবন্ধ করুন AndroidManifest.xml
:
<application
android:name="your.app.package.MyApplication"
android:icon="@drawable/icon"
android:label="@string/app_name" >
যোগ onPause
এবং onResume
প্রত্যেক করার Activity
প্রকল্পে (যদি আপনি চাই আপনি আপনার ক্রিয়াকলাপ জন্য একটি সাধারণ পূর্বপুরুষ তৈরি হতে পারে, কিন্তু যদি আপনার কার্যকলাপের ইতিমধ্যে থেকে প্রসারিত হয়েছে MapActivity
/ ListActivity
ইত্যাদি আপনি এখনও হাতে নিম্নলিখিত লিখতে প্রয়োজন):
@Override
protected void onResume() {
super.onResume();
MyApplication.activityResumed();
}
@Override
protected void onPause() {
super.onPause();
MyApplication.activityPaused();
}
আপডেট
অ্যাক্টিভিটি লাইফিসাইকেলক্যালব্যাকগুলি এপিআই স্তরের 14 (অ্যান্ড্রয়েড 4.0) এ যুক্ত হয়েছিল। আপনার অ্যাপ্লিকেশনটির কোনও ক্রিয়াকলাপ বর্তমানে ব্যবহারকারীর কাছে দৃশ্যমান কিনা তা ট্র্যাক করতে আপনি এগুলি ব্যবহার করতে পারেন। বিস্তারিত জানার জন্য নীচে কর্নস্টালকের উত্তর চেককরুন।
ভুল এক
আমি নিম্নলিখিত সমাধান সুপারিশ ব্যবহৃত:
আপনি বর্তমানে অগ্রভাগ / পটভূমি অ্যাপ্লিকেশন সনাক্ত করতে পারবেন
ActivityManager.getRunningAppProcesses()
যাRunningAppProcessInfo
রেকর্ডের একটি তালিকা দেয় returns যদি আপনার আবেদনটি ফোরগ্রাউন্ড চেক কিনা তা নির্ধারণ করতেRunningAppProcessInfo.importance
করতে সমতার জন্য ক্ষেত্রRunningAppProcessInfo.IMPORTANCE_FOREGROUND
যখনRunningAppProcessInfo.processName
আপনার আবেদন প্যাকেজের নাম সমান।এছাড়াও আপনি যদি
ActivityManager.getRunningAppProcesses()
আপনার অ্যাপ্লিকেশন UI থ্রেড থেকে কল করেন তবে এটিIMPORTANCE_FOREGROUND
আপনার কাজের জন্য গুরুত্বটি ফিরিয়ে দেবে তা প্রকৃতপক্ষে অগ্রভাগে রয়েছে কিনা তা। এটিকে পটভূমির থ্রেডে কল করুন (উদাহরণস্বরূপ মাধ্যমেAsyncTask
) এবং এটি সঠিক ফলাফল আসবে।
যদিও এই সমাধানটি কার্যকর হতে পারে (এবং এটি সত্যই বেশিরভাগ সময় কাজ করে) আমি দৃ strongly়ভাবে এটি ব্যবহার থেকে বিরত থাকার পরামর্শ দিই। এবং কেন এখানে। যেমন ডায়ান হ্যাকবোন লিখেছেন :
এই এপিআইগুলি অ্যাপ্লিকেশনগুলিতে তাদের ইউআই ফ্লোটি চালু করার জন্য নেই, তবে ব্যবহারকারীকে চলমান অ্যাপ্লিকেশনগুলি দেখানো বা কোনও টাস্ক ম্যানেজার, বা এ জাতীয় কিছু করার জন্য রয়েছে।
হ্যাঁ এই বিষয়গুলির জন্য স্মৃতিতে রাখা একটি তালিকা রয়েছে। তবে এটি অন্য প্রক্রিয়াতে বন্ধ রয়েছে, আপনার থেকে পৃথকভাবে চলমান থ্রেডগুলি পরিচালনা করে এবং আপনি (ক) সঠিক সিদ্ধান্ত নেওয়ার জন্য সময় দেখে বা (খ) আপনি ফিরে আসার সাথে ধারাবাহিক চিত্র রাখার মতো কিছু নয়। এছাড়াও "পরবর্তী" ক্রিয়াকলাপটি কী যাবেন সে সম্পর্কে সিদ্ধান্তটি সর্বদা সেই স্থানে করা হয় যেখানে স্যুইচটি ঘটতে হবে, এবং এটি সঠিক বিন্দু (যেখানে ক্রিয়াকলাপের স্ট্যান্ডটি সংক্ষেপে স্যুইচটি করতে লক করা আছে) না হওয়া পর্যন্ত আমরা তা করি না পরের জিনিসটি কী হবে তা নিশ্চিতভাবেই জানেন know
এবং এখানে বাস্তবায়ন এবং বৈশ্বিক আচরণ ভবিষ্যতে একই থাকার গ্যারান্টিযুক্ত নয়।
আশা করি এসও-তে কোনও উত্তর পোস্ট করার আগে আমি এটি পড়েছি তবে আশা করি আমার ত্রুটিটি স্বীকার করতে খুব বেশি দেরি হয়নি।
এর আরেকটি ভুল সমাধান
ড্রয়েড-ফু গ্রন্থাগার ActivityManager.getRunningTasks
তার isApplicationBroughtToBackground
পদ্ধতির জন্য একটির উত্তরে উল্লেখ করেছে । উপরে ডায়ান্নের মন্তব্য দেখুন এবং সেই পদ্ধতিটি ব্যবহার করবেন না।
OnStop
অনুরোধে isActivityVisible
।
ব্যবহারকারী 1269737 এর উত্তর হ'ল এটি করার উপযুক্ত (গুগল / অ্যান্ড্রয়েড অনুমোদিত) উপায় । তাদের উত্তর পড়ুন এবং তাদের একটি +1 দিন।
উত্তরসূরির জন্য আমি এখানে আমার আসল উত্তরটি রেখে যাব। এটি ২০১২ সালে সবচেয়ে ভাল উপলভ্য ছিল তবে এখন এর জন্য অ্যান্ড্রয়েডের উপযুক্ত সমর্থন রয়েছে support
কীটি ব্যবহার করছে ActivityLifecycleCallbacks
(নোট করুন এটির জন্য অ্যান্ড্রয়েড এপিআই স্তর 14 (অ্যান্ড্রয়েড 4.0)) দরকার। বন্ধ হওয়া ক্রিয়াকলাপগুলির সংখ্যা শুরু হওয়া ক্রিয়াকলাপের সংখ্যার সমান কিনা তা পরীক্ষা করে দেখুন। যদি তারা সমান হয় তবে আপনার অ্যাপ্লিকেশনটি ব্যাকগ্রাউন্ড করা হচ্ছে। যদি আরও শুরু করা ক্রিয়াকলাপ থাকে তবে আপনার অ্যাপ্লিকেশনটি এখনও দৃশ্যমান। যদি থেমে থাকা ক্রিয়াকলাপগুলির চেয়ে আরও পুনরায় শুরু করা হয় তবে আপনার অ্যাপ্লিকেশনটি কেবল দৃশ্যমান নয়, এটি পূর্বগ্রন্থেও রয়েছে। এখানে 3 টি প্রধান রাষ্ট্র রয়েছে যা আপনার ক্রিয়াকলাপের মধ্যে থাকতে পারে, তারপরে: দৃশ্যমান এবং অগ্রভূমিতে দৃশ্যমান তবে সম্মুখভাগে নয়, এবং দৃশ্যমান নয় এবং অগ্রভাগে নয় (অর্থাত্ পটভূমিতে)।
এই পদ্ধতি সম্পর্কে সত্যিই চমৎকার জিনিস এটা অ্যাসিঙ্ক্রোনাস বিষয় আছে না getRunningTasks()
, কিন্তু আপনার কাছে যে পরিবর্তন হবে না Activity
সেট / সেট না কিছু আপনার অ্যাপ্লিকেশনের মধ্যে onResumed()
/ onPaused()
। এটি কোডের কয়েকটি মাত্র লাইন যা এতে স্ব রয়েছে এবং এটি আপনার পুরো প্রয়োগ জুড়ে কাজ করে। এছাড়াও, কোনও ভীতু অনুমতি প্রয়োজন হয় না।
MyLifecycleHandler.java:
public class MyLifecycleHandler implements ActivityLifecycleCallbacks {
// I use four separate variables here. You can, of course, just use two and
// increment/decrement them instead of using four and incrementing them all.
private int resumed;
private int paused;
private int started;
private int stopped;
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
}
@Override
public void onActivityDestroyed(Activity activity) {
}
@Override
public void onActivityResumed(Activity activity) {
++resumed;
}
@Override
public void onActivityPaused(Activity activity) {
++paused;
android.util.Log.w("test", "application is in foreground: " + (resumed > paused));
}
@Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
}
@Override
public void onActivityStarted(Activity activity) {
++started;
}
@Override
public void onActivityStopped(Activity activity) {
++stopped;
android.util.Log.w("test", "application is visible: " + (started > stopped));
}
// If you want a static function you can use to check if your application is
// foreground/background, you can use the following:
/*
// Replace the four variables above with these four
private static int resumed;
private static int paused;
private static int started;
private static int stopped;
// And these two public static functions
public static boolean isApplicationVisible() {
return started > stopped;
}
public static boolean isApplicationInForeground() {
return resumed > paused;
}
*/
}
MyApplication.java:
// Don't forget to add it to your manifest by doing
// <application android:name="your.package.MyApplication" ...
public class MyApplication extends Application {
@Override
public void onCreate() {
// Simply add the handler, and that's it! No need to add any code
// to every activity. Everything is contained in MyLifecycleHandler
// with just a few lines of code. Now *that's* nice.
registerActivityLifecycleCallbacks(new MyLifecycleHandler());
}
}
@ মেভেজার এই পদ্ধতি সম্পর্কে কিছু ভাল প্রশ্ন জিজ্ঞাসা করেছেন যা আমি প্রত্যেকের জন্য এই উত্তরে উত্তর দিতে চাই:
onStop()
কম স্মৃতি পরিস্থিতিতে বলা হয় না; এখানে কি সমস্যা?
না। ডকস onStop()
বলার জন্য :
নোট করুন যে এই পদ্ধতিটি কখনই ডাকা যাবে না, কম স্মৃতি পরিস্থিতিতে যেখানে আপনার কার্যকলাপের প্রক্রিয়াটি অনপেজ () পদ্ধতিটি কল করার পরে চলমান রাখতে পর্যাপ্ত মেমরির ব্যবস্থা নেই।
এখানে মূল কীটি হ'ল "আপনার ক্রিয়াকলাপের প্রক্রিয়া চালিয়ে যান ..." যদি এই কম স্মৃতি পরিস্থিতি পৌঁছে যায় তবে আপনার প্রক্রিয়াটি আসলে নিহত হয় (কেবল আপনার কার্যকলাপ নয়)। এর অর্থ হ'ল ব্যাকগ্রাউন্ড-নেস চেক করার এই পদ্ধতিটি এখনও বৈধ কারণ ক) আপনার প্রক্রিয়াটি মারা গেলে আপনি যেভাবেই ব্যাকগ্রাউন্ডিং পরীক্ষা করতে পারবেন না, এবং খ) আপনার প্রক্রিয়াটি আবার শুরু হয় (কারণ একটি নতুন ক্রিয়াকলাপ তৈরি করা হয়েছে), সদস্য এর জন্য ভেরিয়েবল (স্থির হোক বা না) MyLifecycleHandler
পুনরায় সেট করা হবে 0
।
এটি কি কনফিগারেশন পরিবর্তনের জন্য কাজ করে?
ডিফল্টরূপে, না। আপনাকে আপনার ম্যানিফেস্ট ফাইলে স্পষ্টভাবে সেট করতে হবে configChanges=orientation|screensize
( |
আপনার অন্য কোনও কিছুর সাথে) এবং কনফিগারেশন পরিবর্তনগুলি পরিচালনা করতে হবে, অন্যথায় আপনার কার্যকলাপ ধ্বংস হয়ে যাবে এবং পুনরায় তৈরি হবে। আপনি এই সেট না থাকে, তাহলে আপনার কার্যকলাপের এর পদ্ধতি এই অনুক্রমে ডাকা হবে: onCreate -> onStart -> onResume -> (now rotate) -> onPause -> onStop -> onDestroy -> onCreate -> onStart -> onResume
। আপনি দেখতে পাচ্ছেন যে কোনও ওভারল্যাপ নেই (সাধারণত, দু'জনের মধ্যে স্যুইচ করার সময় দুটি ক্রিয়াকলাপ খুব সংক্ষেপে ওভারল্যাপ হয়, যা এই পটভূমি-সনাক্তকরণ পদ্ধতিটি কীভাবে কাজ করে)। এটি কাছাকাছি যাওয়ার জন্য, আপনাকে অবশ্যই সেট করতে হবে configChanges
যাতে আপনার ক্রিয়াকলাপ ধ্বংস না হয়। ভাগ্যক্রমে, আমি সেট করতে হয়েছিলconfigChanges
ইতিমধ্যে আমার সমস্ত প্রকল্পে কারণ আমার সম্পূর্ণ ক্রিয়াকলাপটি স্ক্রিনে ঘোরানো / পুনরায় আকার দেওয়ার কারণে ধ্বংস হওয়া অনাকাঙ্ক্ষিত ছিল, তাই আমি কখনই এটিকে সমস্যাযুক্ত বলে মনে করি না। (এটি সম্পর্কে আমার স্মৃতি সতেজ করার জন্য এবং আমাকে সংশোধন করার জন্য ডিপিমকাকে ধন্যবাদ!)
এক নোট:
আমি যখন এই উত্তরে "পটভূমি" বলেছি, তখন আমি বুঝিয়েছি "আপনার অ্যাপ্লিকেশনটি আর দৃশ্যমান নয়।" অ্যান্ড্রয়েড ক্রিয়াকলাপগুলি অগ্রভাগে দৃশ্যমান হতে পারে (উদাহরণস্বরূপ, যদি স্বচ্ছ নোটিফিকেশন ওভারলে থাকে)। এজন্যই আমি এই উত্তরটি প্রতিফলিত করতে আপডেট করেছি।
এটি জেনে রাখা জরুরী যে অডিওগ্রাউন্ডে কিছুই নেই এমন ক্রিয়াকলাপগুলি স্যুইচ করার সময় অ্যান্ড্রয়েডের একটি অদ্ভুত লম্বা মুহুর্ত রয়েছে । এই কারণে, যদি আপনি কার্যকলাপগুলি (একই অ্যাপ্লিকেশন) এর মধ্যে স্যুইচ করার সময় আপনার অ্যাপ্লিকেশনটি অগ্রভাগে রয়েছে কিনা তা পরীক্ষা করে দেখেন, আপনাকে জানানো হবে আপনি অগ্রভাগে নেই (যদিও আপনার অ্যাপ্লিকেশনটি এখনও সক্রিয় অ্যাপ্লিকেশন এবং দৃশ্যমান রয়েছে )।
আপনি না পরীক্ষা করতে যদি আপনার অ্যাপ আপনার পুরোভূমিতে থাকা Activity
'র onPause()
পদ্ধতি পরে super.onPause()
। আমি কেবল অদ্ভুত লিম্বো রাষ্ট্রের কথা মনে করেছিলাম about
আপনি (অর্থাত যদি এটা পটভূমিতে নয়) পরীক্ষা করতে পারেন আপনার অ্যাপ দৃশ্যমান আপনার Activity
'র onStop()
পদ্ধতি পরে super.onStop()
।
onStop()
পরে super.onStop()
। ইন ব্যাকগ্রাউন্ডিং জন্য চেক করবেন না onPause()
।
গুগল সমাধান - পূর্ববর্তী সমাধানগুলির মতো হ্যাক নয়। প্রসেসলিফাইসাইকেলআপনার কোটলিন ব্যবহার করুন
:
class ArchLifecycleApp : Application(), LifecycleObserver {
override fun onCreate() {
super.onCreate()
ProcessLifecycleOwner.get().lifecycle.addObserver(this)
}
@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
fun onAppBackgrounded() {
//App in background
}
@OnLifecycleEvent(Lifecycle.Event.ON_START)
fun onAppForegrounded() {
// App in foreground
}
}
জাভা:
public class ArchLifecycleApp extends Application implements LifecycleObserver {
@Override
public void onCreate() {
super.onCreate();
ProcessLifecycleOwner.get().getLifecycle().addObserver(this);
}
@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
public void onAppBackgrounded() {
//App in background
}
@OnLifecycleEvent(Lifecycle.Event.ON_START)
public void onAppForegrounded() {
// App in foreground
}
}
app.gradle এ
dependencies {
...
implementation "android.arch.lifecycle:extensions:1.1.0"
//New Android X dependency is this -
implementation "androidx.lifecycle:lifecycle-extensions:2.0.0"
}
allprojects {
repositories {
...
google()
jcenter()
maven { url 'https://maven.google.com' }
}
}
আপনি এখানে লাইফসাইকেল সম্পর্কিত আর্কিটেকচার উপাদানগুলি সম্পর্কে আরও পড়তে পারেন - https://developer.android.com/topic/libraries/architecture/lifecycle
companion object { private var foreground = false fun isForeground() : Boolean { return foreground } }
করতে পারি : তারপরে আপনি অগ্রভাগের রাজ্যটি পেতে পারেনArchLifecycleApp.isForeground()
The LifecycleOwner for the whole application process. Note that if your application has multiple processes, this provider does not know about other processes.
, এটি multiple processes
অ্যাপসের জন্য কাজ করছে না , এমন কিছু এপিআই রয়েছে যা আমরা মার্জিতভাবে অর্জন করতে পারি?
সমর্থন লাইব্রেরি সংস্করণ 26 শুরু করে আপনি প্রসেসলিফাইসাইকেল ওউনারটি ব্যবহার করতে পারেন , কেবল এখানে বর্ণিত মত আপনার নির্ভরতাতে এটি যুক্ত করুন , উদাহরণস্বরূপ:
dependencies {
def lifecycle_version = "1.1.1"
// ViewModel and LiveData
implementation "android.arch.lifecycle:extensions:$lifecycle_version"
// alternatively - Lifecycles only (no ViewModel or LiveData).
// Support library depends on this lightweight import
implementation "android.arch.lifecycle:runtime:$lifecycle_version"
annotationProcessor "android.arch.lifecycle:compiler:$lifecycle_version" // use kapt for Kotlin
}
এবং তারপরে ProcessLifecycleOwner
আপনি যখনই অ্যাপ্লিকেশন রাজ্যের জন্য চান তখন কেবল জিজ্ঞাসা করুন, উদাহরণগুলি:
//Check if app is in background
ProcessLifecycleOwner.get().getLifecycle().getCurrentState() == Lifecycle.State.CREATED;
//Check if app is in foreground
ProcessLifecycleOwner.get().getLifecycle().getCurrentState().isAtLeast(Lifecycle.State.STARTED);
অ্যান্ড্রয়েড এপিআই 16 যেহেতু অ্যাপ্লিকেশনটি অগ্রভাগে রয়েছে কিনা তা পরীক্ষা করার একটি সহজ উপায় রয়েছে is এটি বুদ্ধিমান নাও হতে পারে তবে অ্যান্ড্রয়েডের কোনও পদ্ধতিও বুদ্ধিমানের নয়। এই পরিষেবাটি ব্যবহার করার জন্য যথেষ্ট ভাল যখন আপনার পরিষেবাটি সার্ভার থেকে আপডেট গ্রহণ করে এবং বিজ্ঞপ্তিটি প্রদর্শন করা হবে কি না তা সিদ্ধান্ত নিতে হবে (কারণ যদি UI অগ্রভাগ হয়, ব্যবহারকারী বিজ্ঞপ্তি ছাড়াই আপডেটটি লক্ষ্য করবেন)।
RunningAppProcessInfo myProcess = new RunningAppProcessInfo();
ActivityManager.getMyMemoryState(myProcess);
isInBackground = myProcess.importance != RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
JobService
পটভূমিতে পরিষেবাটি চলছে কিনা তা সনাক্ত করতে আমি এই কোডটি ব্যবহার করতে সক্ষম হয়েছি ।
আইডলনের উত্তরটি ত্রুটিযুক্ত প্রবণ এবং আরও জটিল জটিল পুনরাবৃত্তি এখানে অ্যান্ড্রয়েড অ্যাপ্লিকেশনটি অগ্রভাগে রয়েছে কিনা তা পরীক্ষা করে দেখুন? এবং এখানে একটি পটভূমি টাস্ক বা পরিষেবা থেকে বর্তমান অগ্রভাগ অ্যাপ্লিকেশন নির্ধারণ করা
আরও অনেক সহজ পদ্ধতির রয়েছে:
একটি বেসঅ্যাক্টিভিটি যা সমস্ত ক্রিয়াকলাপ প্রসারিত করে:
protected static boolean isVisible = false;
@Override
public void onResume()
{
super.onResume();
setVisible(true);
}
@Override
public void onPause()
{
super.onPause();
setVisible(false);
}
যখনই আপনাকে আপনার অ্যাপ্লিকেশন কার্যক্রমের কোনও অগ্রভাগে রয়েছে কিনা তা খতিয়ে দেখার প্রয়োজন isVisible()
;
এই পদ্ধতির বিষয়টি বোঝার জন্য পাশের পাশের ক্রিয়াকলাপের এই উত্তরটি পরীক্ষা করে দেখুন: পাশাপাশি জীবনযাত্রার ক্রিয়াকলাপ
Idolon's answer is error prone
- দুর্ভাগ্যক্রমে আমি আপনার সাথে একমত হতে হবে। গুগল গ্রুপগুলিতে ডায়ান হ্যাকোবারের মন্তব্যের ভিত্তিতে আমি আমার উত্তর আপডেট করেছি। বিস্তারিত জানার জন্য এটি পরীক্ষা করুন।
onPause
, onStop
কিংবা onResume
ঘটনা বলা হয়। তাহলে এই ইভেন্টগুলির কোনওটিই যদি বরখাস্ত না করা হয় তবে আপনি কি করবেন ?!
আমি প্রস্তাবিত সমাধানটি চেষ্টা করেছি যা অ্যাপ্লিকেশন.অ্যাক্টিভিটি লাইফিসাইকেলক্যালব্যাকস এবং আরও অনেককে ব্যবহার করে তবে তারা প্রত্যাশা অনুযায়ী কাজ করেনি। সার্জে ধন্যবাদ , আমি নীচে বর্ণনা করছি এমন একটি খুব সহজ এবং সোজা সমাধান নিয়ে এসেছি।
এগুলির সমাধানের মূল বিষয়টি হ'ল বোঝার সত্যতা হল যে আমাদের যদি অ্যাক্টিভিএ এবং অ্যাক্টিভিবি থাকে এবং আমরা ক্রিয়াকলাপ থেকে ক্রিয়াকলাপকে কল করি (এবং কল করি না
ActivityA.finish
), তবে অ্যাক্টিভিটি'র আগে অ্যাক্টিভিএ'র কলonStart()
হবে ।onStop()
এটির মধ্যেও প্রধান পার্থক্য onStop()
এবং onPause()
এটি যেটি আমি পড়ে নিবন্ধগুলিতে উল্লেখ করি নি।
সুতরাং এই ক্রিয়াকলাপের জীবনচক্র আচরণের উপর ভিত্তি করে, আপনি কেবল আপনার প্রোগ্রামে কতবার onStart()
এবং কীভাবে onPause()
ডেকেছেন তা গণনা করতে পারেন । লক্ষ্য করুন প্রত্যেকের জন্য Activity
আপনার প্রোগ্রাম, আপনি ওভাররাইড আবশ্যক onStart()
এবং onStop()
জন্য, বৃদ্ধি / হ্রাস স্ট্যাটিক পরিবর্তনশীল কাউন্টিং জন্য ব্যবহৃত হয়। নীচে কোডটি এই যুক্তি বাস্তবায়ন করছে। মনে রাখবেন যে আমি প্রসারিত একটি শ্রেণি ব্যবহার করছি Application
, সুতরাং Manifest.xml
অ্যাপ্লিকেশন ট্যাগের ভিতরে ঘোষণা করতে ভুলবেন না : android:name=".Utilities"
যদিও এটি একটি সাধারণ কাস্টম শ্রেণীর ব্যবহার করেও প্রয়োগ করা যেতে পারে।
public class Utilities extends Application
{
private static int stateCounter;
public void onCreate()
{
super.onCreate();
stateCounter = 0;
}
/**
* @return true if application is on background
* */
public static boolean isApplicationOnBackground()
{
return stateCounter == 0;
}
//to be called on each Activity onStart()
public static void activityStarted()
{
stateCounter++;
}
//to be called on each Activity onStop()
public static void activityStopped()
{
stateCounter--;
}
}
এখন আমাদের প্রোগ্রাম প্রতিটি কার্যকলাপ চালু, আমরা ওভাররাইড করা উচিত onStart()
এবং onStop()
নিচের চিত্রের এবং বৃদ্ধি / হ্রাস:
@Override
public void onStart()
{
super.onStart();
Utilities.activityStarted();
}
@Override
public void onStop()
{
Utilities.activityStopped();
if(Utilities.isApplicationOnBackground())
{
//you should want to check here if your application is on background
}
super.onStop();
}
এই যুক্তি দিয়ে 2 টি সম্ভাব্য কেস রয়েছে:
stateCounter = 0
: বন্ধ হওয়া সংখ্যা শুরু হওয়া ক্রিয়াকলাপগুলির সংখ্যার সমান, যার অর্থ অ্যাপ্লিকেশনটি পটভূমিতে চলছে isstateCounter > 0
: শুরু হওয়া সংখ্যাটি থামানো সংখ্যার চেয়ে বড়, যার অর্থ এই অ্যাপ্লিকেশনটি অগ্রভাগে চলছে।বিজ্ঞপ্তি: এর stateCounter < 0
অর্থ হ'ল শুরু করার পরিবর্তে আরও বন্ধ হওয়া ক্রিয়াকলাপ রয়েছে যা অসম্ভব। যদি আপনি এই কেসটির মুখোমুখি হন, তবে এর অর্থ হ'ল আপনি যেভাবে কাউন্টারটি করা উচিত তেমন বাড়িয়ে / হ্রাস করছেন না।
আপনি যেতে প্রস্তুত। আপনার অ্যাপ্লিকেশনটি ভিতরের পটভূমিতে রয়েছে কিনা তা আপনার পরীক্ষা করা উচিত onStop()
।
if(Utilities.isApplicationOnBackground()) …
থেকে Utilities
। কারণ অন্যথায় কেবলমাত্র একটি নির্দিষ্ট ক্রিয়াকলাপ ইভেন্টটিতে প্রতিক্রিয়া জানাবে।
আপনার কোনও ক্রিয়াকলাপ দৃশ্যমান আছে কি না তা নির্ধারণ করার জন্য কোনও উপায় নেই, আপনি নিজেরাই এটি ট্র্যাক করে নিন। সম্ভবত আপনি একটি নতুন স্ট্যাকওভারফ্লো প্রশ্ন জিজ্ঞাসা করা বিবেচনা করা উচিত, এটি ব্যবহারকারীর অভিজ্ঞতা থেকে আপনি কী অর্জন করতে চাইছেন তা ব্যাখ্যা করে, তাই আমরা সম্ভবত আপনাকে বিকল্প বাস্তবায়ন সম্পর্কিত ধারণা দিতে পারি।
Service
। যদি তা হয় তবে আপনার ক্রিয়াকলাপগুলি পরিষেবাটি প্রদর্শিত হবে এবং অদৃশ্য হওয়ার সাথে সাথে তাদের অবহিত করুন। যদি Service
নির্ধারণ করে যে কোনও ক্রিয়াকলাপ দৃশ্যমান নয় এবং এটি কিছু সময়ের জন্য একইভাবে থেকে যায় তবে পরবর্তী যৌক্তিক স্টপিং পয়েন্টে ডেটা স্থানান্তর বন্ধ করুন। হ্যাঁ, এটিতে আপনার প্রতিটি ক্রিয়াকলাপের জন্য কোডের প্রয়োজন হবে তবে এখনই এটি অনিবার্য আফ্রিক।
MyActivityClass
থেকে উত্তরাধিকারসূত্রে একটি বর্গ তৈরি করতে পারেন Activity
এবং আপনার সমস্ত ক্রিয়াকলাপ উত্তরাধিকার সূত্রে তৈরি করতে পারেন MyActivityClass
। এটি (যদিও এই প্রশ্নটি দেখুন )PreferenceActivity
MapActivity
অ্যাপটি ব্যাকগ্রাউন্ডে রয়েছে কিনা তা সনাক্ত করতে আপনি কম্পোনেন্টক্যালব্যাকস 2 ব্যবহার করতে পারেন । বিটিডব্লিউ এই কলব্যাকটি কেবলমাত্র API স্তরের 14 (আইসক্রিম স্যান্ডউইচ) এবং তারপরে উপলব্ধ।
আপনি পদ্ধতিতে একটি কল পাবেন:
public abstract void onTrimMemory (int level)
স্তরটি যদি হয় ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN
তবে অ্যাপটি ব্যাকগ্রাউন্ডে রয়েছে।
আপনি একটি এই ইন্টারফেস বাস্তবায়ন করতে পারে activity
, service
ইত্যাদি
public class MainActivity extends AppCompatActivity implements ComponentCallbacks2 {
@Override
public void onConfigurationChanged(final Configuration newConfig) {
}
@Override
public void onLowMemory() {
}
@Override
public void onTrimMemory(final int level) {
if (level == ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) {
// app is in background
}
}
}
বেশ কয়েকটি দরকারী বৈশিষ্ট্য অন্তর্ভুক্ত করার জন্য @ কর্নস্টালকের জবাব দেওয়া হচ্ছে Building
অতিরিক্ত সুবিধাগুলি:
App.java
public class App extends Application {
@Override
public void onCreate() {
super.onCreate();
registerActivityLifecycleCallbacks(AppLifecycleHandler.getInstance());
}
}
AppLifecycleHandler.java
public class AppLifecycleHandler implements Application.ActivityLifecycleCallbacks {
private int resumed;
private int started;
private final String DebugName = "AppLifecycleHandler";
private boolean isVisible = false;
private boolean isInForeground = false;
private static AppLifecycleHandler instance;
public static AppLifecycleHandler getInstance() {
if (instance == null) {
instance = new AppLifecycleHandler();
}
return instance;
}
private AppLifecycleHandler() {
}
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
}
@Override
public void onActivityDestroyed(Activity activity) {
}
@Override
public void onActivityResumed(Activity activity) {
++resumed;
android.util.Log.w(DebugName, "onActivityResumed -> application is in foreground: " + (resumed > 0) + " (" + activity.getClass() + ")");
setForeground((resumed > 0));
}
@Override
public void onActivityPaused(Activity activity) {
--resumed;
android.util.Log.w(DebugName, "onActivityPaused -> application is in foreground: " + (resumed > 0) + " (" + activity.getClass() + ")");
setForeground((resumed > 0));
}
@Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
}
@Override
public void onActivityStarted(Activity activity) {
++started;
android.util.Log.w(DebugName, "onActivityStarted -> application is visible: " + (started > 0) + " (" + activity.getClass() + ")");
setVisible((started > 0));
}
@Override
public void onActivityStopped(Activity activity) {
--started;
android.util.Log.w(DebugName, "onActivityStopped -> application is visible: " + (started > 0) + " (" + activity.getClass() + ")");
setVisible((started > 0));
}
private void setVisible(boolean visible) {
if (isVisible == visible) {
// no change
return;
}
// visibility changed
isVisible = visible;
android.util.Log.w(DebugName, "App Visiblility Changed -> application is visible: " + isVisible);
// take some action on change of visibility
}
private void setForeground(boolean inForeground) {
if (isInForeground == inForeground) {
// no change
return;
}
// in foreground changed
isInForeground = inForeground;
android.util.Log.w(DebugName, "App In Foreground Changed -> application is in foreground: " + isInForeground);
// take some action on change of in foreground
}
public static boolean isApplicationVisible() {
return AppLifecycleHandler.getInstance().started > 0;
}
public static boolean isApplicationInForeground() {
return AppLifecycleHandler.getInstance().resumed > 0;
}
}
ব্যবহারের টাইমারগুলির সাথে আমি সেরা সমাধানটি নিয়ে এসেছি।
আপনি অনপজ () এ একটি টাইমার শুরু করেছেন এবং অন টাইমস () এ একই টাইমার বাতিল করে দিয়েছেন, টাইমারটির 1 টি উদাহরণ রয়েছে (সাধারণত অ্যাপ্লিকেশন শ্রেণিতে সংজ্ঞায়িত হয়)। টাইমার নিজেই 2 সেকেন্ডের পরে (বা আপনার যেটুকু অন্তর যথাযথ বলে মনে হয়) চালানোর পরে চালিত হবে, যখন টাইমার ফায়ার করে আপনি একটি পতাকাটি সেট করেন যা অ্যাপ্লিকেশনটিকে ব্যাকগ্রাউন্ডে রয়েছে বলে চিহ্নিত করে।
টাইমার বাতিল করার আগে অনারিউম () পদ্ধতিতে আপনি কোনও স্টার্টআপ ক্রিয়াকলাপ সম্পাদনের জন্য ব্যাকগ্রাউন্ড পতাকাটি জিজ্ঞাসা করতে পারেন (যেমন ডাউনলোডগুলি শুরু করতে বা অবস্থান পরিষেবাগুলি সক্ষম করুন)।
এই সমাধানটি আপনাকে পিছনে স্ট্যাকের বেশ কয়েকটি ক্রিয়াকলাপ করতে দেয় এবং বাস্তবায়নের জন্য কোনও অনুমতিের প্রয়োজন হয় না।
আপনি যদি কোনও ইভেন্ট বাসও ব্যবহার করেন তবে এই সমাধানটি ভালভাবে কাজ করে, কারণ আপনার টাইমার কেবল কোনও ইভেন্টটিকেই আগুন দিয়ে দিতে পারে এবং আপনার অ্যাপের বিভিন্ন অংশ ততক্ষণে প্রতিক্রিয়া জানাতে পারে।
যদি আপনি বিকাশকারী সেটিংস চালু করেন "ক্রিয়াকলাপগুলি রাখবেন না" - কেবল তৈরি করা ক্রিয়াকলাপগুলির গণনা পরীক্ষা করা যথেষ্ট নয়। আপনার অবশ্যই সেভআইনস্ট্যান্সস্টেট পরীক্ষা করা উচিত । আমার কাস্টম পদ্ধতিটি অ্যাপ্লিকেশন রানিং () চেকটি হচ্ছে অ্যান্ড্রয়েড অ্যাপ চলছে:
এখানে আমার কাজের কোড:
public class AppLifecycleService implements Application.ActivityLifecycleCallbacks {
private int created;
private boolean isSaveInstanceState;
private static AppLifecycleService instance;
private final static String TAG = AppLifecycleService.class.getName();
public static AppLifecycleService getInstance() {
if (instance == null) {
instance = new AppLifecycleService();
}
return instance;
}
public static boolean isApplicationRunning() {
boolean isApplicationRunning = true;
if (getCountCreatedActvities() == 0 && !isSaveInstanceState()) {
isApplicationRunning = false;
}
return isApplicationRunning;
}
public static boolean isSaveInstanceState() {
return AppLifecycleService.getInstance().isSaveInstanceState;
}
public static int getCountCreatedActvities() {
return AppLifecycleService.getInstance().created;
}
private AppLifecycleService() {
}
@Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
this.isSaveInstanceState = true;
}
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
++created;
}
@Override
public void onActivityDestroyed(Activity activity) {
--created;
}
@Override
public void onActivityResumed(Activity activity) { }
@Override
public void onActivityPaused(Activity activity) { }
@Override
public void onActivityStarted(Activity activity) { }
@Override
public void onActivityStopped(Activity activity) { }
}
একমাত্র সঠিক সমাধান:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
MyApp.mainActivity = this;
super.onCreate(savedInstanceState);
...
}
public class MyApp extends Application implements LifecycleObserver {
public static MainActivity mainActivity = null;
@Override
public void onCreate() {
super.onCreate();
ProcessLifecycleOwner.get().getLifecycle().addObserver(this);
}
@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
void onAppBackgrounded() {
// app in background
if (mainActivity != null) {
...
}
}
@OnLifecycleEvent(Lifecycle.Event.ON_START)
void onAppForegrounded() {
// app in foreground
if (mainActivity != null) {
...
}
}
}
কমন্সওয়্যার এবং কী কী বলেছে সে সম্পর্কে পিগব্যাক করার জন্য, আপনি সম্ভবত অ্যাপ্লিকেশন ক্লাসটি প্রসারিত করতে পারেন এবং আপনার সমস্ত ক্রিয়াকলাপকে তাদের অনপেজ / অন রিসুম পদ্ধতিতে কল করতে পারেন। এটি আপনাকে কোন ক্রিয়াকলাপ (আইস) দৃশ্যমান তা জানার অনুমতি দেয় তবে সম্ভবত এটি আরও ভালভাবে পরিচালনা করা যেতে পারে।
আপনার মনে কী আছে তা কি আপনি বিশদভাবে বলতে পারেন? আপনি যখন ব্যাকগ্রাউন্ডে চলমান বলছেন, আপনার পর্দায় বর্তমানে না থাকা সত্ত্বেও কী আপনার অ্যাপ্লিকেশনটি স্মৃতিতে এখনও রয়েছে? আপনার অ্যাপ্লিকেশনটি যখন ফোকাসে নেই তখন কী আপনি পরিষেবাগুলি আরও নিরবচ্ছিন্ন উপায় হিসাবে ব্যবহার করার বিষয়টি দেখেছেন?
Application
নেই onPause()
বা onResume()
।
আমি অ্যাক্টিভিটিফাইসাইক্যালব্যাকগুলি নিজস্ব প্রয়োগ করেছি। আমি শার্লকএকটিভিটি ব্যবহার করছি তবে সাধারণ ক্রিয়াকলাপের জন্য ক্লাস কাজ করতে পারে।
প্রথমত, আমি একটি ইন্টারফেস তৈরি করছি যা ক্রিয়াকলাপের জীবনচক্রের ট্র্যাক করার জন্য সমস্ত পদ্ধতি রয়েছে:
public interface ActivityLifecycleCallbacks{
public void onActivityStopped(Activity activity);
public void onActivityStarted(Activity activity);
public void onActivitySaveInstanceState(Activity activity, Bundle outState);
public void onActivityResumed(Activity activity);
public void onActivityPaused(Activity activity);
public void onActivityDestroyed(Activity activity);
public void onActivityCreated(Activity activity, Bundle savedInstanceState);
}
দ্বিতীয়ত, আমি আমার অ্যাপ্লিকেশনের শ্রেণিতে এই ইন্টারফেসটি প্রয়োগ করেছি:
public class MyApplication extends Application implements my.package.ActivityLifecycleCallbacks{
@Override
public void onCreate() {
super.onCreate();
}
@Override
public void onActivityStopped(Activity activity) {
Log.i("Tracking Activity Stopped", activity.getLocalClassName());
}
@Override
public void onActivityStarted(Activity activity) {
Log.i("Tracking Activity Started", activity.getLocalClassName());
}
@Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
Log.i("Tracking Activity SaveInstanceState", activity.getLocalClassName());
}
@Override
public void onActivityResumed(Activity activity) {
Log.i("Tracking Activity Resumed", activity.getLocalClassName());
}
@Override
public void onActivityPaused(Activity activity) {
Log.i("Tracking Activity Paused", activity.getLocalClassName());
}
@Override
public void onActivityDestroyed(Activity activity) {
Log.i("Tracking Activity Destroyed", activity.getLocalClassName());
}
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
Log.i("Tracking Activity Created", activity.getLocalClassName());
}
}
তৃতীয়, আমি একটি ক্লাস তৈরি করছি যা শার্লকঅ্যাক্টিভিটি থেকে প্রসারিত:
public class MySherlockActivity extends SherlockActivity {
protected MyApplication nMyApplication;
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
nMyApplication = (MyApplication) getApplication();
nMyApplication.onActivityCreated(this, savedInstanceState);
}
protected void onResume() {
// TODO Auto-generated method stub
nMyApplication.onActivityResumed(this);
super.onResume();
}
@Override
protected void onPause() {
// TODO Auto-generated method stub
nMyApplication.onActivityPaused(this);
super.onPause();
}
@Override
protected void onDestroy() {
// TODO Auto-generated method stub
nMyApplication.onActivityDestroyed(this);
super.onDestroy();
}
@Override
protected void onStart() {
nMyApplication.onActivityStarted(this);
super.onStart();
}
@Override
protected void onStop() {
nMyApplication.onActivityStopped(this);
super.onStop();
}
@Override
protected void onSaveInstanceState(Bundle outState) {
nMyApplication.onActivitySaveInstanceState(this, outState);
super.onSaveInstanceState(outState);
}
}
চতুর্থত, শেরলক অ্যাক্টিভিটি থেকে প্রসারিত সমস্ত শ্রেণি, আমি মাই শার্লকঅ্যাক্টিভিটির জন্য প্রতিস্থাপন করেছি:
public class MainActivity extends MySherlockActivity{
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
}
এখন, লগকটে আপনি মাই অ্যাপ্লিকেশনটিতে তৈরি ইন্টারফেস বাস্তবায়নে লগগুলি প্রোগ্রাম করা দেখতে পাবেন।
যেহেতু এটি ইতিমধ্যে উল্লেখ করা হয়নি, আমি পাঠকদের পরামর্শ দেব অ্যান্ড্রয়েড আর্কিটেকচার উপাদানগুলির মাধ্যমে প্রসেসলিফাইসাইকেলওয়ানার অন্বেষণ করার জন্য
সিস্টেমটি অগ্রভাগ এবং পটভূমি অ্যাপ্লিকেশনগুলির মধ্যে পার্থক্য করে। (পরিষেবা সীমাবদ্ধতার উদ্দেশ্যে ব্যাকগ্রাউন্ডের সংজ্ঞা মেমরি ম্যানেজমেন্ট দ্বারা ব্যবহৃত সংজ্ঞা থেকে পৃথক; একটি অ্যাপ্লিকেশনটি মেমরি পরিচালনার সাথে ব্যাকগ্রাউন্ডে থাকতে পারে তবে পরিষেবাগুলি চালু করার দক্ষতার সাথে সামনের অংশে রয়েছে) একটি অ্যাপ্লিকেশনটি নিম্নলিখিতগুলির মধ্যে কোনওটি সত্য হলে অগ্রভাগে বিবেচিত:
যদি এই শর্তগুলির কোনওটি সত্য না হয়, অ্যাপটিকে ব্যাকগ্রাউন্ডে বিবেচনা করা হবে।
এই পুরানো পোস্টের জন্য আরও একটি সমাধান (তাদের জন্য এটি এটি সহায়তা করতে পারে):
<application android:name=".BaseApplication" ... >
public class BaseApplication extends Application {
private class Status {
public boolean isVisible = true;
public boolean isFocused = true;
}
private Map<Activity, Status> activities;
@Override
public void onCreate() {
activities = new HashMap<Activity, Status>();
super.onCreate();
}
private boolean hasVisibleActivity() {
for (Status status : activities.values())
if (status.isVisible)
return true;
return false;
}
private boolean hasFocusedActivity() {
for (Status status : activities.values())
if (status.isFocused)
return true;
return false;
}
public void onActivityCreate(Activity activity, boolean isStarting) {
if (isStarting && activities.isEmpty())
onApplicationStart();
activities.put(activity, new Status());
}
public void onActivityStart(Activity activity) {
if (!hasVisibleActivity() && !hasFocusedActivity())
onApplicationForeground();
activities.get(activity).isVisible = true;
}
public void onActivityWindowFocusChanged(Activity activity, boolean hasFocus) {
activities.get(activity).isFocused = hasFocus;
}
public void onActivityStop(Activity activity, boolean isFinishing) {
activities.get(activity).isVisible = false;
if (!isFinishing && !hasVisibleActivity() && !hasFocusedActivity())
onApplicationBackground();
}
public void onActivityDestroy(Activity activity, boolean isFinishing) {
activities.remove(activity);
if(isFinishing && activities.isEmpty())
onApplicationStop();
}
private void onApplicationStart() {Log.i(null, "Start");}
private void onApplicationBackground() {Log.i(null, "Background");}
private void onApplicationForeground() {Log.i(null, "Foreground");}
private void onApplicationStop() {Log.i(null, "Stop");}
}
public class MyActivity extends BaseActivity {...}
public class BaseActivity extends Activity {
private BaseApplication application;
@Override
protected void onCreate(Bundle state) {
application = (BaseApplication) getApplication();
application.onActivityCreate(this, state == null);
super.onCreate(state);
}
@Override
protected void onStart() {
application.onActivityStart(this);
super.onStart();
}
@Override
public void onWindowFocusChanged(boolean hasFocus) {
application.onActivityWindowFocusChanged(this, hasFocus);
super.onWindowFocusChanged(hasFocus);
}
@Override
protected void onStop() {
application.onActivityStop(this, isFinishing());
super.onStop();
}
@Override
protected void onDestroy() {
application.onActivityDestroy(this, isFinishing());
super.onDestroy();
}
}
অ্যাক্টিভিটিডাস্ট্রয়েড ফাংশনে মন্তব্যটি দেখুন।
এসডিকে লক্ষ্য সংস্করণ 14> এর সাথে কাজ করে:
import android.app.Activity;
import android.app.Application;
import android.os.Bundle;
import android.util.Log;
public class AppLifecycleHandler implements Application.ActivityLifecycleCallbacks {
public static int active = 0;
@Override
public void onActivityStopped(Activity activity) {
Log.i("Tracking Activity Stopped", activity.getLocalClassName());
active--;
}
@Override
public void onActivityStarted(Activity activity) {
Log.i("Tracking Activity Started", activity.getLocalClassName());
active++;
}
@Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
Log.i("Tracking Activity SaveInstanceState", activity.getLocalClassName());
}
@Override
public void onActivityResumed(Activity activity) {
Log.i("Tracking Activity Resumed", activity.getLocalClassName());
active++;
}
@Override
public void onActivityPaused(Activity activity) {
Log.i("Tracking Activity Paused", activity.getLocalClassName());
active--;
}
@Override
public void onActivityDestroyed(Activity activity) {
Log.i("Tracking Activity Destroyed", activity.getLocalClassName());
active--;
// if active var here ever becomes zero, the app is closed or in background
if(active == 0){
...
}
}
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
Log.i("Tracking Activity Created", activity.getLocalClassName());
active++;
}
}
সম্পত্তি সঞ্চয় করতে আপনার ভাগ করা পছন্দ ব্যবহার করা উচিত এবং আপনার ক্রিয়াকলাপ থেকে পরিষেবা বাঁধাই ব্যবহার করে এটিতে কাজ করা উচিত । আপনি যদি কেবল বাঁধাই ব্যবহার করেন, (এটি কখনই স্টার্ট সার্ভিস ব্যবহার করে না), তবে আপনার পরিষেবা কেবল তখনই চলবে যখন আপনি এটি বেঁধে রাখবেন, (onResume এবং unbind অনপজ বন্ধ করুন) এটি কেবল অগ্রভাগে চালিত করবে এবং আপনি যদি কাজ করতে চান তবে পটভূমি আপনি নিয়মিত স্টার্ট স্টপ পরিষেবাটি ব্যবহার করতে পারেন।
আমি মনে করি এই প্রশ্নটি আরও স্পষ্ট হওয়া উচিত। কখন? কোথায়? আপনার অ্যাপটি ব্যাকগ্রাউন্ডে থাকলে আপনি কী করতে চান আপনার নির্দিষ্ট পরিস্থিতি?
আমি কেবল আমার পথে আমার সমাধানটি প্রবর্তন করি।
আমি আমার অ্যাপ্লিকেশনটিতে RunningAppProcessInfo
প্রতিটি ক্রিয়াকলাপের onStop
পদ্ধতিতে ক্লাসের "গুরুত্ব" ক্ষেত্রটি ব্যবহার করে এটি সম্পন্ন করেছি , যা BaseActivity
অন্যান্য ক্রিয়াকলাপকে প্রসারিত করে যা onStop
"গুরুত্ব" এর মান যাচাইয়ের পদ্ধতিটি কার্যকর করে তা সরবরাহ করেই অর্জন করা যায় । কোডটি এখানে:
public static boolean isAppRunning(Context context) {
ActivityManager activityManager = (ActivityManager) context
.getSystemService(Context.ACTIVITY_SERVICE);
List<RunningAppProcessInfo> appProcesses = activityManager
.getRunningAppProcesses();
for (RunningAppProcessInfo appProcess : appProcesses) {
if (appProcess.processName.equals(context.getPackageName())) {
if (appProcess.importance != RunningAppProcessInfo.IMPORTANCE_PERCEPTIBLE) {
return true;
}
}
}
return false;
}
আমি এই পৃষ্ঠার মাধ্যমে পড়ার পরামর্শ দিচ্ছি: http://developer.android.com/references/android/app/Activity.html
সংক্ষেপে, আপনার ক্রিয়াকলাপ ডাকার পরে আর দৃশ্যমান নয় onStop()
।
onStop
; এর মধ্যে onPause
এবং onStop
এটি দৃশ্যমান , তবে অগ্রভাগে নয় ।
onStop()
বলা হওয়ার পরে আর দৃশ্যমান হয় না , যা আপনি যা লিখেছেন তার সাথে সামঞ্জস্য করা হয়েছে।
onPause
: সাম্প্রতিক সম্পাদনা আপনাকে সংশোধন করেছে।
আমার মতে, অনেক উত্তর কোডের একটি ভারী বোঝা প্রবর্তন করে এবং প্রচুর জটিলতা এবং অ-পঠনযোগ্যতা নিয়ে আসে।
লোকেরা যখন Service
ও এর মধ্যে কীভাবে যোগাযোগ করতে হয় তার জন্য জিজ্ঞাসা করে Activity
, আমি সাধারণত লোকালব্রোডকাস্টম্যানেজার ব্যবহার করার পরামর্শ দিই ।
কেন?
ঠিক আছে, দস্তাবেজগুলি উদ্ধৃত করে:
আপনি জানেন যে আপনি যে ডেটা সম্প্রচার করছেন তা আপনার অ্যাপ্লিকেশনটি ছাড়বে না, তাই ব্যক্তিগত ডেটা ফাঁস হওয়ার বিষয়ে চিন্তা করার দরকার নেই।
অন্যান্য অ্যাপ্লিকেশনগুলির জন্য এই অ্যাপ্লিকেশনগুলিতে এই সম্প্রচারগুলি প্রেরণ করা সম্ভব নয়, সুতরাং সেগুলি ব্যবহার করতে পারে এমন সুরক্ষা ছিদ্র থাকার বিষয়ে আপনার চিন্তা করার দরকার নেই।
সিস্টেমের মাধ্যমে বৈশ্বিক সম্প্রচার পাঠানোর চেয়ে এটি আরও দক্ষ।
দস্তাবেজে নেই:
Activity
, Application
...বিবরণ
সুতরাং, আপনি পরীক্ষা করতে চান Activity
যে কোনওটির পূর্বেগ্রাউন্ডে রয়েছে কিনা। আপনি সাধারণত এটি Service
, বা আপনার Application
ক্লাসে করেন।
এর অর্থ, আপনার Activity
অবজেক্টস সিগন্যালের প্রেরক হয়ে উঠেছে (আমি চালু / আমি বন্ধ)। তোমার Service
অন্যদিকে রূপান্তরিত হবে Receiver
।
আছে দুই যা মুহূর্ত আপনারActivity
আপনি বলে যদি এটা পুরোভূমিতে বা পটভূমি (হ্যাঁ মাত্র দুটি ... না 6) মধ্যে যাচ্ছে।
যখন Activity
ফোরগ্রাউন্ড মধ্যে যায়, onResume()
পদ্ধতি সূত্রপাত হয় (এছাড়াও পর বলা onCreate()
)।
Activity
পিছনে যায় যখন , onPause()
বলা হয়।
এগুলি সেই মুহুর্তগুলিতে যেখানে আপনার অবস্থাটি বর্ণনা করার Activity
জন্য আপনার সিগন্যালটি প্রেরণ করা উচিত Service
।
একাধিকের ক্ষেত্রে, প্রথমে পটভূমিতে একটিগুলি Activity
মনে রাখুন Activity
, তারপরে অন্য একটিটি অগ্রভাগে আসে।
সুতরাং পরিস্থিতিটি হবে: *
Activity1 -- send --> Signal:OFF
Activity2 -- send --> Signal:ON
Service
/ Application
কেবল এই সব সংকেতের শুনতে থাকুন এবং সেই অনুযায়ী কাজ করবে।
কোড (টিএলডিআর)
সংকেত শোনার জন্য আপনার Service
অবশ্যই একটি প্রয়োগ করতে হবে BroadcastReceiver
।
this.localBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
// received data if Activity is on / off
}
}
public static final IntentFilter SIGNAL_FILTER = new IntentFilter("com.you.yourapp.MY_SIGNAL")
নিবন্ধন Receiver
মধ্যেService::onCreate()
@Override
protected void onCreate() {
LocalBroadcastManager.getInstance(getApplicationContext()).registerReceiver(this.localBroadcastReceiver, SIGNAL_FILTER);
}
এটিতে নিবন্ধভুক্ত করুন Service::onDestroy()
@Override
protected void onDestroy() {
// I'm dead, no need to listen to anything anymore.
LocalBroadcastManager.getInstance(getApplicationContext()).unregisterReceiver(this.localBroadcastReceiver);
}
এখন আপনার Activity
তাদের অবস্থা অবশ্যই জানাতে হবে।
ভিতরে Activity::onResume()
Intent intent = new Intent();
intent.setAction(SomeActivity.SIGNAL_FILTER); // put ON boolean in intent
LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(intent);
ভিতরে Activity::onPause()
Intent intent = new Intent();
intent.setAction(SomeActivity.SIGNAL_FILTER); // put OFF boolean in intent
LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(intent);
একটি খুব, খুব সাধারণ পরিস্থিতি
বিকাশকারী: আমি আমার থেকে ডেটা প্রেরণ
Service
এবং আপডেট করতে চাইActivity
।Activity
অগ্রভাগে আছে কিনা তা আমি কীভাবে পরীক্ষা করব ?
Activity
অগ্রভাগে আছে কিনা তা সাধারণত যাচাই করার দরকার নেই । LocalBroadcastManager
আপনার মাধ্যমে কেবল ডেটা প্রেরণ করুন Service
। যদি এটি Activity
চালু থাকে, তবে এটি প্রতিক্রিয়া জানাবে এবং অভিনয় করবে।
এই খুব সাধারণ পরিস্থিতির জন্য, Service
প্রেরক হয়ে ওঠে এবং Activity
প্রয়োগ করে BroadcastReceiver
।
সুতরাং, Receiver
আপনার মধ্যে একটি তৈরি করুন Activity
। এটিতে নিবন্ধন করুন onResume()
এবং এটি নিবন্ধভুক্ত করুন onPause()
। অন্যান্য জীবনচক্র পদ্ধতি ব্যবহার করার দরকার নেই ।
(আপডেট তালিকাভিউ আপডেট করুন, এটি করুন, এটি করুন, ...) এ Receiver
আচরণটি সংজ্ঞায়িত করুন onReceive()
।
এই পদ্ধতি Activity
যদি এটা ফোরগ্রাউন্ড আছে এবং এটি যদি ফিরে বা ধ্বংস করা হয় কিছুই হবে না শুধুমাত্র শুনবে।
একাধিকের ক্ষেত্রে Activity
, যা Activity
কিছু আছে তা প্রতিক্রিয়া জানাবে (যদি তারা এটি প্রয়োগ করে Receiver
)।
যদি সমস্ত পটভূমিতে থাকে তবে কেউ প্রতিক্রিয়া জানাবে না এবং সিগন্যালটি কেবল হারিয়ে যাবে।
সিগন্যাল আইডি উল্লেখ করে (উপরের কোডটি দেখুন) Service
মাধ্যমে ডেটা প্রেরণ করুন Intent
।
fun isAppInForeground(): Boolean {
val activityManager = getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager ?: return false
val appProcesses = activityManager.runningAppProcesses ?: return false
val packageName = packageName
for (appProcess in appProcesses) {
if (appProcess.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND && appProcess.processName == packageName) {
return true
}
}
return false
}
কোনও বিশেষ ক্রিয়াকলাপ ভুলে গেছে কিনা তা আপনি যদি সন্ধান করেন এবং আপনি যদি অ্যাপ্লিকেশনটিতে সরাসরি অ্যাক্সেস ছাড়াই কোনও এসডিকে থাকেন তবে উত্তরগুলির কোনওটিতেই নির্দিষ্ট ক্ষেত্রে উপযুক্ত নয়। আমার জন্য আমি ব্যাকগ্রাউন্ড থ্রেডে ছিলাম একটি নতুন চ্যাট বার্তার জন্য সবেমাত্র একটি পুশ বিজ্ঞপ্তি পেয়েছি এবং চ্যাট স্ক্রিনটি পূর্বগ্রাউন্ডে না থাকলে কেবলমাত্র একটি সিস্টেম বিজ্ঞপ্তি প্রদর্শন করতে চাই।
ActivityLifecycleCallbacks
অন্যান্য উত্তরে যেমন প্রস্তাবিত হয়েছিল সেটিকে ব্যবহার করে আমি একটি ছোট ব্যবহারকারীর শ্রেণি তৈরি করেছি যা পূর্বগ্রন্থে রয়েছে কিনা তা যুক্তি রাখে MyActivity
।
class MyActivityMonitor(context: Context) : Application.ActivityLifecycleCallbacks {
private var isMyActivityInForeground = false
init {
(context.applicationContext as Application).registerActivityLifecycleCallbacks(this)
}
fun isMyActivityForeground() = isMyActivityInForeground
override fun onActivityPaused(activity: Activity?) {
if (activity is MyActivity) {
isMyActivityInForeground = false
}
}
override fun onActivityResumed(activity: Activity?) {
if (activity is MyActivity) {
isMyActivityInForeground = true
}
}
}
আমার কর্মসূচি এবং পুনরায় চালু করার সময়ে আমি শেয়ারডপ্রিফেন্সগুলিতে একটি ভিজিবল বুলিয়ান লিখি।
SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this);
Editor editor = sharedPrefs.edit();
editor.putBoolean("visible", false);
editor.commit();
যখন প্রয়োজন হয় তখন তা অন্য কোথাও পড়ুন,
// Show a Toast Notification if App is not visible (ie in background. Not running, etc)
SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(context);
if(!sharedPrefs.getBoolean("visible", true)){...}
হতে পারে মার্জিত না, তবে এটি আমার জন্য কাজ করে ...
উত্তর দিতে দেরি হতে পারে তবে কেউ যদি এখানে আসেন তবে আমার সমাধানটির সমাধানটি এখানে দেওয়া পরামর্শ, কারণ কোনও অ্যাপ্লিকেশন তার পটভূমির অবস্থান বা অগ্রভাগে আসার অবস্থা জানতে চায় তার কারণ অনেকগুলি হতে পারে, কয়েকটি হ'ল, ১। ব্যবহারকারী যখন বিজি তে থাকে তখন টোস্টগুলি এবং বিজ্ঞপ্তিগুলি দেখানোর জন্য। ২. প্রথমবারের মতো কিছু কাজ সম্পাদনের জন্য ব্যবহারকারী বিজি থেকে আসে, যেমন একটি পোল, পুনর্নির্মাণ ইত্যাদি from
আইডলন এবং অন্যান্যদের সমাধান প্রথম অংশটির যত্ন নেয় তবে দ্বিতীয়টির জন্য হয় না। যদি আপনার অ্যাপ্লিকেশনটিতে একাধিক ক্রিয়াকলাপ থাকে এবং ব্যবহারকারী তাদের মধ্যে স্যুইচ করে চলেছে তবে আপনি দ্বিতীয় ক্রিয়াকলাপের সাথে সাথে দৃশ্যমান পতাকাটি মিথ্যা হবে। সুতরাং এটি নির্বিচারে ব্যবহার করা যাবে না।
কমন্সওয়্যার দ্বারা প্রস্তাবিত এমন কিছু আমি করেছি, "যদি পরিষেবাটি নির্ধারণ করে যে কোনও ক্রিয়াকলাপ দৃশ্যমান নয়, এবং এটি কিছু সময়ের জন্য এইভাবে থেকে যায় , তবে পরবর্তী যৌক্তিক স্টপিং পয়েন্টে ডেটা স্থানান্তর বন্ধ করুন।"
গা bold় রেখাটি গুরুত্বপূর্ণ এবং এটি দ্বিতীয় আইটেমটি অর্জন করতে ব্যবহার করা যেতে পারে। তাই আমি যা করি তা হ'ল একবার আমি অ্যাক্টিভিটি পজড () পেয়েছি, সরাসরি দৃশ্যকে মিথ্যাতে বদলে না, পরিবর্তে 3 সেকেন্ডের টাইমার রাখি (এটি পরবর্তী ক্রিয়াকলাপটি চালু করা সর্বাধিক) এবং যদি অ্যাক্টিভিটি পুনরায় চালু না করা হয় ( ) পরবর্তী 3 সেকেন্ডে কল করুন, মিথ্যাতে দৃশ্যমান পরিবর্তন করুন। একইভাবে onActivityResume () এ যদি টাইমার থাকে তবে আমি এটিকে বাতিল করি। সংক্ষিপ্তসার হিসাবে, দৃশ্যমান হয় অ্যাপ্লিকেশনব্যাকগ্রাউন্ড।
দুঃখিত কোডটি অনুলিপি করতে পারবেন না ...
আমি আপনাকে এটি করার জন্য অন্য উপায়টি ব্যবহার করার জন্য সুপারিশ করতে চাই।
আমি অনুমান করি যে প্রোগ্রামটি শুরু হওয়ার সময় আপনি শুরু করার স্ক্রিনটি দেখাতে চান, এটি ইতিমধ্যে ব্যাকএন্ডে চলমান থাকলে, এটি দেখাবেন না।
আপনার অ্যাপ্লিকেশন একটি নির্দিষ্ট ফাইলটিতে অবিচ্ছিন্নভাবে বর্তমান সময় লিখতে পারে। আপনার অ্যাপ্লিকেশন শুরু হওয়ার সময়, সর্বশেষ টাইমস্ট্যাম্পটি পরীক্ষা করুন, যদি বর্তমান_টাইম-শেষ_কাল> সর্বশেষ সময় লেখার জন্য আপনার নির্দিষ্ট সময়সীমাটি নির্দিষ্ট করে থাকে, তার অর্থ আপনার অ্যাপ্লিকেশনটি বন্ধ হয়ে গেছে, হয় সিস্টেম বা ব্যবহারকারী নিজেই মেরেছেন।