এই বিভাগগুলি রেফারেন্সের জন্য বোঝানো হয়েছে এবং এটি আপনাকে উপরের থেকে নীচে পড়ার প্রয়োজন নেই।
ব্যবহারকারীর সম্মতির অনুরোধ করুন
ফ্রেমওয়ার্ক API ব্যবহার করুন:
-
CrossProfileApps.canInteractAcrossProfiles()
-
CrossProfileApps.canRequestInteractAcrossProfiles()
-
CrossProfileApps.createRequestInteractAcrossProfilesIntent()
-
CrossProfileApps.ACTION_CAN_INTERACT_ACROSS_PROFILES_CHANGED
এই APIগুলি আরও সামঞ্জস্যপূর্ণ API পৃষ্ঠের জন্য SDK-তে মোড়ানো হবে (যেমন UserHandle অবজেক্টগুলি এড়িয়ে যাওয়া), কিন্তু আপাতত, আপনি এগুলিকে সরাসরি কল করতে পারেন৷
বাস্তবায়ন সহজবোধ্য: আপনি যদি যোগাযোগ করতে পারেন, এগিয়ে যান। যদি না হয়, তবে আপনি অনুরোধ করতে পারেন, তারপর আপনার ব্যবহারকারীর প্রম্পট/ব্যানার/টুলটিপ/ইত্যাদি দেখান। ব্যবহারকারী সেটিংসে যেতে রাজি হলে, অনুরোধের উদ্দেশ্য তৈরি করুন এবং ব্যবহারকারীকে সেখানে পাঠাতে Context#startActivity
ব্যবহার করুন। এই ক্ষমতা কখন পরিবর্তিত হয় তা সনাক্ত করতে আপনি হয় সম্প্রচার ব্যবহার করতে পারেন, অথবা ব্যবহারকারী ফিরে আসলে আবার পরীক্ষা করতে পারেন।
এটি পরীক্ষা করার জন্য, আপনাকে আপনার কাজের প্রোফাইলে TestDPC খুলতে হবে, একেবারে নীচে যান এবং সংযুক্ত অ্যাপের অনুমতি তালিকায় আপনার প্যাকেজের নাম যোগ করতে নির্বাচন করুন৷ এটি অ্যাডমিনকে আপনার অ্যাপের 'অনুমতি-তালিকা দেওয়ার' অনুকরণ করে।
শব্দকোষ
এই বিভাগটি ক্রস-প্রোফাইল বিকাশের সাথে সম্পর্কিত মূল পদগুলিকে সংজ্ঞায়িত করে।
ক্রস প্রোফাইল কনফিগারেশন
একটি ক্রস প্রোফাইল কনফিগারেশন গ্রুপগুলি একসাথে সম্পর্কিত ক্রস প্রোফাইল প্রদানকারী ক্লাস এবং ক্রস-প্রোফাইল বৈশিষ্ট্যগুলির জন্য সাধারণ কনফিগারেশন প্রদান করে। সাধারণত কোডবেস প্রতি একটি @CrossProfileConfiguration
টীকা থাকবে, কিন্তু কিছু জটিল অ্যাপ্লিকেশনে একাধিক হতে পারে।
প্রোফাইল সংযোগকারী
একটি সংযোগকারী প্রোফাইলের মধ্যে সংযোগ পরিচালনা করে। সাধারণত প্রতিটি ক্রস প্রোফাইল টাইপ একটি নির্দিষ্ট সংযোগকারীকে নির্দেশ করবে। একটি একক কনফিগারেশনের প্রতিটি ক্রস প্রোফাইল টাইপ একই সংযোগকারী ব্যবহার করতে হবে।
ক্রস প্রোফাইল প্রদানকারী ক্লাস
একটি ক্রস প্রোফাইল প্রোভাইডার ক্লাস গ্রুপগুলি একসাথে সম্পর্কিত ক্রস প্রোফাইল প্রকারগুলি।
মধ্যস্থতাকারী
একজন মধ্যস্থতাকারী উচ্চ-স্তরের এবং নিম্ন-স্তরের কোডের মধ্যে বসে, সঠিক প্রোফাইলে কল বিতরণ করে এবং ফলাফল একত্রিত করে। এটি একমাত্র কোড যা প্রোফাইল-সচেতন হওয়া দরকার। এটি SDK-তে নির্মিত কিছুর পরিবর্তে একটি স্থাপত্য ধারণা।
ক্রস প্রোফাইল টাইপ
একটি ক্রস প্রোফাইল টাইপ হল একটি ক্লাস বা ইন্টারফেস যেখানে @CrossProfile
টীকা করা পদ্ধতি রয়েছে। এই ধরনের কোড প্রোফাইল-সচেতন হতে হবে না এবং আদর্শভাবে শুধুমাত্র তার স্থানীয় ডেটাতে কাজ করা উচিত।
প্রোফাইলের ধরন
প্রোফাইলের ধরন | |
---|---|
কারেন্ট | সক্রিয় প্রোফাইল যা আমরা সম্পাদন করছি। |
অন্যান্য | (যদি এটি বিদ্যমান থাকে) আমরা যে প্রোফাইলটি চালাচ্ছি না। |
ব্যক্তিগত | ব্যবহারকারী 0, ডিভাইসে প্রোফাইল যা বন্ধ করা যাবে না। |
কাজ | সাধারণত ব্যবহারকারী 10 কিন্তু বেশি হতে পারে, টগল চালু এবং বন্ধ করা যেতে পারে, কাজের অ্যাপ এবং ডেটা ধারণ করতে ব্যবহৃত হয়। |
প্রাথমিক | ঐচ্ছিকভাবে অ্যাপ্লিকেশন দ্বারা সংজ্ঞায়িত. প্রোফাইল যা উভয় প্রোফাইলের একটি মার্জড ভিউ দেখায়। |
মাধ্যমিক | যদি প্রাথমিক সংজ্ঞায়িত করা হয়, সেকেন্ডারি হল প্রোফাইল যা প্রাথমিক নয়। |
সরবরাহকারী | প্রাথমিক প্রোফাইলের সরবরাহকারী উভয়ই প্রোফাইল, সেকেন্ডারি প্রোফাইলের সরবরাহকারী শুধুমাত্র সেকেন্ডারি প্রোফাইল নিজেই। |
প্রোফাইল শনাক্তকারী
একটি ক্লাস যা এক ধরনের প্রোফাইল (ব্যক্তিগত বা কাজ) প্রতিনিধিত্ব করে। এগুলি এমন পদ্ধতি দ্বারা ফেরত দেওয়া হবে যা একাধিক প্রোফাইলে চলে এবং সেই প্রোফাইলগুলিতে আরও কোড চালানোর জন্য ব্যবহার করা যেতে পারে। এই সুবিধাজনক স্টোরেজ জন্য একটি int
ক্রমিক করা যেতে পারে.
স্থাপত্য প্রস্তাবিত সমাধান
এই নির্দেশিকাটি আপনার Android অ্যাপের মধ্যে দক্ষ এবং রক্ষণাবেক্ষণযোগ্য ক্রস-প্রোফাইল কার্যকারিতা তৈরি করার জন্য প্রস্তাবিত কাঠামোর রূপরেখা দেয়।
আপনার CrossProfileConnector
একটি সিঙ্গলটনে রূপান্তর করুন
আপনার অ্যাপ্লিকেশনের জীবনচক্র জুড়ে শুধুমাত্র একটি একক উদাহরণ ব্যবহার করা উচিত, অন্যথায় আপনি সমান্তরাল সংযোগ তৈরি করবেন। এটি একটি নির্ভরতা ইনজেকশন ফ্রেমওয়ার্ক যেমন ড্যাগার ব্যবহার করে করা যেতে পারে, অথবা একটি ক্লাসিক সিঙ্গেলটন প্যাটার্ন ব্যবহার করে, হয় একটি নতুন ক্লাসে বা বিদ্যমান একটিতে।
আপনি যখন কল করবেন তখন পদ্ধতিতে তৈরি না করে আপনার ক্লাসে জেনারেট করা প্রোফাইল ইন্সট্যান্স ইনজেক্ট করুন বা পাস করুন
এটি আপনাকে পরে আপনার ইউনিট পরীক্ষায় স্বয়ংক্রিয়ভাবে তৈরি FakeProfile
উদাহরণে পাস করতে দেয়।
মধ্যস্থতাকারী প্যাটার্ন বিবেচনা করুন
এই সাধারণ প্যাটার্নটি হল আপনার বিদ্যমান APIগুলির মধ্যে একটি (যেমন getEvents()
) এর সমস্ত কলারদের জন্য প্রোফাইল-সচেতন করা। এই ক্ষেত্রে, আপনার বিদ্যমান API শুধুমাত্র একটি 'মধ্যস্থতাকারী' পদ্ধতি বা শ্রেণীতে পরিণত হতে পারে যাতে জেনারেট করা ক্রস-প্রোফাইল কোডে নতুন কল থাকে।
এইভাবে, আপনি প্রতিটি কলারকে ক্রস-প্রোফাইল কল করতে জানতে বাধ্য করবেন না এটি কেবল আপনার API এর অংশ হয়ে যায়।
একটি প্রদানকারীর মধ্যে আপনার বাস্তবায়নের ক্লাসগুলিকে প্রকাশ করা এড়াতে পরিবর্তে @CrossProfile
হিসাবে একটি ইন্টারফেস পদ্ধতি টীকা করা যায় কিনা তা বিবেচনা করুন
এটি নির্ভরতা ইনজেকশন ফ্রেমওয়ার্কের সাথে সুন্দরভাবে কাজ করে।
আপনি যদি একটি ক্রস-প্রোফাইল কল থেকে কোনো ডেটা গ্রহণ করেন, তাহলে এটি কোন প্রোফাইল থেকে এসেছে তা উল্লেখ করে একটি ক্ষেত্র যোগ করতে হবে কিনা তা বিবেচনা করুন
এটি ভাল অনুশীলন হতে পারে কারণ আপনি এটি UI স্তরে জানতে চাইতে পারেন (যেমন কাজের জিনিসগুলিতে একটি ব্যাজ আইকন যুক্ত করা)। কোনো ডেটা শনাক্তকারী যদি এটি ছাড়া আর অনন্য না হয়, যেমন প্যাকেজ নাম।
ক্রস প্রোফাইল
এই বিভাগটি কীভাবে আপনার নিজের ক্রস প্রোফাইল ইন্টারঅ্যাকশন তৈরি করতে হয় তার রূপরেখা দেয়।
প্রাথমিক প্রোফাইল
এই ডকুমেন্টের উদাহরণের বেশিরভাগ কলে কাজের, ব্যক্তিগত এবং উভয়ই সহ কোন প্রোফাইলগুলি চালানো হবে সে সম্পর্কে স্পষ্ট নির্দেশাবলী রয়েছে৷
অনুশীলনে, শুধুমাত্র একটি প্রোফাইলে একত্রিত অভিজ্ঞতা সহ অ্যাপগুলির জন্য, আপনি সম্ভবত এই সিদ্ধান্তটি আপনি যে প্রোফাইলে চালাচ্ছেন তার উপর নির্ভর করতে চান, তাই একই ধরনের সুবিধাজনক পদ্ধতি রয়েছে যা এটিকে বিবেচনায় নেয়, যাতে আপনার কোডবেসকে নোংরা না করা যায়। if-else প্রোফাইল শর্তসাপেক্ষ।
আপনার সংযোগকারীর উদাহরণ তৈরি করার সময়, আপনি নির্দিষ্ট করতে পারেন কোন প্রোফাইলের ধরনটি আপনার 'প্রাথমিক' (যেমন 'ওয়ার্ক')। এটি অতিরিক্ত বিকল্পগুলি সক্ষম করে, যেমন নিম্নলিখিতগুলি:
profileCalendarDatabase.primary().getEvents();
profileCalendarDatabase.secondary().getEvents();
// Runs on all profiles if running on the primary, or just
// on the current profile if running on the secondary.
profileCalendarDatabase.suppliers().getEvents();
ক্রস প্রোফাইল প্রকার
@CrossProfile
টীকাযুক্ত একটি পদ্ধতি রয়েছে এমন ক্লাস এবং ইন্টারফেসগুলিকে ক্রস প্রোফাইল প্রকার হিসাবে উল্লেখ করা হয়।
ক্রস প্রোফাইল প্রকারের বাস্তবায়ন প্রোফাইল-স্বাধীন হওয়া উচিত, তারা যে প্রোফাইলে চলছে। তাদের অন্যান্য পদ্ধতিতে কল করার অনুমতি দেওয়া হয় এবং সাধারণভাবে তারা একটি একক প্রোফাইলে চলমান মত কাজ করা উচিত। তারা শুধুমাত্র তাদের নিজস্ব প্রোফাইলে রাজ্য অ্যাক্সেস করতে পারবে।
একটি উদাহরণ ক্রস প্রোফাইল প্রকার:
public class Calculator {
@CrossProfile
public int add(int a, int b) {
return a + b;
}
}
ক্লাস টীকা
শক্তিশালী API প্রদান করতে, আপনাকে প্রতিটি ক্রস প্রোফাইল প্রকারের জন্য সংযোগকারী নির্দিষ্ট করতে হবে, যেমন:
@CrossProfile(connector=MyProfileConnector.class)
public class Calculator {
@CrossProfile
public int add(int a, int b) {
return a + b;
}
}
এটি ঐচ্ছিক কিন্তু এর মানে হল যে জেনারেট করা API প্রকারের ক্ষেত্রে আরও নির্দিষ্ট হবে এবং কম্পাইল-টাইম চেকিংয়ের ক্ষেত্রে কঠোর হবে।
ইন্টারফেস
@CrossProfile
হিসাবে একটি ইন্টারফেসে পদ্ধতিগুলি টীকা করে আপনি বলছেন যে এই পদ্ধতির কিছু বাস্তবায়ন হতে পারে যা প্রোফাইল জুড়ে অ্যাক্সেসযোগ্য হওয়া উচিত।
আপনি একটি ক্রস প্রোফাইল প্রদানকারীতে একটি ক্রস প্রোফাইল ইন্টারফেসের যেকোনো বাস্তবায়ন ফিরিয়ে দিতে পারেন এবং এটি করার মাধ্যমে আপনি বলছেন যে এই বাস্তবায়নটি অ্যাক্সেসযোগ্য ক্রস-প্রোফাইল হওয়া উচিত। আপনি বাস্তবায়ন ক্লাস টীকা করতে হবে না.
ক্রস প্রোফাইল প্রদানকারী
প্রতিটি ক্রস প্রোফাইল টাইপ @CrossProfileProvider
টীকাযুক্ত পদ্ধতি দ্বারা প্রদান করা আবশ্যক। প্রতিবার ক্রস-প্রোফাইল কল করা হলে এই পদ্ধতিগুলিকে কল করা হবে, তাই এটি সুপারিশ করা হয় যে আপনি প্রতিটি প্রকারের জন্য একক টন বজায় রাখুন।
কনস্ট্রাক্টর
একটি প্রদানকারীর অবশ্যই একটি পাবলিক কনস্ট্রাক্টর থাকতে হবে যা হয় কোন আর্গুমেন্ট বা একটি একক Context
আর্গুমেন্ট নেয় না।
প্রদানকারী পদ্ধতি
প্রোভাইডার পদ্ধতিগুলিকে অবশ্যই কোন আর্গুমেন্ট বা একটি একক Context
আর্গুমেন্ট নিতে হবে।
নির্ভরতা ইনজেকশন
আপনি যদি নির্ভরতা পরিচালনা করতে ড্যাগারের মতো একটি নির্ভরতা ইনজেকশন ফ্রেমওয়ার্ক ব্যবহার করেন, তাহলে আমরা সুপারিশ করব যে আপনি সেই ফ্রেমওয়ার্কটি আপনার ক্রস প্রোফাইলের প্রকারগুলি তৈরি করুন যেমন আপনি সাধারণত করেন, এবং তারপরে আপনার প্রদানকারী শ্রেণিতে এই প্রকারগুলি ইনজেকশন করুন৷ @CrossProfileProvider
পদ্ধতিগুলি তারপর সেই ইনজেকশনের উদাহরণগুলি ফিরিয়ে দিতে পারে।
প্রোফাইল সংযোগকারী
প্রতিটি ক্রস প্রোফাইল কনফিগারেশনে অবশ্যই একটি একক প্রোফাইল সংযোগকারী থাকতে হবে, যা অন্য প্রোফাইলের সাথে সংযোগ পরিচালনার জন্য দায়ী৷
ডিফল্ট প্রোফাইল সংযোগকারী
যদি একটি কোডবেসে শুধুমাত্র একটি ক্রস প্রোফাইল কনফিগারেশন থাকে, তাহলে আপনি নিজের প্রোফাইল সংযোগকারী তৈরি করা এড়াতে পারেন এবং com.google.android.enterprise.connectedapps.CrossProfileConnector
ব্যবহার করতে পারেন। কোনোটি নির্দিষ্ট না থাকলে এটি ব্যবহার করা ডিফল্ট।
ক্রস প্রোফাইল সংযোগকারী নির্মাণ করার সময়, আপনি নির্মাতার কিছু বিকল্প নির্দিষ্ট করতে পারেন:
নির্ধারিত নির্বাহক পরিষেবা
আপনি যদি SDK দ্বারা তৈরি থ্রেডগুলির উপর নিয়ন্ত্রণ রাখতে চান তবে
#setScheduledExecutorService()
ব্যবহার করুন ,বাইন্ডার
প্রোফাইল বাইন্ডিং সম্পর্কিত আপনার যদি নির্দিষ্ট প্রয়োজন থাকে, তাহলে
#setBinder
ব্যবহার করুন। এটি সম্ভবত শুধুমাত্র ডিভাইস পলিসি কন্ট্রোলারদের দ্বারা ব্যবহৃত হয়।
কাস্টম প্রোফাইল সংযোগকারী
কিছু কনফিগারেশন ( CustomProfileConnector
ব্যবহার করে) সেট করতে সক্ষম হওয়ার জন্য আপনার একটি কাস্টম প্রোফাইল সংযোগকারীর প্রয়োজন হবে এবং একটি কোডবেসে একাধিক সংযোগকারীর প্রয়োজন হলে একটির প্রয়োজন হবে (উদাহরণস্বরূপ যদি আপনার একাধিক প্রক্রিয়া থাকে, আমরা প্রতি প্রক্রিয়ায় একটি সংযোগকারীর সুপারিশ করি)।
একটি ProfileConnector
তৈরি করার সময় এটি দেখতে হবে:
@GeneratedProfileConnector
public interface MyProfileConnector extends ProfileConnector {
public static MyProfileConnector create(Context context) {
// Configuration can be specified on the builder
return GeneratedMyProfileConnector.builder(context).build();
}
}
serviceClassName
উত্পন্ন পরিষেবার নাম পরিবর্তন করতে (যা আপনার
AndroidManifest.xml
এ উল্লেখ করা উচিত),serviceClassName=
ব্যবহার করুন।primaryProfile
প্রাথমিক প্রোফাইল নির্দিষ্ট করতে,
primaryProfile
ব্যবহার করুন।availabilityRestrictions
সংযোগ এবং প্রোফাইল উপলব্ধতার উপর SDK যে সীমাবদ্ধতা রাখে তা পরিবর্তন করতে,
availabilityRestrictions
ব্যবহার করুন।
ডিভাইস পলিসি কন্ট্রোলার
যদি আপনার অ্যাপটি একটি ডিভাইস পলিসি কন্ট্রোলার হয়, তাহলে আপনাকে অবশ্যই আপনার DeviceAdminReceiver
উল্লেখ করে DpcProfileBinder
এর একটি উদাহরণ উল্লেখ করতে হবে।
আপনি যদি আপনার নিজের প্রোফাইল সংযোগকারী বাস্তবায়ন করছেন:
@GeneratedProfileConnector
public interface DpcProfileConnector extends ProfileConnector {
public static DpcProfileConnector get(Context context) {
return GeneratedDpcProfileConnector.builder(context).setBinder(new
DpcProfileBinder(new ComponentName("com.google.testdpc",
"AdminReceiver"))).build();
}
}
অথবা ডিফল্ট CrossProfileConnector
ব্যবহার করে:
CrossProfileConnector connector =
CrossProfileConnector.builder(context).setBinder(new DpcProfileBinder(new
ComponentName("com.google.testdpc", "AdminReceiver"))).build();
ক্রস প্রোফাইল কনফিগারেশন
@CrossProfileConfiguration
টীকাটি সঠিকভাবে মেথড কলগুলি পাঠানোর জন্য একটি সংযোগকারী ব্যবহার করে সমস্ত ক্রস প্রোফাইল প্রকারগুলিকে একসাথে লিঙ্ক করতে ব্যবহৃত হয়। এটি করার জন্য, আমরা @CrossProfileConfiguration
সহ একটি ক্লাস টীকা করি যা প্রতিটি প্রদানকারীকে নির্দেশ করে, যেমন:
@CrossProfileConfiguration(providers = {TestProvider.class})
public abstract class TestApplication {
}
এটি যাচাই করবে যে সমস্ত ক্রস প্রোফাইলের জন্য তাদের হয় একই প্রোফাইল সংযোগকারী আছে বা কোন সংযোগকারী নির্দিষ্ট করা নেই।
serviceSuperclass
ডিফল্টরূপে, জেনারেট করা পরিষেবা
android.app.Service
সুপারক্লাস হিসেবে ব্যবহার করবে। সুপারক্লাস হওয়ার জন্য আপনার যদি আলাদা ক্লাসের প্রয়োজন হয় (যা অবশ্যইandroid.app.Service
এর একটি সাবক্লাস হতে হবে), তাহলেserviceSuperclass=
নির্দিষ্ট করুন।serviceClass
যদি নির্দিষ্ট করা হয়, তাহলে কোনো পরিষেবা তৈরি হবে না। আপনি যে প্রোফাইল সংযোগকারীটি ব্যবহার করছেন সেটিতে এটি অবশ্যই
serviceClassName
সাথে মিলবে৷ আপনার কাস্টম পরিষেবাটি উত্পন্ন_Dispatcher
ক্লাস ব্যবহার করে কলগুলি প্রেরণ করা উচিত যেমন:
public final class TestProfileConnector_Service extends Service {
private Stub binder = new Stub() {
private final TestProfileConnector_Service_Dispatcher dispatcher = new
TestProfileConnector_Service_Dispatcher();
@Override
public void prepareCall(long callId, int blockId, int numBytes, byte[] params)
{
dispatcher.prepareCall(callId, blockId, numBytes, params);
}
@Override
public byte[] call(long callId, int blockId, long crossProfileTypeIdentifier,
int methodIdentifier, byte[] params,
ICrossProfileCallback callback) {
return dispatcher.call(callId, blockId, crossProfileTypeIdentifier,
methodIdentifier, params, callback);
}
@Override
public byte[] fetchResponse(long callId, int blockId) {
return dispatcher.fetchResponse(callId, blockId);
};
@Override
public Binder onBind(Intent intent) {
return binder;
}
}
ক্রস-প্রোফাইল কলের আগে বা পরে অতিরিক্ত ক্রিয়া সম্পাদন করার প্রয়োজন হলে এটি ব্যবহার করা যেতে পারে।
সংযোগকারী
আপনি যদি ডিফল্ট
CrossProfileConnector
ছাড়া অন্য কোনো সংযোগকারী ব্যবহার করেন, তাহলে আপনাকে অবশ্যইconnector=
ব্যবহার করে এটি নির্দিষ্ট করতে হবে।
দৃশ্যমানতা
আপনার অ্যাপ্লিকেশনের প্রতিটি অংশ যা ক্রস-প্রোফাইল ইন্টারঅ্যাক্ট করে আপনার প্রোফাইল সংযোগকারীকে দেখতে সক্ষম হতে হবে।
আপনার @CrossProfileConfiguration
টীকাযুক্ত ক্লাস আপনার অ্যাপ্লিকেশনে ব্যবহৃত প্রতিটি প্রদানকারীকে দেখতে সক্ষম হতে হবে।
সিঙ্ক্রোনাস কল
কানেক্টেড অ্যাপস SDK সিঙ্ক্রোনাস (ব্লকিং) কলগুলিকে সমর্থন করে যেখানে সেগুলি অনিবার্য। যাইহোক, এই কলগুলি ব্যবহার করার অনেকগুলি অসুবিধা রয়েছে (যেমন দীর্ঘ সময়ের জন্য কলগুলি ব্লক করার সম্ভাবনা) তাই এটি সুপারিশ করা হয় যে আপনি যখন সম্ভব সিঙ্ক্রোনাস কলগুলি এড়িয়ে যান ৷ অ্যাসিঙ্ক্রোনাস কল ব্যবহার করার জন্য অ্যাসিঙ্ক্রোনাস কলগুলি দেখুন।
সংযোগ ধারক
আপনি যদি সিঙ্ক্রোনাস কল ব্যবহার করেন, তাহলে আপনাকে অবশ্যই নিশ্চিত করতে হবে যে ক্রস প্রোফাইল কল করার আগে একটি সংযোগ ধারক নিবন্ধিত আছে, অন্যথায় একটি ব্যতিক্রম নিক্ষেপ করা হবে। আরও তথ্যের জন্য সংযোগ হোল্ডার দেখুন।
একটি সংযোগ ধারক যোগ করতে, যে কোনো বস্তুর সাথে ProfileConnector#addConnectionHolder(Object)
কল করুন (সম্ভবত, বস্তুর উদাহরণ যা ক্রস-প্রোফাইল কল করছে)। এটি রেকর্ড করবে যে এই বস্তুটি সংযোগ ব্যবহার করছে এবং একটি সংযোগ করার চেষ্টা করবে। যেকোনো সিঙ্ক্রোনাস কল করার আগে এটি অবশ্যই কল করা উচিত। এটি একটি নন-ব্লকিং কল তাই এটি সম্ভব যে আপনি আপনার কল করার সময় সংযোগটি প্রস্তুত হবে না (বা সম্ভব নাও হতে পারে), এই ক্ষেত্রে স্বাভাবিক ত্রুটি পরিচালনার আচরণ প্রযোজ্য।
আপনি যদি ProfileConnector#addConnectionHolder(Object)
কল করার সময় উপযুক্ত ক্রস-প্রোফাইল অনুমতির অভাব করেন বা সংযোগ করার জন্য কোনো প্রোফাইল উপলব্ধ না থাকে, তাহলে কোনো ত্রুটি করা হবে না কিন্তু সংযুক্ত কলব্যাককে কখনই কল করা হবে না। যদি অনুমতি পরে মঞ্জুর করা হয় বা অন্য প্রোফাইল পাওয়া যায় তাহলে সংযোগ করা হবে এবং কলব্যাক কল করা হবে।
বিকল্পভাবে, ProfileConnector#connect(Object)
হল একটি ব্লকিং পদ্ধতি যা একটি সংযোগ ধারক হিসাবে বস্তুটিকে যুক্ত করবে এবং হয় একটি সংযোগ স্থাপন করবে বা একটি UnavailableProfileException
নিক্ষেপ করবে। এই পদ্ধতিটি UI থ্রেড থেকে কল করা যাবে না ।
ProfileConnector#connect(Object)
এবং অনুরূপ ProfileConnector#connect
এ কল করা স্বয়ংক্রিয়ভাবে বন্ধ হওয়া বস্তু ফেরত দেয় যা বন্ধ হয়ে গেলে স্বয়ংক্রিয়ভাবে সংযোগ ধারককে সরিয়ে দেয়। এটি ব্যবহারের জন্য অনুমতি দেয় যেমন:
try (ProfileConnectionHolder p = connector.connect()) {
// Use the connection
}
একবার আপনার সিঙ্ক্রোনাস কল করা শেষ হলে, আপনাকে ProfileConnector#removeConnectionHolder(Object)
কল করা উচিত। একবার সমস্ত সংযোগ ধারক সরানো হলে, সংযোগটি বন্ধ হয়ে যাবে।
সংযোগ
সংযোগের অবস্থা পরিবর্তিত হলে একটি সংযোগ শ্রোতাকে জানানোর জন্য ব্যবহার করা যেতে পারে এবং সংযোগ উপস্থিত আছে কিনা তা নির্ধারণ করতে connector.utils().isConnected
ব্যবহার করা যেতে পারে। যেমন:
// Only use this if using synchronous calls instead of Futures.
crossProfileConnector.connect(this);
crossProfileConnector.registerConnectionListener(() -> {
if (crossProfileConnector.utils().isConnected()) {
// Make cross-profile calls.
}
});
অ্যাসিঙ্ক্রোনাস কল
প্রোফাইল বিভাজন জুড়ে প্রকাশিত প্রতিটি পদ্ধতিকে অবশ্যই ব্লকিং (সিঙ্ক্রোনাস) বা নন-ব্লকিং (অসিঙ্ক্রোনাস) হিসাবে মনোনীত করতে হবে। যে কোনও পদ্ধতি যা একটি অ্যাসিঙ্ক্রোনাস ডেটা টাইপ (যেমন একটি ListenableFuture
) প্রদান করে বা একটি কলব্যাক প্যারামিটার গ্রহণ করে তা নন-ব্লকিং হিসাবে চিহ্নিত করা হয়। অন্যান্য সমস্ত পদ্ধতি ব্লকিং হিসাবে চিহ্নিত করা হয়েছে।
অ্যাসিঙ্ক্রোনাস কলগুলি সুপারিশ করা হয়। আপনি যদি অবশ্যই সিঙ্ক্রোনাস কল ব্যবহার করেন তবে সিঙ্ক্রোনাস কলগুলি দেখুন।
কলব্যাক
নন-ব্লকিং কলের সবচেয়ে মৌলিক ধরন হল একটি অকার্যকর পদ্ধতি যা তার পরামিতিগুলির মধ্যে একটি হিসাবে গ্রহণ করে একটি ইন্টারফেস যা ফলাফল সহ কল করার একটি পদ্ধতি ধারণ করে। এই ইন্টারফেসগুলিকে SDK-এর সাথে কাজ করার জন্য, ইন্টারফেসটিকে @CrossProfileCallback
টীকা করতে হবে। যেমন:
@CrossProfileCallback
public interface InstallationCompleteListener {
void installationComplete(int state);
}
এই ইন্টারফেসটি তারপর একটি @CrossProfile
টীকা পদ্ধতিতে একটি প্যারামিটার হিসাবে ব্যবহার করা যেতে পারে এবং যথারীতি বলা যেতে পারে। যেমন:
@CrossProfile
public void install(String filename, InstallationCompleteListener callback) {
// Do something on a separate thread and then:
callback.installationComplete(1);
}
// In the mediator
profileInstaller.work().install(filename, (status) -> {
// Deal with callback
}, (exception) -> {
// Deal with possibility of profile unavailability
});
যদি এই ইন্টারফেসে একটি একক পদ্ধতি থাকে, যেটি হয় শূন্য বা একটি প্যারামিটার নেয়, তাহলে এটি একবারে একাধিক প্রোফাইলে কল করার ক্ষেত্রেও ব্যবহার করা যেতে পারে।
একটি কলব্যাক ব্যবহার করে যেকোনো সংখ্যক মান পাস করা যেতে পারে, তবে সংযোগটি শুধুমাত্র প্রথম মানের জন্য খোলা থাকবে। আরও মান পেতে সংযোগ খোলা রাখার বিষয়ে তথ্যের জন্য সংযোগ হোল্ডার দেখুন।
কলব্যাকের সাথে সিঙ্ক্রোনাস পদ্ধতি
SDK এর সাথে কলব্যাক ব্যবহার করার একটি অস্বাভাবিক বৈশিষ্ট্য হল যে আপনি প্রযুক্তিগতভাবে একটি সিঙ্ক্রোনাস পদ্ধতি লিখতে পারেন যা একটি কলব্যাক ব্যবহার করে:
public void install(InstallationCompleteListener callback) {
callback.installationComplete(1);
}
এই ক্ষেত্রে, কলব্যাক সত্ত্বেও পদ্ধতিটি আসলে সিঙ্ক্রোনাস। এই কোড সঠিকভাবে চালানো হবে:
System.out.println("This prints first");
installer.install(() -> {
System.out.println("This prints second");
});
System.out.println("This prints third");
যাইহোক, যখন SDK ব্যবহার করে কল করা হয়, তখন এটি একইভাবে আচরণ করবে না। "এই প্রিন্ট থার্ড" মুদ্রিত হওয়ার আগে ইনস্টল পদ্ধতিটি কল করা হবে এমন কোনও গ্যারান্টি নেই৷ SDK দ্বারা অ্যাসিঙ্ক্রোনাস হিসাবে চিহ্নিত কোনও পদ্ধতির যে কোনও ব্যবহার অবশ্যই কখন পদ্ধতিটি কল করা হবে সে সম্পর্কে কোনও অনুমান করা উচিত নয়।
সহজ কলব্যাক
"সাধারণ কলব্যাকগুলি" হল কলব্যাকের একটি আরও সীমাবদ্ধ ফর্ম যা ক্রস-প্রোফাইল কল করার সময় অতিরিক্ত বৈশিষ্ট্যগুলির জন্য অনুমতি দেয়৷ সাধারণ ইন্টারফেসে একটি একক পদ্ধতি থাকতে হবে, যা শূন্য বা একটি প্যারামিটার নিতে পারে।
আপনি @CrossProfileCallback
টীকাতে simple=true
উল্লেখ করে একটি কলব্যাক ইন্টারফেস অবশ্যই থাকতে হবে তা প্রয়োগ করতে পারেন।
সাধারণ কলব্যাকগুলি বিভিন্ন পদ্ধতি যেমন .both()
, .suppliers()
, এবং অন্যান্যগুলির সাথে ব্যবহারযোগ্য৷
সংযোগ ধারক
একটি অ্যাসিঙ্ক্রোনাস কল করার সময় (কলব্যাক বা ফিউচার ব্যবহার করে) কল করার সময় একটি সংযোগ ধারক যোগ করা হবে এবং একটি ব্যতিক্রম বা একটি মান পাস করা হলে তা সরানো হবে।
আপনি যদি একটি কলব্যাক ব্যবহার করে একাধিক ফলাফল পাস করার আশা করেন, তাহলে আপনাকে ম্যানুয়ালি একটি সংযোগ ধারক হিসাবে কলব্যাক যোগ করা উচিত:
MyCallback b = //...
connector.addConnectionHolder(b);
profileMyClass.other().registerListener(b);
// Now the connection will be held open indefinitely, once finished:
connector.removeConnectionHolder(b);
এটি একটি ট্রাই-ওয়াথ-রিসোর্স ব্লকের সাথেও ব্যবহার করা যেতে পারে:
MyCallback b = //...
try (ProfileConnectionHolder p = connector.addConnectionHolder(b)) {
profileMyClass.other().registerListener(b);
// Other things running while we expect results
}
যদি আমরা একটি কলব্যাক বা ভবিষ্যতের সাথে একটি কল করি, একটি ফলাফল পাস না হওয়া পর্যন্ত সংযোগটি খোলা থাকবে। যদি আমরা নির্ধারণ করি যে একটি ফলাফল পাস করা হবে না, তাহলে আমাদের একটি সংযোগ ধারক হিসাবে কলব্যাক বা ভবিষ্যতে সরানো উচিত:
connector.removeConnectionHolder(myCallback);
connector.removeConnectionHolder(future);
আরও তথ্যের জন্য, সংযোগ হোল্ডার দেখুন।
ফিউচার
ফিউচারগুলিও SDK দ্বারা স্থানীয়ভাবে সমর্থিত। শুধুমাত্র নেটিভলি সমর্থিত ফিউচার টাইপ হল ListenableFuture
, যদিও কাস্টম ফিউচার টাইপ ব্যবহার করা যেতে পারে। ফিউচার ব্যবহার করার জন্য আপনি শুধুমাত্র একটি সমর্থিত ফিউচার টাইপকে ক্রস প্রোফাইল পদ্ধতির রিটার্ন টাইপ হিসাবে ঘোষণা করুন এবং তারপরে এটি স্বাভাবিক হিসাবে ব্যবহার করুন।
এটিতে কলব্যাকগুলির মতো একই "অস্বাভাবিক বৈশিষ্ট্য" রয়েছে, যেখানে একটি সিঙ্ক্রোনাস পদ্ধতি যা একটি ভবিষ্যত প্রদান করে (যেমন immediateFuture
ব্যবহার করে) অন্য প্রোফাইলে চালানোর বিপরীতে বর্তমান প্রোফাইলে চালানোর সময় ভিন্নভাবে আচরণ করবে। SDK দ্বারা অ্যাসিঙ্ক্রোনাস হিসাবে চিহ্নিত কোনও পদ্ধতির যে কোনও ব্যবহার অবশ্যই কখন পদ্ধতিটি কল করা হবে সে সম্পর্কে কোনও অনুমান করা উচিত নয়।
থ্রেড
একটি ক্রস-প্রোফাইল ভবিষ্যতের ফলাফল বা মূল থ্রেডে কলব্যাক ব্লক করবেন না। আপনি যদি এটি করেন, তাহলে কিছু পরিস্থিতিতে আপনার কোড অনির্দিষ্টকালের জন্য ব্লক করবে। এর কারণ হল অন্য প্রোফাইলের সাথে সংযোগটিও মূল থ্রেডে স্থাপিত হয়, যা ক্রস-প্রোফাইলের ফলাফলের জন্য মুলতুবি থাকা অবরুদ্ধ থাকলে কখনই ঘটবে না।
প্রাপ্যতা
প্রাপ্যতা শ্রোতাকে জানানোর জন্য ব্যবহার করা যেতে পারে যখন প্রাপ্যতার অবস্থা পরিবর্তিত হয়, এবং connector.utils().isAvailable
ব্যবহার করা যেতে পারে অন্য প্রোফাইল ব্যবহারের জন্য উপলব্ধ কিনা তা নির্ধারণ করতে। যেমন:
crossProfileConnector.registerAvailabilityListener(() -> {
if (crossProfileConnector.utils().isAvailable()) {
// Show cross-profile content
} else {
// Hide cross-profile content
}
});
সংযোগ ধারক
সংযোগ ধারক হল নির্বিচারে বস্তু যা ক্রস-প্রোফাইল সংযোগ স্থাপন এবং জীবিত রাখা হচ্ছে এবং আগ্রহ হিসাবে রেকর্ড করা হয়।
ডিফল্টরূপে, অ্যাসিঙ্ক্রোনাস কল করার সময়, কল শুরু হলে একটি সংযোগ ধারক যোগ করা হবে এবং কোনো ফলাফল বা ত্রুটি ঘটলে সরানো হবে।
সংযোগ ধারকদের সংযোগের উপর আরো নিয়ন্ত্রণ প্রয়োগ করতে ম্যানুয়ালি যোগ করা এবং সরানো যেতে পারে। সংযোগ হোল্ডার connector.addConnectionHolder
ব্যবহার করে যোগ করা যায় এবং connector.removeConnectionHolder
ব্যবহার করে সরানো যায়।
যখন অন্তত একটি সংযোগ ধারক যোগ করা হয়, SDK একটি সংযোগ বজায় রাখার চেষ্টা করবে৷ যখন শূন্য সংযোগ ধারক যোগ করা হয়, সংযোগ বন্ধ করা যেতে পারে.
আপনার যোগ করা যেকোনো সংযোগ ধারকের একটি রেফারেন্স বজায় রাখতে হবে - এবং এটি আর প্রাসঙ্গিক না হলে এটি সরিয়ে ফেলুন।
সিঙ্ক্রোনাস কল
সিঙ্ক্রোনাস কল করার আগে, একটি সংযোগ ধারক যোগ করা উচিত। এটি যেকোন অবজেক্ট ব্যবহার করে করা যেতে পারে, যদিও আপনাকে অবশ্যই সেই অবজেক্টের ট্র্যাক রাখতে হবে যাতে আপনার আর সিঙ্ক্রোনাস কল করার প্রয়োজন না হলে এটি সরানো যায়।
অ্যাসিঙ্ক্রোনাস কল
অ্যাসিঙ্ক্রোনাস কল করার সময় সংযোগ ধারক স্বয়ংক্রিয়ভাবে পরিচালিত হবে যাতে কল এবং প্রথম প্রতিক্রিয়া বা ত্রুটির মধ্যে সংযোগটি খোলা থাকে। এর বাইরে বেঁচে থাকার জন্য যদি আপনার সংযোগের প্রয়োজন হয় (যেমন একটি একক কলব্যাক ব্যবহার করে একাধিক প্রতিক্রিয়া প্রাপ্ত করার জন্য) তাহলে আপনাকে কলব্যাকটিকে নিজেই একটি সংযোগ ধারক হিসাবে যুক্ত করতে হবে এবং একবার আপনার আর ডেটা গ্রহণের প্রয়োজন হবে না।
ত্রুটি হ্যান্ডলিং
ডিফল্টরূপে, অন্য প্রোফাইলে করা যে কোনো কল যখন অন্য প্রোফাইল উপলব্ধ না থাকে তার ফলে একটি UnavailableProfileException
নিক্ষেপ করা হবে (বা ভবিষ্যতে পাস করা হবে, অথবা একটি async কলের জন্য ত্রুটি কলব্যাক)।
এটি এড়াতে, বিকাশকারীরা #both()
বা #suppliers()
ব্যবহার করতে পারেন এবং ফলাফল তালিকায় যেকোন সংখ্যক এন্ট্রি মোকাবেলা করতে তাদের কোড লিখতে পারেন (অন্য প্রোফাইল অনুপলব্ধ হলে এটি 1 হবে, অথবা যদি এটি উপলব্ধ থাকে 2) .
ব্যতিক্রম
বর্তমান প্রোফাইলে কল করার পরে যে কোনো অচেক করা ব্যতিক্রমগুলি যথারীতি প্রচার করা হবে। এটি কল করার জন্য ব্যবহৃত পদ্ধতি নির্বিশেষে প্রযোজ্য ( #current()
, #personal
, #both
, ইত্যাদি)।
অন্য প্রোফাইলে কল করার পরে যে ব্যতিক্রমগুলি ঘটবে তা টিক চিহ্ন না দেওয়া হলে একটি ProfileRuntimeException
কারণ হিসাবে আসল ব্যতিক্রমের সাথে নিক্ষিপ্ত হবে৷ এটি কল করার জন্য ব্যবহৃত পদ্ধতি নির্বিশেষে প্রযোজ্য ( #other()
, #personal
, #both
, ইত্যাদি)।
যদি পাওয়া যায়
UnavailableProfileException
দৃষ্টান্তগুলি ধরা এবং ডিল করার বিকল্প হিসাবে, আপনি একটি ডিফল্ট মান প্রদান করতে .ifAvailable()
পদ্ধতি ব্যবহার করতে পারেন যা একটি UnavailableProfileException
নিক্ষেপ করার পরিবর্তে ফেরত দেওয়া হবে।
যেমন:
profileNotesDatabase.other().ifAvailable().getNumberOfNotes(/* defaultValue= */ 0);
টেস্টিং
আপনার কোড পরীক্ষাযোগ্য করার জন্য, আপনার প্রোফাইল সংযোগকারীর যেকোন কোডে ইনজেকশন দেওয়া উচিত যা এটি ব্যবহার করে (প্রোফাইল উপলব্ধতা পরীক্ষা করতে, ম্যানুয়ালি সংযোগ করতে ইত্যাদি)। আপনি আপনার প্রোফাইল সচেতন ধরনের উদাহরণ যেখানে তারা ব্যবহার করা হয় ইনজেকশন করা উচিত.
আমরা আপনার সংযোগকারীর নকল এবং প্রকার সরবরাহ করি যা পরীক্ষায় ব্যবহার করা যেতে পারে।
প্রথমে, পরীক্ষা নির্ভরতা যোগ করুন:
testAnnotationProcessor
'com.google.android.enterprise.connectedapps:connectedapps-processor:1.1.2'
testCompileOnly
'com.google.android.enterprise.connectedapps:connectedapps-testing-annotations:1.1.2'
testImplementation
'com.google.android.enterprise.connectedapps:connectedapps-testing:1.1.2'
তারপরে, @CrossProfileTest
এর সাথে আপনার পরীক্ষার ক্লাস টীকা করুন, @CrossProfileConfiguration
টীকাযুক্ত ক্লাস পরীক্ষা করার জন্য চিহ্নিত করুন:
@CrossProfileTest(configuration = MyApplication.class)
@RunWith(RobolectricTestRunner.class)
public class NotesMediatorTest {
}
এটি কনফিগারেশনে ব্যবহৃত সমস্ত ধরণের এবং সংযোগকারীগুলির জন্য জাল তৈরির কারণ হবে৷
আপনার পরীক্ষায় সেই নকলের উদাহরণ তৈরি করুন:
private final FakeCrossProfileConnector connector = new
FakeCrossProfileConnector();
private final NotesManager personalNotesManager = new NotesManager(); //
real/mock/fake
private final NotesManager workNotesManager = new NotesManager(); // real/mock/fake
private final FakeProfileNotesManager profileNotesManager =
FakeProfileNotesManager.builder()
.personal(personalNotesManager)
.work(workNotesManager)
.connector(connector)
.build();
প্রোফাইল অবস্থা সেট আপ করুন:
connector.setRunningOnProfile(PERSONAL);
connector.createWorkProfile();
connector.turnOffWorkProfile();
পরীক্ষার অধীনে আপনার কোডে জাল সংযোগকারী এবং ক্রস প্রোফাইল ক্লাস পাস করুন এবং তারপর কল করুন।
কলগুলি সঠিক টার্গেটে পাঠানো হবে - এবং সংযোগ বিচ্ছিন্ন বা অনুপলব্ধ প্রোফাইলগুলিতে কল করার সময় ব্যতিক্রমগুলি নিক্ষেপ করা হবে৷
সমর্থিত প্রকার
নিম্নলিখিত ধরনের আপনার পক্ষ থেকে কোন অতিরিক্ত প্রচেষ্টা ছাড়া সমর্থিত হয়. এগুলি সমস্ত ক্রস-প্রোফাইল কলের জন্য আর্গুমেন্ট বা রিটার্ন প্রকার হিসাবে ব্যবহার করা যেতে পারে।
- আদিম (
byte
,short
,int
,long
,float
,double
,char
,boolean
), - বক্সযুক্ত আদিম (
java.lang.Byte
,java.lang.Short
,java.lang.Integer
,java.lang.Long
,java.lang.Float
,java.lang.Double
,java.lang.Character
,java.lang.Boolean
,java.lang.Void
), -
java.lang.String
, - যে কোনো কিছু যা
android.os.Parcelable
প্রয়োগ করে, - যে কোনো কিছু যা
java.io.Serializable
প্রয়োগ করে, - একক-মাত্রা অ-আদিম অ্যারে,
-
java.util.Optional
, -
java.util.Collection
, -
java.util.List
, -
java.util.Map
, -
java.util.Set
, -
android.util.Pair
, -
com.google.common.collect.ImmutableMap
যেকোন সমর্থিত জেনেরিক প্রকারের (উদাহরণস্বরূপ java.util.Collection
) তাদের টাইপ প্যারামিটার হিসাবে কোন সমর্থিত প্রকার থাকতে পারে। যেমন:
java.util.Collection<java.util.Map<java.lang.String,MySerializableType[]>>
একটি বৈধ প্রকার।
ফিউচার
নিম্নলিখিত প্রকারগুলি শুধুমাত্র রিটার্ন প্রকার হিসাবে সমর্থিত:
-
com.google.common.util.concurrent.ListenableFuture
কাস্টম পার্সেলযোগ্য মোড়ক
যদি আপনার টাইপটি আগের তালিকায় না থাকে, তাহলে প্রথমে বিবেচনা করুন যে এটি android.os.Parcelable
বা java.io.Serializable
সঠিকভাবে বাস্তবায়ন করা যায় কিনা। যদি এটি না পারে তবে আপনার প্রকারের জন্য সমর্থন যোগ করতে পার্সেলযোগ্য মোড়কগুলি দেখুন৷
কাস্টম ভবিষ্যত মোড়ক
আপনি যদি একটি ভবিষ্যত প্রকার ব্যবহার করতে চান যা পূর্বের তালিকায় নেই, তাহলে সমর্থন যোগ করতে ভবিষ্যতের মোড়কগুলি দেখুন।
পার্সেলযোগ্য মোড়ক
পার্সেলেবল র্যাপার হল এমন উপায় যেটি SDK অ-পার্সেলযোগ্য প্রকারের জন্য সমর্থন যোগ করে যা পরিবর্তন করা যায় না। SDK-তে অনেক ধরনের র্যাপার রয়েছে কিন্তু আপনার যে ধরনের ব্যবহার করতে হবে তা অন্তর্ভুক্ত না হলে আপনাকে নিজের লিখতে হবে।
একটি পার্সেলেবল র্যাপার হল এমন একটি শ্রেণী যা অন্য শ্রেণীকে মোড়ানো এবং এটিকে পার্সেবল করার জন্য ডিজাইন করা হয়েছে। এটি একটি সংজ্ঞায়িত স্ট্যাটিক চুক্তি অনুসরণ করে এবং SDK এর সাথে নিবন্ধিত হয় তাই এটি একটি প্রদত্ত টাইপকে একটি পার্সেলেবল টাইপে রূপান্তর করতে ব্যবহার করা যেতে পারে এবং পার্সেলেবল টাইপ থেকে সেই টাইপটি বের করতে পারে।
টীকা
পার্সেলেবল র্যাপার ক্লাসটি অবশ্যই @CustomParcelableWrapper
টীকা করতে হবে, র্যাপ করা ক্লাসটিকে originalType
হিসাবে উল্লেখ করে। যেমন:
@CustomParcelableWrapper(originalType=ImmutableList.class)
বিন্যাস
পার্সেলেবল র্যাপারগুলিকে অবশ্যই Parcelable
সঠিকভাবে প্রয়োগ করতে হবে এবং অবশ্যই একটি স্ট্যাটিক W of(Bundler, BundlerType, T)
পদ্ধতি থাকতে হবে যা মোড়ানো টাইপকে মোড়ানো হয় এবং একটি নন-স্ট্যাটিক T get()
পদ্ধতি যা মোড়ানো টাইপটি ফেরত দেয়।
SDK প্রকারের জন্য নির্বিঘ্ন সমর্থন প্রদান করতে এই পদ্ধতিগুলি ব্যবহার করবে৷
বান্ডলার
জেনেরিক প্রকারগুলি (যেমন তালিকা এবং মানচিত্র) মোড়ানোর অনুমতি দেওয়ার জন্য, of
একটি Bundler
পাস করা হয় যা পড়তে সক্ষম ( #readFromParcel
ব্যবহার করে) এবং লিখতে ( #writeToParcel
ব্যবহার করে) সমস্ত সমর্থিত প্রকার একটি Parcel
, এবং একটি BundlerType
যা প্রতিনিধিত্ব করে ঘোষিত প্রকার লিখতে হবে।
Bundler
এবং BundlerType
দৃষ্টান্তগুলি নিজেই পার্সেলযোগ্য, এবং পার্সেলযোগ্য মোড়কের পার্সেলিংয়ের অংশ হিসাবে লেখা উচিত, যাতে এটি পার্সেবল র্যাপার পুনর্গঠনের সময় ব্যবহার করা যেতে পারে।
যদি BundlerType
একটি জেনেরিক প্রকারের প্রতিনিধিত্ব করে, তাহলে .typeArguments()
এ কল করে টাইপ ভেরিয়েবল পাওয়া যাবে। প্রতিটি ধরনের আর্গুমেন্ট নিজেই একটি BundlerType
।
একটি উদাহরণের জন্য, ParcelableCustomWrapper
দেখুন:
public class CustomWrapper<F> {
private final F value;
public CustomWrapper(F value) {
this.value = value;
}
public F value() {
return value;
}
}
@CustomParcelableWrapper(originalType = CustomWrapper.class)
public class ParcelableCustomWrapper<E> implements Parcelable {
private static final int NULL = -1;
private static final int NOT_NULL = 1;
private final Bundler bundler;
private final BundlerType type;
private final CustomWrapper<E> customWrapper;
/**
* Create a wrapper for a given {@link CustomWrapper}.
*
* <p>The passed in {@link Bundler} must be capable of bundling {@code F}.
*/
public static <F> ParcelableCustomWrapper<F> of(
Bundler bundler, BundlerType type, CustomWrapper<F> customWrapper) {
return new ParcelableCustomWrapper<>(bundler, type, customWrapper);
}
public CustomWrapper<E> get() {
return customWrapper;
}
private ParcelableCustomWrapper(
Bundler bundler, BundlerType type, CustomWrapper<E> customWrapper) {
if (bundler == null || type == null) {
throw new NullPointerException();
}
this.bundler = bundler;
this.type = type;
this.customWrapper = customWrapper;
}
private ParcelableCustomWrapper(Parcel in) {
bundler = in.readParcelable(Bundler.class.getClassLoader());
int presentValue = in.readInt();
if (presentValue == NULL) {
type = null;
customWrapper = null;
return;
}
type = (BundlerType) in.readParcelable(Bundler.class.getClassLoader());
BundlerType valueType = type.typeArguments().get(0);
@SuppressWarnings("unchecked")
E value = (E) bundler.readFromParcel(in, valueType);
customWrapper = new CustomWrapper<>(value);
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeParcelable(bundler, flags);
if (customWrapper == null) {
dest.writeInt(NULL);
return;
}
dest.writeInt(NOT_NULL);
dest.writeParcelable(type, flags);
BundlerType valueType = type.typeArguments().get(0);
bundler.writeToParcel(dest, customWrapper.value(), valueType, flags);
}
@Override
public int describeContents() {
return 0;
}
@SuppressWarnings("rawtypes")
public static final Creator<ParcelableCustomWrapper> CREATOR =
new Creator<ParcelableCustomWrapper>() {
@Override
public ParcelableCustomWrapper createFromParcel(Parcel in) {
return new ParcelableCustomWrapper(in);
}
@Override
public ParcelableCustomWrapper[] newArray(int size) {
return new ParcelableCustomWrapper[size];
}
};
}
SDK-এর সাথে নিবন্ধন করুন
একবার তৈরি হয়ে গেলে, আপনার কাস্টম পার্সেলেবল র্যাপার ব্যবহার করতে আপনাকে এটি SDK-এর সাথে নিবন্ধন করতে হবে।
এটি করার জন্য, parcelableWrappers={YourParcelableWrapper.class}
একটি CustomProfileConnector
টীকা অথবা একটি ক্লাসে একটি CrossProfile
টীকা উল্লেখ করুন।
ভবিষ্যতের মোড়ক
ফিউচার র্যাপার হল যেভাবে SDK প্রোফাইল জুড়ে ফিউচারের জন্য সমর্থন যোগ করে। SDK ডিফল্টরূপে ListenableFuture
এর জন্য সমর্থন অন্তর্ভুক্ত করে, কিন্তু অন্যান্য ভবিষ্যতের প্রকারের জন্য আপনি নিজে সমর্থন যোগ করতে পারেন।
ফিউচার র্যাপার হল একটি ক্লাস যা একটি নির্দিষ্ট ফিউচার টাইপ মোড়ানো এবং এটি SDK-এর কাছে উপলব্ধ করার জন্য ডিজাইন করা হয়েছে৷ এটি একটি সংজ্ঞায়িত স্ট্যাটিক চুক্তি অনুসরণ করে এবং অবশ্যই SDK-এর সাথে নিবন্ধিত হতে হবে।
টীকা
ভবিষ্যত র্যাপার ক্লাসটি অবশ্যই @CustomFutureWrapper
টীকা করতে হবে, র্যাপ করা ক্লাসটিকে originalType
হিসাবে উল্লেখ করে। যেমন:
@CustomFutureWrapper(originalType=SettableFuture.class)
বিন্যাস
ভবিষ্যতের র্যাপারগুলিকে অবশ্যই com.google.android.enterprise.connectedapps.FutureWrapper
প্রসারিত করতে হবে৷
ভবিষ্যত র্যাপারে অবশ্যই একটি স্ট্যাটিক W create(Bundler, BundlerType)
পদ্ধতি থাকতে হবে যা র্যাপারের একটি উদাহরণ তৈরি করে। একই সময়ে এটি মোড়ানো ভবিষ্যত প্রকারের একটি উদাহরণ তৈরি করা উচিত। এটি একটি নন-স্ট্যাটিক T
getFuture()
পদ্ধতি দ্বারা ফেরত দেওয়া উচিত। onResult(E)
এবং onException(Throwable)
পদ্ধতিগুলি অবশ্যই প্রয়োগ করতে হবে ফলাফল পাস করতে বা মোড়ানো ভবিষ্যতে নিক্ষেপযোগ্য।
ভবিষ্যত র্যাপারগুলিতে অবশ্যই একটি স্থির void writeFutureResult(Bundler,
BundlerType, T, FutureResultWriter<E>)
পদ্ধতি। এটি ফলাফলের জন্য ভবিষ্যতে উত্তীর্ণদের সাথে নিবন্ধন করতে হবে, এবং যখন একটি ফলাফল দেওয়া হবে, কল করুন resultWriter.onSuccess(value)
। যদি একটি ব্যতিক্রম দেওয়া হয়, resultWriter.onFailure(exception)
বলা উচিত।
অবশেষে, ভবিষ্যতের র্যাপারগুলিতে অবশ্যই একটি স্ট্যাটিক T<Map<Profile, E>>
groupResults(Map<Profile, T<E>> results)
পদ্ধতি থাকতে হবে যা একটি মানচিত্রকে প্রোফাইল থেকে ভবিষ্যতে, প্রোফাইল থেকে একটি মানচিত্রের ভবিষ্যতে রূপান্তর করে ফলাফল এই যুক্তিটিকে সহজ করতে CrossProfileCallbackMultiMerger
ব্যবহার করা যেতে পারে।
যেমন:
/** A basic implementation of the future pattern used to test custom future
wrappers. */
public class SimpleFuture<E> {
public static interface Consumer<E> {
void accept(E value);
}
private E value;
private Throwable thrown;
private final CountDownLatch countDownLatch = new CountDownLatch(1);
private Consumer<E> callback;
private Consumer<Throwable> exceptionCallback;
public void set(E value) {
this.value = value;
countDownLatch.countDown();
if (callback != null) {
callback.accept(value);
}
}
public void setException(Throwable t) {
this.thrown = t;
countDownLatch.countDown();
if (exceptionCallback != null) {
exceptionCallback.accept(thrown);
}
}
public E get() {
try {
countDownLatch.await();
} catch (InterruptedException e) {
eturn null;
}
if (thrown != null) {
throw new RuntimeException(thrown);
}
return value;
}
public void setCallback(Consumer<E> callback, Consumer<Throwable>
exceptionCallback) {
if (value != null) {
callback.accept(value);
} else if (thrown != null) {
exceptionCallback.accept(thrown);
} else {
this.callback = callback;
this.exceptionCallback = exceptionCallback;
}
}
}
/** Wrapper for adding support for {@link SimpleFuture} to the Connected Apps SDK.
*/
@CustomFutureWrapper(originalType = SimpleFuture.class)
public final class SimpleFutureWrapper<E> extends FutureWrapper<E> {
private final SimpleFuture<E> future = new SimpleFuture<>();
public static <E> SimpleFutureWrapper<E> create(Bundler bundler, BundlerType
bundlerType) {
return new SimpleFutureWrapper<>(bundler, bundlerType);
}
private SimpleFutureWrapper(Bundler bundler, BundlerType bundlerType) {
super(bundler, bundlerType);
}
public SimpleFuture<E> getFuture() {
return future;
}
@Override
public void onResult(E result) {
future.set(result);
}
@Override
public void onException(Throwable throwable) {
future.setException(throwable);
}
public static <E> void writeFutureResult(
SimpleFuture<E> future, FutureResultWriter<E> resultWriter) {
future.setCallback(resultWriter::onSuccess, resultWriter::onFailure);
}
public static <E> SimpleFuture<Map<Profile, E>> groupResults(
Map<Profile, SimpleFuture<E>> results) {
SimpleFuture<Map<Profile, E>> m = new SimpleFuture<>();
CrossProfileCallbackMultiMerger<E> merger =
new CrossProfileCallbackMultiMerger<>(results.size(), m::set);
for (Map.Entry<Profile, SimpleFuture<E>> result : results.entrySet()) {
result
.getValue()
.setCallback(
(value) -> merger.onResult(result.getKey(), value),
(throwable) -> merger.missingResult(result.getKey()));
}
return m;
}
}
SDK-এর সাথে নিবন্ধন করুন
একবার তৈরি হয়ে গেলে, আপনার কাস্টম ভবিষ্যত মোড়ক ব্যবহার করতে আপনাকে এটি SDK-এর সাথে নিবন্ধন করতে হবে।
এটি করার জন্য, একটি CustomProfileConnector
টীকা বা একটি ক্লাসে একটি CrossProfile
টীকাতে futureWrappers={YourFutureWrapper.class}
উল্লেখ করুন।
ডাইরেক্ট বুট মোড
যদি আপনার অ্যাপ সরাসরি বুট মোড সমর্থন করে, তাহলে প্রোফাইলটি আনলক করার আগে আপনাকে ক্রস-প্রোফাইল কল করতে হতে পারে। ডিফল্টরূপে, SDK শুধুমাত্র সংযোগের অনুমতি দেয় যখন অন্য প্রোফাইলটি আনলক করা থাকে।
এই আচরণটি পরিবর্তন করতে, আপনি যদি একটি কাস্টম প্রোফাইল সংযোগকারী ব্যবহার করেন, তাহলে আপনাকে উল্লেখ করা উচিত availabilityRestrictions=AvailabilityRestrictions.DIRECT_BOOT_AWARE
:
@GeneratedProfileConnector
@CustomProfileConnector(availabilityRestrictions=AvailabilityRestrictions.DIRECT_BO
OT_AWARE)
public interface MyProfileConnector extends ProfileConnector {
public static MyProfileConnector create(Context context) {
return GeneratedMyProfileConnector.builder(context).build();
}
}
আপনি যদি CrossProfileConnector
ব্যবহার করেন, তাহলে বিল্ডারে .setAvailabilityRestrictions(AvailabilityRestrictions.DIRECT_BOOT
_AWARE
ব্যবহার করুন।
এই পরিবর্তনের সাথে, আপনি উপলব্ধতা সম্পর্কে অবহিত হবেন, এবং অন্য প্রোফাইলটি আনলক না থাকলে ক্রস প্রোফাইল কল করতে পারবেন। আপনার কল শুধুমাত্র ডিভাইস এনক্রিপ্ট করা স্টোরেজ অ্যাক্সেস নিশ্চিত করার দায়িত্ব আপনার।
,এই বিভাগগুলি রেফারেন্সের জন্য বোঝানো হয়েছে এবং এটি আপনাকে উপরের থেকে নীচে পড়ার প্রয়োজন নেই।
ব্যবহারকারীর সম্মতির অনুরোধ করুন
ফ্রেমওয়ার্ক API ব্যবহার করুন:
-
CrossProfileApps.canInteractAcrossProfiles()
-
CrossProfileApps.canRequestInteractAcrossProfiles()
-
CrossProfileApps.createRequestInteractAcrossProfilesIntent()
-
CrossProfileApps.ACTION_CAN_INTERACT_ACROSS_PROFILES_CHANGED
এই APIগুলি আরও সামঞ্জস্যপূর্ণ API পৃষ্ঠের জন্য SDK-তে মোড়ানো হবে (যেমন UserHandle অবজেক্টগুলি এড়িয়ে যাওয়া), কিন্তু আপাতত, আপনি এগুলিকে সরাসরি কল করতে পারেন৷
বাস্তবায়ন সহজবোধ্য: আপনি যদি যোগাযোগ করতে পারেন, এগিয়ে যান। যদি না হয়, তবে আপনি অনুরোধ করতে পারেন, তারপর আপনার ব্যবহারকারীর প্রম্পট/ব্যানার/টুলটিপ/ইত্যাদি দেখান। ব্যবহারকারী সেটিংসে যেতে রাজি হলে, অনুরোধের উদ্দেশ্য তৈরি করুন এবং ব্যবহারকারীকে সেখানে পাঠাতে Context#startActivity
ব্যবহার করুন। এই ক্ষমতা কখন পরিবর্তিত হয় তা সনাক্ত করতে আপনি হয় সম্প্রচার ব্যবহার করতে পারেন, অথবা ব্যবহারকারী ফিরে আসলে আবার পরীক্ষা করতে পারেন।
এটি পরীক্ষা করার জন্য, আপনাকে আপনার কাজের প্রোফাইলে TestDPC খুলতে হবে, একেবারে নীচে যান এবং সংযুক্ত অ্যাপের অনুমতি তালিকায় আপনার প্যাকেজের নাম যোগ করতে নির্বাচন করুন৷ এটি অ্যাডমিনকে আপনার অ্যাপের 'অনুমতি-তালিকা দেওয়ার' অনুকরণ করে।
শব্দকোষ
এই বিভাগটি ক্রস-প্রোফাইল বিকাশের সাথে সম্পর্কিত মূল পদগুলিকে সংজ্ঞায়িত করে।
ক্রস প্রোফাইল কনফিগারেশন
একটি ক্রস প্রোফাইল কনফিগারেশন গ্রুপগুলি একসাথে সম্পর্কিত ক্রস প্রোফাইল প্রদানকারী ক্লাস এবং ক্রস-প্রোফাইল বৈশিষ্ট্যগুলির জন্য সাধারণ কনফিগারেশন প্রদান করে। সাধারণত কোডবেস প্রতি একটি @CrossProfileConfiguration
টীকা থাকবে, কিন্তু কিছু জটিল অ্যাপ্লিকেশনে একাধিক হতে পারে।
প্রোফাইল সংযোগকারী
একটি সংযোগকারী প্রোফাইলের মধ্যে সংযোগ পরিচালনা করে। সাধারণত প্রতিটি ক্রস প্রোফাইল টাইপ একটি নির্দিষ্ট সংযোগকারীকে নির্দেশ করবে। একটি একক কনফিগারেশনের প্রতিটি ক্রস প্রোফাইল টাইপ একই সংযোগকারী ব্যবহার করতে হবে।
ক্রস প্রোফাইল প্রদানকারী ক্লাস
একটি ক্রস প্রোফাইল প্রোভাইডার ক্লাস গ্রুপগুলি একসাথে সম্পর্কিত ক্রস প্রোফাইল প্রকারগুলি।
মধ্যস্থতাকারী
একজন মধ্যস্থতাকারী উচ্চ-স্তরের এবং নিম্ন-স্তরের কোডের মধ্যে বসে, সঠিক প্রোফাইলে কল বিতরণ করে এবং ফলাফল একত্রিত করে। এটি একমাত্র কোড যা প্রোফাইল-সচেতন হওয়া দরকার। এটি SDK-তে নির্মিত কিছুর পরিবর্তে একটি স্থাপত্য ধারণা।
ক্রস প্রোফাইল টাইপ
একটি ক্রস প্রোফাইল টাইপ হল একটি ক্লাস বা ইন্টারফেস যেখানে @CrossProfile
টীকা করা পদ্ধতি রয়েছে। এই ধরনের কোড প্রোফাইল-সচেতন হতে হবে না এবং আদর্শভাবে শুধুমাত্র তার স্থানীয় ডেটাতে কাজ করা উচিত।
প্রোফাইলের ধরন
প্রোফাইলের ধরন | |
---|---|
কারেন্ট | সক্রিয় প্রোফাইল যা আমরা সম্পাদন করছি। |
অন্যান্য | (যদি এটি বিদ্যমান থাকে) আমরা যে প্রোফাইলটি চালাচ্ছি না। |
ব্যক্তিগত | ব্যবহারকারী 0, ডিভাইসে প্রোফাইল যা বন্ধ করা যাবে না। |
কাজ | সাধারণত ব্যবহারকারী 10 কিন্তু বেশি হতে পারে, টগল চালু এবং বন্ধ করা যেতে পারে, কাজের অ্যাপ এবং ডেটা ধারণ করতে ব্যবহৃত হয়। |
প্রাথমিক | ঐচ্ছিকভাবে অ্যাপ্লিকেশন দ্বারা সংজ্ঞায়িত. প্রোফাইল যা উভয় প্রোফাইলের একটি মার্জড ভিউ দেখায়। |
মাধ্যমিক | যদি প্রাথমিক সংজ্ঞায়িত করা হয়, সেকেন্ডারি হল প্রোফাইল যা প্রাথমিক নয়। |
সরবরাহকারী | প্রাথমিক প্রোফাইলের সরবরাহকারী উভয়ই প্রোফাইল, সেকেন্ডারি প্রোফাইলের সরবরাহকারীরা শুধুমাত্র সেকেন্ডারি প্রোফাইল নিজেই। |
প্রোফাইল শনাক্তকারী
একটি ক্লাস যা এক ধরনের প্রোফাইল (ব্যক্তিগত বা কাজ) প্রতিনিধিত্ব করে। এগুলি এমন পদ্ধতি দ্বারা ফেরত দেওয়া হবে যা একাধিক প্রোফাইলে চলে এবং সেই প্রোফাইলগুলিতে আরও কোড চালানোর জন্য ব্যবহার করা যেতে পারে। এই সুবিধাজনক স্টোরেজ জন্য একটি int
ক্রমিক করা যেতে পারে.
স্থাপত্য প্রস্তাবিত সমাধান
এই নির্দেশিকাটি আপনার Android অ্যাপের মধ্যে দক্ষ এবং রক্ষণাবেক্ষণযোগ্য ক্রস-প্রোফাইল কার্যকারিতা তৈরি করার জন্য প্রস্তাবিত কাঠামোর রূপরেখা দেয়।
আপনার CrossProfileConnector
একটি সিঙ্গলটনে রূপান্তর করুন
আপনার অ্যাপ্লিকেশনের জীবনচক্র জুড়ে শুধুমাত্র একটি একক উদাহরণ ব্যবহার করা উচিত, অন্যথায় আপনি সমান্তরাল সংযোগ তৈরি করবেন। এটি একটি নির্ভরতা ইনজেকশন ফ্রেমওয়ার্ক যেমন ড্যাগার ব্যবহার করে করা যেতে পারে, অথবা একটি ক্লাসিক সিঙ্গেলটন প্যাটার্ন ব্যবহার করে, হয় একটি নতুন ক্লাসে বা বিদ্যমান একটিতে।
আপনি যখন কল করবেন তখন পদ্ধতিতে তৈরি না করে আপনার ক্লাসে জেনারেট করা প্রোফাইল ইন্সট্যান্স ইনজেক্ট করুন বা পাস করুন
এটি আপনাকে পরে আপনার ইউনিট পরীক্ষায় স্বয়ংক্রিয়ভাবে তৈরি FakeProfile
উদাহরণে পাস করতে দেয়।
মধ্যস্থতাকারী প্যাটার্ন বিবেচনা করুন
এই সাধারণ প্যাটার্নটি হল আপনার বিদ্যমান APIগুলির মধ্যে একটি (যেমন getEvents()
) এর সমস্ত কলারদের জন্য প্রোফাইল-সচেতন করা। এই ক্ষেত্রে, আপনার বিদ্যমান API শুধুমাত্র একটি 'মধ্যস্থতাকারী' পদ্ধতি বা শ্রেণীতে পরিণত হতে পারে যাতে জেনারেট করা ক্রস-প্রোফাইল কোডে নতুন কল থাকে।
এইভাবে, আপনি প্রতিটি কলারকে ক্রস-প্রোফাইল কল করতে জানতে বাধ্য করবেন না এটি কেবল আপনার API এর অংশ হয়ে যায়।
একটি প্রদানকারীর মধ্যে আপনার বাস্তবায়নের ক্লাসগুলিকে প্রকাশ করা এড়াতে পরিবর্তে @CrossProfile
হিসাবে একটি ইন্টারফেস পদ্ধতি টীকা করা যায় কিনা তা বিবেচনা করুন
এটি নির্ভরতা ইনজেকশন ফ্রেমওয়ার্কের সাথে সুন্দরভাবে কাজ করে।
আপনি যদি একটি ক্রস-প্রোফাইল কল থেকে কোনো ডেটা গ্রহণ করেন, তাহলে এটি কোন প্রোফাইল থেকে এসেছে তা উল্লেখ করে একটি ক্ষেত্র যোগ করতে হবে কিনা তা বিবেচনা করুন
এটি ভাল অনুশীলন হতে পারে কারণ আপনি এটি UI স্তরে জানতে চাইতে পারেন (যেমন কাজের জিনিসগুলিতে একটি ব্যাজ আইকন যুক্ত করা)। কোনো ডেটা শনাক্তকারী যদি এটি ছাড়া আর অনন্য না হয়, যেমন প্যাকেজ নাম।
ক্রস প্রোফাইল
এই বিভাগটি কীভাবে আপনার নিজের ক্রস প্রোফাইল ইন্টারঅ্যাকশন তৈরি করতে হয় তার রূপরেখা দেয়।
প্রাথমিক প্রোফাইল
এই ডকুমেন্টের উদাহরণের বেশিরভাগ কলে কাজের, ব্যক্তিগত এবং উভয়ই সহ কোন প্রোফাইলগুলি চালানো হবে সে সম্পর্কে স্পষ্ট নির্দেশাবলী রয়েছে৷
অনুশীলনে, কেবলমাত্র একটি প্রোফাইলে মার্জড অভিজ্ঞতার সাথে অ্যাপ্লিকেশনগুলির জন্য, আপনি সম্ভবত এই সিদ্ধান্তটি আপনি যে প্রোফাইলটি চালিয়ে যাচ্ছেন তার উপর নির্ভর করতে চান, সুতরাং আপনার কোডবেস দ্বারা আবদ্ধ হওয়া এড়াতে এটি একই রকম সুবিধাজনক পদ্ধতিগুলিও বিবেচনা করে যদি-ইলেস প্রোফাইল শর্তাদি।
আপনার সংযোগকারী উদাহরণ তৈরি করার সময়, আপনি কোন প্রোফাইল টাইপটি আপনার 'প্রাথমিক' (যেমন 'কাজ') নির্দিষ্ট করতে পারেন। এটি নিম্নলিখিতগুলির মতো অতিরিক্ত বিকল্পগুলি সক্ষম করে:
profileCalendarDatabase.primary().getEvents();
profileCalendarDatabase.secondary().getEvents();
// Runs on all profiles if running on the primary, or just
// on the current profile if running on the secondary.
profileCalendarDatabase.suppliers().getEvents();
ক্রস প্রোফাইল প্রকার
ক্লাস এবং ইন্টারফেসগুলি যা একটি পদ্ধতি এনোটেটেড @CrossProfile
ধারণ করে ক্রস প্রোফাইল প্রকার হিসাবে উল্লেখ করা হয়।
ক্রস প্রোফাইল প্রকারের বাস্তবায়ন প্রোফাইল-স্বতন্ত্র হওয়া উচিত, তারা যে প্রোফাইলটি চলছে। তাদের অন্যান্য পদ্ধতিতে কল করার অনুমতি দেওয়া হয় এবং সাধারণভাবে তারা যেমন একক প্রোফাইলে চলছে তেমন কাজ করা উচিত। তাদের কেবল তাদের নিজস্ব প্রোফাইলে রাজ্যে অ্যাক্সেস থাকবে।
একটি উদাহরণ ক্রস প্রোফাইল প্রকার:
public class Calculator {
@CrossProfile
public int add(int a, int b) {
return a + b;
}
}
শ্রেণি টীকা
সবচেয়ে শক্তিশালী এপিআই সরবরাহ করতে, আপনার প্রতিটি ক্রস প্রোফাইল প্রকারের জন্য সংযোগকারীটি নির্দিষ্ট করা উচিত:
@CrossProfile(connector=MyProfileConnector.class)
public class Calculator {
@CrossProfile
public int add(int a, int b) {
return a + b;
}
}
এটি al চ্ছিক তবে এর অর্থ হ'ল উত্পন্ন এপিআই প্রকারগুলিতে আরও নির্দিষ্ট হবে এবং সংকলন-সময় চেকিংয়ের ক্ষেত্রে আরও কঠোর হবে।
ইন্টারফেস
@CrossProfile
হিসাবে ইন্টারফেসে পদ্ধতিগুলি টীকা দিয়ে আপনি উল্লেখ করছেন যে এই পদ্ধতির কিছু বাস্তবায়ন হতে পারে যা প্রোফাইলগুলিতে অ্যাক্সেসযোগ্য হওয়া উচিত।
আপনি ক্রস প্রোফাইল সরবরাহকারীর মধ্যে ক্রস প্রোফাইল ইন্টারফেসের যে কোনও বাস্তবায়ন ফিরিয়ে দিতে পারেন এবং এটি করার মাধ্যমে আপনি বলছেন যে এই বাস্তবায়নটি অ্যাক্সেসযোগ্য ক্রস-প্রোফাইল হওয়া উচিত। আপনার বাস্তবায়ন ক্লাসগুলি টীকা দেওয়ার দরকার নেই।
ক্রস প্রোফাইল সরবরাহকারী
প্রতিটি ক্রস প্রোফাইল টাইপ অবশ্যই একটি পদ্ধতি দ্বারা এনোটেটেড @CrossProfileProvider
সরবরাহ করতে হবে। এই পদ্ধতিগুলিকে প্রতিবার ক্রস-প্রোফাইল কল করা হয় বলে বলা হবে, সুতরাং আপনি প্রতিটি ধরণের জন্য সিঙ্গলেটন বজায় রাখার পরামর্শ দেওয়া হয়।
কনস্ট্রাক্টর
একটি সরবরাহকারীর অবশ্যই একটি পাবলিক কনস্ট্রাক্টর থাকতে হবে যা কোনও যুক্তি বা একক Context
যুক্তি নেয় না।
সরবরাহকারী পদ্ধতি
সরবরাহকারী পদ্ধতিগুলি অবশ্যই কোনও যুক্তি বা একক Context
যুক্তি গ্রহণ করতে হবে না।
নির্ভরতা ইনজেকশন
যদি আপনি নির্ভরতাগুলি পরিচালনা করতে ড্যাজারের মতো নির্ভরতা ইনজেকশন ফ্রেমওয়ার্ক ব্যবহার করেন তবে আমরা আপনাকে পরামর্শ দিচ্ছি যে আপনার সেই কাঠামোটি আপনার ক্রস প্রোফাইল প্রকারগুলি সাধারণত যেমন তৈরি করবে তেমন তৈরি করুন এবং তারপরে এই ধরণের প্রকারগুলি আপনার সরবরাহকারী শ্রেণিতে ইনজেকশন করুন। @CrossProfileProvider
পদ্ধতিগুলি তারপরে সেই ইনজেকশনযুক্ত উদাহরণগুলি ফিরিয়ে দিতে পারে।
প্রোফাইল সংযোগকারী
প্রতিটি ক্রস প্রোফাইল কনফিগারেশনের অবশ্যই একটি একক প্রোফাইল সংযোগকারী থাকতে হবে, যা অন্য প্রোফাইলের সাথে সংযোগ পরিচালনার জন্য দায়ী।
ডিফল্ট প্রোফাইল সংযোগকারী
যদি কোনও কোডবেসে কেবলমাত্র একটি ক্রস প্রোফাইল কনফিগারেশন থাকে তবে আপনি নিজের প্রোফাইল সংযোগকারী তৈরি করতে এড়াতে পারেন এবং com.google.android.enterprise.connectedapps.CrossProfileConnector
ব্যবহার করতে পারেন। এটি যদি কোনও নির্দিষ্ট না করা হয় তবে এটি ব্যবহৃত ডিফল্ট।
ক্রস প্রোফাইল সংযোজকটি তৈরি করার সময়, আপনি বিল্ডারটিতে কিছু বিকল্প নির্দিষ্ট করতে পারেন:
নির্ধারিত নির্বাহক পরিষেবা
আপনি যদি এসডিকে দ্বারা তৈরি থ্রেডগুলির উপর নিয়ন্ত্রণ রাখতে চান তবে
#setScheduledExecutorService()
, ব্যবহার করুনবাইন্ডার
প্রোফাইল বাইন্ডিং সম্পর্কিত আপনার যদি নির্দিষ্ট প্রয়োজন থাকে তবে
#setBinder
ব্যবহার করুন। এটি সম্ভবত কেবল ডিভাইস পলিসি কন্ট্রোলারদের দ্বারা ব্যবহৃত হয়।
কাস্টম প্রোফাইল সংযোগকারী
কিছু কনফিগারেশন সেট করতে সক্ষম হতে আপনার একটি কাস্টম প্রোফাইল সংযোজকের প্রয়োজন হবে ( CustomProfileConnector
ব্যবহার করে) এবং যদি আপনার একক কোডবেসে একাধিক সংযোগকারী প্রয়োজন হয় (উদাহরণস্বরূপ আপনার যদি একাধিক প্রক্রিয়া থাকে তবে আমরা প্রতি প্রক্রিয়া প্রতি একটি সংযোগকারীকে সুপারিশ করি)।
ProfileConnector
তৈরি করার সময় এটির মতো দেখতে হওয়া উচিত:
@GeneratedProfileConnector
public interface MyProfileConnector extends ProfileConnector {
public static MyProfileConnector create(Context context) {
// Configuration can be specified on the builder
return GeneratedMyProfileConnector.builder(context).build();
}
}
serviceClassName
উত্পন্ন পরিষেবার নাম পরিবর্তন করতে (যা আপনার
AndroidManifest.xml
উল্লেখ করা উচিত),serviceClassName=
ব্যবহার করুন।primaryProfile
প্রাথমিক প্রোফাইল নির্দিষ্ট করতে,
primaryProfile
ব্যবহার করুন।availabilityRestrictions
সংযোগ এবং প্রোফাইলের প্রাপ্যতার উপর এসডিকে স্থানগুলি বিধিনিষেধ পরিবর্তন করতে,
availabilityRestrictions
ব্যবহার করুন।
ডিভাইস নীতি নিয়ন্ত্রণকারী
যদি আপনার অ্যাপ্লিকেশনটি কোনও ডিভাইস পলিসি নিয়ামক হয় তবে আপনাকে অবশ্যই আপনার DeviceAdminReceiver
উল্লেখ করে DpcProfileBinder
একটি উদাহরণ নির্দিষ্ট করতে হবে।
আপনি যদি নিজের প্রোফাইল সংযোগকারীটি বাস্তবায়ন করছেন:
@GeneratedProfileConnector
public interface DpcProfileConnector extends ProfileConnector {
public static DpcProfileConnector get(Context context) {
return GeneratedDpcProfileConnector.builder(context).setBinder(new
DpcProfileBinder(new ComponentName("com.google.testdpc",
"AdminReceiver"))).build();
}
}
বা ডিফল্ট CrossProfileConnector
ব্যবহার করে:
CrossProfileConnector connector =
CrossProfileConnector.builder(context).setBinder(new DpcProfileBinder(new
ComponentName("com.google.testdpc", "AdminReceiver"))).build();
ক্রস প্রোফাইল কনফিগারেশন
পদ্ধতি কলগুলি সঠিকভাবে প্রেরণ করার জন্য @CrossProfileConfiguration
টীকাটি একটি সংযোগকারী ব্যবহার করে সমস্ত ক্রস প্রোফাইল প্রকারের একসাথে লিঙ্ক করতে ব্যবহৃত হয়। এটি করার জন্য, আমরা @CrossProfileConfiguration
সহ একটি শ্রেণি টিকা দিয়েছি যা প্রতিটি সরবরাহকারীর দিকে নির্দেশ করে, যেমন:
@CrossProfileConfiguration(providers = {TestProvider.class})
public abstract class TestApplication {
}
এটি যাচাই করবে যে সমস্ত ক্রস প্রোফাইল প্রকারের জন্য তাদের কাছে একই প্রোফাইল সংযোগকারী বা কোনও সংযোগকারী নির্দিষ্ট করা আছে।
serviceSuperclass
ডিফল্টরূপে, উত্পন্ন পরিষেবাটি সুপারক্লাস হিসাবে
android.app.Service
ব্যবহার করবে। সুপারক্লাস হওয়ার জন্য যদি আপনার কোনও আলাদা শ্রেণির (যা নিজেই অবশ্যইandroid.app.Service
সার্ভিসের একটি সাবক্লাস হতে হবে) প্রয়োজন হয়, তবেserviceSuperclass=
নির্দিষ্ট করুন।serviceClass
যদি নির্দিষ্ট করা হয় তবে কোনও পরিষেবা উত্পন্ন হবে না। আপনি যে প্রোফাইল সংযোগকারীটি ব্যবহার করছেন তাতে এটি অবশ্যই
serviceClassName
সাথে মেলে। আপনার কাস্টম পরিষেবাটি উত্পন্ন_Dispatcher
ক্লাস ব্যবহার করে কলগুলি প্রেরণ করা উচিত:
public final class TestProfileConnector_Service extends Service {
private Stub binder = new Stub() {
private final TestProfileConnector_Service_Dispatcher dispatcher = new
TestProfileConnector_Service_Dispatcher();
@Override
public void prepareCall(long callId, int blockId, int numBytes, byte[] params)
{
dispatcher.prepareCall(callId, blockId, numBytes, params);
}
@Override
public byte[] call(long callId, int blockId, long crossProfileTypeIdentifier,
int methodIdentifier, byte[] params,
ICrossProfileCallback callback) {
return dispatcher.call(callId, blockId, crossProfileTypeIdentifier,
methodIdentifier, params, callback);
}
@Override
public byte[] fetchResponse(long callId, int blockId) {
return dispatcher.fetchResponse(callId, blockId);
};
@Override
public Binder onBind(Intent intent) {
return binder;
}
}
আপনার ক্রস-প্রোফাইল কলের আগে বা পরে অতিরিক্ত ক্রিয়া সম্পাদন করতে হলে এটি ব্যবহার করা যেতে পারে।
সংযোগকারী
আপনি যদি ডিফল্ট
CrossProfileConnector
ব্যতীত অন্য কোনও সংযোগকারী ব্যবহার করছেন, তবে আপনাকে অবশ্যই এটিconnector=
ব্যবহার করে নির্দিষ্ট করতে হবে।
দৃশ্যমানতা
আপনার অ্যাপ্লিকেশনটির প্রতিটি অংশ যা ক্রস-প্রোফাইলকে ইন্টারঅ্যাক্ট করে তা অবশ্যই আপনার প্রোফাইল সংযোগকারীটি দেখতে সক্ষম হতে হবে।
আপনার @CrossProfileConfiguration
টীকাযুক্ত শ্রেণি অবশ্যই আপনার অ্যাপ্লিকেশনটিতে ব্যবহৃত প্রতিটি সরবরাহকারীকে দেখতে সক্ষম হতে হবে।
সিঙ্ক্রোনাস কল
সংযুক্ত অ্যাপস এসডিকে সিঙ্ক্রোনাস (ব্লকিং) সমর্থন করে যেখানে তারা অনিবার্য নয় এমন ক্ষেত্রে কল করে। যাইহোক, এই কলগুলি ব্যবহার করার জন্য বেশ কয়েকটি অসুবিধা রয়েছে (যেমন কলগুলি দীর্ঘ সময়ের জন্য ব্লক করার সম্ভাবনা) সুতরাং এটি প্রস্তাবিত হয় যে আপনি যখন সম্ভব হয় তখন সিঙ্ক্রোনাস কলগুলি এড়াতে পারেন । অ্যাসিঙ্ক্রোনাস কলগুলি ব্যবহারের জন্য অ্যাসিঙ্ক্রোনাস কলগুলি দেখুন।
সংযোগ ধারক
আপনি যদি সিঙ্ক্রোনাস কলগুলি ব্যবহার করছেন, তবে আপনাকে অবশ্যই নিশ্চিত করতে হবে যে ক্রস প্রোফাইল কল করার আগে কোনও সংযোগ ধারক নিবন্ধিত রয়েছে, অন্যথায় একটি ব্যতিক্রম নিক্ষেপ করা হবে। আরও তথ্যের জন্য সংযোগধারীরা দেখুন।
একটি সংযোগ ধারক যুক্ত করতে, কোনও অবজেক্টের সাথে ProfileConnector#addConnectionHolder(Object)
কল করুন (সম্ভাব্যভাবে, অবজেক্ট উদাহরণ যা ক্রস-প্রোফাইল কল করছে)। এটি রেকর্ড করবে যে এই অবজেক্টটি সংযোগটি ব্যবহার করছে এবং একটি সংযোগ করার চেষ্টা করবে। কোনও সিঙ্ক্রোনাস কল করার আগে এটি অবশ্যই কল করা উচিত। এটি একটি নন-ব্লকিং কল তাই এটি সম্ভব যে আপনি আপনার কল করার সময় পর্যন্ত সংযোগটি প্রস্তুত হবে না (বা সম্ভব নাও হতে পারে), সেক্ষেত্রে সাধারণ ত্রুটি পরিচালনার আচরণটি প্রযোজ্য।
আপনি যখন ProfileConnector#addConnectionHolder(Object)
বা সংযোগের জন্য কোনও প্রোফাইল পাওয়া যায় না তখন আপনার যদি উপযুক্ত ক্রস-প্রোফাইল অনুমতিগুলির অভাব থাকে তবে কোনও ত্রুটি নিক্ষেপ করা হবে না তবে সংযুক্ত কলব্যাকটি কখনই বলা হবে না। যদি পরে অনুমতি দেওয়া হয় বা অন্য প্রোফাইল উপলব্ধ হয় তবে সংযোগটি তখন করা হবে এবং কলব্যাকটি কল করা হবে।
বিকল্পভাবে, ProfileConnector#connect(Object)
একটি ব্লকিং পদ্ধতি যা সংযোগ ধারক হিসাবে অবজেক্টটিকে যুক্ত করবে এবং হয় একটি সংযোগ স্থাপন করবে বা একটি UnavailableProfileException
নিক্ষেপ করবে। এই পদ্ধতিটি ইউআই থ্রেড থেকে কল করা যায় না ।
ProfileConnector#connect(Object)
এবং অনুরূপ ProfileConnector#connect
রিটার্ন অটো-ক্লোসিং অবজেক্টগুলিকে কল করে যা স্বয়ংক্রিয়ভাবে সংযোগ ধারককে বন্ধ করে দেয় এমনটি স্বয়ংক্রিয়ভাবে সরিয়ে ফেলবে। এটি যেমন ব্যবহারের জন্য অনুমতি দেয়:
try (ProfileConnectionHolder p = connector.connect()) {
// Use the connection
}
একবার আপনি সিঙ্ক্রোনাস কল করা শেষ হয়ে গেলে, আপনার ProfileConnector#removeConnectionHolder(Object)
কল করা উচিত। সমস্ত সংযোগ ধারক সরানো হয়ে গেলে, সংযোগটি বন্ধ হয়ে যাবে।
সংযোগ
সংযোগের অবস্থা পরিবর্তিত হলে একটি সংযোগ শ্রোতাকে অবহিত করার জন্য ব্যবহার করা যেতে পারে, এবং connector.utils().isConnected
কোনও সংযোগ উপস্থিত রয়েছে কিনা তা নির্ধারণের জন্য ব্যবহার করা যেতে পারে। যেমন:
// Only use this if using synchronous calls instead of Futures.
crossProfileConnector.connect(this);
crossProfileConnector.registerConnectionListener(() -> {
if (crossProfileConnector.utils().isConnected()) {
// Make cross-profile calls.
}
});
অ্যাসিঙ্ক্রোনাস কল
প্রোফাইল বিভাজন জুড়ে উন্মুক্ত প্রতিটি পদ্ধতি অবশ্যই ব্লকিং (সিঙ্ক্রোনাস) বা নন-ব্লকিং (অ্যাসিঙ্ক্রোনাস) হিসাবে মনোনীত করা উচিত। যে কোনও পদ্ধতি যা একটি অ্যাসিঙ্ক্রোনাস ডেটা টাইপ দেয় (যেমন একটি ListenableFuture
) বা কলব্যাক প্যারামিটার গ্রহণ করে তা নন-ব্লকিং হিসাবে চিহ্নিত করা হয়। অন্যান্য সমস্ত পদ্ধতি অবরুদ্ধ হিসাবে চিহ্নিত করা হয়।
অ্যাসিঙ্ক্রোনাস কলগুলির প্রস্তাব দেওয়া হয়। আপনার যদি অবশ্যই সিঙ্ক্রোনাস কলগুলি ব্যবহার করা হয় তবে সিঙ্ক্রোনাস কলগুলি দেখুন।
কলব্যাক
অ-ব্লকিং কলের সর্বাধিক প্রাথমিক ধরণের একটি শূন্য পদ্ধতি যা এর একটি প্যারামিটার হিসাবে একটি ইন্টারফেস হিসাবে গ্রহণ করে যা ফলাফলের সাথে কল করার জন্য একটি পদ্ধতি রয়েছে। এই ইন্টারফেসগুলি এসডিকে দিয়ে কাজ করতে, ইন্টারফেসটি অবশ্যই টীকাযুক্ত @CrossProfileCallback
করতে হবে। যেমন:
@CrossProfileCallback
public interface InstallationCompleteListener {
void installationComplete(int state);
}
এই ইন্টারফেসটি তখন @CrossProfile
টীকাযুক্ত পদ্ধতিতে প্যারামিটার হিসাবে ব্যবহার করা যেতে পারে এবং যথারীতি কল করা যেতে পারে। যেমন:
@CrossProfile
public void install(String filename, InstallationCompleteListener callback) {
// Do something on a separate thread and then:
callback.installationComplete(1);
}
// In the mediator
profileInstaller.work().install(filename, (status) -> {
// Deal with callback
}, (exception) -> {
// Deal with possibility of profile unavailability
});
যদি এই ইন্টারফেসে একটি একক পদ্ধতি থাকে যা শূন্য বা একটি পরামিতি নেয়, তবে এটি একবারে একাধিক প্রোফাইলগুলিতে কলগুলিতেও ব্যবহার করা যেতে পারে।
কলব্যাক ব্যবহার করে যে কোনও সংখ্যক মান পাস করা যেতে পারে তবে সংযোগটি কেবল প্রথম মানের জন্য খোলা থাকবে। আরও মান পাওয়ার জন্য সংযোগটি খোলা রাখার তথ্যের জন্য সংযোগধারীরা দেখুন।
কলব্যাক সহ সিঙ্ক্রোনাস পদ্ধতি
এসডিকে সহ কলব্যাকগুলি ব্যবহারের একটি অস্বাভাবিক বৈশিষ্ট্য হ'ল আপনি প্রযুক্তিগতভাবে একটি সিঙ্ক্রোনাস পদ্ধতি লিখতে পারেন যা কলব্যাক ব্যবহার করে:
public void install(InstallationCompleteListener callback) {
callback.installationComplete(1);
}
এই ক্ষেত্রে, পদ্ধতিটি কলব্যাক সত্ত্বেও আসলে সিঙ্ক্রোনাস। এই কোডটি সঠিকভাবে কার্যকর করবে:
System.out.println("This prints first");
installer.install(() -> {
System.out.println("This prints second");
});
System.out.println("This prints third");
যাইহোক, যখন এসডিকে ব্যবহার করে ডাকা হয়, এটি একইভাবে আচরণ করবে না। "এই প্রিন্ট তৃতীয়" মুদ্রিত হওয়ার আগে ইনস্টল পদ্ধতিটি কল করা হবে এমন কোনও গ্যারান্টি নেই। এসডিকে দ্বারা অ্যাসিঙ্ক্রোনাস হিসাবে চিহ্নিত কোনও পদ্ধতির যে কোনও ব্যবহার অবশ্যই পদ্ধতিটি কখন বলা হবে সে সম্পর্কে কোনও অনুমান করতে হবে না।
সাধারণ কলব্যাকস
"সিম্পল কলব্যাকস" কলব্যাকের আরও সীমাবদ্ধ ফর্ম যা ক্রস-প্রোফাইল কলগুলি করার সময় অতিরিক্ত বৈশিষ্ট্যগুলির জন্য অনুমতি দেয়। সাধারণ ইন্টারফেসগুলিতে অবশ্যই একটি একক পদ্ধতি থাকতে হবে, যা শূন্য বা একটি পরামিতি নিতে পারে।
আপনি প্রয়োগ করতে পারেন যে একটি কলব্যাক ইন্টারফেস অবশ্যই @CrossProfileCallback
টীকাটিতে simple=true
নির্দিষ্ট করে থাকতে হবে।
সাধারণ কলব্যাকগুলি বিভিন্ন পদ্ধতির সাথে ব্যবহারযোগ্য যেমন। .both()
, .suppliers()
এবং অন্যান্য।
সংযোগ ধারক
একটি অ্যাসিঙ্ক্রোনাস কল করার সময় (কলব্যাকস বা ফিউচার ব্যবহার করে) কল করার সময় একটি সংযোগ ধারক যুক্ত করা হবে এবং কোনও ব্যতিক্রম বা কোনও মান পাস হয়ে গেলে সরানো হবে।
আপনি যদি কলব্যাক ব্যবহার করে একাধিক ফলাফল পাস হওয়ার প্রত্যাশা করেন তবে আপনার সংযোগ ধারক হিসাবে ম্যানুয়ালি কলব্যাকটি যুক্ত করা উচিত:
MyCallback b = //...
connector.addConnectionHolder(b);
profileMyClass.other().registerListener(b);
// Now the connection will be held open indefinitely, once finished:
connector.removeConnectionHolder(b);
এটি ট্রাই-রিসোর্সগুলি ব্লকের সাথেও ব্যবহার করা যেতে পারে:
MyCallback b = //...
try (ProfileConnectionHolder p = connector.addConnectionHolder(b)) {
profileMyClass.other().registerListener(b);
// Other things running while we expect results
}
আমরা যদি কলব্যাক বা ভবিষ্যতের সাথে কল করি তবে ফলাফলটি পাস না হওয়া পর্যন্ত সংযোগটি খোলা থাকবে। যদি আমরা নির্ধারণ করি যে কোনও ফলাফল পাস হবে না, তবে আমাদের সংযোগ ধারক হিসাবে কলব্যাক বা ভবিষ্যতটি সরিয়ে ফেলা উচিত:
connector.removeConnectionHolder(myCallback);
connector.removeConnectionHolder(future);
আরও তথ্যের জন্য, সংযোগধারীরা দেখুন।
ফিউচার
ফিউচারগুলি এসডিকে দ্বারা স্থানীয়ভাবে সমর্থন করা হয়। একমাত্র স্থানীয়ভাবে সমর্থিত ভবিষ্যতের ধরণটি ListenableFuture
, যদিও কাস্টম ভবিষ্যতের প্রকারগুলি ব্যবহার করা যেতে পারে। ফিউচার ব্যবহার করতে আপনি কেবল সমর্থিত ভবিষ্যতের প্রকারকে ক্রস প্রোফাইল পদ্ধতির রিটার্ন প্রকার হিসাবে ঘোষণা করেন এবং তারপরে এটি স্বাভাবিক হিসাবে ব্যবহার করেন।
এটি কলব্যাকসের মতো একই "অস্বাভাবিক বৈশিষ্ট্য" রয়েছে, যেখানে একটি সিঙ্ক্রোনাস পদ্ধতি যা ভবিষ্যতকে ফিরিয়ে দেয় (যেমন immediateFuture
ব্যবহার করে) বর্তমান প্রোফাইলের উপর রান বনাম অন্য প্রোফাইলে রান করার সময় আলাদা আচরণ করবে। এসডিকে দ্বারা অ্যাসিঙ্ক্রোনাস হিসাবে চিহ্নিত কোনও পদ্ধতির যে কোনও ব্যবহার অবশ্যই পদ্ধতিটি কখন বলা হবে সে সম্পর্কে কোনও অনুমান করতে হবে না।
থ্রেড
মূল থ্রেডে ক্রস-প্রোফাইল ভবিষ্যতের ফলাফল বা কলব্যাকের ফলাফলটি অবরুদ্ধ করবেন না। আপনি যদি এটি করেন তবে কিছু পরিস্থিতিতে আপনার কোড অনির্দিষ্টকালের জন্য ব্লক করবে। এটি কারণ অন্যান্য প্রোফাইলের সাথে সংযোগটি মূল থ্রেডেও প্রতিষ্ঠিত হয়, যা ক্রস-প্রোফাইলের ফলাফলের জন্য মুলতুবি থাকা অবরুদ্ধ থাকলে কখনই ঘটবে না।
প্রাপ্যতা
উপলভ্যতা শ্রোতাকে যখন প্রাপ্যতা রাষ্ট্র পরিবর্তিত হয় এবং connector.utils().isAvailable
ব্যবহারের জন্য উপলব্ধ কিনা তা নির্ধারণ করতে ব্যবহার করা যেতে পারে। যেমন:
crossProfileConnector.registerAvailabilityListener(() -> {
if (crossProfileConnector.utils().isAvailable()) {
// Show cross-profile content
} else {
// Hide cross-profile content
}
});
সংযোগ ধারক
সংযোগধারীরা স্বেচ্ছাসেবী বস্তু যা ক্রস-প্রোফাইল সংযোগ প্রতিষ্ঠিত এবং জীবিত রাখার প্রতি আগ্রহী হিসাবে রেকর্ড করা হয়।
ডিফল্টরূপে, অ্যাসিঙ্ক্রোনাস কলগুলি করার সময়, কলটি শুরু হওয়ার সাথে সাথে একটি সংযোগ ধারক যুক্ত করা হবে এবং যখন কোনও ফলাফল বা ত্রুটি ঘটে তখন সরানো হবে।
সংযোগধারীদের সংযোগের উপর আরও নিয়ন্ত্রণ প্রয়োগ করতে ম্যানুয়ালি যুক্ত এবং সরানো যেতে পারে। সংযোগধারীদের connector.addConnectionHolder
ব্যবহার করে যুক্ত করা যেতে পারে এবং connector.removeConnectionHolder
ব্যবহার করে সরানো যেতে পারে।
যখন কমপক্ষে একটি সংযোগ ধারক যুক্ত হয়, এসডিকে একটি সংযোগ বজায় রাখার চেষ্টা করবে। যখন শূন্য সংযোগ ধারক যুক্ত হয়, সংযোগটি বন্ধ করা যেতে পারে।
আপনি যে কোনও সংযোগ ধারককে যুক্ত করার জন্য আপনাকে অবশ্যই একটি রেফারেন্স বজায় রাখতে হবে - এবং এটি আর প্রাসঙ্গিক না হলে এটি সরান।
সিঙ্ক্রোনাস কল
সিঙ্ক্রোনাস কল করার আগে, একটি সংযোগ ধারক যুক্ত করা উচিত। এটি কোনও অবজেক্ট ব্যবহার করে করা যেতে পারে, যদিও আপনাকে অবশ্যই সেই বস্তুর ট্র্যাক রাখতে হবে যাতে আপনাকে আর সিঙ্ক্রোনাস কল করার প্রয়োজন না হলে এটি সরানো যেতে পারে।
অ্যাসিঙ্ক্রোনাস কল
অ্যাসিঙ্ক্রোনাস কল সংযোগধারীদের তৈরি করার সময় স্বয়ংক্রিয়ভাবে পরিচালনা করা হবে যাতে কল এবং প্রথম প্রতিক্রিয়া বা ত্রুটির মধ্যে সংযোগটি খোলা থাকে। এর বাইরে বেঁচে থাকার জন্য যদি আপনার সংযোগের প্রয়োজন হয় (যেমন একক কলব্যাক ব্যবহার করে একাধিক প্রতিক্রিয়া পেতে) আপনার কলব্যাকটি নিজেই একটি সংযোগ ধারক হিসাবে যুক্ত করা উচিত এবং একবার আপনাকে আরও ডেটা পাওয়ার দরকার না হলে এটি সরিয়ে ফেলতে হবে।
ত্রুটি হ্যান্ডলিং
ডিফল্টরূপে, অন্য প্রোফাইল যখন পাওয়া যায় না তখন অন্য প্রোফাইলে যে কোনও কল করা হয় তার ফলস্বরূপ একটি UnavailableProfileException
নিক্ষেপ করা হবে (বা ভবিষ্যতে পাস করা হয়েছে, বা একটি অ্যাসিঙ্ক কলের জন্য ত্রুটি কলব্যাক)।
এটি এড়ানোর জন্য, বিকাশকারীরা #both()
বা #suppliers()
ব্যবহার করতে পারেন এবং ফলাফলের তালিকায় যে কোনও সংখ্যক এন্ট্রি মোকাবেলা করতে তাদের কোড লিখতে পারেন (অন্য প্রোফাইলটি অনুপলব্ধ থাকলে এটি 1 হবে, বা এটি উপলব্ধ থাকলে 2) .
ব্যতিক্রম
বর্তমান প্রোফাইলে কল করার পরে ঘটে যাওয়া কোনও চেক না করা ব্যতিক্রম যথারীতি প্রচারিত হবে। এটি কলটি ( #current()
, #personal
, #both
ইত্যাদি) তৈরি করতে ব্যবহৃত পদ্ধতি নির্বিশেষে প্রযোজ্য।
অন্য প্রোফাইলে কল করার পরে ঘটে যাওয়া চেক না করা ব্যতিক্রমগুলির ফলে একটি ProfileRuntimeException
মূল ব্যতিক্রমকে কারণ হিসাবে নিক্ষেপ করা হবে। এটি কলটি ( #other()
, #personal
, #both
, ইত্যাদি) করার জন্য ব্যবহৃত পদ্ধতি নির্বিশেষে প্রযোজ্য।
ifavailable
UnavailableProfileException
দৃষ্টান্তগুলি ধরা এবং ডিল করার বিকল্প হিসাবে, আপনি একটি ডিফল্ট মান সরবরাহ করতে .ifAvailable()
পদ্ধতিটি ব্যবহার করতে পারেন যা একটি UnavailableProfileException
নিক্ষেপের পরিবর্তে ফিরে আসবে।
যেমন:
profileNotesDatabase.other().ifAvailable().getNumberOfNotes(/* defaultValue= */ 0);
টেস্টিং
আপনার কোডটি পরীক্ষাযোগ্য করতে, আপনার প্রোফাইল সংযোগকারীটির উদাহরণগুলি এটি ব্যবহার করে এমন কোনও কোডে ইনজেকশন করা উচিত (প্রোফাইলের প্রাপ্যতা যাচাই করার জন্য, ম্যানুয়ালি সংযোগ করতে ইত্যাদি)। আপনার প্রোফাইল সচেতন প্রকারের যেখানে সেগুলি ব্যবহার করা হয় তার উদাহরণগুলিও ইনজেকশন করা উচিত।
আমরা আপনার সংযোগকারী এবং প্রকারের নকল সরবরাহ করি যা পরীক্ষায় ব্যবহার করা যেতে পারে।
প্রথমে পরীক্ষার নির্ভরতা যুক্ত করুন:
testAnnotationProcessor
'com.google.android.enterprise.connectedapps:connectedapps-processor:1.1.2'
testCompileOnly
'com.google.android.enterprise.connectedapps:connectedapps-testing-annotations:1.1.2'
testImplementation
'com.google.android.enterprise.connectedapps:connectedapps-testing:1.1.2'
তারপরে, @CrossProfileTest
সাথে আপনার পরীক্ষার ক্লাসটি টিকা দিন, পরীক্ষা করার জন্য @CrossProfileConfiguration
টীকাযুক্ত শ্রেণি চিহ্নিত করে:
@CrossProfileTest(configuration = MyApplication.class)
@RunWith(RobolectricTestRunner.class)
public class NotesMediatorTest {
}
এটি কনফিগারেশনে ব্যবহৃত সমস্ত প্রকার এবং সংযোজকগুলির জন্য জাল প্রজন্মের কারণ ঘটায়।
আপনার পরীক্ষায় সেই নকলগুলির উদাহরণ তৈরি করুন:
private final FakeCrossProfileConnector connector = new
FakeCrossProfileConnector();
private final NotesManager personalNotesManager = new NotesManager(); //
real/mock/fake
private final NotesManager workNotesManager = new NotesManager(); // real/mock/fake
private final FakeProfileNotesManager profileNotesManager =
FakeProfileNotesManager.builder()
.personal(personalNotesManager)
.work(workNotesManager)
.connector(connector)
.build();
প্রোফাইল স্টেট সেট আপ করুন:
connector.setRunningOnProfile(PERSONAL);
connector.createWorkProfile();
connector.turnOffWorkProfile();
পরীক্ষার অধীনে আপনার কোডে জাল সংযোগকারী এবং ক্রস প্রোফাইল ক্লাসটি পাস করুন এবং তারপরে কল করুন।
কলগুলি সঠিক টার্গেটে নিয়ে যাওয়া হবে - এবং সংযোগ বিচ্ছিন্ন বা অনুপলব্ধ প্রোফাইলগুলিতে কল করার সময় ব্যতিক্রমগুলি নিক্ষেপ করা হবে।
সমর্থিত প্রকার
নিম্নলিখিত প্রকারগুলি আপনার পক্ষ থেকে কোনও অতিরিক্ত প্রচেষ্টা ছাড়াই সমর্থিত। এগুলি সমস্ত ক্রস-প্রোফাইল কলগুলির জন্য যুক্তি বা রিটার্ন প্রকার হিসাবে ব্যবহার করা যেতে পারে।
- আদিম (
byte
,short
,int
,long
,float
,double
,char
,boolean
), - বক্সযুক্ত
java.lang.Double
java.lang.Character
java.lang.Byte
,java.lang.Short
java.lang.Boolean
java.lang.Integer
,java.lang.Float
,java.lang.Long
,java.lang.Void
), -
java.lang.String
, - যে কোনও কিছু যা
android.os.Parcelable
প্রয়োগ করে, -
java.io.Serializable
প্রয়োগ করে এমন কিছু, - একক-মাত্রা অ-প্রাথমিক অ্যারে,
-
java.util.Optional
, -
java.util.Collection
, -
java.util.List
, -
java.util.Map
, -
java.util.Set
, -
android.util.Pair
, -
com.google.common.collect.ImmutableMap
।
যে কোনও সমর্থিত জেনেরিক প্রকার (উদাহরণস্বরূপ java.util.Collection
) তাদের টাইপ প্যারামিটার হিসাবে কোনও সমর্থিত প্রকার থাকতে পারে। যেমন:
java.util.Collection<java.util.Map<java.lang.String,MySerializableType[]>>
একটি বৈধ প্রকার।
ফিউচার
নিম্নলিখিত প্রকারগুলি কেবল রিটার্ন প্রকার হিসাবে সমর্থিত:
-
com.google.common.util.concurrent.ListenableFuture
কাস্টম পার্সেলেবল মোড়ক
যদি আপনার প্রকারটি পূর্ববর্তী তালিকায় না থাকে তবে প্রথমে বিবেচনা করুন যে এটি android.os.Parcelable
বা java.io.Serializable
সঠিকভাবে প্রয়োগ করার জন্য তৈরি করা যেতে পারে কিনা তা বিবেচনা করুন। যদি এটি আপনার ধরণের জন্য সমর্থন যুক্ত করতে পার্সেলেবল র্যাপারগুলি দেখতে না পারে।
কাস্টম ভবিষ্যতের মোড়ক
আপনি যদি ভবিষ্যতের ধরণের ব্যবহার করতে চান যা আগের তালিকায় নেই, তবে সমর্থন যুক্ত করতে ভবিষ্যতের মোড়কগুলি দেখুন।
পার্সেলেবল মোড়ক
পার্সেলেবল র্যাপারগুলি হ'ল এসডিকে অ -পার্সেলেবল প্রকারের জন্য সমর্থন যুক্ত করে যা সংশোধন করা যায় না। এসডিকে বিভিন্ন ধরণের জন্য মোড়ক অন্তর্ভুক্ত করে তবে আপনাকে যে ধরণের ব্যবহার করতে হবে তা যদি অন্তর্ভুক্ত না করা হয় তবে আপনাকে অবশ্যই নিজের লিখতে হবে।
একটি পার্সেলেবল র্যাপার হ'ল একটি শ্রেণি যা অন্য শ্রেণিকে মোড়ানোর জন্য এবং এটিকে পার্সেলেবল করার জন্য ডিজাইন করা হয়েছে। এটি একটি সংজ্ঞায়িত স্ট্যাটিক চুক্তি অনুসরণ করে এবং এসডিকে দিয়ে নিবন্ধিত হয় যাতে এটি প্রদত্ত প্রকারকে একটি পার্সেলেবল টাইপে রূপান্তর করতে ব্যবহার করা যেতে পারে এবং পার্সেলেবল টাইপ থেকে এই ধরণের বের করে।
টীকা
পার্সেলেবল র্যাপার ক্লাসটি অবশ্যই টীকাটি @CustomParcelableWrapper
অবশ্যই মোড়ানো শ্রেণিকে originalType
হিসাবে উল্লেখ করে। যেমন:
@CustomParcelableWrapper(originalType=ImmutableList.class)
বিন্যাস
পার্সেলেবল র্যাপারগুলি অবশ্যই Parcelable
সঠিকভাবে প্রয়োগ করতে হবে এবং অবশ্যই W of(Bundler, BundlerType, T)
থাকতে হবে যা মোড়ানো প্রকারটি মোড়ানো এবং একটি নন-স্ট্যাটিক T get()
পদ্ধতি যা মোড়ানো প্রকারটি ফেরত দেয়।
এসডিকে এই পদ্ধতিগুলি প্রকারের জন্য বিরামবিহীন সমর্থন সরবরাহ করতে ব্যবহার করবে।
বান্ডলার
জেনেরিক প্রকারগুলি (যেমন তালিকা এবং মানচিত্র) মোড়ানোর জন্য অনুমতি দেওয়ার জন্য, of
একটি Bundler
পাস করা হয় যা পড়তে সক্ষম ( #readFromParcel
ব্যবহার করে) এবং লেখার ( #writeToParcel
Parcel
করে) সমস্ত সমর্থিত প্রকারগুলি এবং একটি BundlerType
যা প্রতিনিধিত্ব করে ঘোষিত টাইপ লিখতে হবে।
Bundler
এবং BundlerType
উদাহরণগুলি নিজেরাই পার্সেলেবল, এবং পার্সেলেবল র্যাপারের পার্সেলিংয়ের অংশ হিসাবে লেখা উচিত, যাতে পার্সেলেবল র্যাপারটি পুনর্গঠন করার সময় এটি ব্যবহার করা যেতে পারে।
যদি BundlerType
কোনও জেনেরিক প্রকারের প্রতিনিধিত্ব করে তবে টাইপ ভেরিয়েবলগুলি কল করে .typeArguments()
প্রতিটি ধরণের আর্গুমেন্ট নিজেই একটি BundlerType
।
উদাহরণস্বরূপ, ParcelableCustomWrapper
দেখুন:
public class CustomWrapper<F> {
private final F value;
public CustomWrapper(F value) {
this.value = value;
}
public F value() {
return value;
}
}
@CustomParcelableWrapper(originalType = CustomWrapper.class)
public class ParcelableCustomWrapper<E> implements Parcelable {
private static final int NULL = -1;
private static final int NOT_NULL = 1;
private final Bundler bundler;
private final BundlerType type;
private final CustomWrapper<E> customWrapper;
/**
* Create a wrapper for a given {@link CustomWrapper}.
*
* <p>The passed in {@link Bundler} must be capable of bundling {@code F}.
*/
public static <F> ParcelableCustomWrapper<F> of(
Bundler bundler, BundlerType type, CustomWrapper<F> customWrapper) {
return new ParcelableCustomWrapper<>(bundler, type, customWrapper);
}
public CustomWrapper<E> get() {
return customWrapper;
}
private ParcelableCustomWrapper(
Bundler bundler, BundlerType type, CustomWrapper<E> customWrapper) {
if (bundler == null || type == null) {
throw new NullPointerException();
}
this.bundler = bundler;
this.type = type;
this.customWrapper = customWrapper;
}
private ParcelableCustomWrapper(Parcel in) {
bundler = in.readParcelable(Bundler.class.getClassLoader());
int presentValue = in.readInt();
if (presentValue == NULL) {
type = null;
customWrapper = null;
return;
}
type = (BundlerType) in.readParcelable(Bundler.class.getClassLoader());
BundlerType valueType = type.typeArguments().get(0);
@SuppressWarnings("unchecked")
E value = (E) bundler.readFromParcel(in, valueType);
customWrapper = new CustomWrapper<>(value);
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeParcelable(bundler, flags);
if (customWrapper == null) {
dest.writeInt(NULL);
return;
}
dest.writeInt(NOT_NULL);
dest.writeParcelable(type, flags);
BundlerType valueType = type.typeArguments().get(0);
bundler.writeToParcel(dest, customWrapper.value(), valueType, flags);
}
@Override
public int describeContents() {
return 0;
}
@SuppressWarnings("rawtypes")
public static final Creator<ParcelableCustomWrapper> CREATOR =
new Creator<ParcelableCustomWrapper>() {
@Override
public ParcelableCustomWrapper createFromParcel(Parcel in) {
return new ParcelableCustomWrapper(in);
}
@Override
public ParcelableCustomWrapper[] newArray(int size) {
return new ParcelableCustomWrapper[size];
}
};
}
এসডিকে নিয়ে নিবন্ধন করুন
একবার তৈরি হয়ে গেলে, আপনার কাস্টম পার্সেলেবল র্যাপারটি ব্যবহার করতে আপনাকে এটি এসডিকে দিয়ে নিবন্ধন করতে হবে।
এটি করার জন্য, parcelableWrappers={YourParcelableWrapper.class}
CustomProfileConnector
টীকা বা কোনও শ্রেণিতে CrossProfile
টীকাগুলিতে}
ভবিষ্যতের মোড়ক
ভবিষ্যতের মোড়কগুলি হ'ল এসডিকে কীভাবে প্রোফাইল জুড়ে ফিউচারের জন্য সমর্থন যুক্ত করে। এসডিকে ডিফল্টরূপে ListenableFuture
জন্য সমর্থন অন্তর্ভুক্ত করে তবে ভবিষ্যতের অন্যান্য ধরণের জন্য আপনি নিজের সমর্থন যুক্ত করতে পারেন।
ভবিষ্যতের মোড়ক একটি শ্রেণি যা একটি নির্দিষ্ট ভবিষ্যতের ধরণের মোড়ানোর জন্য এবং এটি এসডিকে উপলভ্য করার জন্য ডিজাইন করা একটি শ্রেণি। এটি একটি সংজ্ঞায়িত স্ট্যাটিক চুক্তি অনুসরণ করে এবং অবশ্যই এসডিকে দিয়ে নিবন্ধিত হতে হবে।
টীকা
ভবিষ্যতের মোড়ক শ্রেণিটি অবশ্যই টীকাটি @CustomFutureWrapper
অবশ্যই মোড়ানো শ্রেণিকে originalType
হিসাবে উল্লেখ করে। যেমন:
@CustomFutureWrapper(originalType=SettableFuture.class)
বিন্যাস
ভবিষ্যতের মোড়কগুলি অবশ্যই com.google.android.enterprise.connectedapps.FutureWrapper
প্রসারিত করতে হবে।
ভবিষ্যতের মোড়কের অবশ্যই একটি স্ট্যাটিক W create(Bundler, BundlerType)
পদ্ধতি থাকতে হবে যা মোড়কের উদাহরণ তৈরি করে। একই সাথে এটি মোড়ানো ভবিষ্যতের ধরণের একটি উদাহরণ তৈরি করা উচিত। এটি একটি নন-স্ট্যাটিক T
getFuture()
পদ্ধতি দ্বারা ফিরে আসা উচিত। ফলাফলটি পাস করার জন্য বা মোড়ানো ভবিষ্যতে ছুঁড়ে ফেলার জন্য onResult(E)
এবং onException(Throwable)
পদ্ধতিগুলি প্রয়োগ করতে হবে।
ভবিষ্যতের মোড়কের অবশ্যই একটি স্ট্যাটিক void writeFutureResult(Bundler,
BundlerType, T, FutureResultWriter<E>)
পদ্ধতি থাকতে হবে। এটি ফলাফলের জন্য ভবিষ্যতে পাসগুলির সাথে নিবন্ধন করা উচিত, এবং যখন একটি ফলাফল দেওয়া হয়, কল resultWriter.onSuccess(value)
। যদি কোনও ব্যতিক্রম দেওয়া হয় তবে resultWriter.onFailure(exception)
বলা উচিত।
শেষ অবধি, ভবিষ্যতের মোড়কের অবশ্যই একটি স্ট্যাটিক T<Map<Profile, E>>
groupResults(Map<Profile, T<E>> results)
পদ্ধতি যা প্রোফাইল থেকে ভবিষ্যতে একটি মানচিত্রকে রূপান্তর করে, প্রোফাইল থেকে কোনও মানচিত্রের ভবিষ্যতে রূপান্তর করে ফলাফল এই যুক্তিটি আরও সহজ করার জন্য CrossProfileCallbackMultiMerger
ব্যবহার করা যেতে পারে।
যেমন:
/** A basic implementation of the future pattern used to test custom future
wrappers. */
public class SimpleFuture<E> {
public static interface Consumer<E> {
void accept(E value);
}
private E value;
private Throwable thrown;
private final CountDownLatch countDownLatch = new CountDownLatch(1);
private Consumer<E> callback;
private Consumer<Throwable> exceptionCallback;
public void set(E value) {
this.value = value;
countDownLatch.countDown();
if (callback != null) {
callback.accept(value);
}
}
public void setException(Throwable t) {
this.thrown = t;
countDownLatch.countDown();
if (exceptionCallback != null) {
exceptionCallback.accept(thrown);
}
}
public E get() {
try {
countDownLatch.await();
} catch (InterruptedException e) {
eturn null;
}
if (thrown != null) {
throw new RuntimeException(thrown);
}
return value;
}
public void setCallback(Consumer<E> callback, Consumer<Throwable>
exceptionCallback) {
if (value != null) {
callback.accept(value);
} else if (thrown != null) {
exceptionCallback.accept(thrown);
} else {
this.callback = callback;
this.exceptionCallback = exceptionCallback;
}
}
}
/** Wrapper for adding support for {@link SimpleFuture} to the Connected Apps SDK.
*/
@CustomFutureWrapper(originalType = SimpleFuture.class)
public final class SimpleFutureWrapper<E> extends FutureWrapper<E> {
private final SimpleFuture<E> future = new SimpleFuture<>();
public static <E> SimpleFutureWrapper<E> create(Bundler bundler, BundlerType
bundlerType) {
return new SimpleFutureWrapper<>(bundler, bundlerType);
}
private SimpleFutureWrapper(Bundler bundler, BundlerType bundlerType) {
super(bundler, bundlerType);
}
public SimpleFuture<E> getFuture() {
return future;
}
@Override
public void onResult(E result) {
future.set(result);
}
@Override
public void onException(Throwable throwable) {
future.setException(throwable);
}
public static <E> void writeFutureResult(
SimpleFuture<E> future, FutureResultWriter<E> resultWriter) {
future.setCallback(resultWriter::onSuccess, resultWriter::onFailure);
}
public static <E> SimpleFuture<Map<Profile, E>> groupResults(
Map<Profile, SimpleFuture<E>> results) {
SimpleFuture<Map<Profile, E>> m = new SimpleFuture<>();
CrossProfileCallbackMultiMerger<E> merger =
new CrossProfileCallbackMultiMerger<>(results.size(), m::set);
for (Map.Entry<Profile, SimpleFuture<E>> result : results.entrySet()) {
result
.getValue()
.setCallback(
(value) -> merger.onResult(result.getKey(), value),
(throwable) -> merger.missingResult(result.getKey()));
}
return m;
}
}
এসডিকে নিয়ে নিবন্ধন করুন
একবার তৈরি হয়ে গেলে, আপনার কাস্টম ভবিষ্যতের মোড়কটি ব্যবহার করতে আপনাকে এটি এসডিকে দিয়ে নিবন্ধন করতে হবে।
এটি করার জন্য, futureWrappers={YourFutureWrapper.class}
নির্দিষ্ট করুন কোনও CustomProfileConnector
টীকা বা কোনও শ্রেণিতে CrossProfile
টীকাগুলিতে।
ডাইরেক্ট বুট মোড
যদি আপনার অ্যাপ্লিকেশনটি সরাসরি বুট মোড সমর্থন করে তবে প্রোফাইলটি আনলক হওয়ার আগে আপনাকে ক্রস-প্রোফাইল কলগুলি করতে হবে। ডিফল্টরূপে, এসডিকে কেবল অন্য প্রোফাইলটি আনলক করা হলে সংযোগের অনুমতি দেয়।
এই আচরণটি পরিবর্তন করতে, আপনি যদি একটি কাস্টম প্রোফাইল সংযোগকারী ব্যবহার করছেন তবে আপনার availabilityRestrictions=AvailabilityRestrictions.DIRECT_BOOT_AWARE
@GeneratedProfileConnector
@CustomProfileConnector(availabilityRestrictions=AvailabilityRestrictions.DIRECT_BO
OT_AWARE)
public interface MyProfileConnector extends ProfileConnector {
public static MyProfileConnector create(Context context) {
return GeneratedMyProfileConnector.builder(context).build();
}
}
আপনি যদি CrossProfileConnector
ব্যবহার করে থাকেন তবে .সেটএভ্যালিবিলিটি _AWARE
.setAvailabilityRestrictions(AvailabilityRestrictions.DIRECT_BOOT
এই পরিবর্তনের সাথে সাথে, আপনাকে প্রাপ্যতা সম্পর্কে অবহিত করা হবে এবং অন্য প্রোফাইলটি আনলক করা না থাকলে ক্রস প্রোফাইল কল করতে সক্ষম হবে। আপনার কলগুলি কেবলমাত্র ডিভাইস এনক্রিপ্ট করা স্টোরেজ অ্যাক্সেস নিশ্চিত করা আপনার দায়িত্ব।