অ্যান্ড্রয়েড: আমি কীভাবে বর্তমান অগ্রভাগের ক্রিয়াকলাপটি (কোনও পরিষেবা থেকে) পেতে পারি?


180

কোনও পরিষেবা থেকে বর্তমানে চলমান ক্রিয়াকলাপের একটি রেফারেন্স পাওয়ার জন্য কী কোনও দেশীয় অ্যান্ড্রয়েড উপায় আছে?

আমার পটভূমিতে একটি পরিষেবা চলছে এবং আমি কোনও ঘটনা ঘটলে (পরিষেবাটিতে) আমার বর্তমান কার্যকলাপ আপডেট করতে চাই update এটি করার কোনও সহজ উপায় আছে (আমি উপরে প্রস্তাবিত মত)?


হয়তো এই আপনি একটি ধারণা দিতে পারেন stackoverflow.com/a/28423385/185022
AZ_

উত্তর:


87

কোনও পরিষেবা থেকে বর্তমানে চলমান ক্রিয়াকলাপের একটি রেফারেন্স পাওয়ার জন্য কী কোনও দেশীয় অ্যান্ড্রয়েড উপায় আছে?

আপনার "বর্তমানে চলমান ক্রিয়াকলাপ" এর মালিকানা নাও থাকতে পারে।

আমার পটভূমিতে একটি পরিষেবা চলছে এবং আমি কোনও ঘটনা ঘটলে (পরিষেবাটিতে) আমার বর্তমান কার্যকলাপ আপডেট করতে চাই update এটি করার কোনও সহজ উপায় আছে (আমি উপরে প্রস্তাবিত মত)?

  1. Intentক্রিয়াকলাপে একটি সম্প্রচার প্রেরণ করুন - এখানে এই নমুনাটি প্রদর্শন করে এমন একটি নমুনা প্রকল্প
  2. ক্রিয়াকলাপটি পরিষেবাটির অনুরোধ করে এমন একটি PendingIntent(যেমন, মাধ্যমে createPendingResult()) সরবরাহ করুন
  3. ক্রিয়াকলাপটি পরিষেবাটির মাধ্যমে কলব্যাক বা শ্রোতার অবজেক্টটির মাধ্যমে নিবন্ধভুক্ত করুন bindService()এবং সেই কলব্যাক / শ্রোতার অবজেক্টে পরিষেবাটির কোনও ইভেন্ট পদ্ধতিতে কল করুন
  4. ব্যাকআপ হিসাবে Intentস্বল্প-অগ্রাধিকার সহ ক্রিয়াকলাপে অর্ডার করা সম্প্রচার প্রেরণ করুন BroadcastReceiver( Notificationকার্যকলাপটি যদি স্ক্রিনটি অন-স্ক্রিন না হয় তবে একটি উত্থাপন করুন) - এই প্যাটার্নটিতে আরও একটি ব্লগ পোস্ট এখানে রয়েছে

3
ধন্যবাদ, তবে যেহেতু আমার কাছে প্রচুর ক্রিয়াকলাপ রয়েছে, এবং সেগুলি আপডেট করতে চাই না, তাই আমি অগ্রভাগঅ্যাক্টিভিটি পেতে একটি অ্যান্ড্রয়েড উপায় খুঁজছিলাম। আপনি যেমন বলেছেন, আমার তা করা সম্ভব হবে না। এর অর্থ আমাকে এই পথে যেতে হবে।
জর্জ

1
@ জর্জ: আপনি যা চান তা আপনাকে কোনওভাবেই সহায়তা করবে না। আপনি যেমন উল্লেখ করেছেন, আপনার "প্রচুর ক্রিয়াকলাপ" রয়েছে। সুতরাং, সেগুলি সমস্ত পৃথক শ্রেণি are অতএব, আপনার পরিষেবাটি প্রচুর পরিমাণে instanceofচেকের ব্লক ছাড়াই বা সাধারণ সুপারক্লাস বা ইন্টারফেস ভাগ করার জন্য ক্রিয়াকলাপগুলিকে রিফ্যাক্টর না করেই তাদের সাথে কিছুই করতে পারে না । এবং যদি আপনি ক্রিয়াকলাপগুলিকে রিফেক্টর করতে চলেছেন তবে আপনি এটি এমনভাবে করতে পারেন যা ফ্রেমওয়ার্কের সাথে আরও ভাল ফিট করে এবং আরও দৃশ্যাবলী কভার করে যেমন আপনার কোনও কার্যক্রমই সক্রিয় নয়। # 4 সম্ভবত সবচেয়ে কম কাজ এবং সবচেয়ে নমনীয়।
কমন্সওয়্যার

2
ধন্যবাদ, তবে আমার আরও ভাল সমাধান রয়েছে। আমার সমস্ত ক্রিয়াকলাপগুলি একটি কাস্টমাইজড বেসঅ্যাক্টিভিটি ক্লাস প্রসারিত করে। আমি একটি কনটেক্সট রেজিস্টার সেট করেছি যা আমার বেসএসিটিভিটি ক্লাসে লিটারেরলি 3 লাইন সহ যখনই অগ্রভাগে থাকে তখনকার गतिविधिটি বর্তমান হিসাবে নিবন্ধিত করে। তবুও, সমর্থনের জন্য ধন্যবাদ।
জর্জ

3
@ জর্জি: মেমরি ফাঁসের জন্য নজর রাখুন। পারস্পরিক স্থিতিশীল ডেটা সদস্যদের জাভাতে যেখানেই সম্ভব এড়ানো উচিত।
কমন্সওয়্যার

আমি অবজেক্টটি শক্তভাবে আবদ্ধ করেছি, যদিও আমি অবশ্যই এটি মনে রাখব। ধন্যবাদ।
জর্জ

139

আপডেট : এটি আর অ্যান্ড্রয়েড 5.0 হিসাবে অন্যান্য অ্যাপ্লিকেশনগুলির ক্রিয়াকলাপের সাথে আর কাজ করে না


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

উদাহরণ এখানে

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

আপনার কাছে একবার আপনি আপনার তালিকা থেকে শীর্ষঅ্যাক্টিভিটির জন্য অনুরোধ করে একটি কম্পোনেন্টনাম অবজেক্টটি পেতে পারেন।

এখানে একটি উদাহরণ।

    ActivityManager am = (ActivityManager) this.getSystemService(ACTIVITY_SERVICE);
    List<ActivityManager.RunningTaskInfo> taskInfo = am.getRunningTasks(1);
    Log.d("topActivity", "CURRENT Activity ::" + taskInfo.get(0).topActivity.getClassName());
    ComponentName componentInfo = taskInfo.get(0).topActivity;
    componentInfo.getPackageName();

আপনার ম্যানিফেস্টে আপনাকে নিম্নলিখিত অনুমতি দরকার হবে:

<uses-permission android:name="android.permission.GET_TASKS"/>

3
আপনার উত্তরটি 100% সঠিক han থানেক্সক্স 4 এটি betterএই উত্তরটি এখানে পোস্ট করা আরও ভাল
শাহজাদ ইমাম

1
@ আর্টঅফওয়ারফেয়ার যাচাই করা হয়নি তবে হ্যাঁ, আপনার খণ্ডের সংখ্যা অপ্রাসঙ্গিক কারণ এগুলি সর্বদা একক ক্রিয়াকলাপ দ্বারা হোস্ট করা হয়।
নেলসন রামিরেজ

2
আমার যদি বর্তমান ক্রিয়াকলাপ আরও ঘন ঘন প্রয়োজন হয় তবে আমাকে খুব ঘন ঘন পোলিং করতে হবে? অগ্রভাগের ক্রিয়াকলাপ যখনই পরিবর্তিত হয় তখন কি কলব্যাক ইভেন্ট পাওয়ার কোনও উপায় আছে?
nizam.sp

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

30
সেমিফাকে 21 এপি 21As of LOLLIPOP, this method is no longer available to third party applications: the introduction of document-centric recents means it can leak person information to the caller. For backwards compatibility, it will still return a small subset of its data: at least the caller's own tasks, and possibly some other tasks such as home that are known to not be sensitive.
শেরপ্যা

114

সতর্কতা: গুগল প্লে লঙ্ঘন

গুগল হুমকি দিয়েছে প্লে স্টোর থেকে অ্যাপ্লিকেশনগুলি অ্যাক্সেসযোগ্যতার উদ্দেশ্যে অ্যাক্সেসযোগ্যতার পরিষেবাগুলি ব্যবহার করলে তারা সরানোর হুমকি দেয় । তবে এটি পুনর্বিবেচনা করা হচ্ছে বলে জানা গেছে


একটি ব্যবহার করুন AccessibilityService

  • আপনি বর্তমানে ব্যবহার করে সক্রিয় উইন্ডোটি সনাক্ত করতে পারেন AccessibilityService
  • ইন onAccessibilityEventকলব্যাক, জন্য চেক ঘটনা টাইপ নির্ধারণ করার জন্য যখন বর্তমান উইন্ডোটি পরিবর্তন।TYPE_WINDOW_STATE_CHANGED
  • কল করে উইন্ডোটি কোনও কার্যকলাপ কিনা তা পরীক্ষা করে দেখুন PackageManager.getActivityInfo()

উপকারিতা

  • অ্যান্ড্রয়েড 7.1 (এপিআই 25) এর মাধ্যমে অ্যান্ড্রয়েড 2.2 (এপিআই 8) এ পরীক্ষিত এবং কাজ করছে।
  • ভোটদানের প্রয়োজন নেই।
  • GET_TASKSঅনুমতি প্রয়োজন হয় না ।

অসুবিধেও

  • প্রতিটি ব্যবহারকারীর অবশ্যই অ্যান্ড্রয়েডের অ্যাক্সেসযোগ্যতার সেটিংসে পরিষেবাটি সক্ষম করতে হবে।
  • এটি 100% নির্ভরযোগ্য নয়। মাঝেমধ্যে ইভেন্টগুলি অফ-অর্ডারে আসে।
  • পরিষেবাটি সর্বদা চলমান।
  • যখন কোনও ব্যবহারকারী এটি সক্ষম করার চেষ্টা করে AccessibilityService, কোনও অ্যাপ্লিকেশন যদি স্ক্রিনে ওভারলে রাখে তবে তারা ঠিক আছে বোতামটি টিপতে পারবেন না। এমন কিছু অ্যাপ্লিকেশনগুলি যা ভেলিস অটো ব্রাইটনেস এবং লাক্স। এটি বিভ্রান্তিকর হতে পারে কারণ ব্যবহারকারীরা জানেন না কেন তারা বোতামটি টিপতে পারে না বা কীভাবে এটি ব্যবহার করতে পারে।
  • AccessibilityServiceপ্রথম পর্যন্ত বর্তমান কার্যকলাপ জানবে না পরিবর্তন কার্যকলাপের।

উদাহরণ

সেবা

public class WindowChangeDetectingService extends AccessibilityService {

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

        //Configure these here for compatibility with API 13 and below.
        AccessibilityServiceInfo config = new AccessibilityServiceInfo();
        config.eventTypes = AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED;
        config.feedbackType = AccessibilityServiceInfo.FEEDBACK_GENERIC;

        if (Build.VERSION.SDK_INT >= 16)
            //Just in case this helps
            config.flags = AccessibilityServiceInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS;

        setServiceInfo(config);
    }

    @Override
    public void onAccessibilityEvent(AccessibilityEvent event) {
        if (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) {
            if (event.getPackageName() != null && event.getClassName() != null) {
                ComponentName componentName = new ComponentName(
                    event.getPackageName().toString(),
                    event.getClassName().toString()
                );

                ActivityInfo activityInfo = tryGetActivity(componentName);
                boolean isActivity = activityInfo != null;
                if (isActivity)
                    Log.i("CurrentActivity", componentName.flattenToShortString());
            }
        }
    }

    private ActivityInfo tryGetActivity(ComponentName componentName) {
        try {
            return getPackageManager().getActivityInfo(componentName, 0);
        } catch (PackageManager.NameNotFoundException e) {
            return null;
        }
    }

    @Override
    public void onInterrupt() {}
}

Andro আইডি

এটি আপনার প্রকাশ্যে মার্জ করুন:

<application>
    <service
        android:label="@string/accessibility_service_name"
        android:name=".WindowChangeDetectingService"
        android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE">
        <intent-filter>
            <action android:name="android.accessibilityservice.AccessibilityService"/>
        </intent-filter>
        <meta-data
            android:name="android.accessibilityservice"
            android:resource="@xml/accessibilityservice"/>
    </service>
</application>

পরিষেবা তথ্য

এটি রাখুন res/xml/accessibilityservice.xml:

<?xml version="1.0" encoding="utf-8"?>
<!-- These options MUST be specified here in order for the events to be received on first
 start in Android 4.1.1 -->
<accessibility-service
    xmlns:tools="http://schemas.android.com/tools"
    android:accessibilityEventTypes="typeWindowStateChanged"
    android:accessibilityFeedbackType="feedbackGeneric"
    android:accessibilityFlags="flagIncludeNotImportantViews"
    android:description="@string/accessibility_service_description"
    xmlns:android="http://schemas.android.com/apk/res/android"
    tools:ignore="UnusedAttribute"/>

পরিষেবা সক্ষম করা হচ্ছে

অ্যাপ্লিকেশনটির প্রতিটি ব্যবহারকারীর AccessibilityServiceএটির ব্যবহারের জন্য স্পষ্টভাবে সক্রিয় করতে হবে। কীভাবে এটি করা যায় তার জন্য এই স্ট্যাকওভারফ্লো উত্তরটি দেখুন ।

নোট করুন যে কোনও অ্যাপ্লিকেশন যদি স্ক্রিনে ভেলিস অটো উজ্জ্বলতা বা লাক্সের উপর কোনও ওভারলে স্থাপন করে থাকে তবে অ্যাক্সেসযোগ্যতা পরিষেবা সক্ষম করার চেষ্টা করার সময় ব্যবহারকারী অ্যাক্সেসযোগ্যতা পরিষেবা সক্ষম করার চেষ্টা করতে পারবেন না।


1
@lovemint, আমি বোঝানো: আমি একটি উদাহরণ নিদিষ্ট settingsActivityএর your.app.ServiceSettingsActivity, যাতে আপনি আপনার অভিগম্যতা পরিষেবাতে জন্য আপনার নিজের সেটিংস কার্যকলাপ যে পরিবর্তন করা উচিত। আমি মনে করি সেটিংস ক্রিয়াকলাপ যাইহোক optionচ্ছিক, তাই আমি সেই অংশটিকে আরও সহজ করার জন্য আমার উত্তর থেকে সরিয়েছি।
স্যাম

1
অনেক ধন্যবাদ, শুধুমাত্র শেষ প্রশ্ন। যদি আমাকে এপিআই 8 থেকে বর্তমানের বিষয়ে ডিল করতে হয় তবে এক্সএমএল ব্যবহারের পরিবর্তে কোডটি কাজ করা উচিত?
পাওলো 2988

1
@ লভমিন্ট, ঠিক আছে। আমি এটি করার জন্য উদাহরণ কোডটি আপডেট করেছি।
স্যাম

1
@ সাম আমি নিশ্চিত করতে পারি যে এই পরিষেবাটি নিখুঁতভাবে কাজ করে। একটি অদ্ভুত আচরণ, আমি অ্যাক্সেসিবিলিটি পরিষেবা সক্ষম করতে মূল ক্রিয়াকলাপে একটি অভিপ্রায় ব্যবহার করেছি। এই প্রথম সক্রিয়করণের পরে পরিষেবাটি সক্রিয় হয়েছে তবে onAccessibilityEventকোনও ইভেন্ট পায় না, তবে যদি আমি অক্ষম করে থাকি এবং আবার অ্যাক্সেসিবিলিটি পরিষেবাটি সক্ষম করে তবে পরিষেবাটি এটি পুনরায় সক্রিয় onAccessibilityEventহয় এবং কাজ শুরু করে।
পাওলো 2988

2
আপনার কোডের জন্য আপনাকে ধন্যবাদ। আমি আপনার জন্য এই অ্যাপ্লিকেশনটি তৈরি করেছি :)
ভল্ট

20

এটি দ্বারা করা যেতে পারে:

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

    public class App extends Application {
    
    private Activity activeActivity;
    
    @Override
    public void onCreate() {
        super.onCreate();
        setupActivityListener();
    }
    
    private void setupActivityListener() {
    registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {
            @Override
            public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
            }
            @Override
            public void onActivityStarted(Activity activity) {
            }
            @Override
            public void onActivityResumed(Activity activity) {
                activeActivity = activity;
            }
            @Override
            public void onActivityPaused(Activity activity) {
                activeActivity = null;
            }
            @Override
            public void onActivityStopped(Activity activity) {
            }
            @Override
            public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
            }
            @Override
            public void onActivityDestroyed(Activity activity) {
            }
        });
    }
    
    public Activity getActiveActivity(){
        return activeActivity;
    }
    
    }
  2. আপনার পরিষেবাতে কল করুন getApplication()এবং এটি আপনার অ্যাপ্লিকেশন শ্রেণির নাম (এই ক্ষেত্রে অ্যাপ্লিকেশন) এ কাস্ট করুন। আপনি কল করতে চেয়ে app.getActiveActivity()- এটি আপনাকে একটি বর্তমান দৃশ্যমান কার্যকলাপ দেবে (বা কোনও ক্রিয়াকলাপ দৃশ্যমান না হলে নাল)। আপনি কল করে ক্রিয়াকলাপটির নাম পেতে পারেনactiveActivity.getClass().getSimpleName()


1
আমি activeActivity.getClass () এ Nullpointer exeception পাচ্ছি getSimpleName () আপনাকে সাহায্য করবে দয়া করে করতে
শিক্ষানবিস

যেমন আপনি অ্যাক্টিভিটিফাইসাইক্ল্যাক্যালব্যাকস থেকে দেখতে পারেন - যদি কার্যকলাপটি দৃশ্যমান না হয় তবে অ্যাপ্লিকেশন.সেটঅ্যাকটিভ অ্যাক্টিভিটি () বাতিল করে দেয়। এর অর্থ কোনও ক্রিয়াকলাপ দৃশ্যমান নয়। আপনার পরিষেবাতে বা অন্য যে কোনও জায়গায় আপনি এটি ব্যবহার করেন আপনাকে এটি পরীক্ষা করতে হবে।
ভিট ভেরেস

ঠিক আছে .. তবে যদি ক্রিয়াকলাপটি আবার শুরু হয় তবে এইটি বাতিল হওয়া উচিত নয় ?? আমার ক্রিয়াকলাপ শুরু হয়েছিল এবং এর পুনরায়
শুরুতে

হার্ড অনুমান করা এ ব্রেকপয়েন্ট লাগাতে চেষ্টা onActivityResumed(), onActivityPaused()এবং getActiveActivity()দেখতে এটি কিভাবে কালেট হয়, যদি কখনও তাই।
ভিট ভেরেস

@beginner এক যদি চেক করতে হবে activityএবং activeActivityবরাদ্দ সামনে একই activeActivityসঙ্গে nullবিভিন্ন কার্যক্রম জীবনচক্র পদ্ধতির একত্র আহ্বান আদেশের কারণে এড়ানোর ত্রুটি করার জন্য।
রাহুল তিওয়ারি

16

আমি এমন কোনও সমাধান খুঁজে পাইনি যা আমাদের দল এতে খুশী হবে তাই আমরা আমাদের নিজস্ব ঘূর্ণায়মান। আমরা ActivityLifecycleCallbacksবর্তমান ক্রিয়াকলাপের উপর নজর রাখতে এবং তারপরে একটি পরিষেবার মাধ্যমে তা প্রকাশ করতে ব্যবহার করি:

public interface ContextProvider {
    Context getActivityContext();
}

public class MyApplication extends Application implements ContextProvider {
    private Activity currentActivity;

    @Override
    public Context getActivityContext() {
         return currentActivity;
    }

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

        registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {
            @Override
            public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
                MyApplication.this.currentActivity = activity;
            }

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

            @Override
            public void onActivityResumed(Activity activity) {
                MyApplication.this.currentActivity = activity;
            }

            @Override
            public void onActivityPaused(Activity activity) {
                MyApplication.this.currentActivity = null;
            }

            @Override
            public void onActivityStopped(Activity activity) {
                // don't clear current activity because activity may get stopped after
                // the new activity is resumed
            }

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

            }

            @Override
            public void onActivityDestroyed(Activity activity) {
                // don't clear current activity because activity may get destroyed after
                // the new activity is resumed
            }
        });
    }
}

তারপর ফেরত উদাহরণস্বরূপ আপনার দ্বি ধারক কনফিগার MyApplicationজন্য ContextProviderযেমন

public class ApplicationModule extends AbstractModule {    
    @Provides
    ContextProvider provideMainActivity() {
        return MyApplication.getCurrent();
    }
}

(নোট করুন যে প্রয়োগটি getCurrent()উপরের কোড থেকে বাদ দেওয়া হয়েছে It's এটি কেবলমাত্র একটি স্থির পরিবর্তনশীল যা অ্যাপ্লিকেশন কনস্ট্রাক্টর থেকে সেট করা আছে)


4
এক যদি চেক করতে হবে activityএবং currentActivityবরাদ্দ সামনে একই currentActivityসঙ্গে nullবিভিন্ন কার্যক্রম জীবনচক্র পদ্ধতির একত্র আহ্বান আদেশের কারণে এড়ানোর ত্রুটি করার জন্য।
রাহুল তিওয়ারি

14

ব্যবহার ActivityManager

আপনি যদি কেবল বর্তমান ক্রিয়াকলাপ যুক্ত অ্যাপ্লিকেশনটি জানতে চান তবে আপনি এটি ব্যবহার করে এটি করতে পারেন ActivityManager। আপনি যে কৌশলটি ব্যবহার করতে পারেন তা Android এর সংস্করণের উপর নির্ভর করে:

উপকারিতা

  • সর্বশেষ Android এর সমস্ত সংস্করণে কাজ করা উচিত।

অসুবিধেও

  • অ্যান্ড্রয়েড 5.1+ এ কাজ করে না (এটি কেবল আপনার নিজের অ্যাপ্লিকেশনটি দেয়)
  • এই এপিআইগুলির ডকুমেন্টেশন বলছে যে এগুলি কেবল ডিবাগিং এবং পরিচালনা ব্যবহারকারী ইন্টারফেসের জন্য।
  • আপনি যদি রিয়েল-টাইম আপডেট চান তবে আপনার পোলিং ব্যবহার করতে হবে।
  • একটি লুকানো এপিআই উপর নির্ভর করে: ActivityManager.RunningAppProcessInfo.processState
  • এই প্রয়োগটি অ্যাপ্লিকেশন পরিবর্তনকারী ক্রিয়াকলাপটি গ্রহণ করে না।

উদাহরণ (কে নাইটোর কোডের ভিত্তিতে )

public class CurrentApplicationPackageRetriever {

    private final Context context;

    public CurrentApplicationPackageRetriever(Context context) {
        this.context = context;
    }

    public String get() {
        if (Build.VERSION.SDK_INT < 21)
            return getPreLollipop();
        else
            return getLollipop();
    }

    private String getPreLollipop() {
        @SuppressWarnings("deprecation")
        List<ActivityManager.RunningTaskInfo> tasks =
            activityManager().getRunningTasks(1);
        ActivityManager.RunningTaskInfo currentTask = tasks.get(0);
        ComponentName currentActivity = currentTask.topActivity;
        return currentActivity.getPackageName();
    }

    private String getLollipop() {
        final int PROCESS_STATE_TOP = 2;

        try {
            Field processStateField = ActivityManager.RunningAppProcessInfo.class.getDeclaredField("processState");

            List<ActivityManager.RunningAppProcessInfo> processes =
                activityManager().getRunningAppProcesses();
            for (ActivityManager.RunningAppProcessInfo process : processes) {
                if (
                    // Filters out most non-activity processes
                    process.importance <= ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND
                    &&
                    // Filters out processes that are just being
                    // _used_ by the process with the activity
                    process.importanceReasonCode == 0
                ) {
                    int state = processStateField.getInt(process);

                    if (state == PROCESS_STATE_TOP) {
                        String[] processNameParts = process.processName.split(":");
                        String packageName = processNameParts[0];

                        /*
                         If multiple candidate processes can get here,
                         it's most likely that apps are being switched.
                         The first one provided by the OS seems to be
                         the one being switched to, so we stop here.
                         */
                        return packageName;
                    }
                }
            }
        } catch (NoSuchFieldException | IllegalAccessException e) {
            throw new RuntimeException(e);
        }

        return null;
    }

    private ActivityManager activityManager() {
        return (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
    }

}

স্পষ্ট

এতে GET_TASKSঅনুমতি যুক্ত করুন AndroidManifest.xml:

<!--suppress DeprecatedClassUsageInspection -->
<uses-permission android:name="android.permission.GET_TASKS" />

10
এটি আর অ্যান্ড্রয়েড এম এ কাজ করে না। getRunningAppProcesses () এখন কেবলমাত্র আপনার অ্যাপ্লিকেশনটির প্যাকেজটি ফিরিয়ে দেয়
লাইয়ার ইলুজ

1
এপিআই লেভেল 22 (অ্যান্ড্রয়েড 5.1) এর জন্যও কাজ করে না। বিল্ড এলপিবি 23
sumitb.mdi

9

আমি আমার পরীক্ষার জন্য এটি ব্যবহার করছি। এটি এপিআই> 19, এবং শুধুমাত্র আপনার অ্যাপ্লিকেশনটির ক্রিয়াকলাপের জন্য।

@TargetApi(Build.VERSION_CODES.KITKAT)
public static Activity getRunningActivity() {
    try {
        Class activityThreadClass = Class.forName("android.app.ActivityThread");
        Object activityThread = activityThreadClass.getMethod("currentActivityThread")
                .invoke(null);
        Field activitiesField = activityThreadClass.getDeclaredField("mActivities");
        activitiesField.setAccessible(true);
        ArrayMap activities = (ArrayMap) activitiesField.get(activityThread);
        for (Object activityRecord : activities.values()) {
            Class activityRecordClass = activityRecord.getClass();
            Field pausedField = activityRecordClass.getDeclaredField("paused");
            pausedField.setAccessible(true);
            if (!pausedField.getBoolean(activityRecord)) {
                Field activityField = activityRecordClass.getDeclaredField("activity");
                activityField.setAccessible(true);
                return (Activity) activityField.get(activityRecord);
            }
        }
    } catch (Exception e) {
        throw new RuntimeException(e);
    }

    throw new RuntimeException("Didn't find the running activity");
}

অ্যারেম্যাপটি মানচিত্রে প্রতিস্থাপন করুন এবং এটি 4.3 এও কাজ করবে। আগের অ্যান্ড্রয়েড সংস্করণ পরীক্ষা করা হয়নি।
অলিভার জোনাস

2

21 বা ততোধিকের জন্য এই কোডটি ব্যবহার করুন। অন্যান্য উত্তরগুলির তুলনায় এটি কাজ করে এবং আরও ভাল ফলাফল দেয়, এটি পুরোভাগের প্রক্রিয়াটি পুরোপুরি সনাক্ত করে।

if (Build.VERSION.SDK_INT >= 21) {
    String currentApp = null;
    UsageStatsManager usm = (UsageStatsManager) this.getSystemService(Context.USAGE_STATS_SERVICE);
    long time = System.currentTimeMillis();
    List<UsageStats> applist = usm.queryUsageStats(UsageStatsManager.INTERVAL_DAILY, time - 1000 * 1000, time);
    if (applist != null && applist.size() > 0) {
        SortedMap<Long, UsageStats> mySortedMap = new TreeMap<Long, UsageStats>();
        for (UsageStats usageStats : applist) {
            mySortedMap.put(usageStats.getLastTimeUsed(), usageStats);

        }
        if (mySortedMap != null && !mySortedMap.isEmpty()) {
            currentApp = mySortedMap.get(mySortedMap.lastKey()).getPackageName();
        }
    }

আপনি কি দয়া করে এই পদ্ধতির ফলাফলগুলি অন্যান্য উত্তরের চেয়ে ভাল কীভাবে তা ব্যাখ্যা করতে পারেন?
স্যাম

এটি নোটিফিকেশন মেনুতেও কাজ করে। আমি এমন একটি সমস্যার মুখোমুখি হচ্ছি যাতে যদি আমি কোনও কল বা বার্তা পাই। UsageStatsManager আমার অ্যাপ্লিকেশনটির পরিবর্তে আমাকে SystemUi এর প্যাকেজের নাম দেওয়া শুরু করে।
কুক্রয়েড

@ কুক্রয়েড, একটি পৃথক প্রশ্ন পোস্ট করুন এবং আপনার উত্স কোড, ডিভাইস সম্পর্কিত তথ্য এবং আপনি কোন বার্তা এবং ফোন অ্যাপ ব্যবহার করছেন তা অন্তর্ভুক্ত করুন include
স্যাম

0

এখানে আমার উত্তরটি ঠিক কাজ করে ...

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

এখানে একটি উপায়। আপনি যখন আপনার ক্রিয়াকলাপ শুরু করেন, আপনি সেই ক্রিয়াকলাপটি অ্যাপ্লিকেশন.সেটক্রেনারএকটিভিটি (getIntent ()) দ্বারা সঞ্চয় করেন; এই অ্যাপ্লিকেশন এটি সংরক্ষণ করবে। আপনার পরিষেবা শ্রেণিতে আপনি সহজেই ইন্টেন্ট কারেন্টআইটেন্ট = অ্যাপ্লিকেশন.সেটকারেন্টএসিটিভিটি (); । GetApplication () startActivity (currentIntent);


2
এটি ধরে নিয়েছে যে পরিষেবাটি একই ক্রিয়ায় ক্রিয়াকলাপ হিসাবে চলে, তাইনা?
হেল্লে

0

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


1
আমরা এটি করার একটি নেটিভ উপায় খুঁজছি
IgniteCoders

-3

সবেমাত্র এই সম্পর্কে জানতে পেরেছি। এপিএস সহ:

  • minSdkVersion 19
  • টার্গেটএসডিকি ভার্সন 26

    ActivityManager.getCurrentActivity (প্রসঙ্গ)

আশা করি এটি কোনও কাজে আসবে।


1
আমার আশা ছিল। সম্ভবত যখন এটির উত্তর দেওয়া হয়েছিল এটির অস্তিত্ব ছিল, তবে এখন getCurrentActivity()পর্যন্ত ActivityManagerক্লাসে কোনও কার্যকারিতা নেই ( ডেভেলপার.অ্যান্ড্রয়েড / রেফারেন্স / অ্যান্ড্রয়েড / অ্যাপ / অ্যাক্টিভিটি ম্যানেজার )। মজার অস্তিত্ব এই ফাংশন যে: ActivityManager.isUserAMonkey()
বাইটস্লিংগার

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