android——框架的实现系列(界面跳转的控制)

       原创文章,转载请注明

       请先阅读《 android——框架的实现系列(依赖注入的实现) 》

                       《android——框架的实现系列(资源的依赖注入) 》

       由于接触android不久,对于每个界面必须要写一个activity和fragment的方式深恶痛绝。不知道有什么好的办法,结合开发web的经验,希望能把这个控制层解脱出来。

       之前的web开发中,通过jersey加反射实现了一个控制层类,前端只需要在url中表明后端需要处理业务的类的类名,方法名和json参数即可自动转向业务逻辑层进行处理,通过该控制层类直接返回结果。从此再也不用写控制层了,从而把精力放到业务逻辑的实现上。

       基于这个思路进行改造。虽然目标暂时不可能制定的和web一样,但是初步还是希望能更简洁,逻辑更清晰一些。


       实现目标

       1、整个app中只有一个MainActivity。当然,如果能把这个类也去掉就再好不过了,貌似不现实。该类提供主界面的样式和其他界面的跳转。

       2、页面转向只需要调用一个方法 ,比如route(String position,Map<String,Object> args),position表示需要跳转的页面的类名,args表示需要传递的方法

       3、页面的展现通过实现一个称为AALayout的抽象类来实现

       这样做的好处在于,整个app的开发只需要写一次MainActivity,以后就不需要再写新的activity或fragment了。这样精力就集中在实现界面AALayout中了。

       比如在MainActivity中进行如下调用

   worldTime.setOnClickListener(new OnClickListener(){

			@Override
			public void onClick(View v) {
				Map<String,Object> args=new HashMap<String,Object>();
				args.put("cityData", new ZoneCityData());
				routeFromRoot(ZoneCityLayout.class.getName(),args);
			}
			
		});
     worldTime为主界面的一个资源view,调用routeFromRoot即可跳转到ZoneCityLayout界面。

     需要被管理的界面为了能被框架识别,需要加上@Componet注释,如下

@Component
@Layout(value=R.layout.common_time)
public class CommonTimeLayout extends AALayout{

}

       实现方法

       1、BaseActivity类

       MainActivity需要继承该类。该类提供跳转的逻辑,思路是这样的

      a、通过fragment进行跳转,这里把跳转任务转交给BaseFragment,这里有几个问题

            a.1、getFragmentManager().beginTransaction().replace需要MainActivity的layout文件id,为了区别别的layout,因此使用@Root注释进行依赖注入

                      回顾上一篇文章可以知道,依赖注入在void onCreate(Bundle savedInstanceState)方法中实现即可

            a.2、fragment界面不会取消它所在的activity的监听,这样的话监听会混乱。为了不至于混乱,通过标志位实现,通过BackHandledInterface接口来提供额外的方法来实时判断标志位。并提供了两个方法,一个是routeFromRoot一个是routeFormOthers,我也想把两个方法合成一个,但是没想到好的方法

            a.3、由于fragment的出栈需要其他的操作,比如root标志位的获取,因此需要实现额外的接口BackHandledInterface,这里有两个操作,一个是退栈,一个是root标志的变更。

    

       2、BaseFragment类

       由该接到BaseActivity的跳转需求,由它来完成跳转任务,思路是这样的

       a、由LayoutFactory类通过position来获得需要转向的界面AALayout类的对象,前面已经说过,所有的界面需要实现AALayout这个抽象类。

       b、资源依赖注入到界面对象中,请参考上一篇文章

       c、调用界面对象的getLayout(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState, Context context, Bundle argBundle)方法展示界面。该方法为AALayout的抽象方法,所有界面需要在此方法中实现界面的展示。

       d、按了回退键时,通过BackHandledFragment类进行退栈管理,把当前fragment返回

    

     3、BackHandledFragment类

     该类为fragment的堆栈管理,通过getActivity()获得当前BaseActivity,再通过BackHandledInterface接口,BaseActivity实现了该接口进行退栈操作。

  

     4、BackHandledInterface接口

     该接口提供了退栈操作和root标志位处理的方法


    5、AALayout类

    该类为抽象类,所有界面需要继承它,实现它的抽象方法void getLayout(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState,Context context,Bundle argBundle),该方法用来展示界面


   6、LayoutFactory类

   该类通过需要跳转的界面类名返回界面对象。实现的方法通过BeanHelper获得实例即可。这也是为什么界面需要使用@Component进行标注,对于BeanHelper和@Component可以通过《 android——框架的实现系列(依赖注入的实现) 》这篇文章了解


   以上就是所有的实现思路


   下面来看一下代码吧

    BaseActivity类

public class BaseActivity extends FragmentActivity implements BackHandledInterface{

	protected BackHandledFragment mBackHandedFragment;  
	public static DBHelper helper;
	protected boolean isRoot=true;
	private int xmlId;
	private int layoutId;
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		//框架入口,进行类容器,实例容器,数据库映射工具初始化
		LoadHelper.init();
		Class<?> cls=getClass();
		String childClassName=cls.getSimpleName();
		if(childClassName!=null)
		//解析root注释,获得入口资源id
		try {
			if(cls.isAnnotationPresent(Root.class)){
				Root root=cls.getAnnotation(Root.class);
				xmlId=root.xml_id();
			}
			//获得布局资源
			if(cls.isAnnotationPresent(Layout.class)){
				Layout layout=cls.getAnnotation(Layout.class);
				layoutId=layout.value();
				setContentView(layoutId);
			}
			//依赖注入资源
			Field[] fields=cls.getDeclaredFields();
			for(Field field : fields){
				Class<?> fcls=field.getType();
				if(View.class.isAssignableFrom(fcls)){
					if(field.isAnnotationPresent(Resource.class) && !Modifier.isStatic(field.getModifiers())){
						field.setAccessible(true);
						Resource resource=field.getAnnotation(Resource.class);
						int rid=resource.value();
						Method m=cls.getMethod("findViewById", int.class);
						View v=(View) m.invoke(this, rid);
						field.set(this, v);
					}
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		super.onCreate(savedInstanceState);
	}
	
	@Override
	public void onDestroy(){
		super.onDestroy();
		if(helper!=null){
			helper.close();
		}
	}
	
	@Override
	public void setSelectedFragment(BackHandledFragment selectedFragment) {
		this.mBackHandedFragment = selectedFragment;  
	}

	@Override
	public void setIsRoot(boolean flag) {
		this.isRoot=flag;
	}
	
	public void setmBackHandedFragment(BackHandledFragment mBackHandedFragment) {
		this.mBackHandedFragment = mBackHandedFragment;
	}
	
	public void routeFromRoot(String position,Map<String,Object> args){
		if(isRoot){
			if(getFragmentManager().getBackStackEntryCount() == 1)
        		isRoot=true;
        	else
        		isRoot=false;
			route(position,args);
		}
	}
	
	public void routeFromOthers(String position,Map<String,Object> args){
		isRoot=false;
		route(position,args);
	}
	
	private void route(String position,Map<String,Object> args){
		BaseFragment baseFragment = new BaseFragment();
		/*
		if(this instanceof Activity)
			baseFragment.setFieldMap(getExtraField());
		*/
		mBackHandedFragment=baseFragment;
        Bundle bundle = new Bundle();
        bundle.putString("position", position);
        if(args!=null){
	        for(Map.Entry<String, Object> argEntry : args.entrySet()){
	        	Object arg=argEntry.getValue();
	        	if(arg instanceof String){
	        		bundle.putString(argEntry.getKey(), (String) arg);
	        	}
	        	else if(arg instanceof Integer){
	        		bundle.putInt(argEntry.getKey(), (Integer) arg);
	        	}
	        	else if(arg instanceof Long){
	        		bundle.putLong(argEntry.getKey(), (Long) arg);
	        	}
	        	else if(arg instanceof Float){
	        		bundle.putFloat(argEntry.getKey(), (Float) arg);
	        	}
	        	else if(arg instanceof Double){
	        		bundle.putDouble(argEntry.getKey(), (Double) arg);
	        	}
	        	else if(arg instanceof Boolean){
	        		bundle.putBoolean(argEntry.getKey(), (Boolean) arg);
	        	}
	        	else if(arg instanceof Serializable){
	        		bundle.putSerializable(argEntry.getKey(), (Serializable) arg);
	        	}
	        	else if(arg instanceof IBinder){
	        		bundle.putBinder(argEntry.getKey(), (IBinder) arg);
	        	}
	        	else if(arg instanceof Bundle){
	        		bundle.putAll((Bundle) arg);
	        	}
	        }
        }
        baseFragment.setArguments(bundle);
        getFragmentManager().beginTransaction().replace(xmlId,baseFragment)
        									   .addToBackStack(null)
        									   .commit();
	}
	
	@Override  
    public void onBackPressed(){
    	if(mBackHandedFragment == null || !mBackHandedFragment.onBackPressed()){  
            if(getFragmentManager().getBackStackEntryCount() == 0){  
                super.onBackPressed();  
            }else{  
            	if(getFragmentManager().getBackStackEntryCount() == 1)
            		isRoot=true;
            	else
            		isRoot=false;
            	getFragmentManager().popBackStack();  
            }  
        }  
    }
	
	@SuppressWarnings("rawtypes")
	protected void startService(Class service) {
         Intent i = new Intent(this, service);
         i.setFlags(32);
         //i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
         startService(i);  
	 }

}

     BaseFragment类

public class BaseFragment extends BackHandledFragment {
	
	private Map<String,Object> fieldMap;
	
	@Override
	public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {
		Context context = getActivity();
		Bundle bundle = this.getArguments();
		//通过position获得指定的界面
		position = (String) bundle.get("position");
		View layout = null;
		try {
			Class<?> cls=Class.forName(position);
			AALayout aalayout;
			if(fieldMap!=null){
				aalayout = LayoutFactory.create(cls,fieldMap);
			}
			else{
				aalayout = LayoutFactory.create(cls);
			}
			
			//获取布局资源,依赖注入资源
			Class<?> acls=aalayout.getClass();
			//获取layout资源
			if(acls.isAnnotationPresent(Layout.class)){
				Layout layoutAnno=acls.getAnnotation(Layout.class);
				int layoutXmlId=layoutAnno.value();
				layout = inflater.inflate(layoutXmlId, container, false);
				Field[] fields=cls.getDeclaredFields();
				for(Field field : fields){
					Class<?> fcls=field.getType();
					if(View.class.isAssignableFrom(fcls)){
						//获取Resource资源
						if(field.isAnnotationPresent(Resource.class) && !Modifier.isStatic(field.getModifiers())){
							field.setAccessible(true);
							Resource resource=field.getAnnotation(Resource.class);
							int rid=resource.value();
							View v=layout.findViewById(rid);
							field.set(aalayout, v);
						}
					}
				}
			}
			//相当于页面跳转
			aalayout.getLayout(inflater,container,savedInstanceState,context,bundle);
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} 
		return layout;
	}

	@Override
	public boolean onBackPressed() {
		return false;
	}

	public void setFieldMap(Map<String, Object> fieldMap) {
		this.fieldMap = fieldMap;
	}
	
}

       BackHandledFragment类

public abstract class BackHandledFragment extends Fragment{

	protected String position;
	protected BackHandledInterface mBackHandledInterface;  
    public abstract boolean onBackPressed();  
      
    @Override  
    public void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        if(!(getActivity() instanceof BackHandledInterface)){  
            throw new ClassCastException("Hosting Activity must implement BackHandledInterface");  
        }else{  
            this.mBackHandledInterface = (BackHandledInterface)getActivity();  
        }  
    }  
      
    @Override  
    public void onStart() {  
        super.onStart();  
        mBackHandledInterface.setSelectedFragment(this);  
    }  
	
}

     BackHandledInterface接口

public interface BackHandledInterface {
	public abstract void setSelectedFragment(BackHandledFragment selectedFragment);
	public abstract void setIsRoot(boolean flag);
}

     AALayout类

public abstract class AALayout {

	public abstract void getLayout(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState,Context context,Bundle argBundle);
	
}

    LayoutFactory类

public class LayoutFactory {

	@SuppressWarnings("unchecked")
	public static AALayout create(Class<?> cls){
		Object bean=BeanHelper.getBean(cls);
		Method m;
		try {
			m = cls.getDeclaredMethod("getExtraField");
			Map<String,Object> map=(Map<String, Object>) m.invoke(bean);
			bean=create(cls,map);
		} catch (Exception e) {
			return (AALayout) bean;
		}
		return (AALayout) bean;
	}
	
	public static AALayout create(Class<?> cls,Map<String,Object> map){
		
		Object bean=BeanHelper.getBean(cls);

		try{
			for(Map.Entry<String, Object> filedEntry : map.entrySet()){
				String fieldName=filedEntry.getKey();
				Field field=cls.getDeclaredField(fieldName);
				field.setAccessible(true);
				Object fieldBean=filedEntry.getValue();
				field.set(bean, fieldBean);
			}
		}catch(NoSuchFieldException e){
			return (AALayout) bean;
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		}
		
		return (AALayout) bean;
		
	}
	
}

      Root注释类

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Root {

	int xml_id();
	
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值