Android нейтрон действительно не может обновить UI нить это?

Посетите Android UI не заперт, так что доступ к пользовательскому интерфейсу в нескольких потоках небезопасен. Таким образом, Android положение может получить доступ только пользовательский интерфейс в потоке пользовательского интерфейса.

Но нет крайних случаев? Позволяет нам доступ к пользовательскому интерфейсу в суб-нить может также сделать программу и запустить его? Далее, мы используем пример, чтобы доказать это.

Создайте новый проект, макет activity_main.xml следующим образом:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    >

    <TextView
        android:id="@+id/main_tv"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="18sp"
        android:layout_centerInParent="true"
        />

</RelativeLayout>

Очень просто, добавьте центрированную TextView

MainActivity код следующим образом:

public class MainActivity extends AppCompatActivity {

    private TextView main_tv;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        main_tv = (TextView) findViewById(R.id.main_tv);

        new Thread(new Runnable() {

            @Override
            public void run() {
                main_tv.setText("子线程中访问");
            }
        }).start();
    }
}

Это очень простые линии, создавая дочерний поток в методе OnCreate и операции доступа к UI.

Нажмите кнопку Выполнить. Вы увидите , что даже в доступе ребенка к теме UI, та же программа разбегаются. Результаты приведены ниже:
Here Вставка рисунка Описание
Эй, это то , что вещь перед обновлением UI нити ребенка отдается его? Действительно ли можно получить доступ к UI в суб-нить?

Для того, чтобы не беспокоиться, это крайний случай, изменение MainActivity следующим образом:

public class MainActivity extends AppCompatActivity {

    private TextView main_tv;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        main_tv = (TextView) findViewById(R.id.main_tv);

        new Thread(new Runnable() {

            @Override
            public void run() {
                try {
                    Thread.sleep(200);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                main_tv.setText("子线程中访问");
            }
        }).start();
    }
}

Пусть ребенок нить для сна 200 миллисекунд, а затем просыпаются доступ UI.

Результаты вы увидите, что распад программы. Ну это нормальное явление. Он бросает следующие исключения очень знакомы:

android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
at android.view.ViewRootImpl.checkThread(ViewRootImpl.java:6581)
at android.view.ViewRootImpl.requestLayout(ViewRootImpl.java:924)

Как разработчик, мы должны внимательно прочитать информацию об этих исключениях, можно найти в таком случае, почему же эти аномалии могут получить доступ к UI. Затем мы анализируем информацию об исключении:

Во-первых, информация из следующего за исключением, возможно, знаете

at android.view.ViewRootImpl.checkThread(ViewRootImpl.java:6581)

Это исключение из метода checkThread из android.view.ViewRootImpl.

А теперь checkThread метод следить за ViewRootImpl взгляд, исходный код следующим образом:

void checkThread() {
    if (mThread != Thread.currentThread()) {
        throw new CalledFromWrongThreadException(
                "Only the original thread that created a view hierarchy can touch its views.");
    }
}

Только тогда несколько строк кода, и mThread является основной поток, когда приложение запущено, его инициализации.

Отсюда можно сделать вывод: Во
время посещения UI, ViewRootImpl будет проверять текущий пользовательский интерфейс , какой поток доступен, если не основной поток, он будет бросать следующее исключение:

Only the original thread that created a view hierarchy can touch its views

Это, кажется, не объяснить, что? Продолжить, чтобы увидеть аномалии

at android.view.ViewRootImpl.requestLayout(ViewRootImpl.java:924)

А теперь посмотрим на метод requestLayout,

@Override
public void requestLayout() {
    if (!mHandlingLayoutInLayoutRequest) {
        checkThread();
        mLayoutRequested = true;
        scheduleTraversals();
    }
}

Это также называется методом checkThread (), чтобы проверить текущую нить, а? В дополнении к проверке нити, кажется, нет никакой информации. Затем указать в scheduleTraversals () метод, чтобы увидеть

void scheduleTraversals() {
    if (!mTraversalScheduled) {
        mTraversalScheduled = true;
        mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
        mChoreographer.postCallback(
                Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
        if (!mUnbufferedInputDispatch) {
            scheduleConsumeBatchedInput();
        }
        notifyRendererOfFramePending();
        pokeDrawLockIfNeeded();
    }
}

PostCallback отметил, что метод второго параметра передается так же, как в фоновом режиме. Это еще раз указывает на идти

final class TraversalRunnable implements Runnable {
    @Override
    public void run() {
        doTraversal();
    }
}

Найдено, а затем продолжать следить за метод doTraversal ().

void doTraversal() {
    if (mTraversalScheduled) {
        mTraversalScheduled = false;
        mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);

        if (mProfile) {
            Debug.startMethodTracing("ViewAncestor");
        }

        performTraversals();

        if (mProfile) {
            Debug.stopMethodTracing();
            mProfile = false;
        }
    }
}

Вы можете увидеть внутри метода performTraversals вызова (), процесс рисования Вид от начала этого метода performTraversals. Код метода PerformTraversals не размещен вне немного дольше, если он продолжает идти с, чтобы научиться рисовать View. И теперь мы знаем, каждый раз , когда вы доступ к пользовательскому интерфейсу, Android будет перерисовать View . Анализ здесь, а на самом деле ненормальный информацию , чтобы помочь нам не большой, он только говорит нам доступ ребенка к резьбе UI , где выбрасывается исключение.
И мы будем думать: При обращении интерфейс, ViewRootImpl вызывает checkThread способ проверить текущий доступ к резьбе UI , который, если это не поток пользовательского интерфейса будет сгенерировано исключение, это не является проблемой. Но почему OnCreate метод для создания MainActivity в интерфейсе доступа к югу нити или обычной программы запуска вместе? ?
Единственное объяснение состоит в том, что метод выполнения OnCreate , что время ViewRootImpl не создавать, а не для проверки текущего потока.

Тогда вы можете пойти так глубоко. Looking ViewRootImpl где, в какое время создания. Ну, двигаться дальше

В ActivityThread мы находим метод handleResumeActivity, следующим образом:

final void handleResumeActivity(IBinder token,
        boolean clearHide, boolean isForward, boolean reallyResume) {
    // If we are getting ready to gc after going to the background, well
    // we are back active so skip it.
    unscheduleGcIdler();
    mSomeActivitiesChanged = true;

    // TODO Push resumeArgs into the activity for consideration
    ActivityClientRecord r = performResumeActivity(token, clearHide);

    if (r != null) {
        final Activity a = r.activity;

        //代码省略

            r.activity.mVisibleFromServer = true;
            mNumVisibleActivities++;
            if (r.activity.mVisibleFromClient) {
                r.activity.makeVisible();
            }
        }

      //代码省略    
}

Вы можете увидеть внутренний метод вызова performResumeActivity, который, конечно, видеть имя метода обратного вызова onResume входа, то мы идем с внешним видом.

public final ActivityClientRecord performResumeActivity(IBinder token,
        boolean clearHide) {
    ActivityClientRecord r = mActivities.get(token);
    if (localLOGV) Slog.v(TAG, "Performing resume of " + r
            + " finished=" + r.activity.mFinished);
    if (r != null && !r.activity.mFinished) {
    //代码省略
            r.activity.performResume();

    //代码省略

    return r;
}

См r.activity.performResume () Эта строка кода, следовать методу performResume следующим образом:

final void performResume() {
    performRestart();

    mFragments.execPendingActions();

    mLastNonConfigurationInstances = null;

    mCalled = false;
    // mResumed is set by the instrumentation
    mInstrumentation.callActivityOnResume(this);

    //代码省略
}

Инструментарий вызова callActivityOnResume метод, callActivityOnResume исходный код следующим образом:

public void callActivityOnResume(Activity activity) {
    activity.mResumed = true;
    activity.onResume();

    if (mActivityMonitors != null) {
        synchronized (mSync) {
            final int N = mActivityMonitors.size();
            for (int i=0; i<N; i++) {
                final ActivityMonitor am = mActivityMonitors.get(i);
                am.match(activity, activity, activity.getIntent());
            }
        }
    }
}

Найдено, activity.onResume (). Это подтверждается, метод performResumeActivity действительно вход onResume метод обратного вызова.

После того, как теперь мы посмотрим назад метод handleResumeActivity, выполняющийся метод обратного вызова performResumeActivity onResume метод,
придет в этот блок кода:

r.activity.mVisibleFromServer = true;
mNumVisibleActivities++;
if (r.activity.mVisibleFromClient) {
    r.activity.makeVisible();
}

makeVisible активности вызова метода, то это должно быть показано, что сделать это, чтобы пойти с избиением.

void makeVisible() {
    if (!mWindowAdded) {
        ViewManager wm = getWindowManager();
        wm.addView(mDecor, getWindow().getAttributes());
        mWindowAdded = true;
    }
    mDecor.setVisibility(View.VISIBLE);
}

Добавить DecorView в WindowManager, беспокоит то, что он теперь должен addView метода WindowManager. И WindowManager является интерфейсом, мы должны найти WindowManager класса реализации работы и WindowManager класс реализации является WindowManagerImpl.

WindowManagerImpl нашел способ addView, следующим образом:

@Override
public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
    applyDefaultToken(params);
    mGlobal.addView(view, params, mDisplay, mParentWindow);
}

Что вызывает addView метод WindowManagerGlobal, теперь заперта
WindowManagerGlobal метода addView:

public void addView(View view, ViewGroup.LayoutParams params,
        Display display, Window parentWindow) {

    //代码省略  


    ViewRootImpl root;
    View panelParentView = null;

    //代码省略

        root = new ViewRootImpl(view.getContext(), display);

        view.setLayoutParams(wparams);

        mViews.add(view);
        mRoots.add(root);
        mParams.add(wparams);
    }

    // do this last because it fires off messages to start doing things
    try {
        root.setView(view, wparams, panelParentView);
    } catch (RuntimeException e) {
        // BadTokenException or InvalidDisplayException, clean up.
        synchronized (mLock) {
            final int index = findViewLocked(view, false);
            if (index >= 0) {
                removeViewLocked(index, true);
            }
        }
        throw e;
    }
}

Наконец ломаются, ViewRootImpl создается в методе addView WindowManagerGlobal в.

Ссылаясь на предыдущий анализ, чтобы подвести итог:
создать ViewRootImpl после метода onResume обратного вызова, и мы ОТКРЫТИЯ создается в OnCreate метод в детской нити и доступ к пользовательскому интерфейсу, в тот момент, ViewRootImpl не создается, не может определить , является ли текущий поток UI нить, так что она может работать одни и те же приложения , не врезаться, но позже пересмотрел программу, нить спать после 200 миллисекунд, программа будет разрушаться. Очевидно , после того, как 200 мс ViewRootImpl была создана, вы можете выполнить метод checkThread , чтобы проверить текущий поток.

Анализ таких тем, как этот блог, Android нейтрон действительно не может обновить поток пользовательского интерфейса это? Дочерний поток создается в OnCreate метода интерфейса доступа крайний случай, это не тщательный анализ исходного кода не известен. Я недавно прочитал интервью вопросы, только чтобы обнаружить, что.

Я также узнал из наблюдения от ненормального источника информации, чтобы найти ответ, как насчет вас?

Опубликовано 81 оригинальные статьи · вона похвала 37 · просмотров 50000 +

рекомендация

отblog.csdn.net/gaolh89/article/details/104012167