Android Launcher 专属页和生活页的实现(二)

本文介绍了一种不依赖Widget结构直接加载其他APK视图到Android Launcher的方法,包括获取应用上下文、视图及执行相关函数的过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

渴望是所有成就的起点。

Android Launcher 专属页和生活页的实现(一)章节中,讲解了采用自定义的widget加载到桌面来显示专属页,其中讲到Widget的界面并不是采用RemoteViews,而是用createPackageContext 获取的上下文来加载的其他包的view来替代RemoteView。
那我们可不可以完全脱离widget结构,直接获取其他APK的view加载到桌面呢?当然可以了。

获得APP的上下文Context

Context mRemovteContext = newWidgetContext(context, packagename);
public static Context newWidgetContext(Context context, String packageName) {
        //CONTEXT_INCLUDE_CODE的意思是包括代码,也就是说可以执行这个包里面的代码
        //CONTEXT_IGNORE_SECURITY的意思是忽略安全警告,如果不加这个标志的话,有些功能是用不了的,会出现安全警告。
        int contextPermission = Context.CONTEXT_INCLUDE_CODE | Context.CONTEXT_IGNORE_SECURITY;

        Context theirContext = null;
        try {
            //获取其他应用的上下文
            theirContext = context.createPackageContext(packageName, contextPermission);
        } catch (NameNotFoundException e) {
            e.printStackTrace();
        }
        return theirContext;
    }

获得APP的View视图

根据获取的mRemovteContext获得APP视图View。

//"page_main"是其他APP的布局名称
View mRootView = createView(mRemoteContext, packagename, "page_main");
public static View createView(Context remoteContext, String packagename, String resource) {
        Context theirContext = remoteContext;

        if (theirContext == null) {
            return null;
        }
        LayoutInflater theirInflater = (LayoutInflater) theirContext
                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);

        theirInflater = theirInflater.cloneInContext(theirContext);
        //通过其他包的上下文获得该包的Resources对象
        Resources r = theirContext.getResources();

        int id = 0;
        //getIdentifier()方法可以方便的获各应用包下的指定资源ID。
        //第一个参数为资源名称,第二个为资源属性是ID或者是Drawable或者是layout,第三个为包名。
        id = r.getIdentifier(resource, "layout", packagename);

        if (id == 0) {
            Log.e(TAG, "ERROR! can't get root layout id.");
            return null;
        }
        View v = null;

        try {
            //inflate方法的主要作用就是将xml转换成一个View对象,用于动态的创建布局
            v = theirInflater.inflate(id, null);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return v;
    }

获得APP的函数并执行

要获取APP的函数,我们这里用到Java的反射机制,在上文获得了mRootView类对象,通过getClass方法获得mRootView的Class。再通过Class的getDeclaredMethod*()获取类自身声明的所有方法,包含public、protected和private方法。
从Launcher界面看,我们要获取以下信息:
1、预览图

    public Drawable getPreviewImg() {
            try {
                Method m = null;
                if (mRootView!= null) {
                    //getDeclaredMethod方法返回一个Method对象,该对象反映此Class对象所表示的类或接口的指定已声明方法。"getPreviewImg"为方法名称
                    m = mRootView.getClass().getDeclaredMethod("getPreviewImg", Integer.TYPE);
                    if (m != null) {
                        //invoke方法:对带有指定参数的指定对象调用由此Method对象mRootView表示的基础方法getPreviewImg。
                        return (Drawable) m.invoke(mRootView, 0);
                    }
                }
            } catch (Exception e) {

                e.printStackTrace();
            }
            return null;
        }

2、应用的Title名称
和上文一样,同样采用java反射机制,不在详细叙述:
mRootView.getClass().getDeclaredMethod("getTitleName", Integer.TYPE);
3、页面滑动指示图标
同上文,
info.mRootView.getClass().getDeclaredMethod("getIndicatorIcons", Integer.TYPE);
4、Hotseat的三个快捷图标信息
info.mRootView.getClass().getDeclaredMethod("getDockIntent1Name", Integer.TYPE)

总结分析

········上文通过获得APP的上下文,在通过这个上下文获得APP的视图View。然后又在通过Java反射机制,获得APP的相关信息,在把这个View添加到Launcher的Workspace上,专属页就出现了。

········其实,通过上文的解析,我们可以想象出APP中那个View是如果实现的。
1、 获得APP的View视图
View mRootView = createView(mRemoteContext, packagename, "page_main");

该方法告诉了我们APP的布局文件是:page_main.xml

2、获得APP的函数并执行
mRootView.getClass().getDeclaredMethod("getPreviewImg", Integer.TYPE);
该方法告诉我们,获取的View对象有函数getPreviewImg(),是个自定义的函数,由此我们可以判断出page_main.xml是由一个自定的视图View类组成。并且改类中有:getPreviewImg()、getTitleName()、getIndicatorIcons()、getDockIntent1Name()等函数。

········这一节我们讲到了Java的反射机制。其实我们在Android Launcher 专属页和生活页的实现(一)章节中谈到的实现方法中,也要涉及到Java的反射机制,因为我们的专属页面要和Launcher桌面的生命周期同步,为什么要同步呢,为什么不是原生widget的那种生命周期呢,因为我们做专属页虽然有widget的躯壳,但是缺乏widget的更新机制,再加上我们的专属页比较复杂。所以,我们在Launcher的声明周期中,采用Java的反射机制同时响应专属页应用的相关函数。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值