Android实现通用的ActivityGroup(效果类似Android微博客户端主界面),...

为什么80%的码农都做不了架构师?>>>   hot3.png

2012050811241811

可以说ActivityGroup是Google提供的一个非常优秀的API,但它需要做稍微复杂的重写才能用起来比较方便,本文拟将实现这个稍微复杂的重写。TabActivity作为ActivityGroup唯一的子类却让人大失所望。

  首先来说ActivityGroup的优秀之处以及它的必要性,它为开发者提供了一种可能,这种可能不将Activity作为屏幕的顶级元素(Context)呈现,而是嵌入到ActivityGroup当中。这是一种极大的飞跃,它将场景(Context)细分化了,ActivityGroup是一个主场景,而用户可以通过导航按钮来切换想要的子场景。如使用微博功能,它是一个相当宏大的场景,具有看最新的广播信息、自己发微博、修改资料等子场景,用户可以通过按钮来切换到想要的子场景,而这个子场景仍活动于主场景之中。让一个主场景能拥有多个逻辑处理模块,主场景不再负责子场景逻辑,主场景只负责切换场景的逻辑,即每一个Activity(子场景)拥有一个逻辑处理模块,一个ActivityGroup有多个Activity,却不干预Activity的逻辑,这无疑细分化和模块化了逻辑代码。ActivityGroup和它将要内嵌的Activity所要实现的功能完全可以用只一个Activity来完成,你可以试想,当你把一个ActivityGroup和它所拥有的Activity的逻辑代码放在一个Activity中时,那这个Activity会拥有多少行代码,为维护带来非常的不便。

  再来说说TabActivity的不足之处,首先,TabActivity自己独有的视图几乎没人使用(也就是难看的标签页按钮形式),国内开发者用到的特性几乎都是从ActivityGroup继承下来的。还有就是TabActivity的强制依赖关系,它的布局文件必须将TabHost作根标签,并且id必须为"@android:id/tabhost",必须有TabWidget标签,且它的id必须是"@android:id/tabs",还有加载Activity的View容器,id必须为@android:id/tabcontent。光是强制依赖关系,我就觉得不是很舒服。不仅仅是TabActivity,在一些特殊的Activity中,如ListActivity都存在这种强制依赖关系,ListActivity必须有id为xxx(想不起来了)的ListView,我想这些弊端应该获得Google开发者的重视。

  那么我下面我就将自己实现ActivityGroup,告别强制依赖关系,并随心所欲的建立视图。下面这个类是一个抽象类,开发者只需对这个抽象类稍做修改,并加以实现自己的视图就能告别TabActivity。

package com.chenjun.demo.abstracttabactivity;import android.app.Activity;
import android.app.ActivityGroup;
import android.app.LocalActivityManager;
import android.content.Intent;
import android.os.Bundle;
import android.view.ViewGroup;
import android.widget.CompoundButton;
import android.widget.LinearLayout;
import android.widget.LinearLayout.LayoutParams;
import android.widget.RadioButton; /**  * 自己实现的一个通用ActivityGroup。  * 可以通过简单的重写它来制作有导航按钮和用导航按钮控制动态加载Activity的ActivityGroup。  * 开发者需要在实现类中实现三个方法:  *     1.指定动态加载Activity的容器的对象,getContainer()方法。  *     2.初始化所有的导航按钮,initRadioBtns()方法,开发者要遍历所有的导航按钮并执行initRadioBtn(int id)方法。  *     3.实现导航按钮动作监听器的具体方法,onCheckedChanged(...)方法。这个方法将实现某个导航按钮与要启动对应的Activity的关联关系,可以调用setContainerView(...)方法。  * @author zet  *  */ public abstract class AbstractMyActivityGroup extends ActivityGroup implements
CompoundButton.OnCheckedChangeListener{@Override protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);initRadioBtns();} //加载Activity的View容器,容器应该是ViewGroup的子类 private ViewGroup container; private LocalActivityManager localActivityManager; /**  * 加载Activity的View容器的id并不是固定的,将命名规则交给开发者  * 开发者可以在布局文件中自定义其id,通过重写这个方法获得这个View容器的对象  * @return  */ abstract protected ViewGroup getContainer(); /**  * 供实现类调用,根据导航按钮id初始化按钮  * @param id  */ protected void initRadioBtn(int id){RadioButton btn = (RadioButton) findViewById(id);btn.setOnCheckedChangeListener(this);} /**  * 开发者必须重写这个方法,来遍历并初始化所有的导航按钮  */ abstract protected void initRadioBtns(); /**  * 为启动Activity初始化Intent信息  * @param cls  * @return  */ private Intent initIntent(Class<?> cls){ return new Intent(this,    cls).addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);} /**  * 供开发者在实现类中调用,能将Activity容器内的Activity移除,再将指定的某个Activity加入  * @param activityName 加载的Activity在localActivityManager中的名字  * @param activityClassTye    要加载Activity的类型  */ protected void setContainerView(String activityName, Class<?> activityClassTye){ if(null == localActivityManager){localActivityManager = getLocalActivityManager();} if(null == container){container = getContainer();} //移除内容部分全部的View container.removeAllViews();Activity contentActivity = localActivityManager.getActivity(activityName); if (null == contentActivity) {localActivityManager.startActivity(activityName, initIntent(activityClassTye));} //加载Activity container.addView(localActivityManager.getActivity(activityName).getWindow().getDecorView(), new LinearLayout.LayoutParams(LayoutParams.FILL_PARENT,LayoutParams.FILL_PARENT));}}

需要重写的方法以及为什么需要重写我都已在原代码中标明。下面我们来具体的实现这个类,来达到我们想要的预期。

package com.chenjun.demo.abstracttabactivity;import android.os.Bundle;
import android.view.ViewGroup;
import android.widget.CompoundButton;
import android.widget.RadioButton; public class TestMyActivityGroup extends AbstractMyActivityGroup{ //加载的Activity的名字,LocalActivityManager就是通过这些名字来查找对应的Activity的。 private static final String CONTENT_ACTIVITY_NAME_0 = "contentActivity0"; private static final String CONTENT_ACTIVITY_NAME_1 = "contentActivity1"; private static final String CONTENT_ACTIVITY_NAME_2 = "contentActivity2"; private static final String CONTENT_ACTIVITY_NAME_3 = "contentActivity3"; private static final String CONTENT_ACTIVITY_NAME_4 = "contentActivity4";@Override protected void onCreate(Bundle savedInstanceState) {setContentView(R.layout.my_activity_group);super.onCreate(savedInstanceState);((RadioButton)findViewById(R.id.radio_button0)).setChecked(true);} /**  * 找到自定义id的加载Activity的View  */ @Override protected ViewGroup getContainer() { return (ViewGroup) findViewById(R.id.container);} /**  * 初始化按钮  */ @Override protected void initRadioBtns() {initRadioBtn(R.id.radio_button0);initRadioBtn(R.id.radio_button1);initRadioBtn(R.id.radio_button2);initRadioBtn(R.id.radio_button3);initRadioBtn(R.id.radio_button4);} /**  * 导航按钮被点击时,具体发生的变化  */ @Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { if (isChecked) { switch (buttonView.getId()) { case R.id.radio_button0:setContainerView(CONTENT_ACTIVITY_NAME_0, ContentActivity0.class); break; case R.id.radio_button1:setContainerView(CONTENT_ACTIVITY_NAME_1, ContentActivity1.class); break; case R.id.radio_button2:setContainerView(CONTENT_ACTIVITY_NAME_2, ContentActivity2.class); break; case R.id.radio_button3:setContainerView(CONTENT_ACTIVITY_NAME_3, ContentActivity3.class); break; case R.id.radio_button4:setContainerView(CONTENT_ACTIVITY_NAME_4, ContentActivity4.class); break; default: break;}}}}

布局文件:

<?xml version="1.0" encoding="utf-8"?> <LinearLayout android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_marginTop="0.0px" xmlns:android="http://schemas.android.com/apk/res/android"> <LinearLayout android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent"> <LinearLayout android:id="@+id/container" android:layout_width="fill_parent" android:layout_height="0.0dip" android:layout_weight="1.0" /> <RadioGroup android:gravity="center_vertical" android:layout_gravity="bottom" android:orientation="horizontal" android:layout_width="fill_parent" android:layout_height="wrap_content"> <RadioButton android:id="@+id/radio_button0" android:layout_marginTop="2.0dip" android:text="按钮1" style="@style/tab_radio" android:drawableTop="@android:drawable/ic_menu_call" /> <RadioButton android:id="@+id/radio_button1" android:layout_marginTop="2.0dip" android:text="按钮2" style="@style/tab_radio" android:drawableTop="@android:drawable/ic_menu_camera" /> <RadioButton android:id="@+id/radio_button2" android:layout_marginTop="2.0dip" android:text="按钮3" style="@style/tab_radio" android:drawableTop="@android:drawable/ic_menu_agenda" /> <RadioButton android:id="@+id/radio_button3" android:layout_marginTop="2.0dip" android:text="按钮4" style="@style/tab_radio" android:drawableTop="@android:drawable/ic_menu_delete" /> <RadioButton android:id="@+id/radio_button4" android:layout_marginTop="2.0dip" android:text="按钮5" style="@style/tab_radio" android:drawableTop="@android:drawable/ic_menu_help" /> </RadioGroup> </LinearLayout> </LinearLayout>

具体的实现效果(这里Activity基本没有内容):

2012050811252853

具体的代码演示就差不多了,这里要做一些说明的:

  1.开发者在自己的实现类中的onCreate方法中,必须先设置视图,再调用super.oncreate(...)方法。具体为什么看了抽象类的源代码我相信读者应该会明白。

  2.关于导航按钮使用RadioButton。Android没有特意为我们定制适合我们在这种场合下使用的按钮,也就是上面可以设置简笔画,下面有文字说明。解决方案:1)使用ImageButton,将简笔画和文字说明P在一张图片里面,但这样有一个非常明显的弊端,文字说明的文字字体是固定的,是P在图片里的,那么不和系统的文字一样。如果用户使用一些比较花哨的系统文字,而导航按钮却是宋体,在上面的内容部分是他的系统文字,那么我很难想象他下一次是否还会打开您所开发的应用。2)自己去实现一个View,去代替RadioButton,出于学习目的这是好的。最佳的解决方案我还是认为是用RadioButton,只需对它稍做修改即可,具体可以参照新浪微博的资源文件。

  缺陷反思:这些代码都是我从重构得来的,当时开发的时候并没有设计好开发流程(我是先有那个实现类,才有了那个抽象类的)。自己写的ActivityGroup与TabActivity相比,优点显而易见,缺点就是可能不稳定,但暂时没有发现Bug,动态加载的Activity的逻辑代码都能正确执行。

转载于:https://my.oschina.net/mingxv/blog/123583

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/301486.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

NET问答: 多个 await 和 Task.WaitAll 是等价的吗?

咨询区 vidalsasoon&#xff1a;我有下面两个方法:MethodA: 使用多个 await 方式public async Task<IHttpActionResult> MethodA() {var customer new Customer();customer.Widgets await _widgetService.GetAllWidgets();customer.Foos await _fooService.GetAllFoos…

类选项html 最后无距离,各种距离 一览无遗

offsetLeft,Left,clientLeft的区别假设 obj 为某个 HTML 控件obj.offsetTop 指 obj 相对于版面或由 offsetParent 属性指定的父坐标的计算上侧位置&#xff0c;整型&#xff0c;单位像素。obj.offsetLeft 指 obj 相对于版面或由 offsetParent 属性指定的父坐标的计算左侧位置&a…

华为起诉最新进展,国内航司暂停运行有关客机,收买家庭不得继续抚养被解救儿童,脸书创始人后悔没早学微信,这就是今天的大新闻...

今天是3月11日农历二月初五今天星期一没带耳机线感觉这样用手机是没有灵魂的下面是今天的大新闻华为起诉最新进展&#xff08;环球网&#xff09;多个来自美国的消息证实&#xff0c;美国的联邦法院已经就华为公司起诉美国政府一案给美国政府及其多位部长发去了法院传票。上图&…

前目的地罗伯森是谁_距离目的地只剩10公里,开车师傅却在高速公路上睡着了...

钱江晚报小时新闻记者 吴崇远 通讯员 俞斐“我从杭州过来&#xff0c;刚才开累了&#xff0c;就休息了几分钟……”“杭州到嘉善那么一点路都犯困了&#xff1f;”4月6日凌晨4点30分&#xff0c;高速交警嘉兴支队值班民警在巡逻时发现&#xff0c;一辆厢式小货车开着双跳灯&…

WPF 写一个提醒工具软件(完整项目)

昨天整理硬盘时&#xff0c;偶然发现一个很久之前写的小工具&#xff0c;一个提醒工具。包含定时提醒&#xff0c;间隔提醒功能。看看效果&#xff1a;界面看起来也还凑合&#xff0c;还使用了HandyControl&#xff0c;有桌面托盘功能界面是下面这样的提醒窗口有两种&#xff0…

她只用1个方法,就把英语拿下了!

全世界只有3.14 % 的人关注了数据与算法之美这3招让你未来6个月讲一口流利英语怎么摆脱单词记不住&#xff1f;如何解决听不懂老外讲英语&#xff1f;让老外叹服你口语的唯一方法……请看中国著名口语教学专家写给你的一封信&#xff1a;亲爱的朋友&#xff1a;你好&#xff01…

getch, getche, getchar 转

(1) getch()和getche()函数 这两个函数都是从键盘上读入一个字符。其调用格式为: getch(); getche(); 两者的区别是: getch()函数不将读入的字符回显在显示屏幕上, 而getche() 函数却将读入的字符回显到显示屏幕上。 例1: #include<stdio.h> …

英语计算机工程师求职信,计算机工程师英文求职信范文

计算机工程师英文求职信范文是由个人简历模板网为你提供的一份个人求职信范文&#xff0c;可直接使用或根据实际情况进行修改。祝您职场顺利&#xff0c;早日找到称心如意的工作&#xff01;Dear Sir or Madam,I am writing to apply for a position as a computer engineer in…

WPF实现环(圆)形菜单

WPF开发者QQ群&#xff1a; 340500857 | 微信群 -> 进入公众号主页 加入组织“ 前言&#xff0c;接着上一篇圆形菜单。”欢迎转发、分享、点赞、在看&#xff0c;谢谢~。 01—效果预览效果预览&#xff08;更多效果请下载源码体验&#xff09;&#xff1a;02—代码如下一、…

C#源代码生成器

SdtcnCoder参考了TheBeerHouse的系统结构&#xff0c;采用了三层结构和缓存技术&#xff0c;这里对SdtcnCoder代码生成进行简单介绍.一、数据类型模型 1、 Field类是字段类型的基类&#xff0c;对SqlServer2005数据列属性进行了映射&#xff1b; 2、 BigInt、Binary等是具体类…

win7系统桌面计算机怎么打的开,windows7系统双击计算机打不开怎么解决|win7双击计算机打不开的解决方法...

运行windows7系统的时候双击"计算机"遇到打不开的情况&#xff0c;也不知道怎么回事&#xff0c;尝试用杀毒软件解决也无效。如果要查看磁盘的具体情况&#xff0c;都没办法查看了。针对win7双击"计算机"打不开的问题&#xff0c;下面小编介绍两种解决方法…

每日一笑 | 在俄罗斯人眼里,没有什么是胶带解决不了的

全世界只有3.14 % 的人关注了数据与算法之美&#xff08;图片来源于网络&#xff0c;侵权删&#xff09;

钣金缺口lisp_UG用钣金模块的放样创建天圆地方,还能学钣金展开,必看

上个给大家用“直纹”做了一个天圆地方的圆台模型&#xff0c;今天给大家讲解下UG钣金模块如何使用“放样弯边”做天圆地方管并展开&#xff0c;借用下上次的图纸数据。首先创建天圆地方钣金模型1首先新建模型&#xff0c;点击草图&#xff0c;以XY为草图平面&#xff0c;点击确…

我开发了一款基于web容器的前端项目容器

目前使用比较多的web容器有哪些&#xff1a;Apache php应用大多数用这个Nginx node应用基本都用这个Tomcat java应用基本都用这个IIS .net应用基本用这个 windows服务器才能用 linux的话有宇内大神开发的Jexus前端基本都是node应用&#xff0c;据我了解大体上分2种一种是 最终打…

两个init的区别

容器创建了Servlet实例后&#xff0c;它将调用实例的init&#xff08;ServletConfig)方法初始化Servlet.该方法的参数ServletConfig对象包含了在WEB应用程序的部署描述文件中指定的初始化参数。在init&#xff08;ServletConfig&#xff09;调用完后&#xff0c;容器将调用init…

这些Python骚操作,你值得拥有

全世界只有3.14 % 的人关注了数据与算法之美0x00 世界&#xff0c;你好程序员第一次接触语言或者框架&#xff0c;基本上都有个 Hello World 的例子&#xff0c;这里 Python 直接将它做成了一个包。0x01 Python 哲学Python 执行 import this 时&#xff0c;会打印出 Python 之禅…

晨风机器人突破限制_厉害了!工程建设领域首创!会自动测量、自动调平的测量机器人...

近日中建三局工程技术研究院自主研发的道路工程移动式高精度测量机器人在武汉四环线工程完成20余公里测试应用标志着机器人完成阶段性测试具备工程应用条件道路工程移动式高精度测量机器人是一种集自动行驶、自动调平自动设站、自动测量等功能于一身的机器人系统系首次在道路工…

简述本地组策略中用户和计算机配置的差异,组策略编辑器中的计算机配置和用户配置有什么区别吗?...

满意答案在计算机配置中的“关闭磁盘自动播放”功能&#xff0c;是针对&#xff0c;所有计算机用户的&#xff0c;也就是应用到整个计算机的策略。“用户配置”功能&#xff0c;仅应用到当前用户。如果用别的用户名登录计算机&#xff0c;配置后的组策略将不会启用。关于磁盘自…

晕了!这个配置值从哪来的?

如果有同事问你&#xff0c;数据库连接串的值和appsettings.json配的不一样&#xff0c;从哪来的&#xff1f;你能回答的出来吗?配置读取顺序ASP.NET Core 中的配置是使用一个或多个配置提供程序执行的&#xff0c;配置提供程序使用各种配置源从键值对读取配置数据。ASP.NET C…

鸟哥学习笔记---网络驱动器设备iSCSI

NAS&#xff1a;网络附加存储服务器SAN&#xff1a;存储局域网让LinuxPC变成一台可通过Web管理的NAS&#xff1a;FressNAS:http://sourceforge.net/projects/freenas/SAN提供“磁盘”给主机用&#xff0c;可以格式化&#xff0c;分区等&#xff1b;NAS提供的是“网络协议的文件…