转载请注明出处:http://blog.csdn.net/harryweasley/article/details/73692467
网上已经有很多的介绍“Android动态修改桌面图标”的博客,无非就是用activity-alias,setComponentEnabledSetting方法,但是他们的博客都有一个问题(或许是我没找到正确的),就是当你在切换图标的时候,你的应用会被杀死,重启一次。
就拿下面的这个代码引入本篇博客吧:
ComponentName oldCN = new ComponentName(getPackageName(), "demo.lgx.com.multipleicondemo.IconAlias");
PackageManager pm = getPackageManager();
pm.setComponentEnabledSetting(oldCN, PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP);
通常来隐藏一个桌面icon,都会调用这个方法,但是调用这个方法就会出现一个如下所示的问题:
由官方文档的描述可知:
DONT_KILL_APP
added in API level 1
int DONT_KILL_APP
Flag parameter for setComponentEnabledSetting(android.content.ComponentName, int, int) to indicate that you don't want to kill the app containing the component. Be careful when you set this since changing component states can make the containing application's behavior unpredictable.
当你用DONT_KILL_APP,会发生一些不可预料的问题,尤其是当前的activity尝试要要禁止自己。所以最好是,由一个activity禁止另个一activity。
由上可知,该app最好有一个跳转界面,这样关闭的就是那个跳转界面了:
看下应用效果图吧:
现在看代码,首先是AndroidManifest.xml:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="demo.lgx.com.multipleicondemo">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".SplashActivity">activity>
<activity android:name=".MainActivity">
activity>
<activity-alias
android:name=".IconAlias"
android:enabled="true"
android:icon="@mipmap/ic_launcher_old"
android:label="@string/app_name"
android:targetActivity=".SplashActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
intent-filter>
activity-alias>
<activity-alias
android:name=".IconAliaNew"
android:enabled="false"
android:icon="@mipmap/ic_launcher_new"
android:label="@string/app_name_new"
android:targetActivity=".SplashActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
intent-filter>
activity-alias>
application>
manifest>
可以看到定义了两个activity-alias,一个android:enabled=”true”,一个android:enabled=”false”,android:enabled=”true”的activity-alias将会默认显示在桌面上,
其中android:targetActivity=”.SplashActivity”中的属性,就是真正要显示的activity
从这里可以看到,我们的activity都是没有
和
,这两个属性都放在activity-alias里,这就是为了保证,在使用PackageManager.DONT_KILL_APP时,应用不会重启啊。
SplashActivity代码很简单,就是开启一个线程,过3s后,启动MainActivity,
SplashActivity中的代码如下所示:
package demo.lgx.com.multipleicondemo;
import android.content.Intent;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import java.util.concurrent.TimeUnit;
import io.reactivex.Observable;
import io.reactivex.annotations.NonNull;
import io.reactivex.functions.Consumer;
/**
* Created by Harry on 2017/6/19.
*/
public class SplashActivity extends AppCompatActivity{
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_splash);
Observable.timer(3, TimeUnit.SECONDS).subscribe(new Consumer() {
@Override
public void accept(@NonNull Long aLong) throws Exception {
startActivity(new Intent(SplashActivity.this,MainActivity.class));
finish();
}
});
}
}
我这里的子线程等待3s,再跳转,用的是RxJava哈。
最后就是MainActivity的代码了,如下所示:
package demo.lgx.com.multipleicondemo;
import android.content.ComponentName;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void MyClick(View v) {
PackageManager pm = getPackageManager();
ComponentName oldCN = new ComponentName(getPackageName(), "demo.lgx.com.multipleicondemo.IconAlias");
ComponentName newCN = new ComponentName(getPackageName(), "demo.lgx.com.multipleicondemo.IconAliaNew");
switch (v.getId()) {
case R.id.oldIcon:
pm.setComponentEnabledSetting(oldCN, PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP);
pm.setComponentEnabledSetting(newCN, PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP);
break;
case R.id.newIcon:
pm.setComponentEnabledSetting(newCN, PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP);
pm.setComponentEnabledSetting(oldCN, PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP);
break;
}
}
}
这就是动态改变icon和label的源码了。
下面我开始泼冷水了:
当你修改了icon后,你的app将不能够升级安装了,安装后,打开也会直接崩溃,这就意味着,你的app将一直维持这个版本。
不能安装的错误日志如下所示:
Error while executing: am start -n "demo.lgx.com.multipleicondemo/demo.lgx.com.multipleicondemo.IconAlias" -a android.intent.action.MAIN -c android.intent.category.LAUNCHER
Starting: Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] cmp=demo.lgx.com.multipleicondemo/.IconAlias }
Error type 3
Error: Activity class {demo.lgx.com.multipleicondemo/demo.lgx.com.multipleicondemo.IconAlias} does not exist.
Error while Launching activity
解决这个办法,我目前想到了一个方法,就是你的app不放入各大应用市场(表打我,嘤嘤嘤~),只是自己应用内部实现更新,在更新之前,先变化自己的图标为默认图标,再安装更新。
如果哪个大神有更好的办法,请说一下哈。否则我总是觉得这个app动态更新没什么卵用。