Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/185.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/xamarin/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Android 为什么在线程中添加自定义视图时跳过测量过程?_Android_Xamarin_Xamarin.android_Measure - Fatal编程技术网

Android 为什么在线程中添加自定义视图时跳过测量过程?

Android 为什么在线程中添加自定义视图时跳过测量过程?,android,xamarin,xamarin.android,measure,Android,Xamarin,Xamarin.android,Measure,在Android中使用自定义视图时,我注意到以下布局调用的差异。在LinearLayout中,我有两个来自FrameLayout的自定义视图。使用RunOnUiThread()方法将第一个FrameLayout添加到非UI线程中。第二个FrameLayout是使用UIThread添加的 现在我注意到的区别是,直接使用UIThread添加的FrameLayout的度量命中为2。而使用RunOnUiThread()从非UIThread添加的FrameLayout的度量命中率为1。通常在Android

在Android中使用自定义视图时,我注意到以下布局调用的差异。在LinearLayout中,我有两个来自FrameLayout的自定义视图。使用RunOnUiThread()方法将第一个FrameLayout添加到非UI线程中。第二个FrameLayout是使用UIThread添加的

现在我注意到的区别是,直接使用UIThread添加的FrameLayout的度量命中为2。而使用RunOnUiThread()从非UIThread添加的FrameLayout的度量命中率为1。通常在Android中,自定义视图的命中率为2。但是为什么在使用RunOnUiThread()选项添加视图时跳过第二次测量过程?

在Xamarin.Android中使用线程时,有人知道布局过程中出现这种差异的原因吗? 我已附上我的主要活动代码供您参考:

MainActivity.cs

公共类main活动:活动
{
整数计数=1;
创建时受保护的覆盖无效(捆绑包)
{
base.OnCreate(bundle);
//从“主”布局资源设置视图
SetContentView(Resource.Layout.Main);
var view=findviewbyd(Resource.Id.Linear);
Task.Factory.StartNew(()=>
{
系统.线程.线程.睡眠(500);
RunOnUiThread(()=>
{
var threadView=新的CustomViewInsideThread(此);
view.AddView(threadView);
});
});
var nonThreadView=new CustomViewOusideThread(此);
AddView(非线程视图);
}
}
公共类CustomViewInsideThread:FrameLayout
{
公共CustomViewInsideThread(上下文)
:基本(上下文)
{
}
整数命中率=0;
测量时受保护的覆盖无效(int-widthMeasureSpec、int-heightMeasureSpec)
{
测量基础(宽度测量等级、高度测量等级);
命中率++;
Console.WriteLine(“度量命中率”+hitCount.ToString()+“时间”);
}
}
公共类CustomViewOutsideThread:FrameLayout
{
公共CustomViewOutsideThread(上下文)
:基本(上下文)
{
}
整数命中率=0;
测量时受保护的覆盖无效(int-widthMeasureSpec、int-heightMeasureSpec)
{
测量基础(宽度测量等级、高度测量等级);
命中率++;
Console.WriteLine(“度量命中率”+hitCount.ToString()+“时间”);
}
}
Main.axml


这与
RunOnUiThread
无关。你欺骗了自己,因为这是一个时间问题。该度量被调用两次,因为视图是在android正确度量所有内容之前添加的。这意味着,android将多次调用该度量

当您在一个按钮上添加视图或者在UI线程上稍等一下(非阻塞)时,您可以重现这种情况

[活动(Label=“App3”,MainLauncher=true,Icon=“@drawable/Icon”)]
公共课活动:活动
{
整数计数=1;
创建时受保护的覆盖无效(捆绑包)
{
base.OnCreate(bundle);
SetContentView(Resource.Layout.Main);
var btn=findviewbyd(Resource.Id.btn);
//单击按钮添加视图
点击+=(发送者,参数)=>
{
var view=findviewbyd(Resource.Id.Linear);
var nonThreadView=new CustomViewOusideThread(此);
AddView(非线程视图);
};
}
受保护的异步重写void OnStart()
{
base.OnStart();
var view=findviewbyd(Resource.Id.Linear);
Task.Factory.StartNew(()=>
{
系统.线程.线程.睡眠(1500);
RunOnUiThread(()=>
{
var threadView=新的CustomViewInsideThread(此);
view.AddView(threadView);
});
});
等待任务。延迟(1000);//UI线程上的非阻塞等待
var nonThreadView=new CustomViewOusideThread(此);
AddView(非线程视图);
}
} 
两者都将为您提供:

03-14 16:33:15.990输入/单声道标准输出(31936):用户界面测量命中1次


可能与您的问题无关,但您是否注意到,您调用了
SetContentView(Resource.Layout.Main)两次!?还有:你能添加Main.axml吗?嗨@Sven MichaelStübe,对不起,这是我错误地添加了两次,对这个问题没有任何影响。我已经添加了Main.axml代码。您好@Sven Michael Stube,谢谢您的解释。这是否意味着在我的代码中删除或减少睡眠时间应该可以解决这个问题?嗨@Sven Michael Stube,我并不清楚你的这一点。“测量被调用了两次,因为视图是在android正确测量所有内容之前添加的。”你能告诉我在哪里可以找到这些测量调用的详细信息以及它的工作,以便更好地理解吗?可能是它解决了问题,但这是一个时间问题/竞争条件。因此,只要使用
RunOnUiThread
,您就无法确定什么是第一位的。调度器决定何时执行您的操作。为什么
OnMeasure
调用的数量对您来说至关重要?通常,结果不应该取决于调用的数量,而应该只取决于内容和度量规范。我的意思是,OnMeasure
不应该只调用一次。向您展示生命周期。如您所见,测量是在将视图添加到父视图(
onAttachedToWindow
)之后完成的,如果执行了
requestLayout
。我有一个自定义视图,通常会发生两次测量命中。我的基本上是一个表视图,其中列的宽度可以自定义。如果在使用默认值之外的值命中onAttachedToWindow之前更改列的宽度,我将在fir期间应用该新宽度
public class MainActivity : Activity
{
    int count = 1;

    protected override void OnCreate(Bundle bundle)
    {
        base.OnCreate(bundle);

        // Set our view from the "main" layout resource
        SetContentView(Resource.Layout.Main);

        var view = FindViewById<LinearLayout>(Resource.Id.Linear);
        Task.Factory.StartNew(() =>
        {
            System.Threading.Thread.Sleep(500);
            RunOnUiThread(() =>
            {
                var threadView = new CustomViewInsideThread(this);
                view.AddView(threadView);
            });
        });

        var nonThreadView = new CustomViewOusideThread(this);
        view.AddView(nonThreadView);
    }
}

public class CustomViewInsideThread : FrameLayout
{
    public CustomViewInsideThread(Context context)
        : base(context)
    {

    }
    int hitCount = 0;
    protected override void OnMeasure(int widthMeasureSpec, int heightMeasureSpec)
    {
        base.OnMeasure(widthMeasureSpec, heightMeasureSpec);
        hitCount++;
        Console.WriteLine("Measure hit " + hitCount.ToString() + "time");
    }
}

public class CustomViewOusideThread : FrameLayout
{
    public CustomViewOusideThread(Context context)
        : base(context)
    {

    }
    int hitCount = 0;
    protected override void OnMeasure(int widthMeasureSpec, int heightMeasureSpec)
    {
        base.OnMeasure(widthMeasureSpec, heightMeasureSpec);
        hitCount++;
        Console.WriteLine("Measure hit " + hitCount.ToString() + "time");
    }
}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:id="@+id/Linear"
    android:layout_height="fill_parent" />
[Activity(Label = "App3", MainLauncher = true, Icon = "@drawable/icon")]
public class MainActivity : Activity
{
    int count = 1;

    protected override void OnCreate(Bundle bundle)
    {
        base.OnCreate(bundle);

        SetContentView(Resource.Layout.Main);
        var btn = FindViewById<Button>(Resource.Id.btn);

        // add view on button click
        btn.Click += (sender, args) =>
        {
            var view = FindViewById<LinearLayout>(Resource.Id.Linear);
            var nonThreadView = new CustomViewOusideThread(this);
            view.AddView(nonThreadView);
        };
    }

    protected async override void OnStart()
    {
        base.OnStart();

        var view = FindViewById<LinearLayout>(Resource.Id.Linear);


        Task.Factory.StartNew(() =>
        {
            System.Threading.Thread.Sleep(1500);
            RunOnUiThread(() =>
            {
                var threadView = new CustomViewInsideThread(this);
                view.AddView(threadView);
            });
        });

        await Task.Delay(1000); // non blocking wait on UI thread
        var nonThreadView = new CustomViewOusideThread(this);
        view.AddView(nonThreadView);

    }
}