成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

撩妹神器,打造圣誕雪花特效附加線上熱修復

移動開發 Android
相信去年圣誕節打開過手機淘寶的童鞋都會對當時的特效記憶猶新吧:全屏飄雪,旁邊還有個小雪人來控制八音盒背景音樂的播放,讓人有種身臨其境的感覺,甚至忍不住想狠狠購物了呢(誤)。

相信去年圣誕節打開過手機淘寶的童鞋都會對當時的特效記憶猶新吧:全屏飄雪,旁邊還有個小雪人來控制八音盒背景音樂的播放,讓人有種身臨其境的感覺,甚至忍不住想狠狠購物了呢(誤),大概就是下面這個樣子滴: 

 

嗯,確實很炫,那么我們一步步去分析是如何實現的:

一、實現下雪的 View

首先,最上面一層的全屏雪花極有可能是一個頂層的View,而這個View是通過動態加載去控制顯示的(不更新淘寶也能看到這個效果)。那么我們先得實現雪花效果的 View,人生苦短,拿來就用。打開 gank.io,搜索"雪花": 

 

看樣子第7個庫就是我們想要的了,點進源碼,直接 download 不解釋,記得 star 一個支持作者。那么現在我們的項目中就有一個完整的下雪效果 View 了。

二、實現雪人播放器 View

這個一張雪人圖片+一個按鈕即可實現,就不多解釋了。接下來需要一段圣誕節音頻,直接進行在線音頻播放無疑是節省空間的好方案。『我的滑板鞋』烘托出的寂寞而甜蜜的氛圍無疑是最適合圣誕節的,因此我們得到了『神曲』URL 一枚:

http://cdn.ifancc.com/TomaToDo/bgms/my_hbx.mp3

接下來要找一個小雪人的圖片當作播放器的背景,那么阿姆斯特朗...不對,是這個:  

[[179119]] 

嗯,相當可愛喜慶。那么播放器核心代碼如下:

  1. package com.kot32.christmasview.player; 
  2.  
  3. import android.content.Context; 
  4. import android.media.AudioManager; 
  5. import android.media.MediaPlayer; 
  6. import android.util.AttributeSet; 
  7. import android.view.View
  8. import android.widget.Toast; 
  9.  
  10. import com.kot32.christmasview.R; 
  11.  
  12. import java.io.IOException; 
  13.  
  14. /** 
  15.  * Created by kot32 on 16/12/8. 
  16.  */ 
  17. public class MyPlayer extends View { 
  18.  
  19.     public MediaPlayer mediaPlayer; 
  20.  
  21.     public MyPlayer(Context context) { 
  22.         super(context); 
  23.         init(); 
  24.     } 
  25.  
  26.     public MyPlayer(Context context, AttributeSet attrs) { 
  27.         super(context, attrs); 
  28.         init(); 
  29.     } 
  30.  
  31.     private void init() { 
  32.         setBackgroundResource(R.drawable.pig); 
  33.         mediaPlayer = new MediaPlayer(); 
  34.         mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); 
  35.         playUrl("http://172.20.248.106/IXC5b415fcacfc3c439e25a3e74533d2239/TomaToDo/bgms/my_hbx.mp3"); 
  36.         Toast.makeText(getContext(), "開始播放", Toast.LENGTH_SHORT).show(); 
  37.         setOnClickListener(new OnClickListener() { 
  38.             @Override 
  39.             public void onClick(View v) { 
  40.                 if (!mediaPlayer.isPlaying()) { 
  41.                     mediaPlayer.start(); 
  42.                     Toast.makeText(getContext(), "繼續播放", Toast.LENGTH_SHORT).show(); 
  43.                 } else { 
  44.                     mediaPlayer.pause(); 
  45.                     Toast.makeText(getContext(), "暫停播放", Toast.LENGTH_SHORT).show(); 
  46.                 } 
  47.             } 
  48.         }); 
  49.     } 
  50.  
  51.     public void playUrl(String videoUrl) { 
  52.         try { 
  53.             mediaPlayer.reset(); 
  54.             mediaPlayer.setDataSource(videoUrl); 
  55.             mediaPlayer.prepare();//prepare之后自動播放 
  56.             mediaPlayer.start(); 
  57.         } catch (IllegalArgumentException e) { 
  58.             e.printStackTrace(); 
  59.         } catch (IllegalStateException e) { 
  60.             e.printStackTrace(); 
  61.         } catch (IOException e) { 
  62.             e.printStackTrace(); 
  63.         } 
  64.     } 
  65.  
  66.     @Override 
  67.     protected void onDetachedFromWindow() { 
  68.         super.onDetachedFromWindow(); 
  69.         try { 
  70.             media  

三、動態加載思路

上面基本實現了在本地的雪花以及播放音樂效果,那么在不更新主程序的情況下,如何將這兩個View動態加載到主程序當中去呢?

首先我們明白,Android 的DexClassloader 是擁有加載任意APK 中任意類的能力的,只是有以下限制:

  • 加載出的Activity 由于不在宿主 Manifest 文件中聲明,因此框架無法找到并初始化這個Activity。
  • 加載出的Activity 不具備生命周期,理由同上。
  • 加載出的類的Resource 文件id 會和主程序混淆在一起。

由于我們只是加載View,并不是加載整個Activity,所以前兩個問題并不會遇到,而第三個問題可以想辦法解決掉。

在主程序中我們也要做這三件事:

  • 把能夠裝載View的ViewGroup 的空位留出來
  • 去獲取更新的patch包
  • 把View 從apk包中加載出來之后,放進留好的ViewGroup 中。這樣一來,不僅是圣誕節,在之后的各種活動上都可以在線去加載活動的View。

四、開始加載

在加載View 之前,首先要意識到這個View 是引用了圖片資源的(小豬圖片),因此我們要解決資源問題:

  1. private void initResource() { 
  2.         Resources resources = getContext().getResources(); 
  3.         try { 
  4.             AssetManager newManager = AssetManager.class.newInstance(); 
  5.             Method addAssetPath = newManager.getClass().getMethod("addAssetPath", String.class); 
  6.             addAssetPath.invoke(newManager, DynamicViewManager.getInstance().getUpdateFileFullPath()); 
  7.             Resources newResources = new Resources(newManager, 
  8.                     resources.getDisplayMetrics(), resources.getConfiguration()); 
  9.             Reflect.onObject(getContext()).set("mResources", newResources); 
  10.         } catch (Exception e) { 
  11.             e.printStackTrace(); 
  12.         } 
  13.     }  

上面代碼的作用是:把添加了外部更新包路徑的資源管理器賦值給了App原來的資源管理器,也就是說現在可以在宿主中訪問插件資源了。

核心加載代碼如下:

  1. DexClassLoader classLoader = new DexClassLoader(apkFile.getAbsolutePath() 
  2.                     , "dex_out_put_dir" 
  3.                     , null 
  4.                     , getClass().getClassLoader()); 
  5. Class newViewClazz = classLoader.loadClass("view's package name"); 
  6. Constructor con = newViewClazz.getConstructor(Context.class); 
  7. //first use Activity's Resource lie to View 
  8. if (dynamicView == null) { 
  9.     dynamicView = (View) con.newInstance(getContext()); 
  10. //Replace the View's mResources and recovery the Activity's avoid disorder of Resources 
  11. Reflect.onObject(getContext()).set("mResources"null); 
  12. getContext().getResources(); 
  13.  
  14. RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(DisplayUtil.dip2px(getContext(), viewInfo.layoutParams.width), 
  15.          DisplayUtil.dip2px(getContext(), viewInfo.layoutParams.height)); 
  16. layoutParams.addRule(RelativeLayout.CENTER_IN_PARENT, RelativeLayout.TRUE); 
  17. addView(dynamicView, layoutParams);  

中間對 mResources 的操作的作用是:將宿主的Activity 的mResources 重置,避免在Activity 中使用資源時和插件沖突。

然而機智的我已經把更新包下載、版本管理、動態加載都封裝好了,所以正確的加載方式是:

引用它:https://github.com/kot32go/dynamic-load-view

然后:

1.宿主聲明:

  1. <RelativeLayout 
  2.     xmlns:android="http://schemas.android.com/apk/res/android" 
  3.     xmlns:app="http://schemas.android.com/apk/res-auto" 
  4.     android:layout_width="match_parent" 
  5.     android:layout_height="match_parent" 
  6.     android:background="@drawable/tb_bg" 
  7.     > 
  8.  
  9.     <com.kot32.dynamicloadviewlibrary.core.DynamicViewGroup 
  10.         android:layout_width="match_parent" 
  11.         android:layout_height="match_parent" 
  12.         app:uuid="activity_frame"
  13.  
  14.         <TextView 
  15.             android:layout_width="wrap_content" 
  16.             android:layout_height="wrap_content" 
  17.             android:text="原始頁面" 
  18.             /> 
  19.  
  20.     </com.kot32.dynamicloadviewlibrary.core.DynamicViewGroup> 
  21.  
  22.     <com.kot32.dynamicloadviewlibrary.core.DynamicViewGroup 
  23.         android:layout_width="60dp" 
  24.         android:layout_height="60dp" 
  25.         android:layout_alignParentRight="true" 
  26.         android:layout_centerVertical="true" 
  27.         app:uuid="activity_player"
  28.  
  29.     </com.kot32.dynamicloadviewlibrary.core.DynamicViewGroup> 
  30.  
  31.  
  32. </RelativeLayout>  

以上聲明了主界面的布局,當然,在動態加載之前除了原有的"原始頁面"TextView,是不會有任何其他東西的,也就是圣誕節來臨之前的程序。注意:uuid 會和在線包相匹配。

2.打插件包

其實就是把之前包含了我們所寫的兩個View(雪花和雪人)的程序打包成apk。可以不簽名。

3.把插件包放到服務器

在服務器返回的JSON中聲明插件包地址和動態View 的一些參數,這里的演示程序請求地址為:

http://tomatodo.ifancc.com/php/dynamicView.php

返回值為: 

  1.   "version": 54, 
  2.   "downLoadPath""http://obfgb7oet.bkt.clouddn.com/patch106.apk"
  3.   "fileName""patch106.apk"
  4.   "viewInfo": [ 
  5.     { 
  6.       "packageName""com.kot32.testdynamicviewproject.snow.widgets.SnowingView"
  7.       "uuid""activity_frame"
  8.       "layoutParams": { 
  9.         "width": -1, 
  10.         "height": -1 
  11.       }    }, 
  12.     { 
  13.       "packageName""com.kot32.testdynamicviewproject.player.MyPlayer"
  14.       "uuid""activity_player"
  15.       "layoutParams": { 
  16.         "width": -1, 
  17.         "height": -1 
  18.       }    } 
  19.   ]}  

我們聲明了這次在線包的版本,每個View 的包名和布局參數, 以及最重要的 和宿主程序中聲明對齊的uuid。

另外,Dynamic-load-view 能夠動態加載外部apk中的View以及資源,能夠熱修復線上View,以及模塊化更新。

屏幕截圖 

 

 

 

特點

  • 插件程序完全獨立于宿主。
  • 以 View作為模塊進行模塊化開發更新。
  • 你也可以把View 鋪滿整個Activity,相當于更新Activity。
  • 副作用小,沒有加載Activity 帶來的生命周期等問題。
  • 兼容性好。Android 4.0~6.0 都沒有問題。
  • 簡單。核心代碼不超過400行。可以自行下載源碼,修改更新規則。

如何使用

  • 下載庫,并作為library 引用。
  • 需要在宿主程序的Application 的onCreat 中初始化,代碼如下:.
  1. DynamicViewConfig config = new DynamicViewConfig.Builder() 
  2.     .context(this) 
  3.     .getUpdateInfoApi("http://vpscn.ifancc.com/php/dynamicView.php"
  4.     .build(); 
  5. DynamicViewManager.getInstance(config).init();  

getUpdateInfoApi 這個方法需要傳入一個API地址,這個API地址給客戶端提供更新的信息. 在上面的地址中,服務器返回了下面這樣的JSON 串: 

  1.   "version": 39, 
  2.   "downLoadPath""http://obfgb7oet.bkt.clouddn.com/patch101.apk"
  3.   "fileName""patch101.apk"
  4.   "viewInfo": [ 
  5.     { 
  6.       "packageName""com.kot32.testdynamicviewproject.MyButton"
  7.       "uuid""test"
  8.       "layoutParams": { 
  9.         "width": 100, 
  10.         "height": 100 
  11.       } 
  12.     }, 
  13.     { 
  14.       "packageName""com.kot32.testdynamicviewproject.MyButton1"
  15.       "uuid""test_activity"
  16.       "layoutParams": { 
  17.         "width": -1, 
  18.         "height": -1 
  19.       } 
  20.     } 
  21.   ] 
  22.  

上面的JSON 串定義了本次更新的版本以及更新包的地址,并且提供了對每個View 的詳細更新信息。

packageName :插件APK 中View 的完整包名.

uuid : 和宿主程序中待更新 View 相同的 UUID.

layoutParams:布局參數.

你也可以自己修改服務器需要提供的參數,更改com.kot32.dynamicloadviewlibrary.model 包中的模型類即可。

  • 待更新的View 需要xml 布局文件中如下聲明.注意uuid 屬性必須賦值。更新時會匹配uuid 相同的View。
  1. <com.kot32.dynamicloadviewlibrary.core.DynamicViewGroup 
  2.         android:id="@+id/dv" 
  3.         android:layout_width="200dp" 
  4.         android:layout_height="200dp" 
  5.         app:uuid="test" 
  6.         android:layout_centerInParent="true"
  7.  
  8.         <!--default view --> 
  9.         <ImageView 
  10.             android:layout_width="match_parent" 
  11.             android:layout_height="match_parent" 
  12.             android:src="@mipmap/ic_launcher" /> 
  13.  
  14. </com.kot32.dynamicloadviewlibrary.core.DynamicViewGroup>  

對于插件程序,只需要定義View 就好了,之后直接打成APK 包即可。

更多詳細信息,請直接下載示例源碼查看,源碼不多,也很好理解。

缺陷

  • 現在可以加載插件程序中的string和drawable 資源,但是style.xml 和 dimens.xml 的加載還存在一些問題。
  • 插件程序中的資源文件的名字最好不要和主程序中重復。
  • 在插件中訪問資源請使用:getContext().getResources()
責任編輯:龐桂玉 來源: 安卓巴士Android開發者門戶
相關推薦

2023-02-01 13:15:41

2011-03-29 15:15:06

熱備份熱修復

2018-01-09 15:57:18

熱修復開發編譯

2017-07-12 09:54:33

深度學習AI 人工智能

2024-11-26 06:53:01

雪花算法最大值

2017-12-27 12:04:03

聚劃算

2025-02-25 09:50:21

Java 8Function編程

2023-12-13 09:35:52

算法分布式

2014-10-14 12:51:22

騰訊云

2016-10-11 14:09:33

2016-06-20 10:59:53

SiriWWDC

2015-03-17 19:35:49

Xen漏洞阿里云

2011-08-19 15:04:11

Windows7熱修復補丁

2013-10-09 10:07:01

PS設計

2022-01-06 16:22:23

數字雪花

2014-12-19 11:42:57

LG G3

2018-12-25 09:27:55

Python圣誕帽程序員

2020-04-26 17:04:18

Python代碼數據
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 亚洲成人精品久久久 | 黄色网页在线观看 | 在线观看av网站永久 | 日韩精品在线网站 | 日韩国产在线 | 国产高清免费 | 亚洲www | 日本不卡免费新一二三区 | 亚洲综合首页 | 91久久精品国产 | 日本精品一区二区三区在线观看视频 | 羞羞视频在线观看免费观看 | 日本电影网站 | 在线观看特色大片免费网站 | 一本在线 | 成人午夜在线观看 | 成人午夜视频在线观看 | 毛片一级片 | 国产一区二区观看 | 日韩1区| 久久中文字幕电影 | 综合久久久| 一级毛片免费视频 | 日韩精品在线看 | 在线a视频网站 | 欧美日韩视频在线第一区 | 九色视频网站 | 人成在线 | 99久久99| 成人黄色电影在线观看 | 日韩精品在线播放 | 99国产精品99久久久久久 | 五月天国产视频 | 久久免费看 | 日韩免费中文字幕 | 欧美激情精品久久久久久变态 | 男人天堂久久久 | 国产精品久久久久一区二区三区 | 天天澡天天操 | 亚洲欧美自拍偷拍视频 | 日韩欧美在线精品 |