转载自:http://blog.youkuaiyun.com/pinsengjixuhezhou/article/details/45890569
注:这篇文章 主要内容和思路还是转自上面链接中博主的文章,我在实际使用过程中根据自己的需求有些调整。
主要要的逻辑就是想办法替换掉应用icon的drawable,然后通过自定义drawable的方式来实现动态Icon。
直接贴代码吧,没什么难的。
==============================================================================
2016.5.20号更新:
因为这个时钟图标导致内存泄漏的问题害我查了一个多星期的代码,之前没注意是因为这个时钟图标引起的问题,用mat查看发现这个时钟图标只占了那么几k的内存,以为没什么影响,结果是因为我在时钟图标里用的是3张bitmap不停叠加生成的实时图标,当热插拔sim卡时,会destroy掉Luancher,而我这边没有做bitmap的recycle操作,导致内存里的bitmap一直不停增加。
在这里重新添加资源释放的修改。
==============================================================================
首先在IconCache.java 中的修改
public IconScript getScript(Intent intent, UserHandleCompat user){
synchronized (mCache) {
ComponentName component = intent.getComponent();
if (component == null) {
return null;
}
LauncherActivityInfoCompat launcherActInfo = mLauncherApps.resolveActivity(intent, user);
CacheEntry entry = cacheLocked(component, launcherActInfo, user, true, false);
if("com.android.deskclock".equals(component.getPackageName())) {
if (ClockScript.getClockInstance() == null){
entry.script = new ClockScript();
} else {
entry.script = ClockScript.getClockInstance();
}
}
// if("com.android.calendar".equals(componentName.getPackageName())) {
// entry.script = new CalendarScript();
// }
return entry.script;
}
}
ShortcutInfo.java
Launcher.java , 新增一个Callbacks接口,在onDestroy()的调用,以释放时钟图标的资源
@Thunk WeakReference<ClockCallbacks> mClockCallbacks;
public interface ClockCallbacks {
public void stopClockIcon();
}
@Thunk final Object mLock = new Object();
public void initClockCallbak(ClockCallbacks callbacks){
synchronized (mLock) {
mClockCallbacks = new WeakReference<ClockCallbacks>(callbacks);
}
}
@Override
public void onDestroy() {
……………………
if (mClockCallbacks != null){
ClockCallbacks callbacks = mClockCallbacks.get();
if (callbacks != null) {
callbacks.stopClockIcon();
}
}
}
BubbleTextView.java 继承Launcher.ClockCallBacks接口
public class BubbleTextView extends TextView
implements BaseRecyclerViewFastScrollBar.FastScrollFocusableView , Launcher.ClockCallbacks{ //tangxuankai add Launcher.ClockCallbacks
………………
}
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
private Drawable setIcon(Drawable icon, int iconSize) {
mIcon = icon;
if (iconSize != -1) {
mIcon.setBounds(0, 0, iconSize, iconSize);
}
if (mLayoutHorizontal) {
if (Utilities.ATLEAST_JB_MR1) {
setCompoundDrawablesRelative(mIcon, null, null, null);
} else {
setCompoundDrawables(mIcon, null, null, null);
}
} else {
/****************tangxuankai add start ***********************/
if(mScript != null){
mLauncher.initClockCallbak(this);
mScript.setBounds(0, 0, iconSize, iconSize);
mIcon = mScript;
if(!mScript.isRuning){
mScript.run(this);
}
}
/****************tangxuankai add end ***********************/
setCompoundDrawables(null, mIcon, null, null);
}
return icon;
}
ClockScript.java
/**
* dynamic Clock Icon
*
*/
public class ClockScript extends IconScript {
Rect mSrcRect = new Rect();
Rect mDestRect = new Rect();
private int mIconSize;
private Context mContext;
private Time mTime;
private Bitmap mSecond, mMinute, mHour, mBackground;
private int mHiegtOffset, mWidthOffset;
public static ClockScript mClockInstance;
/**
* Results show target View
*/
private View mView;
/**
* notify System to invalidate
*/
private ClockThread mClockThread = null;
/**
* is showen on the screen now
*/
private boolean mIsShowInScreen = false;
public static ClockScript getClockInstance(){
return mClockInstance;
}
public ClockScript(){
super();
mClockInstance = this;
mContext = LauncherAppState.getInstance().getContext();
mIconSize = LauncherAppState.getInstance().getInvariantDeviceProfile().iconBitmapSize;
}
public void run(View view) {
mView = view;
mTime = new Time();
mBackground = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.launcher_theme_ic_app_clock_bg);//getBounds();
mSecond = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.launcher_theme_ic_app_clock_second_draw_by_pic);
mMinute = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.launcher_theme_ic_app_clock_minute_draw_by_pic);
mHour = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.launcher_theme_ic_app_clock_hour_draw_by_pic);
mDestRect.set(0, 0, mIconSize, mIconSize);
mSrcRect.set(0, 0, mBackground.getWidth(), mBackground.getHeight());
mHiegtOffset = (mIconSize - mBackground.getHeight()) / 2;
mWidthOffset = (mIconSize - mSecond.getWidth()) / 2;
if(mClockThread == null){
mClockThread = new ClockThread();
mClockThread.start();
}
}
@Override
public void onPause() {
mClockThread.pauseRun();
super.onPause();
}
@Override
public void onResume() {
mClockThread.resumeRun();
super.onResume();
}
@Override
public void onStop() {
if (mClockThread != null){
mClockThread.stopRun();
mClockThread.interrupt();
mClockThread = null;
}
super.onStop();
mContext = null;
if (mBackground != null){
mBackground.recycle();
mBackground = null;
}
if (mSecond != null){
mSecond.recycle();
mSecond = null;
}
if (mMinute != null){
mMinute.recycle();
mMinute = null;
}
if (mHour != null){
mHour.recycle();
mHour = null;
}
mClockInstance = null;
}
@Override
public void draw(Canvas canvas) {
super.draw(canvas);
mIsShowInScreen = true;
drawIndicator(canvas);
if(mClockThread.wait){
mClockThread.resumeRun();
}
}
/**
* draw Indicator
* @param canvas
* @param centerX
* @param centerY
* @param p
*/
private void drawIndicator(Canvas canvas){
try{
mTime.setToNow();
// p.setStrokeWidth(2);
// p.setColor(Color.BLACK);
float hourAngle = (float)mTime.hour / 12 * 360 + (float)mTime.minute / 60 * (360 / 12);
float minAngle = (float)mTime.minute / 60 * 360;
float secAngle = (float)mTime.second / 60 * 360;
canvas.save();
canvas.drawBitmap(mBackground, mSrcRect, mDestRect, null);
canvas.restore();
canvas.save();
canvas.rotate(hourAngle, mIconSize / 2, mIconSize / 2);
canvas.drawBitmap(mHour, mWidthOffset, mHiegtOffset, null);
canvas.restore();
canvas.save();
canvas.rotate(minAngle, mIconSize / 2, mIconSize / 2);
canvas.drawBitmap(mMinute, mWidthOffset, mHiegtOffset, null);
canvas.restore();
canvas.save();
canvas.rotate(secAngle, mIconSize / 2, mIconSize / 2);
canvas.drawBitmap(mSecond, mWidthOffset, mHiegtOffset, null);
canvas.restore();
}catch(Exception e){
e.printStackTrace();
}
}
class ClockThread extends Thread {
int times = 0;
boolean running = true;
public boolean wait = false;
public void stopRun() {
running = false;
synchronized (this) {
this.notify();
}
};
public void pauseRun() {
this.wait = true;
synchronized (this) {
this.notify();
}
}
public void resumeRun() {
this.wait = false;
synchronized (this) {
this.notify();
}
}
public void run() {
while (running) {
synchronized (mView) {
mView.postInvalidate();
}
if(!mIsShowInScreen){
pauseRun();
}
mIsShowInScreen = false;
try {
Thread.sleep(500);
} catch (Exception e) {
System.out.println(e);
}
synchronized (this) {
if (wait) {
try {
wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
}
}