অ্যাক্টিভিটির সাথে পরিচয়

Activity ক্লাস হল Android অ্যাপের একটি গুরুত্বপূর্ণ কম্পোনেন্ট এবং যেভাবে অ্যাক্টিভিটি লঞ্চ করা ও একসাথে রাখা হয় তা হল প্ল্যাটফর্মের অ্যাপ্লিকেশন মডেলের একটি মৌলিক অংশ। প্রোগ্রামিং প্যারাডাইমে main মেথডের মাধ্যমে অ্যাপ লঞ্চ করা হয়, কিন্তু Android সিস্টেমে Activity ইনস্ট্যান্সে নির্দিষ্ট কলব্যাক মেথড ইনভোক করার মাধ্যমে কোড ইনিশিয়েট করা হয়, যা লাইফসাইকেলের নির্দিষ্ট স্টেজের সাথে সম্পর্কিত।

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

অ্যাক্টিভিটির ধারণা

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

Activity ক্লাসটি এই প্যারাডাইমকে সহজতর করার জন্য ডিজাইন করা হয়েছে। একটি অ্যাপ অন্য অ্যাপকে ইনভোক করলে, কলিং অ্যাপ অন্য অ্যাপের কোনও অ্যাক্টিভিটি ইনভোক করে, পুরো অ্যাপকে নয়। এইভাবে, অ্যাক্টিভিটি ব্যবহারকারীর সাথে অ্যাপের ইন্টার‍্যাকশনের এন্ট্রি পয়েন্ট হিসেবে কাজ করে। আপনি Activity ক্লাসের সাবক্লাস হিসেবে অ্যাক্টিভিটি প্রয়োগ করেন।

কোনও অ্যাক্টিভিটি সেই উইন্ডো প্রদান করে যেখানে অ্যাপ তার UI ড্র করে। এই উইন্ডোটি সাধারণত স্ক্রিন জুড়ে থাকে, তবে স্ক্রিনের থেকে ছোট হতে পারে এবং অন্যান্য উইন্ডোর উপরে ভাসতে পারে।

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

আপনার অ্যাপে অ্যাক্টিভিটি ব্যবহার করতে, আপনাকে অবশ্যই অ্যাপের ম্যানিফেস্টে তাদের সম্পর্কে তথ্য রেজিস্টার করতে হবে এবং অ্যাক্টিভিটি লাইফসাইকেল সম্পর্কে সচেতন থাকা একটি ভালো অভ্যাস। এই ডকুমেন্টের বাকি অংশে এইসব বিষয় সম্পর্কে আলোচনা করা হয়েছে।

ম্যানিফেস্ট কনফিগার করা হচ্ছে

আপনার অ্যাপ যাতে অ্যাক্টিভিটি ব্যবহার করতে পারে, তার জন্য আপনাকে ম্যানিফেস্টে অ্যাক্টিভিটি এবং সেগুলির নির্দিষ্ট কিছু অ্যাট্রিবিউট ঘোষণা করতে হবে।

অ্যাক্টিভিটি ঘোষণা করুন

আপনার অ্যাক্টিভিটি ঘোষণা করতে, আপনার ম্যানিফেস্ট ফাইল খুলুন এবং <application> এলিমেন্টের চাইল্ড হিসেবে একটি <activity> এলিমেন্ট যোগ করুন। যেমন:

<manifest ... >
  <application ... >
      <activity android:name=".ExampleActivity" />
      ...
  </application ... >
  ...
</manifest >

এই এলিমেন্টের জন্য একমাত্র প্রয়োজনীয় অ্যাট্রিবিউট হল android:name, যা অ্যাক্টিভিটির ক্লাস নেম নির্দিষ্ট করে। এছাড়াও, আপনি এমন অ্যাট্রিবিউট যোগ করতে পারেন যা অ্যাক্টিভিটির বৈশিষ্ট্যকে সংজ্ঞায়িত করে, যেমন লেবেল, আইকন বা UI থিম। এইসব এবং অন্যান্য অ্যাট্রিবিউট সম্পর্কে আরও জানতে, <activity> এলিমেন্ট রেফারেন্স ডকুমেন্টেশন দেখুন।

ইনটেন্ট ফিল্টার ঘোষণা করা

ইনটেন্ট ফিল্টার হল Android প্ল্যাটফর্মের একটি অত্যন্ত শক্তিশালী ফিচার। এগুলি শুধু স্পষ্ট অনুরোধের ভিত্তিতেই নয়, অন্তর্নিহিত অনুরোধের ভিত্তিতেও কোনও অ্যাক্টিভিটি লঞ্চ করার সুবিধা প্রদান করে। যেমন, একটি এক্সপ্লিসিট অনুরোধ সিস্টেমকে বলতে পারে "Gmail অ্যাপে ইমেল পাঠানোর অ্যাক্টিভিটি শুরু করো"। এর বিপরীতে, একটি ইমপ্লিসিট অনুরোধ সিস্টেমকে বলে "যেকোনও অ্যাক্টিভিটিতে একটি ইমেল পাঠানোর স্ক্রিন শুরু করুন যা কাজটি করতে পারে।" কোনও টাস্ক সম্পূর্ণ করার জন্য কোন অ্যাপ ব্যবহার করতে হবে তা সিস্টেম UI ব্যবহারকারীকে জিজ্ঞাসা করলে, সেটি ইনটেন্ট ফিল্টারের কাজ।

<activity> এলিমেন্টে <intent-filter> অ্যাট্রিবিউট ঘোষণা করে আপনি এই ফিচারের সুবিধা নিতে পারবেন। এই এলিমেন্টের সংজ্ঞায় একটি <action> এলিমেন্ট এবং, বিকল্প হিসেবে, একটি <category> এলিমেন্ট এবং/অথবা একটি <data> এলিমেন্ট অন্তর্ভুক্ত থাকে। এইসব এলিমেন্ট একত্রিত হয়ে আপনার অ্যাক্টিভিটি কোন ধরনের ইনটেন্টে সাড়া দিতে পারে তা নির্দিষ্ট করে। যেমন, নিম্নলিখিত কোড স্নিপেট দেখায় যে কীভাবে এমন একটি অ্যাক্টিভিটি কনফিগার করতে হয় যা টেক্সট ডেটা ও ইমেল পাঠায় এবং এটি করার জন্য অন্যান্য অ্যাক্টিভিটি থেকে অনুরোধ গ্রহণ করে:

<activity android:name=".ExampleActivity" android:icon="@drawable/app_icon">
    <intent-filter>
        <action android:name="android.intent.action.SEND" />
        <category android:name="android.intent.category.DEFAULT" />
        <data android:mimeType="text/plain" />
    </intent-filter>
   <intent-filter>
        <action android:name="android.intent.action.SENDTO" />
        <category android:name="android.intent.category.DEFAULT" />
        <data android:scheme="mailto" />
    </intent-filter>
</activity>

এই উদাহরণে, <action> এলিমেন্ট নির্দিষ্ট করে যে এই অ্যাক্টিভিটি ডেটা পাঠায়। <category> এলিমেন্টকে DEFAULT হিসেবে ঘোষণা করলে, অ্যাক্টিভিটি লঞ্চ করার অনুরোধ গ্রহণ করতে পারে। <data> এলিমেন্ট এই অ্যাক্টিভিটি যে ধরনের ডেটা পাঠাতে পারে তা নির্দিষ্ট করে। ইমেল কম্পোজ করার জন্য উপরে বর্ণিত অ্যাক্টিভিটি কীভাবে কল করতে হয় তা নিম্নলিখিত কোড স্নিপেট থেকে জানতে পারবেন:

fun composeEmail(addresses: Array<String>, subject: String) {
    val intent = Intent(Intent.ACTION_SENDTO).apply {
        data = Uri.parse("mailto:") // Only email apps handle this.
        putExtra(Intent.EXTRA_EMAIL, addresses)
        putExtra(Intent.EXTRA_SUBJECT, subject)
    }
    if (intent.resolveActivity(packageManager) != null) {
        startActivity(intent)
    }
}

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

ইনকামিং ইনটেন্ট ম্যানেজ করা

নিম্নলিখিত উদাহরণে একাধিক ইনটেন্ট টাইপ ম্যানেজ করার সময় অ্যাক্টিভিটি লাইফসাইকেল ম্যানেজ করার প্যাটার্ন দেখানো হয়েছে: সিঙ্গল টেক্সট শেয়ার, সিঙ্গল ছবি এবং একাধিক ছবির অ্যারে। এইসব বিভিন্ন ইনপুটকে একটি সেন্ট্রালাইজড handleIntent ফাংশনের মাধ্যমে রাউট করে, এটি নিশ্চিত করে যে ACTION_SEND এবং ACTION_SEND_MULTIPLE অ্যাকশন দুটিই সঠিকভাবে পার্স করা হয়েছে এবং একটি প্রতিক্রিয়াশীল UI আপডেটের জন্য ViewModel-এ ডেলিগেট করা হয়েছে।

class ExampleActivity : ComponentActivity() {
  private val viewModel: MyViewModel by viewModels()

  override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    handleIntent(intent)
    setContent {
      ComposeApp(viewModel)
    }
  }

  override fun onNewIntent(intent: Intent) {
    super.onNewIntent(intent)
    setIntent(intent)
    handleIntent(intent)
  }

  private fun handleIntent(intent: Intent?) {
    when (intent?.action) {
      Intent.ACTION_SEND -> {
        if ("text/plain" == intent.type) {
          intent.getStringExtra(Intent.EXTRA_TEXT)?.let {
            viewModel.handleText(it) // Update UI to reflect text being shared
          }
        } else if (intent.type?.startsWith("image/") == true) {
          (intent.getParcelableExtra(Intent.EXTRA_STREAM, Uri::class.java))?.let {
            viewModel.handleImage(it) // Update UI to reflect image being shared
          }
        }
      }

      Intent.ACTION_SEND_MULTIPLE -> {
          if (intent.type?.startsWith("image/") == true) {
              intent.getParcelableArrayListExtra(Intent.EXTRA_STREAM, Uri::class.java)?.let {
                  viewModel.handleMultipleImages(it) // Update UI to reflect multiple images being shared
              }
          } else {
              // Handle other types
          }
      }

      else -> {
          // Handle other intents
      }
    }
  }
}

অনুমতি ঘোষণা করা

কোন অ্যাপ নির্দিষ্ট অ্যাক্টিভিটি শুরু করতে পারবে তা নিয়ন্ত্রণ করতে আপনি ম্যানিফেস্টের <activity> ট্যাগ ব্যবহার করতে পারবেন। কোনও পেরেন্ট অ্যাক্টিভিটি চাইল্ড অ্যাক্টিভিটি লঞ্চ করতে পারে না, যদি না উভয় অ্যাক্টিভিটির ম্যানিফেস্টে একই অনুমতি থাকে। আপনি যদি মূল অ্যাক্টিভিটির জন্য <uses-permission> এলিমেন্ট ঘোষণা করেন, তাহলে প্রতিটি চাইল্ড অ্যাক্টিভিটির অবশ্যই একটি ম্যাচিং <uses-permission> এলিমেন্ট থাকতে হবে।

যেমন, আপনার অ্যাপ যদি সোশ্যাল মিডিয়ায় পোস্ট শেয়ার করার জন্য SocialApp নামের একটি কাল্পনিক অ্যাপ ব্যবহার করতে চায়, তাহলে SocialApp-কে নিজেই সেই অনুমতি নির্ধারণ করতে হবে যা এটিকে কল করা অ্যাপের কাছে থাকতে হবে:

<manifest>
<activity android:name="...."
   android:permission="com.google.socialapp.permission.SHARE_POST"

/>

তারপর, SocialApp-কে কল করার অনুমতি পেতে, আপনার অ্যাপকে অবশ্যই SocialApp-এর ম্যানিফেস্টে সেট করা অনুমতির সাথে মিলতে হবে:

<manifest>
   <uses-permission android:name="com.google.socialapp.permission.SHARE_POST" />
</manifest>

সাধারণভাবে অনুমতি ও নিরাপত্তা সম্পর্কে আরও তথ্যের জন্য, নিরাপত্তা চেকলিস্ট দেখুন।

অ্যাক্টিভিটি লাইফসাইকেল ম্যানেজ করা

কোনও অ্যাক্টিভিটি শুরু থেকে শেষ পর্যন্ত বিভিন্ন অবস্থার মধ্যে দিয়ে যায়। আপনি একাধিক স্টেটের মধ্যে ট্রানজিশন ম্যানেজ করতে একাধিক কলব্যাক ব্যবহার করেন। নিম্নলিখিত বিভাগে এইসব কলব্যাক সম্পর্কে জানানো হয়েছে। Compose অ্যাপে, সরাসরি এইসব কলব্যাকে হুক করা সাজেস্ট করা হয় না। পরিবর্তে, স্ট্যাটাস পরিবর্তন লক্ষ্য করতে লাইফসাইকেল API ব্যবহার করুন। আরও তথ্যের জন্য, Compose-এর সাথে লাইফসাইকেল ইন্টিগ্রেট করুন।

onCreate

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

Compose অ্যাপে, নিচে দেখানো অনুযায়ী setContent ব্যবহার করে আপনার হোস্ট কম্পোজেবল সেট-আপ করতে এই কলব্যাক ব্যবহার করুন:

class MyActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            Text(text = stringResource(id = R.string.greeting))
        }
    }
}

onCreate শেষ হলে, পরবর্তী কলব্যাক সবসময় onStart হয়।

onStart

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

onResume

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

onPause কলব্যাক সবসময় onResume অনুসরণ করে।

onPause

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

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

অ্যাপ্লিকেশন বা ব্যবহারকারীর ডেটা সেভ করতে, নেটওয়ার্ক কল করতে বা ডেটাবেস ট্রানজ্যাকশন সম্পূর্ণ করতে আপনার onPause ব্যবহার করা উচিত নয়। ডেটা সেভ করা সম্পর্কে তথ্যের জন্য, ট্রানজিয়েন্ট UI স্টেট সেভ ও রিস্টোর করা দেখুন।

onPause-এর এক্সিকিউশন শেষ হয়ে গেলে, পরবর্তী কলব্যাক হয় onStop অথবা onResume হবে, যা নির্ভর করে অ্যাক্টিভিটি পজ করা অবস্থায় প্রবেশ করার পরে কী ঘটে তার উপর।

onStop

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

সিস্টেম যে পরবর্তী কলব্যাক কল করে তা হল onRestart, যদি অ্যাক্টিভিটি ব্যবহারকারীর সাথে ইন্টার‍্যাক্ট করার জন্য ফিরে আসে, অথবা onDestroy যদি এই অ্যাক্টিভিটি সম্পূর্ণভাবে বন্ধ হয়ে যায়।

onRestart

বন্ধ থাকা কোনও অ্যাক্টিভিটি আবার শুরু করার সময় সিস্টেম এই কলব্যাককে কল করে। onRestart অ্যাক্টিভিটি বন্ধ হওয়ার সময় থেকে সেটির স্ট্যাটাস ফিরিয়ে আনে।

এই কলব্যাক সবসময় onStart-এর পরে আসে।

onDestroy

কোনও অ্যাক্টিভিটি নষ্ট হওয়ার আগে সিস্টেম এই কলব্যাককে আহ্বান করে।

এই কলব্যাকটি হল অ্যাক্টিভিটির পাওয়া শেষ কলব্যাক। onDestroy সাধারণত এটি নিশ্চিত করার জন্য প্রয়োগ করা হয় যে কোনও অ্যাক্টিভিটির সমস্ত রিসোর্স রিলিজ করা হয়েছে যখন অ্যাক্টিভিটি বা এটি ধারণকারী প্রসেসটি ধ্বংস হয়ে যায়।

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