سؤال

لقد كنت أعمل مع Asynctasks في Android وأنا أتعامل مع مشكلة.

خذ مثالًا بسيطًا ، نشاطًا مع Asynctask. المهمة على الخلفية لا تفعل أي شيء مذهل ، فهي تنام فقط لمدة 8 ثوان.

في نهاية Asynctask في طريقة OnPostExecute () أنا فقط أقوم بإعداد حالة وضوح زر لعرضها.

الآن ، يعمل هذا بشكل رائع حتى يقرر المستخدم تغيير اتجاه هواتفه أثناء عمل Asynctask (داخل نافذة النوم الثمانية).

أفهم دورة حياة نشاط Android وأعلم أن النشاط يتم تدميره وإعادة إنشائه.

هذا هو المكان الذي تأتي فيه المشكلة. يشير Asynctask إلى زر ويبدو أنه يحمل إشارة إلى السياق الذي بدأ المراهنات في المقام الأول.

أتوقع ، أن يصبح هذا السياق القديم (نظرًا لأن المستخدم تسبب في تغيير الاتجاه) إما أن يصبح فارغًا وأن يرمي Asynctask NPE للإشارة إلى الزر الذي تحاول إقراره.

بدلاً من ذلك ، لم يتم طرح أي NPE ، يعتقد Asynctask أن مرجع الزر ليس فارغًا ، ويعينه على مرئي. النتائج؟ لا شيء يحدث على الشاشة!

تحديث: لقد تعاملت مع هذا من خلال الحفاظ على ملف WeakReference إلى النشاط والتبديل عند حدوث تغيير التكوين. هذا مرهق.

هذا هو الرمز:

public class Main extends Activity {

    private Button mButton = null;
    private Button mTestButton = null;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        mButton = (Button) findViewById(R.id.btnStart);
        mButton.setOnClickListener(new OnClickListener () {
            @Override
            public void onClick(View v) {
                new taskDoSomething().execute(0l);
            }
        });
        mTestButton = (Button) findViewById(R.id.btnTest);   
    }

    private class TaskDoSomething extends AsyncTask<Long, Integer, Integer> 
    {
        @Override
        protected Integer doInBackground(Long... params) {
            Log.i("LOGGER", "Starting...");
            try {
                Thread.sleep(8000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return 0;
        }

        @Override
        protected void onPostExecute(Integer result) {
            Log.i("LOGGER", "...Done");
            mTestButton.setVisibility(View.VISIBLE);
        }
    }
}

حاول تنفيذها ، وبينما يعمل Asynctask ، قم بتغيير اتجاه الهواتف الخاصة بك.

هل كانت مفيدة؟

المحلول

لم يتم تصميم Asynctask لإعادة استخدامه بمجرد هدم النشاط وإعادة تشغيله. يصبح كائن المعالج الداخلي قديمة ، تمامًا كما ذكرت. في مثال الرفوف التي كتبها رومان جاي ، يقوم بإلغاء أي من Asynctask يقوم حاليًا بإعادة تشغيل تغييرات جديدة بعد التوجه.

من الممكن تسليم خيطك إلى النشاط الجديد ، لكنه يضيف الكثير من السباكة. لا يوجد عمومًا متفقًا على الطريق للقيام بذلك ، ولكن يمكنك أن تقرأ عن طريقتي هنا: http://foo.jasonhudgins.com/2010/03/simple-progressbar-tutorial.html

نصائح أخرى

إذا كنت بحاجة فقط إلى سياق ولن تستخدمه لأشياء واجهة المستخدم ، فيمكنك ببساطة تمرير ApplicationContext إلى Asynctask. غالبًا ما تحتاج إلى سياق موارد النظام ، على سبيل المثال.

لا تحاول تحديث واجهة المستخدم من Asynctask ومحاولة تجنب التعامل مع تغييرات التكوين بنفسك لأنه يمكن أن يكون فوضويًا. من أجل تحديث واجهة المستخدم ، يمكنك تسجيل مستقبل البث وإرسال بث.

يجب أن يكون لديك أيضًا Asynctask كطبقة عامة منفصلة عن النشاط كما هو مذكور أعلاه ، مما يجعل الاختبار أسهل كثيرًا. لسوء الحظ ، غالبًا ما تعزز برمجة Android الممارسات السيئة والأمثلة الرسمية لا تساعد.

هذا هو نوع الشيء الذي يقودني إلى منع نشاطي دائمًا من تدمير/إعادة إنشاء تغيير التوجيه.

للقيام بذلك أضف هذا إلى الخاص بك <Activity> علامة في ملف البيان الخاص بك:

android:configChanges="orientation|keyboardHidden" 

وتجاوز onConfigurationChanged في فصل النشاط الخاص بك:

@Override
public void onConfigurationChanged(final Configuration newConfig)
{
    // Ignore orientation change to keep activity from restarting
    super.onConfigurationChanged(newConfig);
}

لتجنب ذلك ، يمكنك استخدام الإجابة givin هنا: https://stackoverflow.com/a/2124731/327011

ولكن إذا كنت بحاجة إلى تدمير النشاط (تخطيطات مختلفة للصور والمناظر الطبيعية) ، فيمكنك جعل المزامنة غير متزامنة فئة عامة (اقرأ هنا لماذا لا ينبغي أن تكون خاصة Android: توصيات Asynctask: الطبقة الخاصة أو الطبقة العامة؟) ثم قم بإنشاء طريقة setActivity لتعيين الإشارة إلى النشاط الحالي كلما تم تدميره/إنشاؤه.

يمكنك الاطلاع على مثال هنا: Android Asynctask في الفصل الخارجي

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top