Android根据xml配置文件动态修改九宫格功能配置(转载)

本文介绍了一种根据XML配置文件动态修改九宫格功能配置的方法,实现了无需修改代码即可更新Gridview显示的功能入口,适用于Android应用首页的快速迭代。

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

看到一篇相当不错的博客,记录了如何将xml动态加载到Gridview中,实现动态加载

在此记录一下:

Android根据xml配置文件动态修改九宫格功能配置

 

再次记录一下,防止走丢。

大家知道很多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隐藏,才能保证数据操作是可充用可拓展的。


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值