সতর্কতা: স্থির ক্ষেত্রগুলিতে অ্যান্ড্রয়েড প্রসঙ্গের ক্লাসগুলি রাখবেন না; এটি একটি মেমরি ফুটো (এবং তাত্ক্ষণিক রানও ভেঙে দেয়)


84

অ্যান্ড্রয়েড স্টুডিও:

স্থির ক্ষেত্রে অ্যান্ড্রয়েড প্রসঙ্গের ক্লাসগুলি রাখবেন না; এটি একটি মেমরি ফুটো (এবং তাত্ক্ষণিক রানও ভেঙে দেয়)

সুতরাং 2 টি প্রশ্ন:

# 1 আপনি startServiceপ্রসঙ্গের জন্য কোনও স্থির পরিবর্তনশীল ছাড়াই স্থির পদ্ধতি থেকে কল করবেন কীভাবে ?
# 2 আপনি একটি স্থিতিশীল পদ্ধতি (একই) থেকে কীভাবে স্থানীয় ব্রডকাস্টটি প্রেরণ করবেন?

উদাহরণ:

public static void log(int iLogLevel, String sRequest, String sData) {
    if(iLogLevel > 0) {

        Intent intent = new Intent(mContext, LogService.class);
        intent.putExtra("UPDATE_MAIN_ACTIVITY_VIEW", "UPDATE_MAIN_ACTIVITY_VIEW");
        mContext.startService(intent);
    }
}

বা

        Intent intent = new Intent(MAIN_ACTIVITY_RECEIVER_INTENT);
        intent.putExtra(MAIN_ACTIVITY_REQUEST_FOR_UPDATE, sRequest));
        intent.putExtra(MAIN_ACTIVITY_DATA_FOR_VIEW, sData);
        intent.putExtra(MAIN_ACTIVITY_LOG_LEVEL, iLogLevel);
        LocalBroadcastManager.getInstance(mContext).sendBroadcast(intent);

ব্যবহার না করে এটি করার সঠিক উপায় কী হবে mContext?

দ্রষ্টব্য: আমি মনে করি আমার মূল প্রশ্নটি হতে পারে কলিং পদ্ধতিটি যে শ্রেণী থেকে আসে সেখান থেকে কীভাবে প্রসঙ্গটি প্রেরণ করা যায়।


আপনি কি পদ্ধতিতে পরামিতি হিসাবে প্রসঙ্গটি পাস করতে পারবেন না?
জুয়ান ক্রুজ সোলার

আমি সেই রুটিনগুলিকে এমন জায়গাগুলিতে কল করব যার প্রসঙ্গটিও নেই।
জন স্মিথ

# 1 পরামিতি হিসাবে এটি পাস # 2 একই the
njzk2

তারপরে আপনাকে কলার পদ্ধতিতে প্রসঙ্গটিও পাস করতে হবে। সমস্যাটি হ'ল স্থির ক্ষেত্রগুলি আবর্জনা সংগ্রহ করা হয় না, তাই আপনি এর সমস্ত দর্শন দিয়ে কোনও কার্যকলাপ ফাঁস করতে পারেন
জুয়ান ক্রুজ সোলার

4
@ জনস্মিত এটি শুরু করার ক্রিয়াকলাপ থেকে (কনস্ট্রাক্টর প্যারামিটার বা পদ্ধতি প্যারামিটারের মাধ্যমে) আপনার প্রয়োজনীয় পয়েন্ট অবধি ক্যাসকেড করুন।
অ্যান্ড্রয়েডমেচনিক - ভাইরাল প্যাটেল

উত্তর:


56

কেবল আপনার পদ্ধতিতে এটি একটি প্যারামিটার হিসাবে পাস করুন। Contextসম্পূর্ণরূপে একটি শুরু করার উদ্দেশ্যে কোনও স্ট্যাটিক উদাহরণ তৈরির কোনও ধারণা নেই Intent

আপনার পদ্ধতিটি এমনভাবে দেখা উচিত:

public static void log(int iLogLevel, String sRequest, String sData, Context ctx) {
    if(iLogLevel > 0) {

        Intent intent = new Intent(ctx, LogService.class);
        intent1.putExtra("UPDATE_MAIN_ACTIVITY_VIEW", "UPDATE_MAIN_ACTIVITY_VIEW");
        ctx.startService(intent);
    }
}

প্রশ্নের মন্তব্য থেকে আপডেট: আপনার প্রয়োজনীয় বিন্দু অবধি প্রারম্ভিক ক্রিয়াকলাপ (কনস্ট্রাক্টর প্যারামিটার বা পদ্ধতি প্যারামিটারের মাধ্যমে) থেকে প্রসঙ্গটি কাস্ট করুন।


আপনি একটি নির্মাণকারীর উদাহরণ প্রদান করতে পারেন?
জন স্মিথ

যদি আপনার শ্রেণির নামটি যদি MyClassকোনও পাবলিক কনস্ট্রাক্টরের সাথে এটির মতো করে যুক্ত হয় public MyClass(Context ctx) { // put this ctx somewhere to use later }(এটি আপনার কনস্ট্রাক্টর) এখন MyClassএই কনস্ট্রাক্টরটি ব্যবহারের নতুন উদাহরণ তৈরি করুন যেমনMyClass mc = new MyClass(ctx);
AndroidMechanic - ভাইরাল প্যাটেল

আমি মনে করি না যে এটি অন-ডিমান্ড পাস করার পক্ষে সহজ। যদিও বাসি প্রসঙ্গে বা এখানে পছন্দ করার মতো বিষয়ে চিন্তা না করার মতো স্পষ্ট সুবিধা রয়েছে তবে এটি একটি স্থির। আসুন বলুন যে আপনার প্রতিক্রিয়া কলব্যাকে আপনার প্রসঙ্গের প্রয়োজন [আপনি প্রেফসগুলিতে লিখতে চান] যা অবিচ্ছিন্নভাবে আহ্বান করা হবে। তাই মাঝে মাঝে আপনাকে এটিকে কোনও সদস্য ক্ষেত্রে রাখতে বাধ্য করা হয়। এবং এখন আপনি এটি স্থির না করতে কিভাবে চিন্তা করতে হবে। stackoverflow.com/a/40235834/2695276 কাজ করছে বলে মনে হচ্ছে।
রজত শর্মা

4
স্থির ক্ষেত্র হিসাবে অ্যাপ্লিকেশন কনটেক্সটটি ব্যবহার করা ঠিক কি? ক্রিয়াকলাপগুলির বিপরীতে, অ্যাপ্লিকেশন অবজেক্টটি ধ্বংস হয় না, তাই না?
নিওওয়াং

তবে, প্রশ্নটি হল, কেন এটির সাথে মেমরি ফুটো হয় না?
juztcode

51

আপনি যদি কোনও সদস্য ক্ষেত্রে সংরক্ষণের সিদ্ধান্ত নেন তবে আপনি যে পদ্ধতিতে / নির্মাতার মাধ্যমে আপনার সিঙ্গলটনে উত্তীর্ণ হয়েছে সেই প্রসঙ্গে আপনি প্রেরণ.গেট অ্যাপ্লিকেশনস কনটেক্সট () বা getApplicationContext () কল করে তা নিশ্চিত করুন।

নির্বোধ প্রমাণ উদাহরণ (এমনকি কেউ যদি কোনও ক্রিয়াকলাপে উত্তীর্ণ হয় তবে এটি অ্যাপ্লিকেশন প্রসঙ্গটি ধরে ফেলবে এবং সিঙ্গেলটন ইনস্ট্যান্ট করতে এটি ব্যবহার করবে):

public static synchronized RestClient getInstance(Context context) {
    if (mInstance == null) {
        mInstance = new RestClient(context.getApplicationContext());
    }
    return mInstance;
}

ডকস অনুসারে getApplicationContext () পান: "বর্তমান প্রক্রিয়ার একক, গ্লোবাল অ্যাপ্লিকেশন অবজেক্টের প্রসঙ্গটি ফিরিয়ে দিন ।"

এর অর্থ হ'ল "getApplicationContext ()" এর দ্বারা প্রত্যাবর্তিত প্রসঙ্গটি পুরো প্রক্রিয়াটির মধ্য দিয়ে যাবে এবং সুতরাং এটির কোনও স্থির রেফারেন্স আপনার কোথাও সংরক্ষণ করা উচিত নয় কারণ এটি আপনার অ্যাপ্লিকেশনটির রানটাইম চলাকালীন সর্বদা উপস্থিত থাকবে (এবং কোনও বস্তুকে ছাড়িয়ে যাবে) ive / এটির মাধ্যমে সিঙ্গলেটগুলি ইনস্ট্যান্টিয়েটেড)।

এর সাথে তুলনা করুন ভিউ / ক্রিয়াকলাপের প্রচুর পরিমাণে ডেটা থাকা ক্রিয়াকলাপের সাথে, আপনি যদি কোনও ক্রিয়াকলাপের দ্বারা রাখা কোনও প্রসঙ্গ ফাঁস করেন তবে সিস্টেমটি সেই উত্সটি মুক্ত করতে সক্ষম হবে না যা স্পষ্টতই ভাল নয়।

তার প্রসঙ্গে কোনও ক্রিয়াকলাপের একটি রেফারেন্সটি ক্রিয়াকলাপের মতোই একই জীবনচক্রটি বেঁচে থাকতে পারে, অন্যথায় এটি প্রসঙ্গটিকে জিম্মি করে রাখবে যা মেমরি ফাঁস করে দেয় (যা লিন্টের সতর্কতার পিছনে কারণ)।

সম্পাদনা করুন: উপরের ডক্স থেকে উদাহরণটিকে আঘাত করা লোকটির কাছে, আমি স্রেফ যা লিখেছি সে সম্পর্কে কোডে একটি মন্তব্য বিভাগও রয়েছে:

    // getApplicationContext() is key, it keeps you from leaking the
    // Activity or BroadcastReceiver if someone passes one in.

8
যে ছেলেটিকে উপরের উদাহরণটিকে ভিত্তিহীন করেছে তাকে কটূক্তি করা ছেলেটির প্রতি: এই থ্রেডের মূল বিষয় হ'ল সিঙ্গেলটন তৈরির নিজস্ব প্রস্তাবিত প্যাটার্নের সাথে দ্বন্দ্বের লিন্টের সতর্কতা।
রাফেল সি

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

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

4
@ মার্কাস যদি আপনার শিশু শ্রেণি কোন প্রসঙ্গে এটি ইনস্ট্যান্ট করছে সে সম্পর্কে সচেতন না হয় তবে স্থির সদস্য হিসাবে এটি সংরক্ষণ করা কেবল খারাপ অভ্যাস। তদ্ব্যতীত, অ্যাপ্লিকেশন প্রসঙ্গটি আপনার অ্যাপ্লিকেশনটির অ্যাপ্লিকেশন অবজেক্টের অংশ হিসাবে বেঁচে থাকে, অ্যাপ্লিকেশন বস্তু চিরকালের স্মৃতিতে থাকবে না, এটি মারা যাবে killed জনপ্রিয় বিশ্বাসের বিপরীতে, অ্যাপটিকে স্ক্র্যাচ থেকে পুনরায় আরম্ভ করা হবে না। অ্যান্ড্রয়েড একটি নতুন অ্যাপ্লিকেশন অবজেক্ট তৈরি করবে এবং সেই অ্যাপ্লিকেশনটিকে প্রথম স্থানে হত্যা করা হয়নি এমন ধারণা দেয়ার আগে ব্যবহারকারীরা এমন কার্যকলাপ শুরু করবে।
রাফেল সি

@ রাফেলসি আপনার কাছে কি এরকম দলিল আছে? এটি সম্পূর্ণরূপে ভুল বলে মনে হচ্ছে কারণ অ্যান্ড্রয়েড প্রতিটি প্রক্রিয়া চালানোর জন্য কেবলমাত্র একটি অ্যাপ্লিকেশন প্রসঙ্গে আশ্বাস দেয়।
হেইডেনকাই

6

এটি কেবল একটি সতর্কতা। চিন্তা করবেন না। আপনি যদি কোনও অ্যাপ্লিকেশন প্রসঙ্গে ব্যবহার করতে চান, আপনি এটি একটি "সিঙ্গলটন" শ্রেণিতে সংরক্ষণ করতে পারেন, যা আপনার প্রকল্পের সমস্ত সিঙ্গলটন ক্লাস সংরক্ষণ করতে ব্যবহৃত হয়।


2

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

তাত্ক্ষণিক রান এখানে কাজ করে ...


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

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

4
"সিঙ্গেল টাস্ক" কেবলমাত্র প্রতিটি কার্য প্রতি গ্যারান্টি দেয়। যদি আপনার অ্যাপ্লিকেশনটিতে গভীর লিঙ্কিং, বা কোনও বিজ্ঞপ্তি থেকে এটি চালু করার মতো একাধিক এন্ট্রি পয়েন্ট থাকে তবে আপনি একাধিক কাজ শেষ করতে পারেন।
ব্লেডকডার

2

WeakReferenceসিঙ্গেলটন ক্লাসে প্রসঙ্গ সংরক্ষণ করার জন্য ব্যবহার করুন এবং সতর্কতাটি চলে যাবে

private WeakReference<Context> context;

//Private contructor
private WidgetManager(Context context) {
    this.context = new WeakReference<>(context);
}

//Singleton
public static WidgetManager getInstance(Context context) {
    if (null == widgetManager) {
        widgetManager = new WidgetManager(context);
    }
    return widgetManager;
}

এখন আপনি প্রসঙ্গে অ্যাক্সেস করতে পারেন

  if (context.get() instanceof MainActivity) {
            ((MainActivity) context.get()).startActivityForResult(pickIntent, CODE_REQUEST_PICK_APPWIDGET);
        }

1

সাধারণত, প্রাসঙ্গিক ক্ষেত্রগুলি স্থির হিসাবে সংজ্ঞায়িত করা এড়িয়ে চলুন। সতর্কতা নিজেই ব্যাখ্যা করেছে কেন: এটি একটি মেমরি ফুটো। ব্রেকিং তাত্ক্ষণিক রান করতে পারে যদিও গ্রহে সবচেয়ে বড় সমস্যা না।

এখন, দুটি পরিস্থিতি রয়েছে যেখানে আপনি এই সতর্কতাটি পেয়ে যাবেন। উদাহরণস্বরূপ (সবচেয়ে সুস্পষ্ট একটি):

public static Context ctx;

এবং তারপরে আরও কিছুটা জটিল বিষয় রয়েছে, যেখানে প্রসঙ্গটি ক্লাসে আবৃত রয়েছে:

public class Example{
    public Context ctx;
    //Constructor omitted for brievety 
}

এবং এই শ্রেণিটি কোথাও স্থির হিসাবে সংজ্ঞায়িত করা হয়েছে:

public static Example example;

এবং আপনি সতর্কতা পাবেন।

সমাধানটি নিজেই মোটামুটি সহজ: প্রচ্ছন্ন ক্ষেত্রগুলি স্থির দৃষ্টান্তে রাখবেন না , তা মোড়ানো শ্রেণির হোক বা সরাসরি স্থির ঘোষণা করুন।

এবং সতর্কতার সমাধানটি সহজ: ক্ষেত্রটি স্থিরভাবে রাখবেন না। আপনার ক্ষেত্রে, পদ্ধতির উদাহরণ হিসাবে প্রসঙ্গটি পাস করুন। যে ক্লাসে একাধিক প্রবন্ধ কল করা হয়, ক্লাসে প্রসঙ্গটি (বা সেই বিষয়ে একটি ক্রিয়াকলাপ) পাস করার জন্য কনস্ট্রাক্টর ব্যবহার করুন।

মনে রাখবেন এটি ত্রুটি নয়, একটি সতর্কতা। আপনার যে কোনও কারণে স্থিতিশীল প্রসঙ্গে প্রয়োজন , আপনি এটি করতে পারেন। যদিও আপনি এটি করার সময় একটি মেমরি ফাঁস তৈরি করেন।


আমরা কীভাবে স্মৃতি ফাঁস না করে এটি করতে পারি?
isululian00

4
আপনি পারবেন না। আপনার যদি পুরোপুরি প্রসঙ্গগুলি পাস করার প্রয়োজন হয় তবে আপনি একটি ইভেন্টের বাসে সন্ধান করতে পারেন
জো

ঠিক এই সমস্যাটি আমার ছিল যদি আপনি যদি দয়া করে এটি দেখতে পারেন তবে এটি করার অন্য কোনও উপায় রয়েছে, তবে বিটিডব্লিউটি পদ্ধতিটি স্থির থাকতে হবে কারণ আমি এটি সি ++ কোড স্ট্যাকওভারফ্লো
isululian00

0

আপনি যদি নিশ্চিত হন যে এটি একটি অ্যাপ্লিকেশন প্রসঙ্গে। এটা গুরুত্বপূর্ণ। এটি যোগ করুন

@SuppressLint("StaticFieldLeak")

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