যখন কোনও অ্যান্ড্রয়েড অ্যাপ ব্যাকগ্রাউন্ডে যায় এবং অগ্রভাগে ফিরে আসে কীভাবে সনাক্ত করতে হয়


382

আমি এমন একটি অ্যাপ্লিকেশন লেখার চেষ্টা করছি যা কিছু সময় পরে ফোরগ্রাউন্ডে ফিরে এলে নির্দিষ্ট কিছু করে। কোনও অ্যাপ্লিকেশন যখন ব্যাকগ্রাউন্ডে প্রেরণ করা হয় বা সম্মুখভাগে আনা হয় তখন এটি সনাক্ত করার কোনও উপায় আছে কি?


2
প্রশ্নটিতে একটি ব্যবহারের কেস যুক্ত করা হতে পারে কারণ এটি সুস্পষ্ট বলে মনে হচ্ছে না, তাই প্রদত্ত উত্তরে এটি সম্বোধন করা হয়নি। অ্যাপ্লিকেশনটি অন্য অ্যাপটি শুরু করতে পারে (উদাহরণস্বরূপ গ্যালারী), যা এখনও একই স্ট্যাকের মধ্যে থাকবে এবং অ্যাপ্লিকেশনটির পর্দার এক হিসাবে উপস্থিত হবে এবং তারপরে হোম বোতাম টিপবে। অ্যাপ লাইফাইসাইকেলের (বা এমনকি মেমরি পরিচালনা) নির্ভর কোনও পদ্ধতিই এটি সনাক্ত করতে সক্ষম নয়। বাহ্যিক ক্রিয়াকলাপটি প্রদর্শিত হলে ঠিক সেগুলি পৃষ্ঠপোষকতার দিকে চালিত করবে, আপনি যখন হোম চাপবেন না তখন not
ডেনিস কে

আপনি যে উত্তরটি সন্ধান করছেন এটি এটি: স্ট্যাকওভারফ্লো.com
ফ্রেড পোরসিঙ্কুলা

1
গুগল সমাধান দেখুন stackoverflow.com/questions/3667022/...
user1269737

উত্তর:


98

onPause()এবং onResume()পদ্ধতি যখন আবেদন আবার পটভূমি প্রয়োজন এবং ফোরগ্রাউন্ড মধ্যে আনা হয় বলা হয়। তবে, অ্যাপ্লিকেশনটি প্রথমবারের জন্য এবং এটি হত্যার আগে শুরু করা হলে তাদেরও ডাকা হয়। আপনি ক্রিয়াকলাপে আরও পড়তে পারেন ।

এখানে কোনো সরাসরি পদ্ধতির ব্যাকগ্রাউন্ড বা পুরোভূমিতে অ্যাপ্লিকেশানটি অবস্থা জানতে হয় না, কিন্তু এমনকি আমি এই বিষয় সম্মুখীন এবং সমাধান পাওয়া যায় onWindowFocusChangedএবং onStop

আরও তথ্যের জন্য এখানে অ্যান্ড্রয়েড চেক করুন : কোনও অ্যান্ড্রয়েড অ্যাপ কখন ব্যাকগ্রাউন্ডে যায় তা সনাক্ত করার সমাধান এবং getRunningTasks বা getRunningAppProcesses ছাড়াই অগ্রভাগে ফিরে আসার সমাধান


173
তবে এই পদ্ধতির ফলে মিথ্যা ইতিবাচক কারণগুলি ঘটায় অন্যরা দেখায় যেহেতু একই অ্যাপ্লিকেশনগুলিতে ক্রিয়াকলাপগুলির মধ্যে স্থানান্তরিত করার সময় এই পদ্ধতিগুলিও ডাকা হয়।
জন লেহম্যান

9
এটি তার চেয়েও খারাপ। আমি এটি চেষ্টা করেছিলাম এবং কখনও কখনও ফোনটি লক থাকা অবস্থায় অনারিউমামকে কল করা হয়। আপনি যদি ডকুমেন্টেশনে অনারিউমের সংজ্ঞাটি দেখতে পান তবে আপনি পাবেন: মনে রাখবেন যে অনারিউমটি আপনার ক্রিয়াকলাপটি ব্যবহারকারীদের কাছে দৃশ্যমান যে সেরা সূচক নয়; কীবোর্ডের মতো একটি সিস্টেম উইন্ডো সামনে থাকতে পারে। আপনার ক্রিয়াকলাপটি ব্যবহারকারীর কাছে দৃশ্যমান (উদাহরণস্বরূপ, গেমটি আবার শুরু করতে) আপনার উইন্ডোফোকাস চেঞ্জড (বুলিয়ান) ব্যবহার করুন। বিকাশকারী.অ্যান্ড্রয়েড.
com/references/android/app/…

2
লিঙ্কটিতে পোস্ট করা সমাধানটি অন-রিসুম / অনপজ ব্যবহার করে না, পরিবর্তে অনব্যাকপ্রেসড, অনস্টপ, অন ​​স্টার্ট এবং অন উইন্ডোজফোকাস পরিবর্তিত সংমিশ্রণ। এটি আমার পক্ষে কাজ করেছে, এবং আমার তুলনায় একটি জটিল UI শ্রেণিবিন্যাস রয়েছে (ড্রয়ার, ডায়নামিক ভিউপ্যাজারস ইত্যাদি)
মার্টিন মার্কনকিনি

18
অনপস এবং অনেসিউম ক্রিয়াকলাপ নির্দিষ্ট। অ্যাপ্লিকেশন নয়। যখন কোনও অ্যাপ্লিকেশনটিকে পটভূমিতে স্থাপন করা হয় এবং তারপরে পুনরায় চালু করা হয়, তখন এটি ব্যাকগ্রাউন্ডে যাওয়ার আগে নির্দিষ্ট কার্যকলাপটি পুনরায় শুরু করে। এর অর্থ হ'ল আপনার অ্যাপ্লিকেশনটির সমস্ত ক্রিয়াকলাপে পটভূমি থেকে আবার শুরু করার জন্য যা কিছু করতে চান তা কার্যকর করতে হবে। আমি বিশ্বাস করি যে আসল প্রশ্নটি ক্রিয়াকলাপের জন্য নয় বরং অ্যাপ্লিকেশনটির জন্য "অনারুমিউম" এর মতো কিছু খুঁজছিল।
সিসহেক্স

4
আমি বিশ্বাস করতে পারি না যে এ জাতীয় সাধারণ প্রয়োজনের জন্য উপযুক্ত এপিআই সরবরাহ করা হয় না। প্রাথমিকভাবে আমি ভেবেছিলাম ইউজারলিভ হিন্ট () এটি কেটে ফেলবে, তবে আপনি বলতে পারবেন না যে ব্যবহারকারী অ্যাপ্লিকেশনটি রেখে চলেছে বা না
atsakiridis

197

2018: অ্যান্ড্রয়েড লাইফসাইकल উপাদানগুলির মাধ্যমে এটিকে স্থানীয়ভাবে সমর্থন করে।

মার্চ 2018 আপডেট : এখন আরও একটি ভাল সমাধান আছে। প্রসেসলিফিসাইকেল ওভনার দেখুন । আপনাকে নতুন আর্কিটেকচার উপাদানগুলি 1.1.0 ব্যবহার করতে হবে (এই মুহূর্তে সর্বশেষ) তবে এটি বিশেষভাবে এটি করার জন্য ডিজাইন করা হয়েছে।

এই উত্তরে একটি সাধারণ নমুনা সরবরাহ করা আছে তবে আমি এটি সম্পর্কে একটি নমুনা অ্যাপ এবং একটি ব্লগ পোস্ট লিখেছি ।

২০১৪ সালে আমি যখন এটি লিখেছিলাম তখন থেকেই বিভিন্ন সমাধান দেখা দিয়েছে। কিছু কাজ করেছে, কেউ কেউ কাজ করছে বলে ধারণা করা হয়েছিল , তবে ত্রুটিগুলি ছিল (আমার সহ!) এবং আমরা একটি সম্প্রদায় হিসাবে (অ্যান্ড্রয়েড) পরিণতিগুলি নিয়ে বাঁচতে শিখেছি এবং বিশেষ মামলার জন্য কাজগুলি লিখেছি।

কখনও কোডের একক স্নিপেটকে সলিউশন হিসাবে সন্ধান করবেন বলে মনে করবেন না, এটি ক্ষেত্রে সম্ভাবনা কম; আরও ভাল, এটি কী করে এবং কেন এটি করে তা বোঝার চেষ্টা করুন।

MemoryBossশ্রেণী কখনোই আসলে যেমন এখানে লেখা আমার দ্বারা ব্যবহৃত হয়, এটা ঠিক ছদ্ম কোড যে কাজ ঘটেছে এক টুকরা ছিল।

আপনি যদি নতুন আর্কিটেকচার উপাদানগুলি ব্যবহার না করার জন্য বৈধ কারণ না থাকে (এবং কিছু রয়েছে, বিশেষত যদি আপনি সুপার ওল্ড এপিআইকে লক্ষ্য করেন) তবে এগিয়ে যান এবং সেগুলি ব্যবহার করুন। তারা নিখুঁত থেকে অনেক দূরে, কিন্তু ছিল না ComponentCallbacks2

আপডেট / নোটস (নভেম্বর ২০১৫) : লোকেরা দুটি মন্তব্য করছে, প্রথমটি তার >=পরিবর্তে ব্যবহার করা উচিত ==কারণ ডকুমেন্টেশনে বলা হয়েছে যে আপনাকে সঠিক মানগুলি পরীক্ষা করা উচিত নয় । এই অধিকাংশ ক্ষেত্রে জন্য জরিমানা, কিন্তু ভালুক মনে যে আপনি যদি হয় শুধুমাত্র করছেন যত্নশীল কিছু যখন অ্যাপ্লিকেশন পটভূমি গিয়েছিলাম, আপনি ব্যবহার == করতে হবে এবং অন্য সমাধান (কার্যকলাপ লাইফ সাইকল callbacks মত) সঙ্গে এটি একত্রিত করা, অথবা আপনি আপনার পছন্দসই প্রভাব নাও পেতে পারে। উদাহরণটি (এবং আমার কাছে এটি ঘটেছে) হ'ল যদি আপনি লক করতে চানপাসওয়ার্ড স্ক্রিন সহ আপনার অ্যাপ্লিকেশনটি যখন ব্যাকগ্রাউন্ডে যায় (যেমন আপনি 1 প্যাসওয়ার্ডের সাথে পরিচিত হন তবে) আপনি যদি মেমরি কম রাখেন এবং হঠাৎ পরীক্ষা করে দেখেন তবে আপনি আপনার অ্যাপ্লিকেশনটি লক করতে পারেন >= TRIM_MEMORYকারণ অ্যান্ড্রয়েড একটি LOW MEMORYকল ট্রিগার করবে এবং এটিই তোমার চেয়ে উঁচু সুতরাং আপনি কীভাবে / কী পরীক্ষা করেন তা যত্নবান হন।

অতিরিক্তভাবে, কিছু লোক আপনি ফিরে এলে কীভাবে সনাক্ত করবেন সে সম্পর্কে জিজ্ঞাসা করেছেন।

আমি যে সহজ উপায়টি ভাবতে পারি তার নীচে ব্যাখ্যা করা হয়েছে তবে কিছু লোক যেহেতু এটির সাথে অপরিচিত তাই আমি এখানে কিছু ছদ্ম কোড যুক্ত করছি। আপনার YourApplicationএবং MemoryBossক্লাসগুলি ধরে রেখে , আপনার class BaseActivity extends Activity(আপনার যদি না থাকে তবে আপনাকে একটি তৈরি করতে হবে)।

@Override
protected void onStart() {
    super.onStart();

    if (mApplication.wasInBackground()) {
        // HERE YOU CALL THE CODE YOU WANT TO HAPPEN ONLY ONCE WHEN YOUR APP WAS RESUMED FROM BACKGROUND
        mApplication.setWasInBackground(false);
    }
}

আমি স্টার্টটির পরামর্শ দিচ্ছি কারণ ডায়ালগগুলি কোনও ক্রিয়াকলাপ বিরতি দিতে পারে তাই আমি বাজি ধরছি আপনার অ্যাপটি "ব্যাকগ্রাউন্ডে চলে গেছে" এমনটি ভাবতে চান না যদি আপনি সমস্ত কিছু পূর্ণ পর্দার কথোপকথন প্রদর্শন করেন তবে আপনার মাইলেজ আলাদা হতে পারে।

এবং যে সব. যদি ব্লক কোড হবে শুধুমাত্র একবার কার্যকর করা , এমনকি যদি আপনি অন্য কার্যকলাপে যান, নতুন এক (যে extends BaseActivity) রিপোর্ট হবে wasInBackgroundহয় false, তাই এটি কোড এক্সিকিউট করা হবে না যতক্ষণ না onMemoryTrimmedবলা হয় এবং পতাকাঙ্কিত আবার সত্যতে সেট করা থাকে

আশা করি এইটি কাজ করবে.

আপডেট / নোটস (এপ্রিল 2015) : আপনি এই কোডটিতে সমস্ত অনুলিপি করুন এবং আটকানোর আগে নোট করুন যে আমি কয়েকটি দৃষ্টান্ত খুঁজে পেয়েছি যেখানে এটি 100% নির্ভরযোগ্য নাও হতে পারে এবং সেরা ফলাফল অর্জনের জন্য অবশ্যই অন্যান্য পদ্ধতির সাথে একত্রিত হতে হবে । উল্লেখযোগ্যভাবে, দুটি জ্ঞাত উদাহরণ রয়েছে যেখানে onTrimMemoryকল ব্যাকটি কার্যকর হওয়ার নিশ্চয়তা নেই:

  1. যদি আপনার ফোনটি আপনার অ্যাপ্লিকেশনটি দৃশ্যমান অবস্থায় স্ক্রিনটিকে লক করে রাখে (বলুন আপনার ডিভাইসটি এনএন মিনিটের পরে লক হয়ে যায়), এই কলব্যাকটি কল করা হয় না (বা সর্বদা নয়) কারণ লকস্ক্রিনটি কেবল শীর্ষে রয়েছে, তবে আপনার অ্যাপ্লিকেশনটি এখনও আচ্ছাদিত "চলমান" রয়েছে is

  2. যদি আপনার ডিভাইসটি মেমরির তুলনায় তুলনামূলকভাবে কম থাকে (এবং মেমরির চাপের মধ্যে থাকে) তবে অপারেটিং সিস্টেমটি এই কলটিকে উপেক্ষা করে সরাসরি আরও সমালোচনামূলক স্তরে চলে যাবে বলে মনে হচ্ছে।

এখন আপনার অ্যাপটি কখন ব্যাকগ্রাউন্ডে চলেছে তা আপনার পক্ষে জানা কতটুকু গুরুত্বপূর্ণ তা নির্ভর করে আপনার ক্রিয়াকলাপের জীবনচক্র এবং কী কী না ট্র্যাক করে এই সমাধানটি একসাথে বাড়িয়ে নিতে বা প্রয়োজন হতে পারে not

কেবল উপরের বিষয়টি মাথায় রাখুন এবং একটি ভাল QA দল রাখুন;)

আপডেট শেষ

এটি দেরিতে হতে পারে তবে আইসক্রিম স্যান্ডউইচ (এপিআই 14) এবং উপরে একটি নির্ভরযোগ্য পদ্ধতি রয়েছে ।

দেখা যাচ্ছে যে যখন আপনার অ্যাপ্লিকেশনটির আর দৃশ্যমান UI নেই, তখন একটি কলব্যাক ট্রিগার হয়। কলব্যাক, যা আপনি একটি কাস্টম ক্লাসে প্রয়োগ করতে পারেন, তাকে কম্পোনেন্টক্যালব্যাকস 2 (হ্যাঁ, একটি দুটি সহ) বলা হয়। এই কলব্যাকটি কেবলমাত্র API স্তরের 14 (আইসক্রিম স্যান্ডউইচ) এবং তারপরে উপলব্ধ।

আপনি মূলত পদ্ধতিতে একটি কল পান:

public abstract void onTrimMemory (int level)

স্তরটি 20 বা আরও নির্দিষ্টভাবে

public static final int TRIM_MEMORY_UI_HIDDEN

আমি এটি পরীক্ষা করে চলেছি এবং এটি সর্বদা কার্যকর হয়, কারণ স্তর 20 কেবলমাত্র একটি "পরামর্শ" যা আপনার অ্যাপ্লিকেশনটি আর দৃশ্যমান না হওয়ায় আপনি কিছু সংস্থান প্রকাশ করতে চাইতে পারেন।

সরকারী দস্তাবেজের উদ্ধৃতি দিতে:

OnTrimMemory (int) এর স্তর: প্রক্রিয়াটি একটি ইউজার ইন্টারফেস দেখায় এবং এখন আর তা করে না। মেমরির আরও ভাল পরিচালিত হওয়ার জন্য ইউআই সহ বড় বরাদ্দগুলি এই মুহুর্তে ছেড়ে দেওয়া উচিত।

অবশ্যই এটি বাস্তবায়িতভাবে যা বলা হয়েছে তা করার জন্য আপনার এটি প্রয়োগ করা উচিত (নির্দিষ্ট সময়ে ব্যবহৃত হয়নি এমন মেমরির শুদ্ধি, অবকাশহীন বসে থাকা কিছু সংগ্রহ সাফ করুন ইত্যাদি সম্ভাবনাগুলি অন্তহীন (আরও সম্ভাব্য আরও কিছু সরকারী দস্তাবেজ দেখুন সমালোচনামূলক স্তর)।

তবে, মজার বিষয় হ'ল ওএস আপনাকে বলে দিচ্ছে: ওহে, আপনার অ্যাপটি ব্যাকগ্রাউন্ডে চলে গেছে!

আপনি প্রথমে যা জানতে চেয়েছিলেন তা হ'ল।

আপনি কখন ফিরে আসবেন তা নির্ধারণ করবেন?

আচ্ছা এটি সহজ, আমি নিশ্চিত যে আপনার একটি "বেসঅ্যাক্টিভিটি" রয়েছে যাতে আপনি নিজের অনারিউম () ব্যবহার করতে পারেন যাতে আপনি ফিরে এসেছেন তা চিহ্নিত করতে। কারণ আপনি কেবল যখন ফিরে আসবেন না কেবল যখন আপনি উপরের onTrimMemoryপদ্ধতিটিতে কল পাবেন তখনই আপনি যাবেন ।

এটা কাজ করে। আপনি মিথ্যা ধনাত্মক পাবেন না। যদি কোনও ক্রিয়াকলাপ আবার শুরু হয় তবে আপনি 100% বার ফিরে এসেছেন। যদি ব্যবহারকারী আবার পিছনে যায়, আপনি অন্য onTrimMemory()কল পান।

আপনাকে আপনার ক্রিয়াকলাপগুলি (বা আরও ভাল, একটি কাস্টম ক্লাস) গ্রাহক করতে হবে।

আপনি সর্বদা এটি পাওয়ার গ্যারান্টি দেওয়ার সবচেয়ে সহজ উপায় হ'ল এর মতো একটি সাধারণ ক্লাস তৈরি করা:

public class MemoryBoss 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) {
            // We're in the Background
        }
        // you might as well implement some memory cleanup here and be a nice Android dev.
    }
}

এটি প্রয়োগ করার জন্য, আপনার অ্যাপ্লিকেশন বাস্তবায়নে ( আপনার একটি আছে, সঠিক? ), এর মতো কিছু করুন:

MemoryBoss mMemoryBoss;
@Override
public void onCreate() {
   super.onCreate();
   if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
      mMemoryBoss = new MemoryBoss();
      registerComponentCallbacks(mMemoryBoss);
   } 
}

আপনি একটি তৈরি করেন Interfaceআপনি একটি যোগ করতে পারিনি elseযে ifও বাস্তবায়ন ComponentCallbacks(ছাড়া 2) এপিআই 14. নিচের কিছু ব্যবহৃত কলব্যাক শুধুমাত্র করেছেন যে onLowMemory()পদ্ধতি এবং বলা না হয়ে যায় যখন আপনি পটভূমিতে যাওয়ার , কিন্তু আপনি ট্রিম মেমরি ব্যবহার করা উচিত ।

এখন আপনার অ্যাপটি চালু করুন এবং হোম টিপুন। আপনার onTrimMemory(final int level)পদ্ধতিটি কল করা উচিত (ইঙ্গিত: লগিং যোগ করুন)।

শেষ পদক্ষেপটি কলব্যাক থেকে নিবন্ধন করা। সম্ভবত সেরা জায়গাটি হ'ল onTerminate()আপনার অ্যাপের পদ্ধতি, তবে , সেই পদ্ধতিটি কোনও আসল ডিভাইসে কল করা যায় না:

/**
 * This method is for use in emulated process environments.  It will
 * never be called on a production Android device, where processes are
 * removed by simply killing them; no user code (including this callback)
 * is executed when doing so.
 */

সুতরাং আপনার যদি সত্যিই এমন পরিস্থিতি না থাকে যেখানে আপনি আর নিবন্ধভুক্ত হতে চান না, তবে আপনি এটির নিরাপত্তা এড়াতে পারবেন, যেহেতু আপনার প্রক্রিয়া যেভাবেই ওএস স্তরে মারা যাচ্ছে।

যদি আপনি কোনও পর্যায়ে নিবন্ধভুক্ত হওয়ার সিদ্ধান্ত নেন (যদি আপনি, উদাহরণস্বরূপ, আপনার অ্যাপ্লিকেশনটি পরিষ্কার এবং মরে যাওয়ার জন্য একটি শাটডাউন প্রক্রিয়া সরবরাহ করেন), আপনি এটি করতে পারেন:

unregisterComponentCallbacks(mMemoryBoss);

এবং এটাই.


কোনও পরিষেবা থেকে এটি পরীক্ষা করার সময়, কেবলমাত্র হোম বোতাম টিপলে আগুন লাগবে। পিছনের বোতামটি টিপানো কিটকেটে এটি জ্বলবে না।
ওপেনজিএল ইএস

পরিষেবাটির কোনও ইউআই নেই সুতরাং এটি এর সাথে সম্পর্কিত হতে পারে। কোনও পরিষেবা নয়, আপনার বেস কার্যকলাপে চেক করুন the আপনার ইউআই কখন লুকানো আছে তা আপনি জানতে চান (এবং সম্ভবত পরিষেবাটি বলুন, সুতরাং এটি
অগ্রভাগে

1
আপনি যখন আপনার ফোনটি বন্ধ করবেন তখন এটি কাজ করে না। এটি ট্রিগার করা হয় না।
জুয়াংসিগ

2
কম্পোনেন্টক্যালব্যাকস ২.অনটিরিমমেমোরি () (অ্যাক্টিভিটিফাইসাইকেলক্যালব্যাক্সের সংমিশ্রণে) এখন পর্যন্ত পাওয়া একমাত্র নির্ভরযোগ্য সমাধান হ'ল ধন্যবাদ মার্টিন! আগ্রহীদের জন্য, আমার সরবরাহিত উত্তর দেখুন।
রিকুল

3
আমি এক বছর আগে থেকে এই পদ্ধতিটি ব্যবহার করে আসছি এবং এটি আমার কাছে সর্বদা নির্ভরযোগ্য। অন্যান্য লোকেরাও এটি ব্যবহার করে তা জেনে রাখা ভাল। আমি কেবল এটি ব্যবহার করি level >= ComponentCallbacks2.TRIM_MEMORY_UI_HIDDENযা আপনার আপডেট, পয়েন্ট ২ এ সমস্যাটি এড়ায় 1 পয়েন্ট 1 সম্পর্কিত, এটি আমার পক্ষে উদ্বেগের বিষয় নয়, যেহেতু অ্যাপটি সত্যই ব্যাকগ্রাউন্ডে যায় নি, সুতরাং এটি কাজ করার কথা।
sorianiv

175

আমি কীভাবে এটি সমাধান করতে পেরেছি তা এখানে। এটি এই ভিত্তিতে কাজ করে যে ক্রিয়াকলাপ স্থানান্তরগুলির মধ্যে সময়ের রেফারেন্স ব্যবহার করা সম্ভবত কোনও অ্যাপ্লিকেশন "ব্যাকগ্রাউন্ড" হয়েছে কিনা তা পর্যাপ্ত প্রমাণ সরবরাহ করবে।

প্রথমত, আমি একটি android.app. অ্যাপ্লিকেশন উদাহরণ ব্যবহার করেছি (আসুন একে মাই অ্যাপ্লিকেশন বলা যাক) যার একটি টাইমার, একটি টাইমার টাস্ক রয়েছে, যা একটি ক্রিয়াকলাপ থেকে অন্য ক্রিয়াকলাপে যুক্ত হতে পারে এমন সর্বাধিক সংখ্যক মিলিসেকেন্ডের প্রতিনিধিত্ব করার ধ্রুবক (আমি গিয়েছিলাম) 2s এর মান সহ) এবং অ্যাপ্লিকেশনটি "ব্যাকগ্রাউন্ডে" ছিল কিনা তা বোঝাতে একটি বুলিয়ান:

public class MyApplication extends Application {

    private Timer mActivityTransitionTimer;
    private TimerTask mActivityTransitionTimerTask;
    public boolean wasInBackground;
    private final long MAX_ACTIVITY_TRANSITION_TIME_MS = 2000;
    ...

অ্যাপ্লিকেশনটি টাইমার / টাস্ক শুরু এবং বন্ধ করার জন্য দুটি পদ্ধতিও সরবরাহ করে:

public void startActivityTransitionTimer() {
    this.mActivityTransitionTimer = new Timer();
    this.mActivityTransitionTimerTask = new TimerTask() {
        public void run() {
            MyApplication.this.wasInBackground = true;
        }
    };

    this.mActivityTransitionTimer.schedule(mActivityTransitionTimerTask,
                                           MAX_ACTIVITY_TRANSITION_TIME_MS);
}

public void stopActivityTransitionTimer() {
    if (this.mActivityTransitionTimerTask != null) {
        this.mActivityTransitionTimerTask.cancel();
    }

    if (this.mActivityTransitionTimer != null) {
        this.mActivityTransitionTimer.cancel();
    }

    this.wasInBackground = false;
}

এই সমাধানের শেষ টুকরোটি হ'ল অনক্রমে () এবং অনপস () সমস্ত ক্রিয়াকলাপের ইভেন্টগুলি থেকে বা এই পদ্ধতিতে প্রতিটিটিতে একটি কল যুক্ত করা বা সম্ভবত, আপনার সমস্ত কংক্রিটের ক্রিয়াকলাপের উত্তরাধিকার সূত্রে একটি বেস ক্রিয়াকলাপ:

@Override
public void onResume()
{
    super.onResume();

    MyApplication myApp = (MyApplication)this.getApplication();
    if (myApp.wasInBackground)
    {
        //Do specific came-here-from-background code
    }

    myApp.stopActivityTransitionTimer();
}

@Override
public void onPause()
{
    super.onPause();
    ((MyApplication)this.getApplication()).startActivityTransitionTimer();
}

সুতরাং যখন ব্যবহারকারী কেবল আপনার অ্যাপের ক্রিয়াকলাপগুলির মধ্যে সরাসরি নেভিগেট করছেন, তখন প্রস্থানের ক্রিয়াকলাপের অনপজ () টাইমার শুরু করে, তবে তত্ক্ষণাত নতুন ক্রিয়াকলাপটি প্রবেশ করানো টাইমারটিকে সর্বাধিক সংক্রমণের সময় পৌঁছানোর আগেই বাতিল করে দেয়। এবং তাই wasInBackground হবে মিথ্যা

অন্যদিকে একটি ভ্রমণ লঞ্চার থেকে ফোরগ্রাউন্ড, ডিভাইসের জেগে ওঠা, শেষ ফোন কল, ইত্যাদি সম্ভাবনা বেশি চেয়ে টাইমার টাস্ক এই ইভেন্টে পূর্বে মৃত্যুদন্ড কার্যকর, এবং এইভাবে বিষয় আসে, তখন wasInBackground সেট ছিল সত্য


4
হাই ডি 60402, আপনার উত্তরটি সত্যই সহায়ক আমার মতো কেউ
প্রবীণব

2
দুর্দান্ত প্রোগ্রামার হিসাবে চিহ্নিত হওয়া, আমার মধ্যে সবচেয়ে জটিল সমস্যার মধ্যে সবচেয়ে সহজ সমাধানটি আমি এসেছি।
আশিষ ভাটনগর

2
অসাধারণ সমাধান! ধন্যবাদ। যদি কারও "ক্লাসকাস্টএক্সেপশন" ত্রুটি হয়ে যায় তবে আপনি এটি আপনার ম্যানিফেস্ট.এক্সএমএল <অ্যাপ্লিকেশন অ্যান্ড্রয়েড: নাম = "আপনার.প্যাকেজ.মাই অ্যাপ্লিকেশন"
ওয়াহিব উল হক

27
এটি একটি দুর্দান্ত এবং সাধারণ বাস্তবায়ন। তবে আমি বিশ্বাস করি এটি অনপস / অন রেসুমির পরিবর্তে অন স্টার্ট / অনস্টপ এ প্রয়োগ করা উচিত। আমি কোনও ডায়ালগ শুরু করি যা আংশিকভাবে ক্রিয়াকলাপটি কভার করে। এবং কথোপকথনটি বন্ধ করা
অনুরুপভাবে রিসুমকে

7
আমি এই সমাধানটির একটি প্রকরণ ব্যবহার করার আশা করছি। উপরে চিহ্নিত ডায়লগগুলির বিষয়টি আমার পক্ষে সমস্যা, তাই আমি @ শুভায়ুর পরামর্শ (অন স্টার্ট / অনস্টপ) চেষ্টা করেছিলাম। তবে সাহায্য করে না কারণ এ-> বি যাওয়ার সময় অ্যাক্টিভিটি বি এর অন স্টার্ট () কে ক্রিয়াকলাপ এ এর ​​অনস্টপ () এর আগে ডাকা হয়।
ট্রেভর

150

সম্পাদনা: নতুন স্থাপত্য উপাদান প্রতিশ্রুতি কিছু এসেছে: ProcessLifecycleOwner দেখুন @ vokilam এর উত্তর


গুগল আই / ও আলাপ অনুসারে আসল সমাধান :

class YourApplication : Application() {

  override fun onCreate() {
    super.onCreate()
    registerActivityLifecycleCallbacks(AppLifecycleTracker())
  }

}


class AppLifecycleTracker : Application.ActivityLifecycleCallbacks  {

  private var numStarted = 0

  override fun onActivityStarted(activity: Activity?) {
    if (numStarted == 0) {
      // app went to foreground
    }
    numStarted++
  }

  override fun onActivityStopped(activity: Activity?) {
    numStarted--
    if (numStarted == 0) {
      // app went to background
    }
  }

}

হ্যাঁ. আমি জানি যে আমাদের সহজ সমাধান এখানে কার্যকর কারণ এই সহজ সমাধান কাজ করে বিশ্বাস করা কঠিন।

তবে আশা আছে।


3
এটি পুরোপুরি কাজ করে! আমি ইতিমধ্যে অনেকগুলি অদ্ভুত সমাধানের চেষ্টা করেছি যার মধ্যে অনেক ত্রুটি ছিল ... খুব ধন্যবাদ! আমি কিছুক্ষণের জন্য এটি খুঁজছিলাম
এগগাকিন বেকনওয়ালকার

7
এটি একাধিক ক্রিয়াকলাপের জন্য কাজ করে, তবে একের জন্য - অ্যানরোটেট সমস্ত ক্রিয়াকলাপ শেষ হয়ে গেছে বা পটভূমিতে নির্দেশ করবে
ডেডফিশ

2
@ শেহরি আপনি সঠিক, তবে এটি এই সমাধানের অংশ তাই উদ্বেগ হওয়া দরকার। যদি ফায়ারবেস এটির উপর নির্ভর করে তবে আমার মনে হয় আমার মধ্যযুগীয় অ্যাপটিও এটি করতে পারে :) দুর্দান্ত উত্তর বিটিডাব্লু।
এলিয়টএম

3
@ ডেডফিশ উত্তরের উপরে প্রদত্ত I / O এর লিঙ্কটি পরীক্ষা করুন। আপনি ক্রিয়াকলাপ বন্ধের মধ্যে সময়ের ব্যবধানগুলি পরীক্ষা করতে পারেন এবং আপনি সত্যিই ব্যাকগ্রাউন্ডে গিয়েছিলেন কিনা তা নির্ধারণ করতে শুরু করতে পারেন। এটি আসলে একটি উজ্জ্বল সমাধান।
অ্যালেক্স বার্ডনিকভ

2
জাভা সমাধান আছে কি? এটি কোটলিন।
গিয়াকোম বার্টোলি

116

ProcessLifecycleOwner এটি একটি প্রতিশ্রুতিবদ্ধ সমাধান বলে মনে হয়।

প্রসেসলিফাইসাইকেলওয়ানার প্রথম ক্রিয়াকলাপটি এই ইভেন্টগুলির মধ্য দিয়ে প্রেরণ ON_START, ON_RESUMEইভেন্টগুলি প্রেরণ করবে । ON_PAUSE,, ON_STOPইভেন্টগুলি একটি শেষ কার্যকলাপ তাদের মধ্য দিয়ে যাওয়ার পরে বিলম্বের সাথে প্রেরণ করা হবে । ProcessLifecycleOwnerকোনও কনফিগারেশন পরিবর্তনের কারণে ক্রিয়াকলাপ ধ্বংস এবং পুনরায় তৈরি করা হলে কোনও অনুষ্ঠান প্রেরণ করবে না এই গ্যারান্টিটি দেওয়ার জন্য এই বিলম্বটি যথেষ্ট দীর্ঘ ।

একটি বাস্তবায়ন হিসাবে সহজ হতে পারে

class AppLifecycleListener : LifecycleObserver {

    @OnLifecycleEvent(Lifecycle.Event.ON_START)
    fun onMoveToForeground() { // app moved to foreground
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
    fun onMoveToBackground() { // app moved to background
    }
}

// register observer
ProcessLifecycleOwner.get().lifecycle.addObserver(AppLifecycleListener())

উত্স কোড অনুসারে, বর্তমান বিলম্ব মান 700ms

এছাড়াও এই বৈশিষ্ট্যটি ব্যবহার করার জন্য dependencies:

implementation "androidx.lifecycle:lifecycle-extensions:$lifecycleVersion"

10
নোট করুন যে আপনাকে লাইফসাইকেল নির্ভরতা যুক্ত করতে হবে implementation "android.arch.lifecycle:extensions:1.0.0"এবং annotationProcessor "android.arch.lifecycle:compiler:1.0.0"গুগলের সংগ্রহস্থল থেকে (যেমন google())
স্যার কোডসালট

1
এটি আমার জন্য দুর্দান্ত কাজ করেছে, আপনাকে ধন্যবাদ। আমাকে এপিআই 'অ্যান্ড্রয়েড.আরচ.লাইফাইসাইকেল: এক্সটেনশানগুলি: 1.1.0' ব্যবহারের পরিবর্তে বাস্তবায়নের পরিবর্তে অ্যান্ড্রয়েড নির্ভরতা সংকলন এবং রানটাইম ক্লাসপাথের জন্য আলাদা সংস্করণ উল্লেখ করে বলেছে ating
FSUWX2011

এটি দুর্দান্ত সমাধান কারণ এটি কোনও কার্যকলাপের উল্লেখের প্রয়োজন ছাড়াই মডিউলগুলিতে কাজ করে!
সর্বোচ্চ

অ্যাপ ক্রাশ হওয়ার পরে এটি কাজ করছে না। অ্যাপ্লিকেশানের ক্র্যাশ হওয়া ইভেন্টটি পাওয়ার কোনও সমাধান কি এই সমাধানের মাধ্যমে রয়েছে
তেজরাজ

দুর্দান্ত সমাধান। আমার দিন বাঁচিয়েছে
সানি

69

মার্টন মার্কনকিনিস উত্তরের ভিত্তিতে (ধন্যবাদ!) আমি শেষ পর্যন্ত একটি নির্ভরযোগ্য (এবং খুব সহজ) সমাধান পেয়েছি found

public class ApplicationLifecycleHandler implements Application.ActivityLifecycleCallbacks, ComponentCallbacks2 {

    private static final String TAG = ApplicationLifecycleHandler.class.getSimpleName();
    private static boolean isInBackground = false;

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

    @Override
    public void onActivityStarted(Activity activity) {
    }

    @Override
    public void onActivityResumed(Activity activity) {

        if(isInBackground){
            Log.d(TAG, "app went to foreground");
            isInBackground = false;
        }
    }

    @Override
    public void onActivityPaused(Activity activity) {
    }

    @Override
    public void onActivityStopped(Activity activity) {
    }

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

    @Override
    public void onActivityDestroyed(Activity activity) {
    }

    @Override
    public void onConfigurationChanged(Configuration configuration) {
    }

    @Override
    public void onLowMemory() {
    }

    @Override
    public void onTrimMemory(int i) {
        if(i == ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN){
            Log.d(TAG, "app went to background");
            isInBackground = true;
        }
    }
}

তারপরে এটি আপনার অ্যাপ্লিকেশন ক্লাসের আপনারআনক্রিট () এ যুক্ত করুন

public class MyApp extends android.app.Application {

    @Override
    public void onCreate() {
        super.onCreate();

        ApplicationLifeCycleHandler handler = new ApplicationLifeCycleHandler();
        registerActivityLifecycleCallbacks(handler);
        registerComponentCallbacks(handler);

    }

}

আপনি কী এটিকে অ্যাপ্লিকেশনটিতে ব্যবহার করেন তা কী আপনি প্রদর্শন করতে পারেন, আমি কি এটি অ্যাপ ক্লাস বা অন্য কোথাও কল করি?
জেপিএম

এই নিখুঁত ধন্যবাদ আপনাকে !! এখন পর্যন্ত পরীক্ষায় দুর্দান্ত কাজ করে
অ্যারিক

অসম্পূর্ণ হলে এই উদাহরণ। রেজিস্ট্রেশনএকটিভিটি লাইফিসাইকেলক্যালব্যাকস কী?
নোমান


1
ভাল কাজ করেছেন +1 টি, শীর্ষ যেতে হয়েছে কারণ এটি নিখুঁত, অন্যান্য উত্তর তাকান না, এই @reno উত্তরে কিন্তু বাস্তব উদাহরণ ভিত্তি করে
Stoycho Andreev

63

আমরা এই পদ্ধতিটি ব্যবহার করি। এটি কাজ করা খুব সহজ দেখায়, তবে এটি আমাদের অ্যাপ্লিকেশনটিতে ভালভাবে পরীক্ষা করা হয়েছিল এবং বাস্তবে "হোম" বোতামে, "রিটার্ন" বোতাম দ্বারা বা স্ক্রীন লক করার পরে হোম স্ক্রিনে যাওয়াসহ সমস্ত ক্ষেত্রে আশ্চর্যজনকভাবে ভাল কাজ করে। একবার চেষ্টা করে দেখো.

আইডিয়াটি হ'ল, যখন অগ্রভাগে হয়, অ্যান্ড্রয়েড সর্বদা নতুন ক্রিয়াকলাপ শুরু করার ঠিক আগে শুরু করে। এটি গ্যারান্টিযুক্ত নয়, তবে এটি কীভাবে কাজ করে। বিটিডাব্লু, ফ্লুরি একই যুক্তি ব্যবহার করে বলে মনে হচ্ছে (কেবলমাত্র অনুমান, আমি এটি চেক করি নি, তবে এটি একই ঘটনাগুলিতে দেখায়)।

public abstract class BaseActivity extends Activity {

    private static int sessionDepth = 0;

    @Override
    protected void onStart() {
        super.onStart();       
        sessionDepth++;
        if(sessionDepth == 1){
        //app came to foreground;
        }
    }

    @Override
    protected void onStop() {
        super.onStop();
        if (sessionDepth > 0)
            sessionDepth--;
        if (sessionDepth == 0) {
            // app went to background
        }
    }

}

সম্পাদনা করুন: মতামত অনুসারে আমরা কোডের পরবর্তী সংস্করণগুলিতে অন স্টার্ট () এও চলে এসেছি। এছাড়াও, আমি সুপার কলগুলি যুক্ত করছি, যা আমার প্রাথমিক পোস্টটি থেকে অনুপস্থিত ছিল, কারণ এটি একটি ওয়ার্কিং কোডের চেয়ে বেশি ধারণা ছিল।


2
এটি সবচেয়ে নির্ভরযোগ্য উত্তর, যদিও আমি অন-রিসুমের পরিবর্তে অন স্টার্ট ব্যবহার করি use
গ্রেগ এনিস

ওভারডেড পদ্ধতিতে আপনার সুপার.অনিসিউম () এবং সুপার.অনস্টপ () এ কলগুলি যুক্ত করা উচিত। অন্যথায় একটি Android.app.SuperNotCalledException নিক্ষেপ করা হয়।
জান লাউসমান

1
আমার জন্য এটি কাজ করে না ... বা আপনি যখন খুব বেশি ডিভাইসটি ঘোরান তখন এটি অন্তত ইভেন্টটিকে আগুন দেয় (যা এক ধরণের মিথ্যা ইতিবাচক ইমো)।
নয়া

খুব সহজ এবং কার্যকর সমাধান! তবে আমি নিশ্চিত নই যে এটি আংশিক স্বচ্ছ ক্রিয়াকলাপগুলির সাথে কাজ করে যা পূর্ববর্তী ক্রিয়াকলাপের কিছু অংশ দৃশ্যমান হতে দেয়। ডক্স থেকে onStop is called when the activity is no longer visible to the user,।
নিকোলাস বুয়েট

3
ব্যবহারকারী যদি প্রথম ক্রিয়ায় ওরিয়েন্টেশন পরিবর্তন করে তবে কী ঘটে? এটি প্রতিবেদন করবে যে অ্যাপটি ব্যাকগ্রাউন্ডে গেছে যা সত্য নয়। আপনি এই পরিস্থিতিটি কীভাবে পরিচালনা করবেন?
নিমরোড দয়ান

54

যদি আপনার অ্যাপ্লিকেশনটিতে একাধিক অ্যাক্টিভেটস এবং / অথবা ট্যাব বার উইজেটের মতো সজ্জিত অ্যাক্টিভেটস থাকে তবে অনপস () এবং onResume () কাজ করে না। অর্থাত্ একটি নতুন ক্রিয়াকলাপ শুরু করার সাথে সাথে নতুন ক্রিয়াকলাপ তৈরি হওয়ার আগে বর্তমান অ্যাক্টিভিটিগুলি বিরতি দেওয়া হবে। কোনও ক্রিয়াকলাপ শেষ করার পরে ("ফিরে" বোতামটি ব্যবহার করে) একই প্রয়োগ হয়।

আমি দুটি পদ্ধতি খুঁজে পেয়েছি যা মনে হয় হিসাবে কাজ করে।

প্রথমটির জন্য GET_TASKS অনুমতি প্রয়োজন এবং এটি একটি সাধারণ পদ্ধতি নিয়ে গঠিত যা প্যাকেজের নামগুলির সাথে তুলনা করে ডিভাইসে শীর্ষস্থানীয় ক্রিয়াকলাপটি অ্যাপ্লিকেশন সম্পর্কিত কিনা তা পরীক্ষা করে:

private boolean isApplicationBroughtToBackground() {
    ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
    List<RunningTaskInfo> tasks = am.getRunningTasks(1);
    if (!tasks.isEmpty()) {
        ComponentName topActivity = tasks.get(0).topActivity;
        if (!topActivity.getPackageName().equals(context.getPackageName())) {
            return true;
        }
    }

    return false;
}

এই পদ্ধতিটি ড্রড-ফু (বর্তমানে ইগনিশন নামে পরিচিত) কাঠামোর মধ্যে পাওয়া গেছে।

আমি যে দ্বিতীয় পদ্ধতিটি আমার নিজের প্রয়োগ করেছি তা GET_TASKS অনুমতি প্রয়োজন হয় না, যা ভাল। পরিবর্তে এটি বাস্তবায়নের জন্য আরও কিছুটা জটিল।

আপনার মেইন অ্যাপ্লিকেশন ক্লাসে আপনার একটি ভেরিয়েবল রয়েছে যা আপনার আবেদনে চলমান ক্রিয়াকলাপ ট্র্যাক করে। প্রতিটি ক্রিয়াকলাপের জন্য অনারিউম () -এ আপনি পরিবর্তনশীল বৃদ্ধি করেন এবং অনপেজ () এ আপনি এটি হ্রাস করেন।

চলমান ক্রিয়াকলাপের সংখ্যা 0 এ পৌঁছানোর পরে, নিম্নলিখিত শর্তগুলি সত্য হলে অ্যাপ্লিকেশনটিকে ব্যাকগ্রাউন্ডে রেখে দেওয়া হয়েছে:

  • ক্রিয়াকলাপ থামিয়ে দেওয়া হচ্ছে না ("পিছনে" বোতামটি ব্যবহৃত হয়েছিল)। এটি পদ্ধতি ক্রিয়াকলাপটি ব্যবহার করে করা যেতে পারে is
  • একটি নতুন ক্রিয়াকলাপ (একই প্যাকেজের নাম) শুরু হচ্ছে না। আপনি ভেরিয়েবল সেট করার জন্য স্টার্টঅ্যাক্টিভিটি () পদ্ধতিটি ওভাররাইড করতে পারেন যা এটি নির্দেশ করে এবং তারপরে এটি পোস্টপ্রেসিউম () এ পুনরায় সেট করুন, এটি কোনও ক্রিয়াকলাপ তৈরি / পুনঃসূচনা হওয়ার পরে চালানো শেষ পদ্ধতি।

আপনি যখন সনাক্ত করতে পারবেন যে অ্যাপ্লিকেশনটি পটভূমিতে পদত্যাগ করেছে, যখন এটি অগ্রভাগেও ফিরিয়ে আনা হবে তখন এটি সহজেই সনাক্ত করা যায়।


18
গুগল সম্ভবত এমন একটি অ্যাপ্লিকেশন প্রত্যাখ্যান করবে যা অ্যাক্টিভিটি ম্যানেজ.আরজিটরুনিংটাস্ক () ব্যবহার করে। ডকুমেন্টেশনে বলা হয়েছে যে এটি কেবল শত্রু দেব উদ্দেশ্য। বিকাশকারী.অ্যান্ড্রয়েড.
স্কাই কেলসি


1
আমি দেখেছি আমাকে এই পদ্ধতির সংমিশ্রণটি ব্যবহার করতে হয়েছে। 14-এ কোনও কার্যকলাপ শুরু করার সময় onUserLeaveHint () ডাকা হয়েছিল। } `
তালিকা বোট

7
ব্যবহারকারীরা একটি শক্তিশালী অনুমতি android.permission.GET_TASKS ব্যবহার করে খুব বেশি খুশি হবে না।
এমএসকিয়ার

6
getRunningTasks এপিআই লেভেল 21-এ অবহিত করা হয়েছে
নয়া

33

প্রসারিত একটি বর্গ তৈরি করুন Application। তারপরে এটির ওভাররাইড পদ্ধতিটি আমরা ব্যবহার করতে পারি onTrimMemory()

অ্যাপ্লিকেশনটি ব্যাকগ্রাউন্ডে গেছে কিনা তা সনাক্ত করতে আমরা ব্যবহার করব:

 @Override
    public void onTrimMemory(final int level) {
        if (level == ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) { // Works for Activity
            // Get called every-time when application went to background.
        } 
        else if (level == ComponentCallbacks2.TRIM_MEMORY_COMPLETE) { // Works for FragmentActivty
        }
    }

1
জন্য FragmentActivityআপনার কাছে জুড়তে চাইতে পারেন level == ComponentCallbacks2.TRIM_MEMORY_COMPLETEখুব।
শ্রুজান সিমহা

2
এই পদ্ধতির দিকে ইঙ্গিত করার জন্য অনেক ধন্যবাদ, আমাকে যখনই পটভূমির জন্য ক্রিয়াকলাপটি পুনরায় শুরু করা হয়, প্রিফ মান লেখার জন্য এই পদ্ধতিটি ব্যবহার করে এবং বেসএকটিভিটির উপর এই মানটি পরীক্ষা করা হয় তখনই আমাকে একটি পিন ডায়ালগ দেখাতে হবে।
স্যাম

18

OnUserLeaveHint ব্যবহার বিবেচনা করুন। আপনার অ্যাপটি ব্যাকগ্রাউন্ডে গেলেই এটি ডাকা হবে। অনপেজের পরিচালনা করার জন্য কোণার কেস থাকবে, যেহেতু এটি অন্যান্য কারণে ডাকা যেতে পারে; উদাহরণস্বরূপ যদি ব্যবহারকারী আপনার অ্যাপ্লিকেশান যেমন আপনার সেটিংস পৃষ্ঠা হিসাবে অন্য কোনও ক্রিয়াকলাপ খোলে, আপনার মূল ক্রিয়াকলাপের অনপেজ পদ্ধতিটি এখনও আপনার অ্যাপে থাকা সত্ত্বেও কল করা হবে; যা চলছে তা ট্র্যাক করার ফলে আপনি বাগের দিকে নিয়ে যাবে যখন আপনি পরিবর্তে অনারউজারলিভ হিন্ট কলব্যাকটি ব্যবহার করতে পারবেন যা আপনি যা জিজ্ঞাসা করছেন তা করে।

যখন ইউজারলিভহিন্টকে বলা হয়, আপনি বুলেয়ান ইনব্যাকগ্রাউন্ড পতাকাটি সত্য হিসাবে সেট করতে পারেন। অনারিউমেকে যখন ডাকা হয়, কেবল তখনই ধরে নিন যে ইনব্যাকগ্রাউন্ড পতাকাটি সেট করা থাকলে আপনি অগ্রভাগে ফিরে এসেছেন। এর কারণ এটি হল যে ব্যবহারকারী যদি আপনার সেটিংস মেনুতে থাকেন এবং কখনও অ্যাপ্লিকেশনটি না ফেলে থাকেন তবে অনুরুপটিকে আপনার মূল ক্রিয়াকলাপেও ডাকা হবে।

মনে রাখবেন যে ব্যবহারকারী যদি আপনার সেটিংসের স্ক্রিনে থাকাকালীন হোম বোতামটি হিট করে তবে আপনার সেটিংস ক্রিয়াকলাপে ইউজারলিভ হিন্ট কল করা হবে এবং তারা যখন ফিরে আসবে তখন আপনার সেটিংস কার্যকলাপে ডাকা হবে। আপনার প্রধান ক্রিয়াকলাপে যদি কেবলমাত্র এই সনাক্তকরণ কোডটি থাকে তবে আপনি এই ব্যবহারের ক্ষেত্রে মিস করবেন। সদৃশ কোড ছাড়াই আপনার সমস্ত ক্রিয়াকলাপে এই কোডটি রাখতে, একটি বিমূর্ত ক্রিয়াকলাপ শ্রেণি রয়েছে যা ক্রিয়াকলাপ প্রসারিত করে এবং এতে আপনার সাধারণ কোডটি রেখে দেয়। তারপরে আপনার প্রতিটি ক্রিয়াকলাপ এই বিমূর্ত ক্রিয়াকে প্রসারিত করতে পারে।

উদাহরণ স্বরূপ:

public abstract AbstractActivity extends Activity {
    private static boolean inBackground = false;

    @Override
    public void onResume() {
        if (inBackground) {
            // You just came from the background
            inBackground = false;
        }
        else {
            // You just returned from another activity within your own app
        }
    }

    @Override
    public void onUserLeaveHint() {
        inBackground = true;
    }
}

public abstract MainActivity extends AbstractActivity {
    ...
}

public abstract SettingsActivity extends AbstractActivity {
    ...
}

19
অন্য ব্যবহারে নেভিগেট করার সময় অন ইউজারলিভ হিন্টকেও ডাকা হয়
জোনাস স্টাওস্কি

3
onUserLeaveHint কল করা হয় না যখন উদাহরণস্বরূপ একটি ফোন কল আসে এবং কলিং ক্রিয়াকলাপটি সক্রিয় হয়ে যায়, সুতরাং এটির একটি প্রান্তের কেসও রয়েছে - অন্য ক্ষেত্রেও হতে পারে, যেহেতু আপনি onUserLeaveHint কলটি দমন করার উদ্দেশ্যে একটি পতাকা যুক্ত করতে পারেন। বিকাশকারী.অ্যান্ড্রয়েড
রেফারেন্স

1
এছাড়াও, onResume ভাল কাজ করে না। আমি এটি চেষ্টা করেছিলাম এবং কখনও কখনও ফোনটি লক থাকা অবস্থায় অনারিউমামকে কল করা হয়। আপনি যদি ডকুমেন্টেশনে অনারিউমের সংজ্ঞাটি দেখতে পান তবে আপনি পাবেন: মনে রাখবেন যে অনারিউমটি আপনার ক্রিয়াকলাপটি ব্যবহারকারীদের কাছে দৃশ্যমান যে সেরা সূচক নয়; কীবোর্ডের মতো একটি সিস্টেম উইন্ডো সামনে থাকতে পারে। আপনার ক্রিয়াকলাপটি ব্যবহারকারীর কাছে দৃশ্যমান (উদাহরণস্বরূপ, গেমটি আবার শুরু করতে) আপনার উইন্ডোফোকাস চেঞ্জড (বুলিয়ান) ব্যবহার করুন। বিকাশকারী.অ্যান্ড্রয়েড.
com/references/android/app/…

এই সমাধানটি একাধিক ক্রিয়াকলাপ থাকলে অগ্রভাগ / পটভূমি সিদ্ধান্ত নিতে সহায়তা করে না P প্লাজ স্ট্যাকওভারফ্লো.com
রাজ ত্রিবেদী

14

ActivityLifecycleCallbacks আগ্রহী হতে পারে তবে এটি নথিবদ্ধ নয়।

যদিও, আপনি যদি রেজিস্টারএকটিভিটি লাইফেসাইকেলক্যালব্যাকস () কল করেন তবে ক্রিয়াকলাপগুলি তৈরি করা, ধ্বংস হওয়া ইত্যাদির জন্য আপনার কলব্যাক পেতে সক্ষম হওয়া উচিত get ক্রিয়াকলাপের জন্য আপনি getComp घटकName () কল করতে পারেন ।


11
API স্তর 14 = \ যেহেতু
imort

দেখে মনে হচ্ছে এটি পরিষ্কার এবং আমার জন্য কাজ করে। ধন্যবাদ
duanbo1983

এটি গৃহীত উত্তর থেকে কীভাবে পৃথক, উভয়ই একই ক্রিয়াকলাপের লাইফসাইকেলের উপর নির্ভর করে?
মধ্যে Saitama

13

Android.arch.lifecycle প্যাকেজ ক্লাস এবং ইন্টারফেস যে আপনি জীবনচক্র-সচেতন উপাদান গড়ে তুলতে দেয় উপলব্ধ

আপনার অ্যাপ্লিকেশনটির লাইফাইসাইক্লসবার্স ইন্টারফেসটি প্রয়োগ করা উচিত:

public class MyApplication extends Application implements LifecycleObserver {

    @Override
    public void onCreate() {
        super.onCreate();
        ProcessLifecycleOwner.get().getLifecycle().addObserver(this);
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
    private void onAppBackgrounded() {
        Log.d("MyApp", "App in background");
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_START)
    private void onAppForegrounded() {
        Log.d("MyApp", "App in foreground");
    }
}

এটি করতে, আপনার বিল্ড.gradle ফাইলটিতে এই নির্ভরতা যুক্ত করতে হবে:

dependencies {
    implementation "android.arch.lifecycle:extensions:1.1.1"
}

গুগল দ্বারা প্রস্তাবিত হিসাবে, আপনার ক্রিয়াকলাপের আজীবন পদ্ধতিতে সম্পাদিত কোডটি ছোট করা উচিত:

একটি সাধারণ প্যাটার্ন হ'ল ক্রিয়াকলাপ এবং খণ্ডগুলির জীবনকালীন পদ্ধতিতে নির্ভরশীল উপাদানগুলির ক্রিয়াটি বাস্তবায়ন করা। যাইহোক, এই প্যাটার্নটি কোডের একটি দুর্বল সংস্থার এবং ত্রুটিগুলির প্রসারকে বাড়ে। লাইফাইসাইকেল-সচেতন উপাদানগুলি ব্যবহার করে আপনি নির্ভরশীল উপাদানগুলির কোডটি জীবনচক্র পদ্ধতি থেকে এবং উপাদানগুলিতে নিজেই স্থানান্তর করতে পারেন।

আপনি এখানে আরও পড়তে পারেন: https://developer.android.com/topic/libraries/architecture/lifecycle


এবং এটিকে প্রকাশ করতে এই যুক্ত করুন: <অ্যাপ্লিকেশন অ্যান্ড্রয়েড: নাম = "। অন্য অ্যাপ্লিকেশন">
ড্যান আলবোোটানু 20:48

9

আপনার অ্যাপ্লিকেশনটিতে কলব্যাক যুক্ত করুন এবং এর মতো রুট ক্রিয়াকলাপটি পরীক্ষা করুন:

@Override
public void onCreate() {
    super.onCreate();
    registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {
        @Override
        public void onActivityStopped(Activity activity) {
        }

        @Override
        public void onActivityStarted(Activity activity) {
        }

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

        @Override
        public void onActivityResumed(Activity activity) {
        }

        @Override
        public void onActivityPaused(Activity activity) {
        }

        @Override
        public void onActivityDestroyed(Activity activity) {
        }

        @Override
        public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
            if (activity.isTaskRoot() && !(activity instanceof YourSplashScreenActivity)) {
                Log.e(YourApp.TAG, "Reload defaults on restoring from background.");
                loadDefaults();
            }
        }
    });
}

আমি বাস্তবায়ন এই পদ্ধতি ব্যবহার বিবেচনা করব। এক ক্রিয়াকলাপ থেকে অন্য ক্রিয়াকলাপে স্থানান্তরিত হতে কয়েক মিলি সেকেন্ড সময় লাগে। শেষ ক্রিয়াকলাপটি অদৃশ্য হয়ে যাওয়ার সময়ের উপর ভিত্তি করে একটি নির্দিষ্ট কৌশল দ্বারা ব্যবহারকারীকে পুনরায় লগইন করার জন্য বিবেচনা করা যেতে পারে।
12'16 এ ড্রিঙ্ক্ট

6

আমি গিথুব অ্যাপ-ফোরগ্রাউন্ড-ব্যাকগ্রাউন্ড- শোনোতে একটি প্রকল্প তৈরি করেছি

আপনার অ্যাপ্লিকেশনটিতে সমস্ত ক্রিয়াকলাপের জন্য একটি বেসঅ্যাক্টিভিটি তৈরি করুন।

public class BaseActivity extends Activity {

    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
    }

    public static boolean isAppInFg = false;
    public static boolean isScrInFg = false;
    public static boolean isChangeScrFg = false;

    @Override
    protected void onStart() {
        if (!isAppInFg) {
            isAppInFg = true;
            isChangeScrFg = false;
            onAppStart();
        }
        else {
            isChangeScrFg = true;
        }
        isScrInFg = true;

        super.onStart();
    }

    @Override
    protected void onStop() {
        super.onStop();

        if (!isScrInFg || !isChangeScrFg) {
            isAppInFg = false;
            onAppPause();
        }
        isScrInFg = false;
    }

    public void onAppStart() {

        // Remove this toast
        Toast.makeText(getApplicationContext(), "App in foreground",    Toast.LENGTH_LONG).show();

        // Your code
    }

    public void onAppPause() {

        // Remove this toast
        Toast.makeText(getApplicationContext(), "App in background",  Toast.LENGTH_LONG).show();

        // Your code
    }
}

এখন এই বেসএক্টিভিটিটিকে আপনার সমস্ত ক্রিয়াকলাপের সুপার ক্লাস হিসাবে ব্যবহার করুন যেমন মেইনএকটিভিটি বেসঅ্যাক্টিভিটি প্রসারিত করে এবং আপনি যখন অ্যাপ্লিকেশন শুরু করবেন তখন অনপস্টার্ট কল হবে এবং অ্যাপ্লিকেশনটি কোনও পর্দা থেকে ব্যাকগ্রাউন্ডে চলে গেলে অনপপস () কল হবে।


@ কিরণ বোঘরা: আপনার সমাধানে কি কোনও ভ্রান্ত ইতিবাচক আছে?
হরিশ বিশ্বকর্মা

এই ক্ষেত্রে অনস্টার্ট () এবং অনস্টপ () ফাংশনটির সঠিক উত্তর ব্যবহার করা যেতে পারে। যা আপনাকে আপনার অ্যাপ্লিকেশন সম্পর্কে বলেছে
পীর ফাহিম শাহ

6

এটি সঙ্গে খুব সহজ প্রসেসলিফাইসাইক্লওয়ানারের

এই নির্ভরতা যুক্ত করুন

implementation "android.arch.lifecycle:extensions:$project.archLifecycleVersion"
kapt "android.arch.lifecycle:compiler:$project.archLifecycleVersion"

ইন Kotlin :

class ForegroundBackgroundListener : LifecycleObserver {


    @OnLifecycleEvent(Lifecycle.Event.ON_START)
    fun startSomething() {
        Log.v("ProcessLog", "APP IS ON FOREGROUND")
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
    fun stopSomething() {
        Log.v("ProcessLog", "APP IS IN BACKGROUND")
    }
}

তারপরে আপনার বেস ক্রিয়াকলাপে:

override fun onCreate() {
        super.onCreate()

        ProcessLifecycleOwner.get()
                .lifecycle
                .addObserver(
                        ForegroundBackgroundListener()
                                .also { appObserver = it })
    }

এই বিষয়টিতে আমার নিবন্ধটি দেখুন: https://medium.com/@egek92/how-to-actually-detect-fireground-background-changes-in-your-android-application-without-anting-9719cc822c48


5

আপনি এটিতে একটি জীবনচক্র পর্যবেক্ষক সংযুক্ত করে প্রসেসলিফিসাইকেলওয়ানার ব্যবহার করতে পারেন ।

  public class ForegroundLifecycleObserver implements LifecycleObserver {

    @OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
    public void onAppCreated() {
        Timber.d("onAppCreated() called");
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_START)
    public void onAppStarted() {
        Timber.d("onAppStarted() called");
    }

    @OnLifecycleEvent(Event.ON_RESUME)
    public void onAppResumed() {
        Timber.d("onAppResumed() called");
    }

    @OnLifecycleEvent(Event.ON_PAUSE)
    public void onAppPaused() {
        Timber.d("onAppPaused() called");
    }

    @OnLifecycleEvent(Event.ON_STOP)
    public void onAppStopped() {
        Timber.d("onAppStopped() called");
    }
}

তারপরে onCreate()আপনার অ্যাপ্লিকেশন ক্লাসে আপনি এটি কল করুন:

ProcessLifecycleOwner.get().getLifecycle().addObserver(new ForegroundLifecycleObserver());

এই সঙ্গে তোমাদের ঘটনা ক্যাপচার করতে সক্ষম হবে ON_PAUSEএবং ON_STOPআপনার আবেদনের যে ঘটতে যখন এটি ব্যাকগ্রাউন্ডে চলে যায়।


4

পুরো অ্যাপ্লিকেশনটি পটভূমিতে / অগ্রভাগে কখন চলে যায় তা বলার জন্য কোনও সরল লাইফসাইকেল পদ্ধতি নেই।

আমি সহজ পদ্ধতিতে এটি করেছি। অ্যাপ্লিকেশন পটভূমি / অগ্রভূমি ফেজ সনাক্ত করতে নীচের নির্দেশাবলী অনুসরণ করুন।

একটু workaround সঙ্গে, এটি সম্ভব। এখানে, অ্যাক্টিভিটি লাইফিসাইকেলক্যালব্যাকস উদ্ধার করতে আসে। আমাকে ধাপে ধাপে চলতে দিন।

  1. প্রথমে, এমন একটি শ্রেণি তৈরি করুন যা অ্যান্ড্রয়েড.এপ. প্রয়োগ করে এবং অ্যাক্টিভিটিফাইসাইকেলক্যালব্যাকস ইন্টারফেসটি প্রয়োগ করে । অ্যাপ্লিকেশন.অনক্রিয়েট () এ কলব্যাকটি নিবন্ধ করুন।

    public class App extends Application implements 
        Application.ActivityLifecycleCallbacks {
    
        @Override
        public void onCreate() {
            super.onCreate();
            registerActivityLifecycleCallbacks(this);
        }
    }
  2. নীচে হিসাবে ম্যানিফেস্টে "অ্যাপ" ক্লাসটি নিবন্ধ করুন <application android:name=".App"

  3. অ্যাপ্লিকেশনটি অগ্রভাগে থাকা অবস্থায় শুরু হওয়া অবস্থায় কমপক্ষে একটি ক্রিয়াকলাপ থাকবে এবং অ্যাপটি ব্যাকগ্রাউন্ডে থাকা অবস্থায় শুরু হওয়া অবস্থায় কোনও ক্রিয়াকলাপ থাকবে না।

    নীচে “অ্যাপ” শ্রেণিতে 2 টি ভেরিয়েবল ঘোষণা করুন।

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

    activityReferencesশুরু হওয়া অবস্থায় ক্রিয়াকলাপের সংখ্যা গণনা রাখে । isActivityChangingConfigurationsবর্তমান ক্রিয়াকলাপটি ওরিয়েন্টেশন সুইচের মতো কনফিগারেশন পরিবর্তনের মধ্য দিয়ে চলছে কিনা তা নির্দেশ করার জন্য এটি একটি পতাকা।

  4. নিম্নলিখিত কোড ব্যবহার করে আপনি সনাক্ত করতে পারবেন অ্যাপটি অগ্রভাগে আসে কিনা।

    @Override
    public void onActivityStarted(Activity activity) {
        if (++activityReferences == 1 && !isActivityChangingConfigurations) {
            // App enters foreground
        }
    }
  5. অ্যাপটি ব্যাকগ্রাউন্ডে চলে যায় কীভাবে এটি সনাক্ত করতে হয়।

    @Override
    public void onActivityStopped(Activity activity) {
        isActivityChangingConfigurations = activity.isChangingConfigurations();
        if (--activityReferences == 0 && !isActivityChangingConfigurations) {
            // App enters background
        }
    }

কিভাবে এটা কাজ করে:

লাইফাইসাইক্যাল পদ্ধতিগুলি ক্রম অনুসারে যেভাবে বলা হয় এটি দিয়ে এটি একটি সামান্য কৌশল। আমাকে একটি দৃশ্যে হাঁটতে দাও।

ধরে নিন যে ব্যবহারকারী অ্যাপটি চালু করে এবং লঞ্চার অ্যাক্টিভিটি এ চালু করা হয়েছে। লাইফাইসাইকেল কলগুলি হবে,

A.onCreate ()

এ। স্টার্ট () (++ ক্রিয়াকলাপের উল্লেখসমূহ == 1) (অ্যাপ ফোরগ্রাউন্ডে প্রবেশ করে)

A.onResume ()

এখন অ্যাক্টিভিটি এ কার্যক্রম বি শুরু করে B.

A.onPause ()

B.onCreate ()

বি স্টার্ট () (++ ক্রিয়াকলাপের উল্লেখসমূহ == 2)

B.onResume ()

এ.অনস্টপ () (--অ্যাক্টিভিটি রিফারেন্সস == 1)

তারপরে ব্যবহারকারী ক্রিয়াকলাপ বি থেকে আবার নেভিগেট করে,

B.onPause ()

এ স্টার্ট () (++ ক্রিয়াকলাপের উল্লেখসমূহ == 2)

A.onResume ()

বি। স্টপ () (--অ্যাক্টিভিটি রিফারেন্সস == 1)

B.onDestroy ()

তারপরে ব্যবহারকারী হোম বোতাম টিপুন,

A.onPause ()

এঅনস্টপ () (--অ্যাক্টিভিটি রেফারেন্সগুলি == 0) (অ্যাপ্লিকেশন পটভূমিতে প্রবেশ করে)

যদি ব্যবহারকারী ব্যাক বোতামের পরিবর্তে অ্যাক্টিভিটি বি থেকে হোম বোতাম টিপেন, তবুও এটি একই হবে এবং ক্রিয়াকলাপের উল্লেখগুলি হবে 0 । সুতরাং, আমরা অ্যাপ্লিকেশনটিকে পটভূমিতে প্রবেশ করার সময় সনাক্ত করতে পারি।

তো, এর ভূমিকা কী isActivityChangingConfigurations? উপরের দৃশ্যে, ধরুন ক্রিয়াকলাপ বিটি ওরিয়েন্টেশনকে পরিবর্তন করে। কলব্যাক ক্রম হবে,

B.onPause ()

বি.এস.এস.পি () (--অ্যাক্টিভিটি রেফারেন্সস == 0) (অ্যাপ্লিকেশন পটভূমিতে প্রবেশ করেছে ??)

B.onDestroy ()

B.onCreate ()

বি। স্টার্ট () (++ ক্রিয়াকলাপের উল্লেখসমূহ == 1) (অ্যাপ ফোরগ্রাউন্ডে প্রবেশ করেছে ??)

B.onResume ()

এই কারণে isActivityChangingConfigurationsযখন কার্যকলাপটি কনফিগারেশনের পরিবর্তনের মধ্য দিয়ে চলছে তখন দৃশ্যপট এড়াতে আমাদের একটি অতিরিক্ত চেক রয়েছে ।


3

অগ্রভাগ বা পটভূমি প্রবেশ করুক না কেন অ্যাপ্লিকেশন সনাক্ত করার জন্য আমি একটি ভাল পদ্ধতি পেয়েছি। এখানে আমার কোড । আশা করি এটি আপনাকে সহায়তা করবে।

/**
 * Custom Application which can detect application state of whether it enter
 * background or enter foreground.
 *
 * @reference http://www.vardhan-justlikethat.blogspot.sg/2014/02/android-solution-to-detect-when-android.html
 */
 public abstract class StatusApplication extends Application implements ActivityLifecycleCallbacks {

public static final int STATE_UNKNOWN = 0x00;
public static final int STATE_CREATED = 0x01;
public static final int STATE_STARTED = 0x02;
public static final int STATE_RESUMED = 0x03;
public static final int STATE_PAUSED = 0x04;
public static final int STATE_STOPPED = 0x05;
public static final int STATE_DESTROYED = 0x06;

private static final int FLAG_STATE_FOREGROUND = -1;
private static final int FLAG_STATE_BACKGROUND = -2;

private int mCurrentState = STATE_UNKNOWN;
private int mStateFlag = FLAG_STATE_BACKGROUND;

@Override
public void onCreate() {
    super.onCreate();
    mCurrentState = STATE_UNKNOWN;
    registerActivityLifecycleCallbacks(this);
}

@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
    // mCurrentState = STATE_CREATED;
}

@Override
public void onActivityStarted(Activity activity) {
    if (mCurrentState == STATE_UNKNOWN || mCurrentState == STATE_STOPPED) {
        if (mStateFlag == FLAG_STATE_BACKGROUND) {
            applicationWillEnterForeground();
            mStateFlag = FLAG_STATE_FOREGROUND;
        }
    }
    mCurrentState = STATE_STARTED;

}

@Override
public void onActivityResumed(Activity activity) {
    mCurrentState = STATE_RESUMED;

}

@Override
public void onActivityPaused(Activity activity) {
    mCurrentState = STATE_PAUSED;

}

@Override
public void onActivityStopped(Activity activity) {
    mCurrentState = STATE_STOPPED;

}

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

}

@Override
public void onActivityDestroyed(Activity activity) {
    mCurrentState = STATE_DESTROYED;
}

@Override
public void onTrimMemory(int level) {
    super.onTrimMemory(level);
    if (mCurrentState == STATE_STOPPED && level >= TRIM_MEMORY_UI_HIDDEN) {
        if (mStateFlag == FLAG_STATE_FOREGROUND) {
            applicationDidEnterBackground();
            mStateFlag = FLAG_STATE_BACKGROUND;
        }
    }else if (mCurrentState == STATE_DESTROYED && level >= TRIM_MEMORY_UI_HIDDEN) {
        if (mStateFlag == FLAG_STATE_FOREGROUND) {
            applicationDidDestroyed();
            mStateFlag = FLAG_STATE_BACKGROUND;
        }
    }
}

/**
 * The method be called when the application been destroyed. But when the
 * device screen off,this method will not invoked.
 */
protected abstract void applicationDidDestroyed();

/**
 * The method be called when the application enter background. But when the
 * device screen off,this method will not invoked.
 */
protected abstract void applicationDidEnterBackground();

/**
 * The method be called when the application enter foreground.
 */
protected abstract void applicationWillEnterForeground();

}


3

তুমি ব্যবহার করতে পার:

সুরক্ষিত শূন্য অন রিস্টার্ট ()

নতুন শুরু এবং পুনরায় আরম্ভের মধ্যে পার্থক্য।

এখানে চিত্র বর্ণনা লিখুন


3

সম্পাদনা 2: আমি নীচে যা লিখেছি তা বাস্তবে কার্যকর হবে না। গুগল এমন একটি অ্যাপ্লিকেশনকে প্রত্যাখ্যান করেছে যা ক্রিয়াকলাপে ম্যানেজ.আরজিটরুনিংটাস্কস () এ কল অন্তর্ভুক্ত করে। ডকুমেন্টেশন থেকে , এটি স্পষ্ট যে এই API টি কেবলমাত্র ডিবাগিং এবং বিকাশের উদ্দেশ্যে purposes নীচে গিটহাব প্রকল্পটি নতুন স্কিম যা টাইমার ব্যবহার করে এবং প্রায় ভাল হিসাবে আপডেট করার সময় পাওয়ার সাথে সাথে আমি এই পোস্টটি আপডেট করব।

সম্পাদনা করুন 1: আমি একটি আপ লিখেছি ব্লগ পোস্ট এবং তৈরি একটি সহজ GitHub সংগ্রহস্থলের এই সত্যিই সহজ করতে।

গৃহীত এবং শীর্ষ রেট দেওয়া উত্তর দুটিই সত্যই সেরা পদ্ধতির নয়। শীর্ষ অ্যাপ্লিকেশনটির প্রধান ক্রিয়াকলাপ একই অ্যাপ্লিকেশনে সংজ্ঞায়িত এমন ক্রিয়াকলাপের জন্য যে অ্যাপ্লিকেশনটির প্রধান ক্রিয়াকলাপটি অর্জন করছে তা হ্যান্ডেল করে না অ্যাপলিকেশনব্রোটটোব্যাকগ্রাউন্ড () এর শীর্ষ রেটেড উত্তরটির বাস্তবায়ন, তবে এর আলাদা জাভা প্যাকেজ রয়েছে। আমি এটি করার একটি উপায় নিয়ে এসেছি যা সেই ক্ষেত্রে কাজ করবে।

এটিকে অনপেজ () এ কল করুন এবং এটি আপনাকে বলবে যে আপনার অ্যাপ্লিকেশনটি পটভূমিতে চলে যাচ্ছে কারণ অন্য কোনও অ্যাপ্লিকেশন শুরু হয়েছে, বা ব্যবহারকারী হোম বোতাম টিপছেন।

public static boolean isApplicationBroughtToBackground(final Activity activity) {
  ActivityManager activityManager = (ActivityManager) activity.getSystemService(Context.ACTIVITY_SERVICE);
  List<ActivityManager.RunningTaskInfo> tasks = activityManager.getRunningTasks(1);

  // Check the top Activity against the list of Activities contained in the Application's package.
  if (!tasks.isEmpty()) {
    ComponentName topActivity = tasks.get(0).topActivity;
    try {
      PackageInfo pi = activity.getPackageManager().getPackageInfo(activity.getPackageName(), PackageManager.GET_ACTIVITIES);
      for (ActivityInfo activityInfo : pi.activities) {
        if(topActivity.getClassName().equals(activityInfo.name)) {
          return false;
        }
      }
    } catch( PackageManager.NameNotFoundException e) {
      return false; // Never happens.
    }
  }
  return true;
}

এফওয়াইআই, এর পরিবর্তে এটি অন স্টার্ট () এ কল করা যখন একটি সাধারণ ডায়ালগ থেকে বের করা হয় তখন কল করা এড়ানো হবে, উদাহরণস্বরূপ, একটি অ্যালার্ম বন্ধ হয়ে যায়।
স্কাই কেলসি

2

সঠিক উত্তর এখানে

নীচের মত মাই অ্যাপ নামের সাথে ক্লাস তৈরি করুন:

public class MyApp implements Application.ActivityLifecycleCallbacks, ComponentCallbacks2 {

    private Context context;
    public void setContext(Context context)
    {
        this.context = context;
    }

    private boolean isInBackground = false;

    @Override
    public void onTrimMemory(final int level) {
        if (level == ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) {


            isInBackground = true;
            Log.d("status = ","we are out");
        }
    }


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

    }

    @Override
    public void onActivityStarted(Activity activity) {

    }

    @Override
    public void onActivityResumed(Activity activity) {

        if(isInBackground){

            isInBackground = false;
            Log.d("status = ","we are in");
        }

    }

    @Override
    public void onActivityPaused(Activity activity) {

    }

    @Override
    public void onActivityStopped(Activity activity) {

    }

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

    }

    @Override
    public void onActivityDestroyed(Activity activity) {

    }

    @Override
    public void onConfigurationChanged(Configuration configuration) {

    }

    @Override
    public void onLowMemory() {

    }
}

তারপরে, আপনি যেদিকেই চান (অ্যাপ্লিকেশনে আরও ভাল প্রথম ক্রিয়াকলাপটি চালু করা হয়েছে), নীচের কোডটি যুক্ত করুন:

MyApp myApp = new MyApp();
registerComponentCallbacks(myApp);
getApplication().registerActivityLifecycleCallbacks(myApp);

সম্পন্ন! এখন যখন অ্যাপটি ব্যাকগ্রাউন্ডে রয়েছে status : we are out তখন আমরা লগ পাই এবং যখন আমরা অ্যাপে যাই তখন আমরা লগ পাইstatus : we are out


1

আমার সমাধান @ d60402 এর উত্তর দ্বারা অনুপ্রাণিত হয়েছিল এবং সময়-উইন্ডোতেও নির্ভর করে, তবে এটি ব্যবহার করে না Timer:

public abstract class BaseActivity extends ActionBarActivity {

  protected boolean wasInBackground = false;

  @Override
  protected void onStart() {
    super.onStart();
    wasInBackground = getApp().isInBackground;
    getApp().isInBackground = false;
    getApp().lastForegroundTransition = System.currentTimeMillis();
  }

  @Override
  protected void onStop() {
    super.onStop();
    if( 1500 < System.currentTimeMillis() - getApp().lastForegroundTransition )
      getApp().isInBackground = true;
  }

  protected SingletonApplication getApp(){
    return (SingletonApplication)getApplication();
  }
}

যেখানে ক্লাসের SingletonApplicationএক্সটেনশন Application:

public class SingletonApplication extends Application {
  public boolean isInBackground = false;
  public long lastForegroundTransition = 0;
}

1

আমি গুগল অ্যানালিটিকস ইজিট্র্যাকার দিয়ে এটি ব্যবহার করছিলাম এবং এটি কার্যকর হয়েছিল। আপনি একটি সাধারণ পূর্ণসংখ্যা ব্যবহার করে যা করতে চান তা করার জন্য এটি বাড়ানো যেতে পারে।

public class MainApplication extends Application {

    int isAppBackgrounded = 0;

    @Override
    public void onCreate() {
        super.onCreate();
        appBackgroundedDetector();
    }

    private void appBackgroundedDetector() {
        registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {
            @Override
            public void onActivityCreated(Activity activity, Bundle bundle) {

            }

            @Override
            public void onActivityStarted(Activity activity) {
                EasyTracker.getInstance(MainApplication.this).activityStart(activity);
            }

            @Override
            public void onActivityResumed(Activity activity) {
                isAppBackgrounded++;
                if (isAppBackgrounded > 0) {
                    // Do something here
                }
            }

            @Override
            public void onActivityPaused(Activity activity) {
                isAppBackgrounded--;
            }

            @Override
            public void onActivityStopped(Activity activity) {
                EasyTracker.getInstance(MainApplication.this).activityStop(activity);
            }

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

            }

            @Override
            public void onActivityDestroyed(Activity activity) {

            }
        });
    }
}

1

আমি এটি কিছুটা দেরিতে জানি তবে আমি মনে করি নীচের মত এটি করার সময় এই সমস্ত উত্তরগুলির কিছু সমস্যা আছে এবং এটি নিখুঁতভাবে কাজ করে।

এই জাতীয় কার্যকলাপ চক্র কলব্যাক তৈরি করুন:

 class ActivityLifeCycle implements ActivityLifecycleCallbacks{

    @Override
    public void onActivityCreated(Activity activity, Bundle savedInstanceState) {

    }

    @Override
    public void onActivityStarted(Activity activity) {

    }

    Activity lastActivity;
    @Override
    public void onActivityResumed(Activity activity) {
        //if (null == lastActivity || (activity != null && activity == lastActivity)) //use this condition instead if you want to be informed also when  app has been killed or started for the first time
        if (activity != null && activity == lastActivity) 
        {
            Toast.makeText(MyApp.this, "NOW!", Toast.LENGTH_LONG).show();
        }

        lastActivity = activity;
    }

    @Override
    public void onActivityPaused(Activity activity) {

    }

    @Override
    public void onActivityStopped(Activity activity) {

    }

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

    }

    @Override
    public void onActivityDestroyed(Activity activity) {

    }
}

এবং এটি নীচের মত আপনার অ্যাপ্লিকেশন ক্লাসে নিবন্ধন করুন:

public class MyApp extends Application {

@Override
public void onCreate() {
    super.onCreate();
    registerActivityLifecycleCallbacks(new ActivityLifeCycle());
}

এটি প্রতিটি ক্রিয়াকলাপে সর্বদা ডাকা হয়। আমি কীভাবে এটি ব্যবহার করতে পারি যদি উদাহরণস্বরূপ আমি ব্যবহারকারীর অনলাইন স্থিতি সনাক্ত করতে চাই
মাকসিম নিয়াজেভ

প্রশ্ন কি চায় thats। আপনি কেবল তখন হোম স্ক্রিনে যান এবং কোনও ক্রিয়াকলাপে ফিরে এলে এটি কল হয়।
আমির জিয়ারাটি

আপনি যদি ইন্টারনেট সংযোগ বোঝাতে চান তবে আপনার যখন প্রয়োজন হবে তখন তা পরীক্ষা করা ভাল বলে মনে করি। আপনার যদি কোনও এপি কল করার প্রয়োজন হয়, ফোন করার ঠিক আগে ইন্টারনেট সংযোগটি পরীক্ষা করে দেখুন।
আমির জিয়ারাটি

1

এটি এন্ড্রয়েডের মধ্যে অন্যতম জটিল প্রশ্ন হিসাবে দেখা যাচ্ছে যেহেতু (এই লেখা হিসাবে) অ্যান্ড্রয়েডের আইওএস সমতুল্যতা applicationDidEnterBackground()বা applicationWillEnterForeground()কলব্যাক নেই। আমি একটি অ্যাপস্টেট লাইব্রেরি ব্যবহার করেছি যা @ জেনজ একসাথে রেখেছিল

[অ্যাপস্টেট হ'ল) ​​একটি সহজ, বিক্রিয়াশীল অ্যান্ড্রয়েড লাইব্রেরি আরএক্সজাভা ভিত্তিক যা অ্যাপের রাজ্যের পরিবর্তনগুলি পর্যবেক্ষণ করে। অ্যাপটি পটভূমিতে যায় এবং অগ্রভাগে ফিরে আসে প্রতিবার এটি গ্রাহকদের জানিয়ে দেয়।

দেখা গেল এটি ঠিক আমার যা প্রয়োজন, বিশেষত কারণ আমার অ্যাপ্লিকেশনটিতে একাধিক ক্রিয়াকলাপ ছিল তাই কেবল চেক করা onStart()বা onStop()কোনও ক্রিয়াকলাপ এটিকে কাটছে না।

প্রথমে আমি এই নির্ভরতাগুলি গ্রেডে যুক্ত করেছি:

dependencies {
    compile 'com.jenzz.appstate:appstate:3.0.1'
    compile 'com.jenzz.appstate:adapter-rxjava2:3.0.1'
}

তাহলে আপনার কোডের একটি উপযুক্ত জায়গায় এই লাইনগুলি যুক্ত করা সহজ বিষয় ছিল:

//Note that this uses RxJava 2.x adapter. Check the referenced github site for other ways of using observable
Observable<AppState> appState = RxAppStateMonitor.monitor(myApplication);
//where myApplication is a subclass of android.app.Application
appState.subscribe(new Consumer<AppState>() {
    @Override
    public void accept(@io.reactivex.annotations.NonNull AppState appState) throws Exception {
        switch (appState) {
            case FOREGROUND:
                Log.i("info","App entered foreground");
                break;
            case BACKGROUND:
                Log.i("info","App entered background");
                break;
        }
    }
});

আপনি কীভাবে পর্যবেক্ষণযোগ্যতে সাবস্ক্রাইব করেছেন তার উপর নির্ভর করে মেমরি ফাঁস এড়াতে আপনাকে এ থেকে সদস্যতা ছাড়তে হতে পারে। গিথুব পৃষ্ঠায় আরও তথ্য ।


1

এটি @ d60402 এর উত্তরের পরিবর্তিত সংস্করণ: https://stackoverflow.com/a/15573121/4747587

সেখানে উল্লিখিত সমস্ত কিছু করুন। তবে এটি না Base Activityকরে এবং প্রতিটি ক্রিয়াকলাপের জন্য পিতামাতা হিসাবে তৈরি করা এবং ওভাররাইডিং onResume()এবংonPause , নীচের করুন:

আপনার অ্যাপ্লিকেশন শ্রেণিতে, লাইনটি যুক্ত করুন:

রেজিস্টারঅ্যাক্টিভিটি লাইফিসাইকেলক্যালব্যাকস (অ্যাপ্লিকেশন.অ্যাক্টিভিটি লাইফসাইকেলক্যালব্যাকস কলব্যাক);

এই callbackসমস্ত কার্যকলাপ জীবনচক্র পদ্ধতি হয়েছে এবং আপনি এখন ওভাররাইড করতে পারে onActivityResumed()এবংonActivityPaused()

এই গিস্টটি একবার দেখুন: https://gist.github.com/thsaravana/1fa576b6af9fc8fff20acfb2ac79fa1b


1

আপনি নীচের মত ActivityLifecycleCallbacksএবং এর সাহায্যে সহজেই এটি অর্জন ComponentCallbacks2করতে পারেন।

AppLifeCycleHandlerউপরে বর্ণিত ইন্টারফেস প্রয়োগকারী একটি শ্রেণি তৈরি করুন ।

package com.sample.app;

import android.app.Activity;
import android.app.Application;
import android.content.ComponentCallbacks2;
import android.content.res.Configuration;
import android.os.Bundle;

/**
 * Created by Naveen on 17/04/18
 */
public class AppLifeCycleHandler
    implements Application.ActivityLifecycleCallbacks, ComponentCallbacks2 {

  AppLifeCycleCallback appLifeCycleCallback;

  boolean appInForeground;

  public AppLifeCycleHandler(AppLifeCycleCallback appLifeCycleCallback) {
    this.appLifeCycleCallback = appLifeCycleCallback;
  }

  @Override
  public void onActivityResumed(Activity activity) {
    if (!appInForeground) {
      appInForeground = true;
      appLifeCycleCallback.onAppForeground();
    }
  }

  @Override
  public void onTrimMemory(int i) {
    if (i == ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) {
      appInForeground = false;
      appLifeCycleCallback.onAppBackground();
    }
  }

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

  }

  @Override
  public void onActivityStarted(Activity activity) {

  }

  @Override
  public void onActivityPaused(Activity activity) {

  }

  @Override
  public void onActivityStopped(Activity activity) {

  }

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

  }

  @Override
  public void onActivityDestroyed(Activity activity) {

  }

  @Override
  public void onConfigurationChanged(Configuration configuration) {

  }

  @Override
  public void onLowMemory() {

  }

  interface AppLifeCycleCallback {

    void onAppBackground();

    void onAppForeground();
  }
}

আপনার শ্রেণিতে যা অ্যাপ্লিকেশনটি অগ্রভূমি এবং পটভূমির মধ্যে স্যুইচ করলে কলব্যাকগুলি পাওয়ার জন্য Applicationপ্রয়োগকে প্রসারিত করে AppLifeCycleCallback। নীচের মত কিছু।

public class BaseApplication extends Application implements AppLifeCycleHandler.AppLifeCycleCallback{

    @Override
    public void onCreate() {
        super.onCreate();
        AppLifeCycleHandler appLifeCycleHandler = new AppLifeCycleHandler(this);
        registerActivityLifecycleCallbacks(appLifeCycleHandler);
        registerComponentCallbacks(appLifeCycleHandler);
    }

    @Override
    public void onAppBackground() {
        Log.d("LifecycleEvent", "onAppBackground");
    }

    @Override
    public void onAppForeground() {
        Log.d("LifecycleEvent", "onAppForeground");
    }
}

আশাকরি এটা সাহায্য করবে.

সম্পাদনা করুন বিকল্প হিসাবে আপনি এখন লাইফ চক্র সচেতন আর্কিটেকচার উপাদান ব্যবহার করতে পারেন।


1

যেহেতু আমি এমন কোনও পদ্ধতির সন্ধান পাইনি, যা টাইম স্ট্যাম্পগুলি পরীক্ষা না করেও ঘূর্ণন পরিচালনা করে, তাই আমি ভেবেছিলাম যে আমরা এখন কীভাবে এটি আমাদের অ্যাপে করি। এই উত্তরটির একমাত্র সংযোজন https://stackoverflow.com/a/42679191/5119746 হ'ল, আমরা সেই দিকটিও বিবেচনায় রাখি।

class MyApplication : Application(), Application.ActivityLifecycleCallbacks {

   // Members

   private var mAppIsInBackground = false
   private var mCurrentOrientation: Int? = null
   private var mOrientationWasChanged = false
   private var mResumed = 0
   private var mPaused = 0

তারপরে, কলব্যাকের জন্য আমাদের প্রথমে পুনরায় শুরু করুন:

   // ActivityLifecycleCallbacks

   override fun onActivityResumed(activity: Activity?) {

      mResumed++

      if (mAppIsInBackground) {

         // !!! App came from background !!! Insert code

         mAppIsInBackground = false
      }
      mOrientationWasChanged = false
    }

এবংঅ্যাক্টিভিটিসটপড:

   override fun onActivityStopped(activity: Activity?) {

       if (mResumed == mPaused && !mOrientationWasChanged) {

       // !!! App moved to background !!! Insert code

        mAppIsInBackground = true
    }

এবং তারপরে, এখানে সংযোজনটি আসে: ওরিয়েন্টেশন পরিবর্তনের জন্য পরীক্ষা করা:

   override fun onConfigurationChanged(newConfig: Configuration) {

       if (newConfig.orientation != mCurrentOrientation) {
           mCurrentOrientation = newConfig.orientation
           mOrientationWasChanged = true
       }
       super.onConfigurationChanged(newConfig)
   }

এটাই. আশা করি এটি কাউকে সাহায্য করবে :)


1

আমরা এই সমাধানটি ব্যবহার করে প্রসারিত করতে পারি LiveData:

class AppForegroundStateLiveData : LiveData<AppForegroundStateLiveData.State>() {

    private var lifecycleListener: LifecycleObserver? = null

    override fun onActive() {
        super.onActive()
        lifecycleListener = AppLifecycleListener().also {
            ProcessLifecycleOwner.get().lifecycle.addObserver(it)
        }
    }

    override fun onInactive() {
        super.onInactive()
        lifecycleListener?.let {
            this.lifecycleListener = null
            ProcessLifecycleOwner.get().lifecycle.removeObserver(it)
        }
    }

    internal inner class AppLifecycleListener : LifecycleObserver {

        @OnLifecycleEvent(Lifecycle.Event.ON_START)
        fun onMoveToForeground() {
            value = State.FOREGROUND
        }

        @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
        fun onMoveToBackground() {
            value = State.BACKGROUND
        }
    }

    enum class State {
        FOREGROUND, BACKGROUND
    }
}

এখন আমরা এই লাইভ ডেটাতে সাবস্ক্রাইব করতে এবং প্রয়োজনীয় ইভেন্টগুলি ধরতে পারি। উদাহরণ স্বরূপ:

appForegroundStateLiveData.observeForever { state ->
    when(state) {
        AppForegroundStateLiveData.State.FOREGROUND -> { /* app move to foreground */ }
        AppForegroundStateLiveData.State.BACKGROUND -> { /* app move to background */ }
    }
}

0

এই উত্তরগুলি সঠিক বলে মনে হচ্ছে না। এই ক্রিয়াকলাপগুলি যখন অন্য ক্রিয়াকলাপ শুরু হয় এবং শেষ হয় তখন তাকে ডাকা হয়। আপনি যা করতে পারেন তা হ'ল একটি বিশ্ব পতাকা রাখা (হ্যাঁ, গ্লোবালগুলি খারাপ) :) এবং আপনি যখনই কোনও নতুন ক্রিয়াকলাপ শুরু করবেন প্রতিবার এটি সত্যে সেট করুন। প্রতিটি ক্রিয়াকলাপের অনক্রিট এটিকে মিথ্যাতে সেট করুন। তারপরে, অনপজে আপনি এই পতাকাটি পরীক্ষা করে দেখুন। যদি এটি মিথ্যা হয়, আপনার অ্যাপ্লিকেশনটি পটভূমিতে চলেছে বা এটি মারা যাচ্ছে।


আমি একটি ডাটাবেস সম্পর্কে কথা বলিনি ... আপনার মানে কি?
জোরিস ওয়েইমার

আমি আপনার উত্তর সমর্থন করছি। যদিও আমরা উইন্ডোজ কল করার সময় ডাটাবেজে সেই পতাকাটির মানটি সংরক্ষণ করতে পারি এটি ভাল সমাধান নয় ...
সন্দীপ পি
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.