zoukankan      html  css  js  c++  java
  • 实现Android 动态载入APK(Fragment or Activity实现)

    尊重原创http://blog.csdn.net/yuanzeyao/article/details/38565345

    近期由于项目太大了。导致编译通只是(Android对一个应用中的方法个数貌似有限制),所以一直琢磨着是否能将某些模块的APK不用安装,动态载入,通过在网上查找资料和网友的帮助,最终实现了APK的动态载入。网络上介绍APK动态载入的文章许多,可是我觉得写得很好的就是这位大牛的,我基本上就是使用他的这样的方案,然后增加了自己的元素。这位大牛是通过Activity实现的。我稍作改动。通过Fragment实现动态载入,我个人觉得使用Fragmnet更加简单。由于使用Fragment实现不须要考虑Fragment的生命周期。

    文章地址:http://blog.csdn.net/singwhatiwanna/article/details/22597587
              http://blog.csdn.net/singwhatiwanna/article/details/23387079
    一定要读了这两篇文章之后再来读我这篇,由于我是借鉴了这篇文章的思想的。

    首先我们须要明确。实现动态载入就是要解决两个问题:(假设使用Fragments实现,则是一个问题)

    1、Activity生命周期的管理。

    2、动态载入的apk的资源怎样获取。

    第一个问题是由于在java中不论什么一个程序要执行起来,必须通过类载入器将某个类增加内存,当我们通过一个类载入器将Activity增加内存时,事实上这个Activity就是一个普通的类。它已经没有生命周期的概念了,在Android系统中,Activity的生命周期是通过ActivityManager来控制的,假设我们通过动态载入的方式载入这个Activity,那么ActivityManager根本就不知道这个Activity的存在。所以我们必须处理好这个Activity的生命周期。至于第二个问题,在Android中。我们获取资源都是通过Context拿到的。而动态载入的APK是没有Context的。所以我们不能和曾经一样那样来拿。

    前面的两篇文章推荐的方法已经能够很好的解决以上两个问题,因此实现了APK的动态载入。
    我先来描写叙述一下大牛博客中实现动态载入的思路吧:
    创建一个ProxyActivity,通过名字知道。它就是一个代理Activity,我们调用不论什么一个Activity都是通过调用ProxyActivity实现的,我仅仅须要传入动态载入apk的路径和须要动态载入的类名,比方载入了一个Activity之后。通过反射机制读取到Activity的全部的生命周期函数以及onActivityResult等函数,并保存在一个列表中。在ProxyActivity的onCreate中通过反射调用动态载入的Activity的onCreate,由于ProxyActivity是一个正常的Activity,它的生命周期是正常的,所以在ProxyActivity的生命周期函数中调用动态载入Activity的生命周期函数就ok了,从而实现动态载入的Activity也有生命周期了。

    同一时候尽然是代理。那么就代理彻底一点。就干脆把动态载入的Activity中的全部的逻辑都转入到ProxyActivity中。

    那么这就要求被载入的Activity有一个ProxyActivity的引用,这个能够让全部动态载入的Activity继承一个BaseActivity,这个BaseActivity中有一个setProxy方法。用来设置ProxyActivity。所以不是不论什么APK。都能够动态载入的。一般仅仅有动态载入自己编写的apk,动态载入别人的apk不太现实。


    看了上面的思路,是不是有点借腹生子的感觉,事实上就是把动态载入的Activity的逻辑转移到了ProxyActivity

    解决资源訪问的问题方法就是造ProxyActivity中重载者两个函数
    public abstract AssetManager getAssets();
    public abstract Resources getResources();
    至于为什么能解决资源的问题,我还是推荐几篇文章大家去学习一下吧:
    本人的另外一篇文章:http://blog.csdn.net/yuanzeyao/article/details/12955459
    解说Android资源载入机制的一篇文章:http://blog.csdn.net/singwhatiwanna/article/details/24532419
     
    好了,上面就是通过Activity实现的动态载入apk,以下看看我是怎么通过Fragment来实现动态载入的,假设熟悉Fragment的同学们应该知道。Fragment就相当于一个有生命周期的View,它的生命周期被所在的Activity的生命周期管理。即使我们通过类载入器把一个Fragment增加到内存,它和曾经我们使用的Fragment没有什么两样。仅仅要我们将这个Fragment增加到ProxyActivity,ProxyActivity就会自己主动的管理好这个Fragment的生命周期。

    所以我们就不须要操心Fragment的生命周期,以下就来看看代码实现吧:

    1、BaseFragment.java

    public class BaseFragment extends Fragment implements IConstant
    {
      private static final String TAG = "BaseFragment";
      protected String mDexPath;
      @Override
      public void onCreate(Bundle savedInstanceState)
      {
        super.onCreate(savedInstanceState);
        Bundle bundle=this.getArguments();
    	//动态载入apk的路径
        mDexPath=bundle.getString(DEX_PATH);
      }
      
      //在Fragment中启动另外一个Fragment
      protected void replaceFragmentByProxy(String name)
      {
        if(mDexPath==null)
          return;
        //PROXY_VIEW_ACTION 是ProxyActivity的action
        Intent intent=new Intent(PROXY_VIEW_ACTION);
    	//传递apk路径
        intent.putExtra(DEX_PATH, mDexPath);
    	//是启动Fragment还是启动Fragment,这里启动的是Fragment
        intent.putExtra(START_TYPE, TYPE_FRAGMENT);
    	//须要载入的fragment的类名
        intent.putExtra(CLASS_NAME, name);
        this.startActivity(intent);
        
      }
    }

    全部须要动态载入的Fragment都须要继承这个BaseFragment,每次启动一个Fragment,仅仅须要传递apk的路径就可以。
    以下是我写的一个MyFragment,用来使用BitmapFun载入网络图片的,这里仅仅是载入并显示图片。没有考虑其它的。假设想深入了解BitmapFun的使用,请看我的另外一篇文章:
    http://blog.csdn.net/yuanzeyao/article/details/38355719

    public class MyFragment extends BaseFragment
    {
      private static final String TAG = "MyFragment";
      
    
      private static final String IMAGE_CACHE_DIR = "thumbs";
      private ImageFetcher mImageFetcher;
    
      private GridView mGridView;
      private Context context;
      private Button btn;
      
      @Override
      public void onCreate(Bundle savedInstanceState)
      {
        super.onCreate(savedInstanceState);
        ImageCacheParams cacheParams = new ImageCacheParams(getActivity(), IMAGE_CACHE_DIR);
    
        cacheParams.setMemCacheSizePercent(0.25f); // Set memory cache to 25% of app memory
    
        // The ImageFetcher takes care of loading images into our ImageView children asynchronously
        mImageFetcher = new ImageFetcher(getActivity(), 200);
        mImageFetcher.setLoadingImage(R.drawable.empty_photo);
        mImageFetcher.addImageCache(getActivity().getSupportFragmentManager(), cacheParams);
      }
      
      @Override
      public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
      {
    	//这里事实上能够直接使用R.layout.fragment
        Resources mResources=this.getActivity().getResources();
        return inflater.inflate(mResources.getIdentifier("fragment", "layout", "com.dl.client"), container,false);
      }
      
      @Override
      public void onViewCreated(View view, Bundle savedInstanceState)
      {
        super.onViewCreated(view, savedInstanceState);
        mGridView=(GridView) view.findViewById(R.id.gridView);
        btn=(Button)view.findViewById(R.id.btn_fragment);
        btn.setOnClickListener(new View.OnClickListener()
        {
          
          @Override
          public void onClick(View arg0)
          {
    		//在Fragment中动态载入另外一个Fragment
            replaceFragmentByProxy("com.dl.client.TempFragment");
          }
        });
        context=this.getActivity();
        mGridView.setAdapter(new BaseAdapter()
        {
          
          @Override
          public View getView(int position, View contentView, ViewGroup arg2)
          {
            ImageView mImg;
            if(contentView==null)
            {
              contentView=LayoutInflater.from(context).inflate(R.layout.item,null);
            }
            mImg=(ImageView)contentView.findViewById(R.id.img_11);
            //mImg.setImageResource(R.drawable.empty_photo);
            mImageFetcher.loadImage(Images.imageThumbUrls[position], mImg);
            return contentView;
          }
          
          @Override
          public long getItemId(int arg0)
          {
            return 0;
          }
          
          @Override
          public Object getItem(int arg0)
          {
            return Images.imageThumbUrls[arg0];
          }
          
          @Override
          public int getCount()
          {
            return Images.imageThumbUrls.length;
          }
        });
      }
    }

    以下看看这个应用的效果吧:


    最后须要注意的一点就是动态载入的apk不能和宿主应用包括同样的jar包,不然会报错的。。


  • 相关阅读:
    分享15个专业且免费的HTML5模板
    项目环境的搭建
    DNS预解析 dns-prefetch
    页面布局
    计划与准备
    Hogan的安装和使用
    代理工具--fiddle
    vue.js加入购物车小球动画
    vue.js笔记1.0
    url,href,src区别
  • 原文地址:https://www.cnblogs.com/zfyouxi/p/5260799.html
Copyright © 2011-2022 走看看