রোটেশন অ্যান্ড্রয়েডে ক্রিয়াকলাপ পুনরায় চালু হয়


1378

আমার অ্যান্ড্রয়েড অ্যাপ্লিকেশনটিতে, যখন আমি ডিভাইসটি ঘোরান (কীবোর্ডটি স্লাইড করুন) তখন আমার Activityপুনরায় চালু হয় ( onCreateডাকা হয়)। এখন, এটি সম্ভবত এটি হওয়ার কথা, তবে onCreateপদ্ধতিটিতে আমি প্রচুর প্রাথমিক সেটআপ করি, সুতরাং আমারও প্রয়োজন:

  1. সমস্ত প্রাথমিক সেটিংটি অন্য ফাংশনে রাখুন যাতে এটি সমস্ত ডিভাইস রোটেশনে বা হারিয়ে যায় না
  2. এটি তৈরি করুন যাতে onCreateআবার বলা হয় না এবং লেআউটটি ঠিক সামঞ্জস্য হয় বা
  3. অ্যাপটিকে কেবল প্রতিকৃতিতে সীমাবদ্ধ করুন যাতে এটি onCreateবলা হয় না।

4
এই ব্লগ পোস্টেও ক্রিয়াকলাপ কনফিগারেশনের পরিবর্তনের সময় কীভাবে দীর্ঘমেয়াদী অ্যাসিনক্রোনাস কাজগুলি বজায় রাখা যায় তার একটি সম্পূর্ণ ব্যাখ্যা রয়েছে !
অ্যাড্রিয়ান সন্ন্যাস

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

উত্তর:


965

অ্যাপ্লিকেশন ক্লাস ব্যবহার করে

আপনি আপনার সূচনাতে যা করছেন তার উপর নির্ভর করে আপনি একটি নতুন শ্রেণি তৈরির বিষয়টি বিবেচনা করতে পারেন যা Applicationআপনার সূচনা কোডটিকে onCreateশ্রেণীর মধ্যে একটি ওভাররাইড পদ্ধতিতে প্রসারিত এবং সরিয়ে নিয়ে যেতে পারে ।

public class MyApplicationClass extends Application {
  @Override
  public void onCreate() {
    super.onCreate();
    // TODO Put your application initialization code here.
  }
}

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

এই শ্রেণীর উদাহরণটি সিঙ্গলটন হিসাবে প্রকাশ করা এবং অ্যাপ্লিকেশন ভেরিয়েবলগুলি আপনি গেটর এবং সেটারগুলি ব্যবহার করে আরম্ভ করছেন তা প্রকাশ করা ভাল অনুশীলন।

দ্রষ্টব্য: আপনার নতুন অ্যাপ্লিকেশন শ্রেণির নামটি নিবন্ধভুক্ত এবং ব্যবহারের জন্য আপনাকে ম্যানিফেস্টে উল্লেখ করতে হবে:

<application
    android:name="com.you.yourapp.MyApplicationClass"

কনফিগারেশন পরিবর্তনগুলিতে প্রতিক্রিয়া ব্যক্ত করা [আপডেট করা: এপিআই 13 এর পরে এটি অবহেলা করা হয়েছে; প্রস্তাবিত বিকল্প দেখুন ]

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

android:configChangesআপনার ক্রিয়াকলাপের ম্যানিফেস্ট নোডে নোড যুক্ত করে শুরু করুন

 <activity android:name=".MyActivity"
      android:configChanges="orientation|keyboardHidden"
      android:label="@string/app_name">

বা অ্যান্ড্রয়েড 3..২ (এপিআই স্তর ১৩) এবং আরও নতুনের জন্য :

<activity android:name=".MyActivity"
      android:configChanges="keyboardHidden|orientation|screenSize"
      android:label="@string/app_name">

তারপরে ক্রিয়াকলাপের মধ্যে onConfigurationChangedপদ্ধতিটি ওভাররাইড করে এবং setContentViewজিইউআই লেআউটটিকে নতুন অভিযোজনে পুনরায় কাজ করতে বাধ্য করার জন্য কল করুন ।

@Override
public void onConfigurationChanged(Configuration newConfig) {
  super.onConfigurationChanged(newConfig);
  setContentView(R.layout.myLayout);
}

17
আমি মনে করি না দ্বিতীয় পন্থাটি কাজ করে। আমি এটা চেষ্টা করেছি; একটি সম্পাদনা পাঠ্য সহ একটি ক্রিয়াকলাপ। আমি সেখানে কিছু পাঠ্য লিখেছি, ওরিয়েন্টেশন পরিবর্তন করেছি এবং পাঠ্যটি চলে গেছে / পুনরায় সেট করা হয়েছে।
টেড

231
এখানে আশা করা হচ্ছে আমরা ভবিষ্যতে একটি অনরোটেট () পদ্ধতি দেখি। এমনকি এ জাতীয় বিষয় নিয়েও উদ্বিগ্ন হওয়া হতাশাজনক।
কেলি সাটন 15

84
নোট করুন যে অ্যান্ড্রয়েড ডেভ গাইড এটি ব্যবহারের বিরুদ্ধে সতর্কতা অবলম্বন করেছে : দ্রষ্টব্য: ( android:configChanges) ব্যবহার করা এড়িয়ে চলতে হবে এবং কেবল সর্বশেষ-রিসোর্ট হিসাবে ব্যবহার করা উচিত। একটি কনফিগারেশন পরিবর্তনের কারণে পুনরায় চালু করতে কীভাবে সঠিকভাবে পরিচালনা করতে হবে সে সম্পর্কে আরও তথ্যের জন্য দয়া করে হ্যান্ডলিং রানটাইম পরিবর্তনগুলি পড়ুন। পরিবর্তে, ঘূর্ণন ইভেন্ট জুড়ে ডেটা বজায় রাখতে তারা মনে হয় এটি ব্যবহার করা পছন্দ করে onSaveInstanceState Bundle; অথবা @ জন-হে উল্লেখ , onRetainNonConfigurationInstance
জেফরো 19

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

16
আমি মনে করি আপনার এই উত্তরটি আপনার উত্তরটিতে ৩.২-এ যুক্ত করা উচিত , এটি বেশ গুরুত্বপূর্ণ (কেবলমাত্র সেই সমস্যার মুখোমুখি হয়েছিল) এবং এটি উপেক্ষা হতে পারে।
বড়স্টোনস

185

অ্যান্ড্রয়েড ৩.২ এবং উচ্চতর জন্য আপডেট:

সতর্কতা : অ্যান্ড্রয়েড ৩.২ (এপিআই লেভেল ১৩) দিয়ে শুরু করে, ডিভাইস প্রতিকৃতি এবং ল্যান্ডস্কেপ অভিযোজনের মধ্যে স্যুইচ করলে "স্ক্রিনের আকার" পরিবর্তন হয় । সুতরাং, যদি আপনি API স্তরের 13 বা ততোধিক (minSdkVersion এবং টার্গেটএসডকভিশন বৈশিষ্ট্য দ্বারা ঘোষিত হিসাবে) বিকাশ করার সময় ওরিয়েন্টেশন পরিবর্তনের কারণে রানটাইম পুনরায় আর্টসগুলি প্রতিরোধ করতে চান, আপনাকে অবশ্যই "screenSize"মানটির পাশাপাশি মানটি অন্তর্ভুক্ত করতে হবে "orientation"। অর্থাৎ, আপনাকে অবশ্যই ঘোষণা করতে হবে android:configChanges="orientation|screenSize"। তবে, যদি আপনার অ্যাপ্লিকেশনটি এপিআই লেভেল 12 বা তার চেয়ে কমের লক্ষ্যবস্তু করে, তবে আপনার ক্রিয়াকলাপ সর্বদা এই কনফিগারেশন পরিবর্তনটিকে নিজেরাই পরিচালনা করে (কোনও অ্যান্ড্রয়েড 3.2 বা উচ্চতর ডিভাইসে চলাকালীন এই কনফিগারেশন পরিবর্তনটি আপনার ক্রিয়াকলাপটি পুনঃসূচনা করে না)।


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

এটি নির্দেশ করার জন্য ধন্যবাদ, আমার কাছে কেবল অ্যান্ড্রয়েড ছিল: কনফিগারেশন = "ওরিয়েন্টেশন | স্ক্রিনসাইজ" সেট, এবং ওরিয়েন্টেশন স্যুইচিং আমার ক্রিয়াকলাপটি পুনরুদ্ধার করছিল, এবং আমার জীবনের জন্য আমি বুঝতে পারি না কেন!
ক্রিস্টোফার পেরি

5
অ্যান্ড্রয়েড যুক্ত করা হচ্ছে: কনফিগার চেঞ্জগুলি কেবল সর্বশেষ রিসোর্ট হিসাবে ব্যবহার করা উচিত । পরিবর্তে ব্যবহার Fragmentsএবং বিবেচনা করুন setRetainInstance
সাইমন ফোর্সবার্গ

মূল বিষয়টি screenSizeঅ্যান্ড্রয়েড 3..২ এবং এর থেকেও উচ্চতর জন্য, যা আমার সমস্যার সমাধান করেছে, আপনাকে ধন্যবাদ!
ফান্টুচ

127

onCreate()পুরোপুরি বরখাস্ত হওয়া থেকে বিরত করার চেষ্টা করার পরিবর্তে, Bundle savedInstanceStateঘটনাটি শূন্য হয়েছে কিনা তা পরীক্ষা করে দেখার চেষ্টা করুন ।

উদাহরণস্বরূপ, যদি আমার কিছু যুক্তি থাকে যা Activityযথাযথভাবে তৈরি হওয়ার সময় চালানো উচিত , প্রতিটি অভিমুখী পরিবর্তনের উপর নয়, আমি কেবল সেই যুক্তিটি কেবল তখনই চালিত করি onCreate()যদি savedInstanceStateশূন্য থাকে।

অন্যথায়, আমি এখনও অভিমুখীকরণের জন্য লেআউটটি সঠিকভাবে পুনরায় আঁকতে চাই।

public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_game_list);

        if(savedInstanceState == null){
            setupCloudMessaging();
        }
}

নিশ্চিত না যে এটি চূড়ান্ত উত্তর কিনা, তবে এটি আমার পক্ষে কাজ করে।


6
এবং আপনি প্রকৃতপক্ষে রাজ্যটি কোথায় সংরক্ষণ করছেন?
ইওকস

5
এটি আমার পক্ষে কাজ করে বলে মনে হচ্ছে এবং এটি খুব সহজ পদ্ধতি বলে মনে হচ্ছে। আমি লক্ষ্য করেছি যে আপনি সাবক্লাসিং অ্যাপ্লিকেশন সম্পর্কে ধারণাটির জন্য এই (খনি সহ 5 টি) বনাম 373 এর জন্য কেবলমাত্র 4 টি আপ পেয়েছিলেন যা আমার কাছে আরও জটিল বলে মনে হচ্ছে। এই পদ্ধতিতে কোন খারাপ দিক নেই?
স্টিভ

4
এই সমাধানটি আমার পক্ষে দুর্দান্ত কাজ করেছে। আমি পারতাম Intent serverintent = new Intent(MainActivity.this, MessageListener.class);এবং startService(serverintent);একটি তৈরি করতে serverSocket = new ServerSocket(0xcff2);এবং Socket client = serverSocket.accept();একটি সঙ্গে BufferedReader(new InputStreamReader(client.getInputStream()));এবং আমার Android ঘোরাতে এবং ক্লায়েন্ট / সার্ভার সংযোগ সক্রিয় রাখতে, এখনো গুই ঘোরান ফেলতে পারে। ম্যানুয়াল অনুসারে, শেষ ক্রিয়াকলাপটি বন্ধ হয়ে গেলে সেভড ইনস্ট্যান্সস্টেটটি আরম্ভ হয়।
ফ্রেড এফ

3
বুঝতে পারছি না, কী ধরা? এটি দুর্দান্ত সমাধান করে এবং অন্যান্য সমাধানগুলির তুলনায় অনেক কম জটিলতার সাথে।
আরটিএফ

3
এটি অ্যান্ড্রয়েডে করার সঠিক উপায়। মূলত কনফিগার চেঞ্জগুলির সাথে ঘোরানো এবং অন্যান্য যেগুলি জটিল, এবং অপ্রয়োজনীয়।
লুক ওয়েগননার

99

আমি কি করেছিলাম...

ম্যানিফেস্টে ক্রিয়াকলাপ বিভাগে যোগ করা হয়েছে:

android:configChanges="keyboardHidden|orientation"

ক্রিয়াকলাপের কোডে, প্রয়োগ করা হয়েছে:

//used in onCreate() and onConfigurationChanged() to set up the UI elements
public void InitializeUI()
{
    //get views from ID's
    this.textViewHeaderMainMessage = (TextView) this.findViewById(R.id.TextViewHeaderMainMessage);

    //etc... hook up click listeners, whatever you need from the Views
}

//Called when the activity is first created.
@Override
public void onCreate(Bundle savedInstanceState)
{
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    InitializeUI();
}

//this is called when the screen rotates.
// (onCreate is no longer called when screen rotates due to manifest, see: android:configChanges)
@Override
public void onConfigurationChanged(Configuration newConfig)
{
    super.onConfigurationChanged(newConfig);
    setContentView(R.layout.main);

    InitializeUI();
}

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

2
আমি এখানে বর্ণিত হিসাবে সবকিছু করেছি, তবে ওরিয়েন্টেশন পরিবর্তনের পরে যখন আমি একটি বোতাম টিপতে চেষ্টা করি তখন আমি নলপয়েন্টারএক্সসেপশন পাই। ভুল হতে পারে?
ফিনবয় 11

5
মনে রাখবেন আমার উত্তরটি 3 বছরের পুরানো এবং অ্যান্ড্রয়েড বিকশিত হতে চলেছে ... সাইমন - আপনার কি নমুনা কোডের কোনও লিঙ্ক আছে? মানুষের এটাই দরকার।
কেউ কোথাও কোথাও

3
অ্যান্ড্রয়েডের বিরুদ্ধে সতর্ক করার সময়: কনফিগারেশনগুলি, @ সিমোনআন্ড্রো ফোর্সবার্গ আসলে অ্যান্ড্রয়েড ডক্সকে প্যারাফ্রেস করছে । রানটাইম পরিবর্তনগুলি পরিচালনা করে বিকল্পগুলির (নমুনা কোড সহ) আরও বিস্তারিত তথ্য রয়েছে।
লিফ আরে স্টারসেট

67

আপনি যা বর্ণনা করেন তা হ'ল ডিফল্ট আচরণ। আপনাকে এই ইভেন্টগুলি যুক্ত করে সনাক্ত করতে এবং পরিচালনা করতে হবে:

android:configChanges

আপনার ম্যানিফেস্টে এবং তারপরে যে পরিবর্তনগুলি আপনি পরিচালনা করতে চান তা। অভিমুখীকরণের জন্য, আপনি ব্যবহার করবেন:

android:configChanges="orientation"

এবং কীবোর্ড খোলার বা বন্ধ হওয়ার জন্য আপনি ব্যবহার করবেন:

android:configChanges="keyboardHidden"

আপনি যদি উভয়কেই পরিচালনা করতে চান তবে আপনি কেবল পাইপ কমান্ডের সাথে এগুলি পৃথক করতে পারেন:

android:configChanges="keyboardHidden|orientation"

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

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


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

48

আমি এই লোরটি সবেমাত্র আবিষ্কার করেছি:

একটি অভিযোজন পরিবর্তনের মাধ্যমে ভ্রমণ জীবিত রাখার, এবং এটি মাধ্যমে পরিচালনা করার জন্য onConfigurationChanged, ডকুমেন্টেশন এবং কোড নমুনা উপরে ফাইল এর পরামর্শ:

<activity android:name=".MyActivity"
      android:configChanges="orientation|keyboardHidden"
      android:label="@string/app_name">

এটির অতিরিক্ত সুবিধা রয়েছে যা এটি সর্বদা কার্যকর হয়।

বোনাস বিদ্যা যে বাদ হয় keyboardHiddenযৌক্তিক বলে মনে হতে পারে, কিন্তু এটা ব্যর্থতা এমুলেটর মধ্যে (অ্যান্ড্রয়েড 2.1 জন্য অন্তত) ঘটায়: শুধুমাত্র নির্দিষ্ট orientationএমুলেটর কল উভয় করতে হবে OnCreateএবং onConfigurationChangedমাঝে মাঝে, এবং শুধুমাত্র OnCreateঅন্যান্য বার।

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


14
সতর্কতা: অ্যান্ড্রয়েড ৩.২ (এপিআই লেভেল ১৩) দিয়ে শুরু করে, ডিভাইস প্রতিকৃতি এবং ল্যান্ডস্কেপ অভিযোজনের মধ্যে স্যুইচ করলে "স্ক্রিনের আকার" পরিবর্তন হয়। সুতরাং, আপনি যদি 13 স্তরের বা ততোধিক স্তরের জন্য বিকাশকালে ওরিয়েন্টেশন পরিবর্তনের কারণে রানটাইম পুনরায় চালু করতে বাধা দিতে চান: অ্যান্ড্রয়েড: কনফিগারেশন = "ওরিয়েন্টেশন | কীবোর্ডহাইডার | স্ক্রিনসাইজ"
গেলট্রুড

হ্যাঁ, এমুলেটরটি বড় সময় চুষছে। কনফিগার পরিবর্তনের সঠিকভাবে রিপোর্ট করতে আপনি এটির উপর নির্ভর করতে পারবেন না।
ইগোরগানাপলস্কি

অ্যান্ড্রয়েড যুক্ত করা হচ্ছে: কনফিগার চেঞ্জগুলি কেবল সর্বশেষ রিসোর্ট হিসাবে ব্যবহার করা উচিত । পরিবর্তে ব্যবহার Fragmentsএবং বিবেচনা করুন setRetainInstance
সাইমন ফোর্সবার্গ

38

আপনি অ্যান্ড্রয়েড প্ল্যাটফর্মের ওরিয়েন্টেশন পরিবর্তনগুলি জুড়ে ডেটা টিকিয়ে রাখার উপায়টিও বিবেচনা করতে পারেন: onRetainNonConfigurationInstance()এবং getLastNonConfigurationInstance()

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

দেখুন এখানে অথবা এখানে

এটি লক্ষ করা উচিত যে এই পদ্ধতিগুলি এখন অবহিত করা হয়েছে (যদিও উপরের সমাধানগুলির বেশিরভাগ সমাধানের পরামর্শ হিসাবে নিজেকে পরিবর্তন করার চেয়ে এখনও আরও নমনীয়) আপনি যে প্রতিদ্বন্দ্বিতা করতে চান তার প্রতিটিতে স্যুইচ করুন Fragmentsএবং পরিবর্তে ব্যবহার setRetainInstance(true)করুন Fragment


3
আমি সত্যিই ভাবি খণ্ডগুলি এবং সেটটেটইনস্ট্যান্স এটি করার সেরা উপায় (এবং গুগলের প্রস্তাবিত উপায়), আপনার কাছে +1 এবং অন্যদের কাছে -1। অ্যান্ড্রয়েড যুক্ত করা হচ্ছে: কনফিগারচেন্জগুলি কেবলমাত্র সর্বশেষ অবলম্বন হিসাবে ব্যবহার করা উচিত
সাইমন ফোর্সবার্গ

32

পদ্ধতির দরকারী তবে টুকরোটি ব্যবহার করার সময় এটি অসম্পূর্ণ।

খণ্ডগুলি সাধারণত কনফিগারেশন পরিবর্তনে পুনরায় তৈরি হয়। আপনি যদি এটিটি ঘটতে না চান তবে ব্যবহার করুন

setRetainInstance(true); খণ্ডের কনস্ট্রাক্টরগুলিতে

এটি কনফিগারেশন পরিবর্তনের সময় টুকরো টিকিয়ে রাখতে পারে।

http://developer.android.com/reference/android/app/Fragment.html#setRetainInstance(boolean)


7
একমত। সর্বশেষতম অ্যান্ড্রয়েড এপিআইয়ের সাথে, মনে হয় এটিগুলি হ্যান্ডেল করার জন্য খণ্ডগুলি হ'ল সঠিক উপায়। আমি নিজে নিজে এটি চেষ্টা করে দেখিনি, তবে এই পৃষ্ঠাটি পড়ে যা সংগ্রহ করেছি তা থেকে আপনি মূলত আপনি কোনও কার্যকলাপে প্রয়োগ করার জন্য 99 শতাংশকে একটি খণ্ডের সাবক্লাসে নিয়ে যান, তারপরে সেই খণ্ডটিকে ক্রিয়াকলাপে যুক্ত করুন। কার্যকলাপ এখনও ধ্বংস করা হবে এবং পর্দা ঘূর্ণন উপর recreated, কিন্তু আপনি বিশেষভাবে অ্যান্ড্রয়েড বলতে পারেন না ব্যবহার অসম্পূর্ণ অংশ ধ্বংস করার setRetainInstance()পদ্ধতি @Abdo উল্লেখ করেছে।
brianmearn

25

আমি কেবল সহজভাবে যুক্ত

     android:configChanges="keyboard|keyboardHidden|orientation"

ম্যানিফেস্ট ফাইলটিতে এবং আমার ক্রিয়াকলাপে কোনও পদ্ধতি যুক্ত করেনিonConfigurationChanged

সুতরাং প্রতিবার কীবোর্ড স্লাইড আউট বা কিছুই ঘটে না


যোগ <application ...android:configChanges="keyboard|keyboardHidden|orientation">এবং এটি কাজ করছে। Build.gradle এ আমার সেটিংস:minSdkVersion 15, compileSdkVersion 23, buildToolsVersion "23.0.2"
জুনিয়র মেহে

19

onCreateপদ্ধতি থাকা সত্বেও বলা হয় যখন আপনি পরিবর্তন orientationAndroid এর। সুতরাং এই পদ্ধতিতে সমস্ত ভারী কার্যকারিতা সরিয়ে নেওয়া আপনাকে সাহায্য করবে না



17
 onConfigurationChanged is called when the screen rotates. 
 (onCreate is no longer called when screen rotates due to manifest, see:  
 android:configChanges)

প্রকাশের কোন অংশ এটি "কল করবেন না" বলে onCreate()?

এছাড়াও, গুগলের দস্তাবেজগুলি android:configChanges(শেষ অবলম্বন ছাড়া) ব্যবহার এড়াতে বলেছে .... তবে তারপরে বিকল্প বিকল্পগুলি তারা সমস্ত ডিও ব্যবহারের পরামর্শ দেয় android:configChanges

এটি আমার অভিজ্ঞতা হয়েছে যে এমুলেটরটি সবসময় onCreate()আবর্তনের দিকে ডাকে ।
তবে আমি যে 1-2 ডিভাইসগুলিতে একই কোড চালিত করি ... তা করি না। (কেন কোনও পার্থক্য হবে তা নিশ্চিত নয়))


16

এটি খুব সহজ কেবল নিম্নলিখিত পদক্ষেপগুলি করুন:

<activity
    android:name=".Test"
    android:configChanges="orientation|screenSize"
    android:screenOrientation="landscape" >
</activity>

এটি আমার পক্ষে কাজ করে:

দ্রষ্টব্য: ওরিয়েন্টেশন আপনার প্রতিদানের উপর নির্ভর করে


15

অ্যান্ড্রয়েড ম্যানিফেস্টে করা পরিবর্তনগুলি হ'ল:

android:configChanges="keyboardHidden|orientation" 

ক্রিয়াকলাপের ভিতরে করা সংযোজনগুলি হ'ল:

public void onConfigurationChanged(Configuration newConfig) {
    super.onConfigurationChanged(newConfig);

    // Checks the orientation of the screen
    if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
        Toast.makeText(this, "landscape", Toast.LENGTH_SHORT).show();
    } else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) {
        Toast.makeText(this, "portrait", Toast.LENGTH_SHORT).show();
    }
}

15

আপনার ম্যানিফেস্টে এই লাইনটি যুক্ত করুন: -

android:configChanges="orientation|keyboard|keyboardHidden|screenSize|screenLayout|uiMode"

এবং ক্রিয়াকলাপের এই স্নিপেট: -

@Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
                WindowManager.LayoutParams.FLAG_FULLSCREEN);
    }

14

এই কাজ করার বিভিন্ন উপায় আছে:

ক্রিয়াকলাপের অবস্থা সংরক্ষণ করুন

আপনি এতে ক্রিয়াকলাপের অবস্থাটি সংরক্ষণ করতে পারেন onSaveInstanceState

@Override
public void onSaveInstanceState(Bundle outState) {
    /*Save your data to be restored here
    Example : outState.putLong("time_state", time); , time is a long variable*/
    super.onSaveInstanceState(outState);
}

এবং তারপরে bundleরাষ্ট্রটি পুনরুদ্ধার করতে ব্যবহার করুন ।

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    if(savedInstanceState!= null){
       /*When rotation occurs
        Example : time = savedInstanceState.getLong("time_state", 0); */
    } else {
      //When onCreate is called for the first time
    }
}

নিজের দ্বারা পরিচালনা ওরিয়েন্টেশন পরিবর্তন করুন

অন্য বিকল্প হ'ল ওরিয়েন্টেশন পরিবর্তনগুলি নিজের দ্বারা পরিচালনা করা। তবে এটি একটি ভাল অনুশীলন হিসাবে বিবেচিত হয় না।

এটি আপনার মেনিফেস্ট ফাইলটিতে যুক্ত করুন।

android:configChanges="keyboardHidden|orientation"

অ্যান্ড্রয়েড ৩.২ এবং তারপরের জন্য:

android:configChanges="keyboardHidden|orientation|screenSize"

@Override
public void onConfigurationChanged(Configuration config) {
    super.onConfigurationChanged(config);

if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) {
        //Handle rotation from landscape to portarit mode here
    } else if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE){
        //Handle rotation from portrait to landscape mode here
    }
}

ঘূর্ণন সীমাবদ্ধ করুন

ঘূর্ণন এড়ানোর জন্য আপনি নিজের কার্যকলাপ প্রতিকৃতি বা ল্যান্ডস্কেপ মোডেও সীমাবদ্ধ রাখতে পারেন।

আপনার মেনিফেস্ট ফাইলটিতে এটি ক্রিয়াকলাপ ট্যাগটিতে যুক্ত করুন:

        android:screenOrientation="portrait"

অথবা আপনার ক্রিয়াকলাপে এই প্রোগ্রামটিমেটিক্যালি প্রয়োগ করুন:

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
}

11

আমি এটি করতে গিয়ে যেভাবে খুঁজে পেয়েছি তা হ'ল কিছু সংরক্ষণ করার জন্য onRestoreInstanceStateএবং onSaveInstanceStateইভেন্টগুলি ব্যবহার করুন Bundle(এমনকি যদি আপনার কোনও ভেরিয়েবলের সংরক্ষণের প্রয়োজন নাও হয় তবে সেখানে কিছু রাখুন যাতে Bundleখালি নেই)। তারপরে, onCreateপদ্ধতিতে, Bundleখালি কিনা তা পরীক্ষা করে দেখুন এবং যদি এটি হয়, তবে আরম্ভ করুন, যদি না হয়, তবে এটি করুন।


11

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

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


আমি এর কিছু নমুনা কোড দেখতে পছন্দ করব, উজ্জ্বল বলে মনে হচ্ছে!
হেনরিক ডি সোসা

8

প্রতিবার যখন স্ক্রিনটি ঘোরানো হয় তখন খোলা ক্রিয়াকলাপ শেষ হয়ে যায় এবং অনক্রিটকে (আবার) কল করা হয়।

ঘ। স্ক্রিনটি ঘোরার সময় আপনি ক্রিয়াকলাপের অবস্থা বাঁচাতে একটি জিনিস করতে পারেন যাতে, ক্রিয়াকলাপের অনক্রিট () আবার কল করার পরে আপনি সমস্ত পুরানো জিনিস পুনরুদ্ধার করতে পারেন। পড়ুন এই লিংক

ঘ। আপনি যদি ক্রিয়াকলাপটি পুনরায় আরম্ভ করতে বাধা দিতে চান তবে আপনার ম্যানিফেস্ট.এক্সএমএল ফাইলটিতে নিম্নলিখিত লাইনগুলি রাখুন।

  <activity android:name=".Youractivity"
  android:configChanges="orientation|screenSize"/>

7

আপনার প্যারামিটারে সমস্ত মান সংরক্ষণ করতে onSaveInstanceState পদ্ধতিটি ব্যবহার করতে হবে এটি বান্ডিল রয়েছে

@Override
    public void onSaveInstanceState(Bundle outState, PersistableBundle outPersistentState) {
        super.onSaveInstanceState(outState, outPersistentState);
        outPersistentState.putBoolean("key",value);
    }

আর ব্যবহার করুন

@Override
    protected void onRestoreInstanceState(Bundle savedInstanceState) {
        super.onRestoreInstanceState(savedInstanceState);
        savedInstanceState.getBoolean("key");
    } 

পুনরুদ্ধার এবং অবজেক্টগুলি দেখার মান সেট করতে এটি স্ক্রিনের ঘূর্ণন পরিচালনা করবে


এই API স্তর 22. প্রয়োজন
মোঃ Afrashteh

6

দ্রষ্টব্য: ভবিষ্যতে যদি কেউ আমার মতো একই সমস্যার মুখোমুখি হয় তবে আমি এই উত্তরটি পোস্ট করি। আমার জন্য নিম্নলিখিত লাইনটি কল্পনা করা হয়নি:

android:configChanges="orientation"

আমি যখন স্ক্রিনটি ঘোরালাম তখন `onConfigrationChanged (কনফিগারেশন নিউকনফিগ) পদ্ধতিটি কল করা হয়নি।

সমাধান: সমস্যাটি ওরিয়েন্টেশনের সাথে সম্পর্কিত হলেও আমাকে "স্ক্রিনসাইজ" যুক্ত করতে হয়েছিল। সুতরাং AndroidManLive.xML - ফাইলটিতে এটি যুক্ত করুন:

android:configChanges="keyboardHidden|orientation|screenSize"

তারপরে পদ্ধতিটি বাস্তবায়ন করুন onConfigurationChanged(Configuration newConfig)




4

লোকেরা বলছে যে আপনার ব্যবহার করা উচিত

android:configChanges="keyboardHidden|orientation"

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

অবশ্যই, অন্য উপায় হিসাবে, আপনি onSaveInstanceState এর সাথে মানগুলি বা ভিউগুলি সংরক্ষণ করতে এবং ওনস্টোরআইনস্ট্যান্সস্টেটের সাথে সেগুলি পড়তে পারেন। এটা সত্যিই আপনার উপর নির্ভর করে।


হ্যাঁ, "পেশাদার" দেখতে অতিরিক্ত কোডের গবগুলি যুক্ত করা যাক। অথবা কীভাবে কনফিগারেশন পরিবর্তন বৈশিষ্ট্য সহ এটি করার চটজলদি, সহজ, সত্য এবং চেষ্টা করার পদ্ধতিতে কীভাবে আটকে থাকুন।
অ্যান্ড্রয়েডদেভ

3

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

ম্যানিফেস্ট কনফিগারেশন:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
          package="com.pepperonas.myapplication">

    <application
        android:name=".App"
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity
            android:name=".MainActivity"
            android:configChanges="orientation|keyboardHidden|screenSize">
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>

                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>
    </application>

</manifest>

প্রধান কাজ:

import android.content.res.Configuration;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.Button;

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    private static final String TAG = "MainActivity";

    private Fragment mFragment;

    private int mSelected = -1;


    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.d(TAG, "onCreate  " + "");

        // null check not realy needed - but just in case...
        if (savedInstanceState == null) {

            initUi();

            // get an instance of FragmentTransaction from your Activity
            FragmentManager fragmentManager = getSupportFragmentManager();
            FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();

            /*IMPORTANT: Do the INITIAL(!) transaction only once!
            * If we call this everytime the layout changes orientation,
            * we will end with a messy, half-working UI.
            * */
            mFragment = FragmentOne.newInstance(mSelected = 0);
            fragmentTransaction.add(R.id.frame, mFragment);
            fragmentTransaction.commit();
        }
    }


    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        Log.d(TAG, "onConfigurationChanged  " +
                   (newConfig.orientation
                    == Configuration.ORIENTATION_LANDSCAPE
                    ? "landscape" : "portrait"));

        initUi();

        Log.i(TAG, "onConfigurationChanged - last selected: " + mSelected);
        makeFragmentTransaction(mSelected);
    }


    /**
     * Called from {@link #onCreate} and {@link #onConfigurationChanged}
     */
    private void initUi() {
        setContentView(R.layout.activity_main);
        Log.d(TAG, "onCreate  instanceState == null / reinitializing..." + "");
        Button btnFragmentOne = (Button) findViewById(R.id.btn_fragment_one);
        Button btnFragmentTwo = (Button) findViewById(R.id.btn_fragment_two);
        btnFragmentOne.setOnClickListener(this);
        btnFragmentTwo.setOnClickListener(this);
    }


    /**
     * Not invoked (just for testing)...
     */
    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        Log.d(TAG, "onSaveInstanceState  " + "YOU WON'T SEE ME!!!");
    }


    /**
     * Not invoked (just for testing)...
     */
    @Override
    protected void onRestoreInstanceState(Bundle savedInstanceState) {
        super.onRestoreInstanceState(savedInstanceState);
        Log.d(TAG, "onSaveInstanceState  " + "YOU WON'T SEE ME, AS WELL!!!");
    }


    @Override
    protected void onResume() {
        super.onResume();
        Log.d(TAG, "onResume  " + "");
    }


    @Override
    protected void onPause() {
        super.onPause();
        Log.d(TAG, "onPause  " + "");
    }


    @Override
    protected void onDestroy() {
        super.onDestroy();
        Log.d(TAG, "onDestroy  " + "");
    }


    @Override
    public void onClick(View v) {

        switch (v.getId()) {
            case R.id.btn_fragment_one:
                Log.d(TAG, "onClick btn_fragment_one " + "");
                makeFragmentTransaction(0);
                break;

            case R.id.btn_fragment_two:
                Log.d(TAG, "onClick btn_fragment_two " + "");
                makeFragmentTransaction(1);
                break;

            default:
                Log.d(TAG, "onClick  null - wtf?!" + "");
        }
    }


    /**
     * We replace the current Fragment with the selected one.
     * Note: It's called from {@link #onConfigurationChanged} as well.
     */
    private void makeFragmentTransaction(int selection) {

        switch (selection) {
            case 0:
                mFragment = FragmentOne.newInstance(mSelected = 0);
                break;
            case 1:
                mFragment = FragmentTwo.newInstance(mSelected = 1);
                break;
        }

        // Create new transaction
        FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();

        // Replace whatever is in the fragment_container view with this fragment,
        // and add the transaction to the back stack
        transaction.replace(R.id.frame, mFragment);

        /*This would add the Fragment to the backstack...
        * But right now we comment it out.*/
        //        transaction.addToBackStack(null);

        // Commit the transaction
        transaction.commit();
    }

}

এবং নমুনা খণ্ড:

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

/**
 * @author Martin Pfeffer (pepperonas)
 */
public class FragmentOne extends Fragment {

    private static final String TAG = "FragmentOne";


    public static Fragment newInstance(int i) {
        Fragment fragment = new FragmentOne();
        Bundle args = new Bundle();
        args.putInt("the_id", i);
        fragment.setArguments(args);
        return fragment;
    }


    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        Log.d(TAG, "onCreateView  " + "");
        return inflater.inflate(R.layout.fragment_one, container, false);
    }

}

গিথুব পাওয়া যাবে ।


3

orientationবিভিন্ন শ্রেনীর উপর বিভিন্ন কাজ সম্পাদন করতে শ্রোতাদের ব্যবহার করুন ।

@Override
public void onConfigurationChanged(Configuration myConfig) 
{
    super.onConfigurationChanged(myConfig);
    int orient = getResources().getConfiguration().orientation; 
    switch(orient) 
    {
       case Configuration.ORIENTATION_LANDSCAPE:
          setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
                    break;
       case Configuration.ORIENTATION_PORTRAIT:
          setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
                    break;
       default:
          setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
    }
}

3

আপনার কোড নিচে এই রাখুন Activityমধ্যে Android Manifest

android:configChanges="orientation"

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


2
@ মাভামার্টেন সম্ভবত কারণ অন্যরা যেমন বলেছে, এটি খারাপ অভ্যাস এবং অন্য দশটি উত্তর ইতিমধ্যে এটি কভার করেছে।
মিক্কোপ

3

এর মধ্যে স্ক্রিন ওরিয়েন্টেশন (ল্যান্ডস্কেপ বা প্রতিকৃতি) ঠিক করুন AndroidManifest.xml

android:screenOrientation="portrait" অথবা android:screenOrientation="landscape"

এই জন্য আপনার onResume()পদ্ধতি বলা হয় না।


5
কীভাবে কিছু ঠিক করার একটা উত্তর? আমরা যদি ব্যবহারকারীদের এটি ব্যবহার করে লক করি তবে আমাদের ডিভাইসগুলি কেন ঘোরানো যাবে?
পুনরায়হিন্ড

3

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

এটি ইউআই সম্পর্কিত তথ্য লাইফসাইकल উপায়ে সংরক্ষণ এবং পরিচালনা করতে ডিজাইন করা হয়েছে যা স্ক্রিনটি ঘোরার সাথে সাথে ডেটা টিকে থাকতে পারে

class MyViewModel : ViewModel() {

দয়া করে এটিকে উল্লেখ করুন: https://developer.android.com/topic/libraries/architecture/viewmodel


1

আপনি আপনার ক্রিয়াকলাপে ভিউমোডেল অবজেক্টটি ব্যবহার করতে পারেন।

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

https://developer.android.com/topic/libraries/architecture/viewmodel

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