Xamarin.Android WebView App性能问题

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Xamarin.Android WebView App性能问题相关的知识,希望对你有一定的参考价值。

我正在开发一个Xamarin.android应用程序,该应用程序正在遭遇性能问题。

该应用包含以下内容:

  • 启动画面延迟1秒。
  • 主要活动包括视图寻呼机,标签式布局,9个片段,广告视图。
  • 每个片段都包含Webview。

主要活动代码:

namespace XXXXX
{
   [Activity(Label = "XXX", Theme = "@style/AppTheme", ScreenOrientation = 
  Android.Content.PM.ScreenOrientation.Portrait)]
public class MainActivity : AppCompatActivity
{
    AdView adView;
    protected override void OnCreate(Bundle savedInstanceState)
    {
        base.OnCreate(savedInstanceState);

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

        Toolbar toolbar = FindViewById<Toolbar>(Resource.Id.toolbar);
      SetSupportActionBar(toolbar);
        Window.AddFlags(WindowManagerFlags.DrawsSystemBarBackgrounds);
        var fragments = new Fragment[]
       {
            new homeFragment(),
            new XXXFragment(),
            new XXXFragment(),
            new XXXFragment(),
            new XXXFragment(),
            new XXXFragment(),
            new XXXFragment(),
            new XXXFragment(),
            newXXXFragment(),

       };


        var titles = CharSequence.ArrayFromStringArray(new[]
            {
                "XXX",
                "XXX",
                "XXX",
                "XXX",
                 "XXX",
                "XXX",
                "XXX",
                "XXX",
                "XXX"
            });

        var viewPager = FindViewById<ViewPager>(Resource.Id.viewpager);
        viewPager.OffscreenPageLimit = 1;
        viewPager.Adapter = new TabsFragmentPagerAdapter(SupportFragmentManager, fragments, titles);

        // Give the TabLayout the ViewPager
        var tabLayout = FindViewById<TabLayout>(Resource.Id.sliding_tabs);
        tabLayout.SetupWithViewPager(viewPager);
        var isConnected = CrossConnectivity.Current.IsConnected;

        if (isConnected)
        {

            Task.Run(() =>
            {
                // Log.Debug("TAG", "InstanceID token: " + FirebaseInstanceId.Instance.Token);dddd
                var instanceid = FirebaseInstanceId.Instance;
                instanceid.DeleteInstanceId();
                Log.Debug("TAG", "{0} {1}", instanceid.Token, instanceid.GetToken(this.GetString(Resource.String.gcm_defaultSenderId), Firebase.Messaging.FirebaseMessaging.InstanceIdScope));
            });
            FirebaseMessaging.Instance.SubscribeToTopic("custom");

        }
        var iid = "#####";
        Android.Gms.Ads.MobileAds.Initialize(ApplicationContext, iid);
        adView = FindViewById<AdView>(Resource.Id.adView);
        AdRequest adRequest = new AdRequest.Builder().Build();
        adView.LoadAd(adRequest);
        adView.BringToFront();
    }
    protected override void OnResume()
    {
        if (adView != null) adView.Resume();
        base.OnResume();
    }
    protected override void OnPause()
    {
        if (adView != null) adView.Pause();
        base.OnPause();
    }
    public override bool OnCreateOptionsMenu(IMenu menu)
    {
        MenuInflater.Inflate(Resource.Menu.top_menus, menu);


        return base.OnCreateOptionsMenu(menu);

    }
    public override bool OnOptionsItemSelected(IMenuItem item)
    {

        Intent intent;
        switch (item.ItemId)
        {

            case Resource.Id.nav_feedback:

                intent = new Intent(this, typeof(Feedback));
                StartActivity(intent);
                return true;

            case Resource.Id.nav_settings:
                intent = new Intent(this, typeof(Settings));
                StartActivity(intent);
                return true;

            default:
                break;
        }


        return base.OnOptionsItemSelected(item);

    }

   }
  }

每个片段包含:

namespace XXXXX
 {
public class HomeFragment : Fragment
{
    public ProgressBar progress;
    public WebView mWebView;

    public override void OnCreate(Bundle savedInstanceState)
    {
        base.OnCreate(savedInstanceState);

        // Create your fragment here

    }

    public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
    {


      View  view = inflater.Inflate(Resource.Layout.HomeFragmentLayout, container, false);
        mWebView = view.FindViewById<WebView>(Resource.Id.webView1);

        progress = view.FindViewById<ProgressBar>(Resource.Id.progressBar);
         progress.Visibility = ViewStates.Visible;










        mWebView.Settings.DomStorageEnabled = true;
        mWebView.Settings.javascriptEnabled = true;

        mWebView.Settings.LoadWithOverviewMode = true;
        mWebView.Settings.UseWideViewPort = true;
        mWebView.Settings.SetSupportZoom(false);
        mWebView.Settings.BuiltInZoomControls = false;
        mWebView.Settings.SetEnableSmoothTransition(true);
        mWebView.Settings.SetAppCacheEnabled(true);
        mWebView.Settings.SetAppCacheMaxSize(1024 * 1024 * 8);
        mWebView.Settings.SetAppCachePath(Context.CacheDir.ToString());


        if (Build.VERSION.SdkInt >= BuildVersionCodes.Kitkat)
            mWebView.SetLayerType(LayerType.Hardware, null);
        else
            mWebView.SetLayerType(LayerType.Software, null);

        mWebView.LoadUrl("link");

        mWebView.SetWebViewClient(new HybridWebViewClient(Context, this));
        mWebView.SetWebChromeClient(new WebChromeClient());
        if (CrossConnectivity.Current.IsConnected)
        {
            mWebView.Settings.CacheMode = CacheModes.Default;
            mWebView.Reload();
        }
        else
        {
            mWebView.Settings.CacheMode = CacheModes.CacheElseNetwork;
        }


        return view;

    }




    public class HybridWebViewClient : WebViewClient
    {



        private Context context;
        private HomeFragment homeFragment;
        public HybridWebViewClient(Context context, HomeFragment homeFragment)
        {
            this.context = context;
            this.homeFragment = homeFragment;
        }



        public override bool ShouldOverrideUrlLoading(WebView view, string url)
        {
            System.Diagnostics.Debug.WriteLine("ShouldOverrideUrlLoading:" + url);
            if (url.StartsWith("whatsapp:") || url.StartsWith("tel:"))
            {
                Intent intent = new Intent(Intent.ActionView,
                        Android.Net.Uri.Parse(url));
                context.StartActivity(intent);
                return true;
            }
            else if (url.StartsWith("tohttp:"))
            {
                var DetailedNewsIntent = new Intent(context, typeof(DetailedNewsActivity));
                DetailedNewsIntent.PutExtra("Url", url);
                context.StartActivity(DetailedNewsIntent);
                return true;
            }
            else
            {

                view.LoadUrl(url);
                return true;
            }

        }
        public override void OnPageStarted(WebView view, string url, Android.Graphics.Bitmap favicon)
        {


            base.OnPageStarted(view, url, favicon);

        }
        public override void OnPageFinished(WebView view, string url)
        {



            homeFragment.progress.Visibility = ViewStates.Gone;

            base.OnPageFinished(view, url);


        }
        public override void OnReceivedError(WebView view, [GeneratedEnum] ClientError errorCode, string description, string failingUrl)
        {
            base.OnReceivedError(view, errorCode, description, failingUrl);
        }

    }

   }

  }

启动画面:

namespace XXXX
{
 [Activity(Theme = "@style/MyTheme.Splash", NoHistory = true, MainLauncher = 
true)]
public class SplashActivity : Activity
{
    static readonly string TAG = "X:" + typeof(SplashActivity).Name;
    protected override void OnCreate(Bundle savedInstanceState)
    {
        base.OnCreate(savedInstanceState);
        Log.Debug(TAG, "SplashActivity.OnCreate");

        // Create your application here
    }
    protected override void OnResume()
    {
        base.OnResume();

        Task startupWork = new Task(() => {
            Log.Debug(TAG, "Performing some startup work that takes a bit of time.");
            Task.Delay(1000);  // Simulate a bit of startup work.
            Log.Debug(TAG, "Working in the background - important stuff.");
        });


            startupWork.ContinueWith(t => {
                Log.Debug(TAG, "Work is finished - start Activity1.");


                    StartActivity(new Intent(Application.Context, typeof(MainActivity)));
                Finish();


            }, TaskScheduler.FromCurrentSynchronizationContext());

            startupWork.Start();





      }
    }
 }

现在为了提高性能,我已尝试过以下但性能未受到预期的影响

  • 最小启动延迟(静态应用程序需要花时间进行启动
  • viewPager.OffscreenPageLimit = 1; (从1到9)
  • Adview异步(需要同时)

该应用程序花费大部分时间进行启动活动

  • 我想更快地启动应用程序。
  • 想要在交换片段时保持页面加载。 (目前,页面在淹没时闪烁)

应用环境 -

  • XA Marin.Android 8.0
  • 适用于Xamarin 4.7的Visual Studio工具
  • Visual Studio 15.4.3
  • minSDK API - 14
  • 有针对性的SDK API - 25
  • 建筑 - armeabi-v7a

套餐 -

  • Plugin.CurrentActivity
  • Plugin.Share
  • Xam.Plugin.Connectivity
  • XA Marin.Android.support.design 25.4.0.2
  • Xamarin.GooglePlayServices.Ads.Lite 42.1021.1
  • Xamarin.Firebase.Messaging 42.1021.1

请任何人知道调整/提示/黑客提高性能请分享。 TIA !!

答案

FragmentStatePagerAdapter

如果有大量的页面,比如你的9页,你的TabsFragmentPagerAdapter应该扩展FragmentStatePagerAdapter类。因为当片段对用户不可见时,片段可能被破坏,并且它允许寻呼机保持更少的内存,它将具有比FragmentPagerAdapter更好的性能。您可以通过链接比较它们。两者在使用上都相似。

UserVisibleHint

下面是UserVisibleHint的一个简单的片段延迟加载,在你的片段可见之前你不需要加载数据:

public class Fragment1 : Fragment
{
    bool isViewInit;
    bool isDataLoad;
    public override void OnCreate(Bundle savedInstanceState)
    {
        base.OnCreate(savedInstanceState);

        // Create your fragment here
    }

    public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
    {
        // Use this to return your custom view for this Fragment
        var view= inflater.Inflate(Resource.Layout.YourFragment, container, false);
        isViewInit = true;
        return view;
    }

    public override void OnActivityCreated(Bundle savedInstanceState)
    {
        base.OnActivityCreated(savedInstanceState);
        if (UserVisibleHint) {
            loadData();
        }

    }
    public override bool UserVisibleHint {
        get => base.UserVisibleHint;
        set {
            base.UserVisibleHint = value;
            if (UserVisibleHint && isViewInit && !isDataLoad) {
                loadData();
            }

        }
    }

    private void loadData()
    {
        //load your data here
        isDataLoad = true;
    }
}

以上是关于Xamarin.Android WebView App性能问题的主要内容,如果未能解决你的问题,请参考以下文章

在 Xamarin Android App 中使用 webview 上传文件

如果“target=_blank”,Xamarin Android WebView 不会触发导航

Android WebView:用 PDF 显示网站

Xamarin.Form与Xamarin.Android或Xamarin.IOS的区别简述

vs2015 Xamarin.Android安装

Xamarin.Android 反复报 Please Download android_m2repository_rxx.zip 的解决办法