سؤال

في مشروع Android الحالي ، واجهت جزءًا من التعليمات البرمجية التالية (حيث قمت بإدراج فضلات التصحيح)

ImageView img = null;

public void onCreate(...) {

    img = (ImageView)findViewById(R.id.image);

    new Thread() {
        public void run() {
            final Bitmap bmp = BitmapFactory.decodeFile("/sdcard/someImage.jpg");
            System.out.println("bitmap: "+bmp.toString()+" img: "+img.toString());
            if ( !img.post(new Runnable() {
                public void run() {
                    System.out.println("setting bitmap...");
                    img.setImageBitmap(bmp);
                    System.out.println("bitmap set.");
                }
            }) ) System.out.println("Runnable won't run!");
            System.out.println("runnable posted");
        }
    }.start();

جديد على تطوير Android ، ووجود غوغل حوله ، أفهم أن هذه هي الطريقة للقيام بالأشياء دون حظر مؤشر ترابط (UI) الرئيسي ، مع استمرار ضبط الصورة على مؤشر ترابط واجهة المستخدم بعد فك التشفير. (على الأقل وفقًا لمطورات Android) (الذي تحققه عن طريق التسجيل Thread.currentThread().getName() في أماكن مختلفة)

حاليا بعض الأحيان الصورة فقط لا تظهر ، وتقول stdout فقط

I/System.out( 8066): bitmap: android.graphics.Bitmap@432f3ee8 img: android.widget.ImageView@4339d698
I/System.out( 8066): runnable posted

مع عدم وجود أثر للرسائل من Runnable. لذلك المظهر لا يمكن تشغيله run(), ، رغم img.post() عائدات true. سحب ImageView في onCreate() وإعلان ذلك final لا يساعد.

أنا جاهل. ما عليك سوى إعداد صورة نقطية مباشرة ، أثناء حظر موضوع واجهة المستخدم ، يقوم بإصلاح الأشياء ، لكنني أريد أن أصطاد الأمور بشكل صحيح. هل يفهم أي شخص ما يحدث هنا؟

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

المحلول

إذا نظرت إلى المستندات View.post هناك بعض المعلومات ذات الصلة:

يمكن استدعاء هذه الطريقة من خارج مؤشر ترابط واجهة المستخدم فقط عندما يتم إرفاق هذا العرض بنافذة.

لأنك تفعل هذا في onCreate, ، من المحتمل أن تكون في بعض الأحيان View لن يتم إرفاقها بالنافذة بعد. يمكنك التحقق من ذلك عن طريق تجاوز onAttachedToWindow ووضع شيء في السجلات وأيضًا تسجيل الدخول عند النشر. سترى أنه عندما يفشل المنشور ، تحدث مكالمة النشر من قبل onAttachedToWindow.

كما ذكر الآخرون ، يمكنك استخدام Activity.runOnUiThread أو توفير معالجك الخاص. ومع ذلك ، إذا كنت تريد القيام بذلك مباشرة من View نفسها ، يمكنك ببساطة الحصول على Viewمعالج:

view.getHandler().post(...);

هذا مفيد بشكل خاص إذا كان لديك طريقة عرض مخصصة تتضمن نوعًا من تحميل الخلفية. هناك أيضًا مكافأة إضافية لعدم الاضطرار إلى إنشاء معالج منفصل جديد.

نصائح أخرى

امتدت ImageView الفصل لحل هذه المشكلة. أجمع Runnables تم تمريرها للنشر أثناء العرض غير متصل بالنافذة وفي onAttachedToWindow بعد جمعها.

public class ImageView extends android.widget.ImageView
{
    List<Runnable> postQueue = new ArrayList<Runnable>();
    boolean attached;

    public ImageView(Context context)
    {
        super(context);
    }

    public ImageView(Context context, AttributeSet attrs)
    {
        super(context, attrs);
    }

    public ImageView(Context context, AttributeSet attrs, int defStyle)
    {
        super(context, attrs, defStyle);
    }

    @Override
    protected void onAttachedToWindow()
    {
        super.onAttachedToWindow();

        attached = true;

        for (Iterator<Runnable> posts = postQueue.iterator(); posts.hasNext();)
        {
            super.post(posts.next());
            posts.remove();
        }
    }

    @Override
    protected void onDetachedFromWindow()
    {
        attached = false;
        super.onDetachedFromWindow();
    }

    @Override
    public boolean post(Runnable action)
    {
        if (attached) return super.post(action);
        else postQueue.add(action);
        return true;
    }
}

أعتقد أن المشكلة هي أنك تقوم بتحديث واجهة المستخدم (ImageView) بخيط منفصل ، وهو ليس مؤشر ترابط واجهة المستخدم. لا يمكن تحديث واجهة المستخدم إلا بواسطة مؤشر ترابط واجهة المستخدم.

يمكنك حل هذا باستخدام معالج:

Handler uiHandler;

public void onCreate(){
    ...
    uiHandler = new Handler(); // This makes the handler attached to UI Thread
    ...
}

ثم استبدل:

if ( !img.post(new Runnable() {

مع

uiHandler.post(new Runnable() {

للتأكد من تحديث ImageView في مؤشر ترابط واجهة المستخدم.

Handler هو مفهوم مربك للغاية ، كما أخذت ساعات من البحث لفهم هذا حقًا ؛)

لا أرى أي شيء خاطئ بشكل واضح بما لديك هناك ؛ يجب أن يتسبب الاتصال في View.Post () على تشغيل مؤشر ترابط واجهة المستخدم. إذا ذهب نشاطك (ربما من خلال دوران الشاشة) ، فلن يتم تحديث ImageView الخاص بك ، لكنني ما زلت أتوقع إدخال السجل ليقول "إعداد صورة نقطية ..." ، حتى لو لم تتمكن من رؤيته.

أقترح تجربة ما يلي ومعرفة ما إذا كان يحدث فرقًا:

1) استخدم log.d (سجل Android القياسي) بدلاً من ذلك system.out

2) تمرير Runnable الخاص بك إلى Activity.runonuithread () بدلاً من View.post ()

استخدم الكود التالي ، يمكنك نشر الكود الخاص بك إلى mainthread في أي وقت في أي مكان ، ولكن لا يعتمد على أي Context أو Activity. يمكن أن تمنع view.getHandler() الفشل أو مملة onAttachedToWindow() المواد وما إلى ذلك

    new Handler(Looper.getMainLooper()).post(new Runnable() {
        @Override
        public void run() {
            //TODO
        }
    });

واجهت نفس المشكلة ، واستخدمت View.Gethandler () فشل أيضًا لأن المعالج لم يكن موجودًا. RunonuithRead () حل المشكلة. من المفترض أن هذا في الواقع يقوم ببعض الانتظار حتى تصبح واجهة المستخدم جاهزة.

كان السبب بالنسبة لي هو استدعاء مهمة تحميل الأيقونة في فئة أساسية والنتيجة التي يتم إرجاعها بهذه السرعة بحيث لم تنظر الفصل الرئيسي عن العرض (getView () في الجزء).

أنا متشكك بعض الشيء في أنه قد يفشل في وقت ما. لكنني الآن مستعد لذلك! شكرا يا رفاق.

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