先写桌面部件的布局 widget_love.xml :
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:layout_width="300dp"
android:layout_height="200dp"
android:id="@+id/widget_img"/>
<TextView
android:layout_gravity="center_horizontal"
android:textColor="@color/colorPrimary"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="22sp"
android:id="@+id/boy_girl_name"/>
<TextView
android:layout_gravity="center_horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text=""
android:textColor="@android:color/holo_red_dark"
android:id="@+id/record"/>
</LinearLayout>
写一个xml, 设置初始显示的布局
<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
android:minHeight="300dp"
android:minWidth="400dp"
android:updatePeriodMillis="0"
android:previewImage="@mipmap/ic_launcher"
android:initialLayout="@layout/widget_love"> //这里是初始显示上面定义好的布局
</appwidget-provider>
然后就是定义provider继承 AppWidgetProvider
package com.example.loverappwidget;
import android.app.Service;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.widget.RemoteViews;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
/**
* Created by uwei on 2018/2/17.
*/
public class LoveRecordWidgetProvider extends AppWidgetProvider {
private static String mDate;
private static String mTime;
private static String boy_name;
private static String girl_name;
static void updateAppWidget(Context context, AppWidgetManager appWidgetManager,
int appWidgetId) {
boy_name = context.getSharedPreferences("setting", Context.MODE_PRIVATE).getString("boy_name", "");
girl_name = context.getSharedPreferences("setting", Context.MODE_PRIVATE).getString("girl_name", "");
mDate = context.getSharedPreferences("setting", Context.MODE_PRIVATE).getString("date", "");
mTime = context.getSharedPreferences("setting", Context.MODE_PRIVATE).getString("time", "");
String widgetText = boy_name + " 与 " + girl_name;
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget_love);
views.setTextViewText(R.id.boy_girl_name, widgetText);
String path = context.getFilesDir().getPath() + File.separator + SetActivity.IMAGE_FILE_NAME;
InputStream is = null;
try {
is = new FileInputStream(path);
Bitmap bitmap = BitmapFactory.decodeStream(is);
views.setImageViewBitmap(R.id.widget_img, bitmap);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
appWidgetManager.updateAppWidget(appWidgetId, views);
}
@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
// There may be multiple widgets active, so update all of the
for (int appWidgetId : appWidgetIds) {
updateAppWidget(context, appWidgetManager, appWidgetId);
}
Intent intent = new Intent(context,RecordService.class); //启动service,更新计时的时间
context.startService(intent);
}
@Override
public void onEnabled(Context context) {
// Enter relevant functionality for when the first widget is created
super.onEnabled(context);
Intent intent = new Intent(context,RecordService.class);
context.startService(intent);
}
@Override
public void onDisabled(Context context) {
// Enter relevant functionality for when the last widget is disabled
Intent intent = new Intent(context,RecordService.class);
context.stopService(intent);
}
@Override
public void onReceive(Context context, Intent intent) {
boy_name = context.getSharedPreferences("setting", Context.MODE_PRIVATE).getString("boy_name", "");
girl_name = context.getSharedPreferences("setting", Context.MODE_PRIVATE).getString("girl_name", "");
super.onReceive(context, intent);
AppWidgetManager manager = AppWidgetManager.getInstance(context);
RemoteViews views = new RemoteViews(context.getPackageName(),R.layout.widget_love);
views.setTextViewText(R.id.boy_girl_name,boy_name + " 与 " + girl_name);
InputStream is = null;
try {
String path = context.getFilesDir().getPath() + File.separator + SetActivity.IMAGE_FILE_NAME;
is = new FileInputStream(path);
Bitmap bitmap = BitmapFactory.decodeStream(is);
views.setImageViewBitmap(R.id.widget_img, bitmap);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
ComponentName componentName = new ComponentName(context,LoveRecordWidgetProvider.class);
manager.updateAppWidget(componentName,views);
Intent service = new Intent(context,RecordService.class);
context.startService(service);
}
}
界面设置代码:
package com.example.loverappwidget;
import android.Manifest;
import android.app.DatePickerDialog;
import android.app.TimePickerDialog;
import android.appwidget.AppWidgetManager;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.provider.MediaStore;
import android.support.annotation.NonNull;
import android.support.annotation.RequiresApi;
import android.support.design.widget.Snackbar;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.DatePicker;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.TimePicker;
import android.widget.Toast;
import org.w3c.dom.Text;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.util.Calendar;
public class SetActivity extends AppCompatActivity {
private ImageView mChooseImg;
private TextView mChooseTime;
private TextView mChooseDate;
private TextView mShowDate, mShowTime;
private EditText mBoyName, mGirlName,mShowTitle;
private final int IMAGE_REQUEST_CODE = 0x123;
private final int PHOTO_REQUEST_CUT = 0x125;
private final int SHOW_PHOTO = 0x124;
public static final String IMAGE_FILE_NAME = "CropedImgName.jpg";
private String mTime, mDate;
private Uri uritempFile;
private Button mSave;
private Button mSetImg;
@RequiresApi(api = Build.VERSION_CODES.M)
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_set);
mChooseImg = findViewById(R.id.choose_img);
mChooseTime = findViewById(R.id.choose_time);
mChooseDate = findViewById(R.id.choose_date);
mShowDate = findViewById(R.id.show_date);
mShowTime = findViewById(R.id.show_time);
mBoyName = findViewById(R.id.boy_name);
mGirlName = findViewById(R.id.girl_name);
mShowTitle = findViewById(R.id.show_title);
mSave = findViewById(R.id.save);
mSetImg = findViewById(R.id.choose_img_btn);
if(!hasPermission()){
requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},0);
}
init();
mSave.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (mDate == null || mTime == null) {
Snackbar.make(v, "请完整设置好信息", Snackbar.LENGTH_SHORT).show();
}
SharedPreferences sharedPreferences = getSharedPreferences("setting",MODE_PRIVATE);
sharedPreferences.edit().putString("boy_name", mBoyName.getText().toString())
.putString("girl_name", mGirlName.getText().toString())
.putString("title", mShowTitle.getText().toString())
.putString("date", mDate )
.putString("time",mTime).commit();
Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
sendBroadcast(intent);
Toast.makeText(SetActivity.this,"保存成功",Toast.LENGTH_SHORT).show();
}
});
mChooseImg.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(
Intent.ACTION_PICK,
android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
// 打开手机相册,设置请求码
startActivityForResult(intent, IMAGE_REQUEST_CODE);
}
});
mSetImg.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(
Intent.ACTION_PICK,
android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
// 打开手机相册,设置请求码
startActivityForResult(intent, IMAGE_REQUEST_CODE);
}
});
mChooseTime.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Calendar c = Calendar.getInstance();
new TimePickerDialog(SetActivity.this,
new TimePickerDialog.OnTimeSetListener() {
@Override
public void onTimeSet(TimePicker view, int hourOfDay, int minute) {
mShowTime.setText(hourOfDay + "时" + minute + "分");
mTime = "" + hourOfDay + ":" + minute + ":" + 00;
}
}, c.get(Calendar.HOUR), c.get(Calendar.MINUTE), true).show();
}
});
mChooseDate.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Calendar c = Calendar.getInstance();
new DatePickerDialog(SetActivity.this,
new DatePickerDialog.OnDateSetListener() {
@Override
public void onDateSet(DatePicker view, int year, int month, int dayOfMonth) {
mShowDate.setText(year + "年" + (month + 1) + "月" + dayOfMonth + "日");
mDate = "" + year + "-" + (month + 1) + "-" + dayOfMonth;
}
}, c.get(Calendar.YEAR), c.get(Calendar.MONTH), c.get(Calendar.DAY_OF_MONTH)).show();
}
});
}
@RequiresApi(api = Build.VERSION_CODES.M)
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode != RESULT_OK) {
return;
} else {
switch (requestCode) {
case IMAGE_REQUEST_CODE:
if (resultCode == RESULT_OK) {//resultcode是setResult里面设置的code值
try {
Uri selectedImage = data.getData(); //获取系统返回的照片的Uri
String[] filePathColumn = {MediaStore.Images.Media.DATA};
Cursor cursor = getContentResolver().query(selectedImage,
filePathColumn, null, null, null);//从系统表中查询指定Uri对应的照片
cursor.moveToFirst();
int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
String path = cursor.getString(columnIndex); //获取照片路径
cursor.close();
Bitmap bitmap = getSmallBitmap(path);
mChooseImg.setImageBitmap(bitmap);
getSharedPreferences("setting",MODE_PRIVATE).edit().putString("path",path).commit();
} catch (Exception e) {
// TODO Auto-generatedcatch block
e.printStackTrace();
}
}
break;
case PHOTO_REQUEST_CUT:
Bitmap bitmap = null;
try {
bitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(uritempFile));
} catch (FileNotFoundException e) {
e.printStackTrace();
}
Drawable drawable = new BitmapDrawable(bitmap);
mChooseImg.setBackground(drawable);
String path = getFilesDir().getPath() + File.separator + IMAGE_FILE_NAME;
File file = new File(path);
FileOutputStream outputStream = null;
try {
outputStream = new FileOutputStream(file);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, outputStream);
//TODO,将裁剪的bitmap显示在imageview控件上
break;
}
}
}
private void init(){
SharedPreferences sharedPreferences = getSharedPreferences("setting", MODE_PRIVATE);
mDate = sharedPreferences.getString("date",null);
mTime = sharedPreferences.getString("time",null);
mBoyName.setText(sharedPreferences.getString("boy_name",""));
mGirlName.setText(sharedPreferences.getString("girl_name",""));
mShowDate.setText(sharedPreferences.getString("date","未设置日期"));
mShowTime.setText(sharedPreferences.getString("time","未设置时间"));
mShowTitle.setText(sharedPreferences.getString("title","未设置前缀"));
// String path = getFilesDir().getPath() + File.separator + IMAGE_FILE_NAME;
String path = getSharedPreferences("setting",MODE_PRIVATE).getString("path",null);
if(path == null){
return;
}
Bitmap bitmap = getSmallBitmap(path);
mChooseImg.setImageBitmap(bitmap);
}
public boolean hasPermission(){
int result = ContextCompat
.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE);
return result == PackageManager.PERMISSION_GRANTED;
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode) {
case 0: { //这个0是requestCode,上面requestPermissions有用到
// If request is cancelled, the result arrays are empty.
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Toast.makeText(this, "已获取权限,可以设置图片", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(this, "您拒绝了写文件权限,无法设置图片", Toast.LENGTH_SHORT).show();
}
return;
}
}
}
private Bitmap getSmallBitmap(String path){
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
Bitmap bitmap = BitmapFactory.decodeFile(path,options);
float w = options.outWidth;
float h = options.outHeight;
options.inJustDecodeBounds = false;
float ww = 240f;
float hh = 400f;
int scale = Math.max(Math.round(w/ww),Math.round(h/hh));
options.inSampleSize = scale;
return BitmapFactory.decodeFile(path,options);
}
}
Service代码
package com.example.loverappwidget;
import android.app.Service;
import android.appwidget.AppWidgetManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.os.IBinder;
import android.support.annotation.Nullable;
import android.util.Log;
import android.widget.RemoteViews;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;
/**
* Created by uwei on 2018/2/18.
*/
public class RecordService extends Service {
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
super.onCreate();
new Thread(new Runnable() {
@Override
public void run() {
new Timer().schedule(new TimerTask() {
@Override
public void run() {
update();
}
},0,1000);
}
}).start();
}
public void update(){
String mDate = getSharedPreferences("setting", Context.MODE_PRIVATE).getString("date", "");
String mTime = getSharedPreferences("setting", Context.MODE_PRIVATE).getString("time", "");
String mTitle = getSharedPreferences("setting", Context.MODE_PRIVATE).getString("title", "");
String beginTime = mDate + " " + mTime;
Log.d("ww",beginTime);
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date now = new Date();
try {
Date begin = df.parse(beginTime);
long l = now.getTime() - begin.getTime();
Log.d("ww",now+"");
Log.d("ww",begin+"");
long day = l / (24 * 60 * 60 * 1000);
long hour = (l / (60 * 60 * 1000) - day * 24);
long min = ((l / (60 * 1000)) - day * 24 * 60 - hour * 60);
long s = (l / 1000 - day * 24 * 60 * 60 - hour * 60 * 60 - min * 60);
RemoteViews views = new RemoteViews(getPackageName(), R.layout.widget_love);
Log.d("ww",""+day+"天"+hour+"小时"+min+"分"+s+"秒");
views.setTextViewText(R.id.record, mTitle +": " + day + "天" + hour + "小时" + min + "分" + s + "秒");
AppWidgetManager manager = AppWidgetManager.getInstance(this);
ComponentName componentName = new ComponentName(this, LoveRecordWidgetProvider.class);
//调用APPWidgetManager将RemoteViews添加到ComponentName中
manager.updateAppWidget(componentName, views);
} catch (ParseException e) {
e.printStackTrace();
}
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
flags = START_STICKY; //防止因内存不足而销毁service,所以设置成START_STICKY,当因内存不足销毁后会自动启动
return super.onStartCommand(intent, flags, startId);
}
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
flags = START_STICKY; //防止因内存不足而销毁service,所以设置成START_STICKY,当因内存不足销毁后会自动启动
return super.onStartCommand(intent, flags, startId);
}
如果桌面小部件不显示widget的话,
加上
minResizeHeight,minResizeWidth就可以