首先说明一下,这篇文章包含了几个小列子,算是整合了,有些是从网上找到的相关资源。
第一个例子是应用具有多个icon程序入口:及在launcher中显示多个icon图标,此好处是方便用户选择其所需要的模块,比如:拨号键和通讯录,google地图和google纵横。
需要修改的地方有两处:
①AndroidManifest.xml处添加一个activity属性
<activity
android:name=".TestIconWidgetActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".TestIcon2Acvtivity"
android:icon="@drawable/ic_power"
android:label="@string/app_name_1"
android:launchMode="singleInstance" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
此处添加了第二个activity,需要注意的是android:launchMode="singleInstance",此模式的意思请看本人转载的博客Android Activity的四种LaunchMode!!!
②添加一个activity类
public class TestIcon2Acvtivity extends Activity{
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_2);
}
}
此时安装应用,在launcher功能列表中出现两个icon入口,截图如下:
第二个例子widget的开发,widget属性的配置,以及如何给应用添加多个widget:
①AndroidManifest.xml中添加相应配置,内容如下:
<!-- 添加一个4*3的widget -->
<receiver
android:name="com.pb09java.widget.MyWidgetProvider3"
android:label="全部 4 x 3" >
<meta-data
android:name="android.appwidget.provider"
android:resource="@xml/my_widget3" />
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
</receiver>
<!-- 添加一个4*2的widget -->
<receiver
android:name="com.pb09java.widget.MyWidgetProvider2"
android:label="全部 4 x 2" >
<meta-data
android:name="android.appwidget.provider"
android:resource="@xml/my_widget2"/>
<intent-filter>
<action android:name="com.action.widget.click"/>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE"/>
</intent-filter>
</receiver>
<!-- 添加一个4*1的widget -->
<receiver
android:name="com.pb09java.widget.MyWidgetProvider1"
android:label="全部4 x 1" >
<meta-data
android:name="android.appwidget.provider"
android:resource="@xml/my_widget1" />
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
</receiver>
<!-- widget中跳转前设置activity -->
<activity android:name="com.pb09java.widget.MyNoteConf2"
android:icon="@drawable/ic_launcher" android:screenOrientation="portrait">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_CONFIGURE" />
</intent-filter>
</activity>
以上代码包含三个widget的文件布局,android:resource="@xml/my_widget2"
包含三个AppWidgetProvider类,MyWidgetProvider2继承AppWidgetProvider,此类里面做widget的刷新和逻辑的处理
包含一个属性配置类,此类用于启动widget时跳转到activity进行配置,配置完成后跳转到widget,下面都会有介绍
②/xml/my_widget2.xml
<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
android:minWidth="@dimen/widget2_width"
android:minHeight="@dimen/widget2_height"
android:updatePeriodMillis="1000"
android:configure="com.pb09java.widget.MyNoteConf2"
android:initialLayout="@layout/widget2"
/>
<!-- 最小尺寸 = (单元格数*74)-2 -->
<!-- android:updatePeriodMillis 1.5版本后无用-->
上面包含五个属性分别作出解释: minwidth为最小宽度,minHeight为最小高度,由于此widget是4*2的宽高,所以设置为294dip和142dip
updatePeriodMillis属性本是widget刷新周期,但是无用,所以需要自定义Timer类刷新
configure属性配置,及上文提到的启动widget时跳转的activity类,在manifest中已经配置
/values/dimens.xml此文件为配置widget的宽高
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- add 4*1 widget -->
<dimen name="widget1_width">294dip</dimen>
<dimen name="widget1_height">72dip</dimen>
<!-- add 4*2 widget -->
<dimen name="widget2_width">294dip</dimen>
<dimen name="widget2_height">142dip</dimen>
<!-- add 4*3 widget -->
<dimen name="widget3_width">294dip</dimen>
<dimen name="widget3_height">220dip</dimen>
</resources>
③MyNoteConf2.java代码如下:
public class MyNoteConf2 extends Activity {
int mAppWidgetId;
private ProgressDialog dialog;
private Button ok;
private Button cancel;
private EditText userName;
private EditText passWord;
final public static int progressDialogId = 119;
final public static int NotId = 1973;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.widgetconf2);
ok = (Button) findViewById(R.id.ok);
cancel = (Button) findViewById(R.id.cancel);
userName = (EditText)findViewById(R.id.edit_name);
passWord = (EditText)findViewById(R.id.edit_password);
ok.setOnClickListener(okListener);
cancel.setOnClickListener(cancelListener);
// Find the widget id from the intent.
//添加如下语句,其意图在于保存mAppWidgetId,传给AppWidgetProvider
Intent intent = getIntent();
Bundle extras = intent.getExtras();
if (extras != null) {
mAppWidgetId = extras.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID,
AppWidgetManager.INVALID_APPWIDGET_ID);
}
// If they gave us an intent without the widget id, just bail.
if (mAppWidgetId == AppWidgetManager.INVALID_APPWIDGET_ID) {
finish();
}
}
@Override
protected Dialog onCreateDialog(int id)
{
switch (id){
case progressDialogId:
dialog = new ProgressDialog(this);
dialog.setCancelable(true);
dialog.setTitle("加载页面中....");
return dialog;
}
return super.onCreateDialog(id);
}
OnClickListener okListener = new OnClickListener() {
@Override
public void onClick(View v) {
showDialog(progressDialogId);
final Context context = MyNoteConf2.this;
new Thread(){
public void run() {
try {
saveTitlePref();
// 取得AppWidgetManager实例
AppWidgetManager appWidgetManager = AppWidgetManager
.getInstance(context);
// 更新AppWidget
MyWidgetProvider2.updateAppWidget(context, appWidgetManager,
mAppWidgetId, MyNoteConf2.this.getUserName(),MyNoteConf2.this.getPassWord());
//此处休眠1秒代替其他耗时间的操作,比如网络的用户验证
Thread.sleep(1000);
//通过返回,Launcher中的onActivityResult方法通过传入的intent调用widget
Intent resultValue = new Intent();
resultValue.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID,
mAppWidgetId);
setResult(RESULT_OK, resultValue);
dialog.dismiss();
finish();
} catch (InterruptedException e) {
e.printStackTrace();
}
};
}.start();
}
};
OnClickListener cancelListener = new OnClickListener() {
@Override
public void onClick(View v) {
finish();
}
};
void saveTitlePref(){
SharedPreferences localSharedPreferences = getSharedPreferences(
"WIDGET_DATA", Context.MODE_PRIVATE);
Editor localEditor = localSharedPreferences.edit();
//添加用户名
if(userName != null && userName.getText().toString().length()>0){
localEditor.putString("USER_NAME", userName.getText().toString()).commit();
}else{
localEditor.putString("USER_NAME", "guest").commit();
}
//添加密码
if(passWord != null && passWord.getText().toString().length()>0){
localEditor.putString("PASSWORD", passWord.getText().toString()).commit();
}else{
localEditor.putString("PASSWORD", "guest").commit();
}
}
public String getUserName() {
return userName.getText().toString();
}
public String getPassWord() {
return passWord.getText().toString();
}
}
此activity的布局文件/layout/widgetconf2.xml如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<!-- 进入widget时的配置activity类的布局文件 -->
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/widget_conf" />
<EditText android:id="@+id/edit_name"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:hint="@string/input_name"/>
<EditText android:id="@+id/edit_password"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:hint="@string/input_passwd"/>
<RelativeLayout android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<Button android:id="@+id/ok"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/ok"/>
<Button android:id="@+id/cancel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="@+id/ok"
android:text="@string/cancel"/>
</RelativeLayout>
</LinearLayout>
包含两个编辑框,填写用户名和密码,确认和取消button。
④widget的显示ui配置文件/layout/widget2.xml代码如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
android:background="@drawable/appwidget_bg">
<TextView android:id="@+id/widgetText"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/hello" />
<TextView android:id="@+id/userName"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/hello" />
<TextView android:id="@+id/password"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/hello" />
<TextView android:id="@+id/olympicGames"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/hello" />
</LinearLayout>
⑤MyWidgetProvider2.java代码如下:
public class MyWidgetProvider2 extends AppWidgetProvider {
private static final String CLICK_NAME_ACTION = "com.action.widget.click";
private static RemoteViews rv;
private String userName, password;
//为接收广播时调用更新UI
@Override
public void onReceive(Context context, Intent intent) {
super.onReceive(context, intent);
if (rv == null) {
rv = new RemoteViews(context.getPackageName(), R.layout.widget2);
}
if (intent.getAction().equals(CLICK_NAME_ACTION)) {
if (Uitil.isChange) {
rv.setTextViewText(R.id.widgetText, context.getResources()
.getString(R.string.load));
} else {
rv.setTextViewText(R.id.widgetText, context.getResources()
.getString(R.string.change));
}
Toast mToast = Toast.makeText(context, Boolean.toString(Uitil.isChange),
Toast.LENGTH_SHORT);
//此处设置显示的位置
mToast.setGravity(Gravity.TOP, 0, 10);
//让其显示
mToast.show();
Uitil.isChange = !Uitil.isChange;
}
AppWidgetManager appWidgetManger = AppWidgetManager
.getInstance(context);
int[] appIds = appWidgetManger.getAppWidgetIds(new ComponentName(
context, MyWidgetProvider2.class));
appWidgetManger.updateAppWidget(appIds, rv);
}
//删除组件时调用
@Override
public void onDeleted(Context context, int[] appWidgetIds) {
super.onDeleted(context, appWidgetIds);
}
//当第一个组件删除时调用
@Override
public void onDisabled(Context context) {
super.onDisabled(context);
}
//当第一个组件创建时调用
@Override
public void onEnabled(Context context) {
super.onEnabled(context);
}
/**
* 周期更新时调用
* android:updatePeriodMillis 1.5版本后无用
* 故需要周期刷新widget得自动通过Timer更新
*/
public void onUpdate(Context context, AppWidgetManager appWidgetManager,
int[] appWidgetIds) {
if(userName == null && password == null){
SharedPreferences localSharedPreferences = context.getSharedPreferences(
"WIDGET_DATA", Context.MODE_PRIVATE);
this.userName = localSharedPreferences.getString("USER_NAME", "guest");
this.password = localSharedPreferences.getString("PASSWORD", "guest");
}
final int N = appWidgetIds.length;
for (int i = 0; i < N; i++) {
int appWidgetId = appWidgetIds[i];
updateAppWidget(context, appWidgetManager, appWidgetId, userName, password);
}
// Timer timer = new Timer();
// timer.scheduleAtFixedRate(new MyTime(context,appWidgetManager), 1, 1000);
}
public static void updateAppWidget(Context context,
AppWidgetManager appWidgeManger, int appWidgetId, String userName, String password) {
//构建RemoteViews对象来对桌面部件进行更新
rv = new RemoteViews(context.getPackageName(), R.layout.widget2);
//更新文本内容,指定布局的组件
rv.setTextViewText(R.id.userName, userName);
rv.setTextViewText(R.id.password, password);
//为RemoteViews添加点击事件监听
Intent intentClick = new Intent(CLICK_NAME_ACTION);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0,
intentClick, 0);
rv.setOnClickPendingIntent(R.id.widgetText, pendingIntent);
//将RemoteViews的更新传入AppWidget进行更新
appWidgeManger.updateAppWidget(appWidgetId, rv);
}
}
此时代码修改完毕,看实际效果图:
第三个例子,安装应用后提示是否创建DeskShortCut:
①Androidmanifest.xml文件添加权限
<!-- 添加快捷方式的权限 -->
<uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT"/>
②TestIconWidgetActivity.java源码如下:
public class TestIconWidgetActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
@Override
protected void onResume() {
super.onResume();
SharedPreferences preferences = getSharedPreferences("first",
Context.MODE_PRIVATE);
boolean isFirst = preferences.getBoolean("isfrist", true);
if (isFirst) {
HandlerThread mHandlerThread = new HandlerThread("handler_thread");
mHandlerThread.start();
MyHandler myHandler = new MyHandler(mHandlerThread.getLooper());
myHandler.post(new Runnable() {
@Override
public void run() {
Dialog mDialog = new AlertDialog.Builder(TestIconWidgetActivity.this)
.setTitle("是否添加桌面快捷键")
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
createDeskShortCut();
dialog.dismiss();
}
})
.setNegativeButton(android.R.string.no, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
})
.setOnKeyListener(new DialogInterface.OnKeyListener() {
public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) {
if(event.getKeyCode() == KeyEvent.KEYCODE_SEARCH){
return true;
}
return false;
}
})
.setCancelable(false)
.create();
mDialog.show();
}
});
}
SharedPreferences.Editor editor = preferences.edit();
editor.putBoolean("isfrist", false);
editor.commit();
}
class MyHandler extends Handler{
public MyHandler(){
}
public MyHandler(Looper looper){
super(looper);
}
@Override
public void handleMessage(Message msg) {
System.out.println("Handler--->" + Thread.currentThread().getId());
System.out.println("handlerMessage");
}
}
/**
* 创建快捷方式
*/
public void createDeskShortCut() {
Log.i("coder", "------createShortCut--------");
// 创建快捷方式的Intent
Intent shortcutIntent = new Intent(
"com.android.launcher.action.INSTALL_SHORTCUT");
// 不允许重复创建
shortcutIntent.putExtra("duplicate", false);
// 需要现实的名称
shortcutIntent.putExtra(Intent.EXTRA_SHORTCUT_NAME,
getString(R.string.app_name));
// 快捷图片
Parcelable icon = Intent.ShortcutIconResource.fromContext(
getApplicationContext(), R.drawable.ic_pressure);
shortcutIntent.putExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE, icon);
Intent intent = new Intent(getApplicationContext(),
TestIconWidgetActivity.class);
// 下面两个属性是为了当应用程序卸载时桌面 上的快捷方式会删除
intent.setAction("android.intent.action.MAIN");
intent.addCategory("android.intent.category.LAUNCHER");
// 点击快捷图片,运行的程序主入口
shortcutIntent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, intent);
// 发送广播。
sendBroadcast(shortcutIntent);
}
}
在onResume方法中开启handler完成判断是否为一次开启,并询问第一次开启是否创建桌面快捷方式
效果图如下: