launcher widget如何加载自定义视图

       有关launcher的widget加载的过程可以参考下图,主要介绍了从AppWidgetProvider到RemoteViews的整个流程,但是没有画出Launcher是如何显示widget的布局,以及LayoutInflater是如何加载布局的xml的。

launcher widget如何加载自定义视图_第1张图片


       在Launcher加载widget的布局,android主要做了两方面的限制:(1)widget布局中的视图类必须含有RemoteViews的标注;(2)视图类必须是android.view和android.widget包下的视图类,即第三方不能在widget布局中自定义视图类。那如何在widget布局中加载第三方自定义控件呢?答案就是在上图的RemoteViews到LayoutInflter之间想办法,因为上述两个限制都是在LayoutInflater中判断的,所以我们就可以想一个绕过限制并且不影响其他布局加载的方法。

       如何在LayoutInflater中绕过上述的限制呢?首先,我们需要分析LayoutInflater是如何加载布局的,如下图所示:


launcher widget如何加载自定义视图_第2张图片


       在LayoutInflater类的createView()方法中,通过ClassLoader类调用loadClass()方法就可以创建视图类。这里有一个问题ClassLoader类是怎么得到的,也许你会说这很简单,直接通过Context.getClassLoader()方法得到。但是又引出另一个问题,LayoutInflater类中的Context是哪个上下文呢?从不同的地方请求LayoutInflater的服务都会传递不同的context给它,此时我们要回想我们的初衷,我们的初衷是什么?我们初衷就是在launcher加载自定义的视图类,所以我们请求LayoutInflater的服务时传递给它的Context是launcher的上下文。

       通过launcher的context去获得第三方apk(假设是音乐apk)自定义视图类是拿不到的,一定会报class not found的错误。这跟android的类加载有关, ClassLoader跟package是绑定的,在LoadApk类中我们可以看到相关的代码。因此我们需要拿到第三方apk的Context对象才能获得相应的ClassLoader才能加载自定义的视图类。以下是修改前createView()方法中的一段代码:

launcher widget如何加载自定义视图_第3张图片

然后附上修改后的一段代码:

launcher widget如何加载自定义视图_第4张图片

        通过对比修改前后的代码,我们发现使用createPackageContext创建第三方apk的Context,这样就可以加载第三方自定义的视图类了。为了安全起见,需要根据实际情况限制apk的权限。另外在性能方面,我们知道LayoutInflater的加载过程是相当耗时的,所以我们不应该增加LayoutInflater的负担,这也是android为什么会自己实现解析xml文件类XmlPullParser。

你可能感兴趣的:(launcher widget如何加载自定义视图)