Android根据xml配置文件动态修改九宫格效能配置
Android根据xml配置文件动态修改九宫格功能配置
为了简单就改了displayName和icon,其他都一样了,实际使用的时候可根据需求来配置自己想要的Activity。
有了xml和数据的封装,接下来就要解析了,为了xml文件的拓展,这里用反射来自动为bean设定值,当xml字段增加的时候,解析器类不需要修改代码:
用泛型的原因是为了进一步拓展,以后需要解析其他xml文件时,拓展这个类就可以了,暂时还没有全部完成,不过用来做九宫格是没问题了。好了,接下来就是对上层Activity封装xml解析,提供跳转activity等功能。
因为bean list生成时的顺序正好对应九宫格的顺序,所以上层的调用将变得非常轻松愉快,老规矩写一个adapter配给GridView就可以了,先看Adapter:
注意这里的getResourseId方法,因为xml文件里配置的是icon的名称,是一个string,需要把这个string转换成R类里对应的id,又要用到反射,这个小技巧大家可以参考下。真实的项目中,这里的icon应该是一个url,用ImageLoader来加载。好了,下面就是轻松愉快地写个Activity来调用上面这些类来服务了~
是不是轻松愉快,本人的理念就是要让Activity就只做一个控件的控制器,其他所有数据相关的细节,都应该对Activity隐藏,才能保证数据操作是可充用可拓展的。最后上一张完成图,感谢韩MM提供切图~
大家知道很多app的首页都是由GridView组成的功能入口,这个九宫格一般在第一版的时候把功能写死的,这显然不能适应需求的不断变更的,所以今天在这里想写一个简单的根据配置文件自动生成的gridView,点击之后可跳转到配置好的Activity而不用修改一行代码。
首先设计一个简单的xml配置文件,塞到res/xml文件夹下,当然这里后期可以配置到服务器上动态获取更新,demo的话就先放在apk里了。
<?xml version="1.0" encoding="utf-8"?> <Functions> <Function name="pay" displayName="功能1" icon="icon_1" packageName="com.suning.epa_plugin.pay" activityName="PayActivity" /> <Function name="assets" displayName="功能2" icon="icon_2" packageName="com.suning.epa_plugin.assets" activityName="AssetsActivity" /> <Function name="assets" displayName="功能3" icon="icon_3" packageName="com.suning.epa_plugin.assets" activityName="AssetsActivity" /> <Function name="assets" displayName="功能4" icon="icon_4" packageName="com.suning.epa_plugin.assets" activityName="AssetsActivity" /> <Function name="assets" displayName="功能5" icon="icon_5" packageName="com.suning.epa_plugin.assets" activityName="AssetsActivity" /> <Function name="assets" displayName="功能6" icon="icon_6" packageName="com.suning.epa_plugin.assets" activityName="AssetsActivity" /> <Function name="assets" displayName="功能7" icon="icon_7" packageName="com.suning.epa_plugin.assets" activityName="AssetsActivity" /> <Function name="assets" displayName="功能8" icon="icon_8" packageName="com.suning.epa_plugin.assets" activityName="AssetsActivity" /> </Functions>
为了简单就改了displayName和icon,其他都一样了,实际使用的时候可根据需求来配置自己想要的Activity。
接下来写一个bean类来封装xml中的每一个item,这个很简单,不多说。
package com.suning.functions; import android.os.Parcel; import android.os.Parcelable; public class FunctionBean implements Parcelable { private String name; private String packageName; private String activityName; private String displayName; private String icon; public FunctionBean() { } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getPackageName() { return packageName; } public void setPackageName(String packageName) { this.packageName = packageName; } public String getActivityName() { return activityName; } public void setActivityName(String activityName) { this.activityName = activityName; } public String getDisplayName() { return displayName; } public void setDisplayName(String displayName) { this.displayName = displayName; } public String getIcon() { return icon; } public void setIcon(String icon) { this.icon = icon; } @Override public int describeContents() { return 0; } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeString(name); dest.writeString(packageName); dest.writeString(activityName); dest.writeString(displayName); dest.writeString(icon); } public static final Creator<FunctionBean> CREATOR = new Creator<FunctionBean>() { public FunctionBean createFromParcel(Parcel in) { return new FunctionBean(in); } public FunctionBean[] newArray(int size) { return new FunctionBean[size]; } }; private FunctionBean(Parcel in) { name = in.readString(); packageName = in.readString(); activityName = in.readString(); displayName = in.readString(); icon = in.readString(); } }
有了xml和数据的封装,接下来就要解析了,为了xml文件的拓展,这里用反射来自动为bean设定值,当xml字段增加的时候,解析器类不需要修改代码:
package com.suning.functions; import java.lang.reflect.Field; import java.util.ArrayList; import java.util.List; import org.xmlpull.v1.XmlPullParser; import com.amuro.xmlparsertest.R; import android.content.Context; import android.content.res.XmlResourceParser; public class FunctionXMLReader<T> { private Context context; private Class<T> classT; private XmlResourceParser xmlParser; private List<T> beans; public FunctionXMLReader(Context context, Class<T> classT) { this.context = context; this.classT = classT; init(); } private void init() { xmlParser = context.getResources().getXml(R.xml.functions); beans = new ArrayList<T>(); } public void parse() { try { int eventType = xmlParser.getEventType(); while(eventType != XmlPullParser.END_DOCUMENT) { switch(eventType) { case XmlPullParser.START_DOCUMENT: break; case XmlPullParser.START_TAG: parseTags(); break; case XmlPullParser.END_TAG: break; case XmlPullParser.END_DOCUMENT: break; } eventType = xmlParser.next(); } } catch (Exception e) { e.printStackTrace(); } } private void parseTags() throws InstantiationException, IllegalAccessException { String tagName = xmlParser.getName(); if("Function".equals(tagName)) { T bean = classT.newInstance(); Field[] fields = classT.getDeclaredFields(); for(int i = 0;i < xmlParser.getAttributeCount();i++) { String attrName = xmlParser.getAttributeName(i); String attrValue = xmlParser.getAttributeValue(i); for(Field f : fields) { f.setAccessible(true); String fName = f.getName(); if(fName.equals(attrName)) { f.set(bean, attrValue); } } } beans.add(bean); } } public List<T> getBeans() { return beans; } }
用泛型的原因是为了进一步拓展,以后需要解析其他xml文件时,拓展这个类就可以了,暂时还没有全部完成,不过用来做九宫格是没问题了。好了,接下来就是对上层Activity封装xml解析,提供跳转activity等功能。
package com.suning.functions; import java.util.List; import android.content.Context; import android.content.Intent; public class FunctionManager { private static volatile FunctionManager instance = null; private FunctionManager(Context context) { this.context = context; } public static FunctionManager getInstance(Context context) { if(instance == null) { synchronized (FunctionManager.class) { if(instance == null) { instance = new FunctionManager(context); } } } return instance; } private Context context; private FunctionXMLReader<FunctionBean> xmlReader; private List<FunctionBean> beans; public void init() { xmlReader = new FunctionXMLReader<FunctionBean>(context, FunctionBean.class); xmlReader.parse(); beans = xmlReader.getBeans(); } public List<FunctionBean> getBeans() { return beans; } public void lauchFunction(int position) throws ClassNotFoundException { FunctionBean bean = beans.get(position); String className = bean.getPackageName() + "." + bean.getActivityName(); Intent intent = new Intent(); intent.setClass(context, Class.forName(className)); context.startActivity(intent); } }
因为bean list生成时的顺序正好对应九宫格的顺序,所以上层的调用将变得非常轻松愉快,老规矩写一个adapter配给GridView就可以了,先看Adapter:
package com.suning.test; import java.lang.reflect.Field; import java.util.List; import com.amuro.xmlparsertest.R; import com.suning.functions.FunctionBean; import android.annotation.SuppressLint; import android.content.Context; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ArrayAdapter; import android.widget.ImageView; import android.widget.TextView; public class GridAdapter extends ArrayAdapter<FunctionBean> { private LayoutInflater layoutInflater; public GridAdapter(Context context, List<FunctionBean> beans) { super(context, 0, beans); layoutInflater = LayoutInflater.from(context); } @SuppressLint("InflateParams") @Override public View getView(int position, View convertView, ViewGroup parent) { FunctionBean bean = getItem(position); ViewHolder viewHolder = null; if(convertView == null) { convertView = layoutInflater.inflate(R.layout.adapter_grid_layout, null); viewHolder = new ViewHolder(convertView); convertView.setTag(viewHolder); } else { viewHolder = (ViewHolder)convertView.getTag(); } viewHolder.textViewName.setText(bean.getDisplayName()); viewHolder.imageViewIcon.setImageResource(getResourceId(bean.getIcon())); return convertView; } private int getResourceId(String iconName) { Field field; int resId = R.drawable.ic_launcher; try { field = R.drawable.class.getField(iconName); resId = (int) field.get(null); } catch (NoSuchFieldException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (IllegalArgumentException e) { e.printStackTrace(); } return resId; } static class ViewHolder { private ImageView imageViewIcon; private TextView textViewName; public ViewHolder(View convertView) { imageViewIcon = (ImageView)convertView.findViewById(R.id.iv_icon); textViewName = (TextView)convertView.findViewById(R.id.tv_display_name); } } }
注意这里的getResourseId方法,因为xml文件里配置的是icon的名称,是一个string,需要把这个string转换成R类里对应的id,又要用到反射,这个小技巧大家可以参考下。真实的项目中,这里的icon应该是一个url,用ImageLoader来加载。好了,下面就是轻松愉快地写个Activity来调用上面这些类来服务了~
package com.suning.test; import com.amuro.xmlparsertest.R; import com.suning.functions.FunctionManager; import android.app.Activity; import android.os.Bundle; import android.view.View; import android.view.View.OnClickListener; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.GridView; public class TestActivity extends Activity { private FunctionManager fManager; private GridView gridView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main_layout); initFunctionManager(); initView(); } private void initFunctionManager() { fManager = FunctionManager.getInstance(this); fManager.init(); } private void initView() { findViewById(R.id.bt).setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { } }); gridView = (GridView) findViewById(R.id.gv); gridView.setAdapter(new GridAdapter(this, fManager.getBeans())); gridView.setOnItemClickListener(new OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { lauchActivity(position); } }); } private void lauchActivity(int position) { try { fManager.lauchFunction(position); } catch (ClassNotFoundException e) { e.printStackTrace(); } } }
界面的xml就不贴了,太简单了,自己随便写个就好。
是不是轻松愉快,本人的理念就是要让Activity就只做一个控件的控制器,其他所有数据相关的细节,都应该对Activity隐藏,才能保证数据操作是可充用可拓展的。最后上一张完成图,感谢韩MM提供切图~
版权声明:本文为博主原创文章,未经博主允许不得转载。