Еще одно решение: 1) Сначала установите groupIndicator в ExpandableListView равным @null:
<ExpandableListView [...]
android:groupIndicator="@null" />
2) Затем создайте файл group_indicator.xml со следующими подробностями:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/down_icon" android:state_selected="false"></item>
<item android:drawable="@drawable/up_icon" android:state_selected="true"></item>
<item android:drawable="@drawable/down_icon"></item>
</selector>
3) Затем создайте макет group_header.xml со следующими деталями и накачайте этот макет в методе getGroupView () ExpandableListAdapter.java:
<?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="wrap_content"
android:padding="10dp">
<TextView
android:id="@+id/tvHeader"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:textColor="@color/white"
android:layout_centerVertical="true"
android:textSize="16sp"/>
<ImageView
android:id="@+id/ivGroupIndicator"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/group_indicator"
android:layout_centerVertical="true"
android:layout_alignParentRight="true"/>
</RelativeLayout>
3) В методе getGroupView () вашего класса ExpandableListAdapter.java просто установите следующее:
ivGroupIndicator.setSelected(isExpanded);
При таком подходе ваши down_icon и up_icon будут работать правильно. Надеюсь, это поможет.
Это потому, что вы смешиваете SetData / GetData с LogicalSetData / LogicalGetData. Есть статья , в которой вы можете узнать больше о различиях между этими двумя методами. Практическое правило здесь - всегда использовать SetData вместе с GetData и LogicalSetData вместе с LogicalGetData.
Эта модификация сделает ваш тест пройденным:
[Test]
public void aaa()
{
CallContext.SetData("aa", "1");
Action parallelMethod = () => CallContext.SetData("aa", "2");
var r = parallelMethod.BeginInvoke(null, null);
Assert.That(CallContext.GetData("aa"), Is.EqualTo("1"));
parallelMethod.EndInvoke(r);
Assert.That(CallContext.GetData("aa"), Is.EqualTo("1"));
}
Поведение, проиллюстрированное вашим примером, действительно задумано. LogicalCallContext может передаваться в двух направлениях через асинхронный вызов или удаленный вызов .net. Когда вы вызываете EndInvoke, LogicalCallContext дочернего контекста снова объединяется с родительским, как вы заметили. Это сделано намеренно, чтобы вызывающие удаленные методы могли получить доступ к любым значениям, установленным удаленным методом. Вы можете использовать эту функцию для передачи данных обратно от дочернего, если хотите.
Отлаживая это с помощью степпинга исходного кода .NET Framework, есть явные комментарии на этот счет:
в System.Runtime.Remoting.Proxies.RemotingProxy.Invoke:
case Message.EndAsync:
// This will also merge back the call context
// onto the thread that called EndAsync
RealProxy.EndInvokeHelper(m, false);
в System.Runtime.Remoting.Proxies.RealProxy.EndInvokeHelper:
// Merge the call context back into the thread that
// called EndInvoke
CallContext.GetLogicalCallContext().Merge(
mrm.LogicalCallContext);
Если вы хотите избежать слияния данных, его довольно легко пропустить, просто избегайте вызова EndInvoke из основного потока. Вы можете, например, использовать ThreadPool.QueueUserWorkItem, который передает LogicalCallContext в , но не выводится, или вызывать EndInvoke из AsyncCallback.
Если посмотреть на пример на сайте Microsoft Connect, причина того, что вы: Если вы не видите, что значение LogicalSetData возвращается из вызова RunWorkerCompleted, это означает, что BackgroundWorker не передает контекст обратно. Кроме того, помните, что LogicalSetData - это не то же самое, что и локальное хранилище потока, поэтому не имеет значения, что RunWorkerCompleted выполняется в потоке пользовательского интерфейса - у LogicalCallContext все еще есть дочерний контекст, и если родитель явно не вернет его обратно, вызвав EndInvoke из порождающего потока, он будет оставлен. Если вам нужно локальное хранилище потока, вы можете получить к нему доступ из потока, например:
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
Thread.SetData(Thread.GetNamedDataSlot("foo"), "blah!!");
}
private void button1_Click(object sender, EventArgs e)
{
var val = (string)Thread.GetData(Thread.GetNamedDataSlot("foo"));
MessageBox.Show(val ?? "no value");
}
В этом примере появляется MessageBox с отображением «blah !!». Причина в том, что оба обратных вызова выполняются в потоке пользовательского интерфейса, поэтому имеют доступ к одному и тому же локальному хранилищу потока.
Надеюсь, это поможет прояснить ситуацию.