写这篇博客主要是为了纪念一下我转做App之后的第一个应用,当时确实很多都不懂,一点一点开始研究,虽然写的很一般,但是当时真的很用心在做,连续做了2周,每天加班都在10点以后,全公司最后走的就是我,现在想想真的不错。
这个应用的需求改了又改,改了又改,经过无数次的需求修改,终于确定下来了,首先桌面要有一个widget负责定时显示图片内容,图片地址给出来的很多张图片,每张图片的显示时间也不同,对应每个图片还有不同的消息内容,如果是应用那么就去打开应用,如果是网页就去打开网页,数据为每12小时获取一次,图片要在wifi的情况下获得,原本还有获得手机的各种状态,包括地理位置,mac地址,蓝牙地址,如果有卡的话要获得基站信息,ip地址等发给后台,而且时间很短,10分钟发一次,由于这样做太费电,所以后面的需求被拿掉了。
需求就这么多,说说实现吧,widget在开机时接收到开机广播,去拿图片,并使用handler做12小时延迟操作,拿到数据后,放到一个list里面,然后通过list里面的对象获得图片地址,然后去下载每张图片,保存在本地,如果下次拿到数据后图片已经有了就不再去下载。
有的同学会说还有什么下载现在网上N多的显示网络图片的框架,improt进来直接用多方便,对不起我到现在还不知道widget中imageview怎么来设置网络图片,至少我找到的还不支持这种设置,如果有同学做过,请千万告诉我,省得写download图片的代码,好了话不多说开始上代码。
如果你想在桌面上生成一个widget,那么在AndroidManifest里面需要定义一个receiver,并且包含meta-data为
<receiver android:name=".LogoAppWidgetProvider">
<intent-filter>
<action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
<action android:name="android.net.wifi.WIFI_STATE_CHANGED" />
<action android:name="android.net.wifi.STATE_CHANGE" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="@xml/adv_widget_provider" />
</receiver>
这里面resource = @xml/adv_widget_provider就是用来获得布局的
<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
android:initialLayout="@layout/adv_service_layout"
android:minHeight="30dp"
android:minWidth="250dp"
android:previewImage="@drawable/ic_launcher" >
</appwidget-provider>
简单说说第一行布局文件,用来绘制你的widget的形体,后面的就是宽高,最下面的是你这个widget在launcher里面注册的图标样式,其中我要吐槽一下,金立做的launcher实在是让人发指,定制的launcher的大小完全和其他手机不同,我在其他手机上面写一行的数据,到了他这就是2行,而且左右两边无法对齐,好了这不是重点。
@layout/adv_service_layout
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/transparent"
android:gravity="center"
android:orientation="vertical">
<ImageView
android:id="@+id/adv_imageview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="fitXY" />
</LinearLayout>
这个没什么了,就一个imageview
后面就是Java代码了,首先是Application
public class LogoApplication extends Application {
public static List<LogoInfo> logoinfolist = new ArrayList<LogoInfo>();
public static List<LogoInfo> tempLogoInfoList = new ArrayList<LogoInfo>();
public static int logoinfolistLength;
public static int logoeverytime;
public static RequestQueue queues;
public static String picPath = "/sdcard/LogoWidget/";
public static List<String> picNameList = new ArrayList<String>();
public void onCreate() {
super.onCreate();
queues = Volley.newRequestQueue(getApplicationContext());
mHandler.sendEmptyMessage(0);
startService(new Intent(LogoApplication.this, DownloadPicFromClient.class));
}
Handler mHandler = new Handler() {
public void handleMessage(Message msg) {
super.handleMessage(msg);
try {
startService(new Intent(LogoApplication.this, LogoService.class));
} catch (Exception e) {
mHandler.sendEmptyMessageDelayed(0, 12 * 60 * 60 * 1000);
}
mHandler.sendEmptyMessageDelayed(0, 12 * 60 * 60 * 1000);
}
};
public static RequestQueue getHttpQueues() {
return queues;
}
}
代码没什么难度,这里用初始化Volley,然后生命一个Handler每12小时拿一次数据,
后面还要写一个
public class LogoAppWidgetProvider extends AppWidgetProvider {
private static final String TAG = "LogoAppWidgetProvider";
public static final String ACTION_APPWIDGET_UPDATE = "android.appwidget.action.APPWIDGET_UPDATE";
// android:debuggable="false"
@Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
Intent stateintent = new Intent(context, LogoService.class);
context.startService(stateintent);
}
public void onUpdate(Context context, AppWidgetManager appWidgetManager,
int[] appWidgetIds) {
}
@Override
public void onDeleted(Context context, int[] appWidgetIds) {
}
@Override
public void onEnabled(Context context) {
}
@Override
public void onDisabled(Context context) {
//context.stopService(new Intent(context, LogoService.class));
}
}
这个是保证Application启动之后wifi没有打开,一旦wifi打开程序会在重新去拿数据
DownloadPicFromClient.java
public class GetDataFromClient implements HttpResponseListener {
private final static String loadJson = "https://cloud.yuyutechnology.com/adserver/adversFetch.do?deviceId=123&init=true&advertuserId=7";//pro
// private final static String loadJson = "https://cloud888.yuyutechnology.com/adserver/adversFetch.do?deviceId=123&init=true&advertuserId=7";//test
private final static String TAG_CHECK = "tag_check";
public static GetDataFromClient getInstace() {
return new GetDataFromClient();
}
public static void getdataFromClient(Context context) {
if (CheckWifiConnect.isNetworkConnected(context)) {
if (CheckWifiConnect.isWifiConnected(context)) {
if (!CheckWifiConnect.isMobileConnected(context)) {
VolleyRequest volleyRequest = new VolleyRequest();
volleyRequest.setHttpResponseListener(getInstace());
volleyRequest.RequestPost(loadJson, TAG_CHECK);
}
}
}
}
@Override
public void httpResponse(String data) {
LG.e(GetDataFromClient.class, data);
dataToObject(data);
}
public void dataToObject(String data) {
if (data == null)
return;
try {
JSONArray valarray = new JSONArray(data);
LogoApplication.logoinfolistLength = valarray.length();
LogoApplication.logoeverytime = Integer.parseInt(valarray.getJSONObject(0)
.getString("adImageShowInterval"));
LogoApplication.tempLogoInfoList.clear();
for (int i = 0; i < valarray.length(); i++) {
JSONObject arr = valarray.getJSONObject(i);
LogoInfo advinfo = new LogoInfo();
advinfo.adAppActionPackageName = arr
.optString("adAppActionPackageName");
advinfo.adAppActionClassName = arr
.optString("adAppActionClassName");
advinfo.adBrowserAction = arr
.optString("adBrowserAction");
advinfo.adImageUrl = arr.optString("adImageUrl");
LogoApplication.tempLogoInfoList.add(advinfo);
}
EventBus.getDefault().post(LogoApplication.tempLogoInfoList);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
@Override
public void httpREsponseError(VolleyError error) {
}
}
获得数据放入到一个静态的list里面后续下载图片以及播放图片都要用到,这里面拿到图片之后就使用EventBus发送通知去下载图片
DownloadPicFromClient.java
public class DownloadPicFromClient extends Service {
Context context;
public static int i = 0;
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
super.onCreate();
context = getApplicationContext();
}
@Override
public void onStart(Intent intent, int startId) {
super.onStart(intent, startId);
if (!EventBus.getDefault().isRegistered(this))
EventBus.getDefault().register(this);
}
public void onEventMainThread(List<LogoInfo> logoinfolist) {
if (CheckWifiConnect.isNetworkConnected(context)) {
if (CheckWifiConnect.isWifiConnected(context)) {
for (int i = 0; i < logoinfolist.size(); i++) {
File file = new File(logoinfolist.get(i).adImageUrl.trim());
String fileName = file.getName();
File sdFile = new File(LogoApplication.picPath + fileName);
boolean iAllPic = true;
if (!sdFile.exists()) {
iAllPic = false;
MyAsynaTask mTask = new MyAsynaTask(logoinfolist.get(i));
mTask.execute(logoinfolist.get(i).adImageUrl);
} else {
logoinfolist.get(i).downPicName = fileName;
}
if (iAllPic)
EventBus.getDefault().post("play advertisement");
}
}
}
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
super.onDestroy();
EventBus.getDefault().unregister(this);
startService(new Intent(this, LogoService.class));
}
public class MyAsynaTask extends AsyncTask<String, Integer, Bitmap> {
LogoInfo logoInfo;
public MyAsynaTask(LogoInfo logoInfo) {
this.logoInfo = logoInfo;
}
@Override
protected void onPreExecute() {
// TODO Auto-generated method stub
super.onPreExecute();
}
@Override
protected Bitmap doInBackground(String... params) {
// TODO Auto-generated method stub
Bitmap bitmap = null;
try {
URL url = new URL(params[0]);
HttpURLConnection connection = (HttpURLConnection) url
.openConnection();
connection.setDoInput(true);
connection.connect();
InputStream inputStream = connection.getInputStream();
bitmap = BitmapFactory.decodeStream(inputStream);
inputStream.close();
} catch (Exception e) {
// TODO: handle exception
}
return bitmap;
}
@Override
protected void onProgressUpdate(Integer... values) {
// TODO Auto-generated method stub
}
@Override
protected void onPostExecute(Bitmap result) {
// TODO Auto-generated method stub
super.onPostExecute(result);
boolean isFullBitmap = true;
this.logoInfo.picbitmap = result;
for (int j = 0; j < LogoApplication.tempLogoInfoList.size(); j++) {
if (LogoApplication.tempLogoInfoList.get(j).picbitmap == null) {
isFullBitmap = false;
break;
}
}
File file = new File(this.logoInfo.adImageUrl.trim());
String fileName = file.getName();
this.logoInfo.downPicName = fileName;
File sdFile = new File(LogoApplication.picPath + fileName);
if (!sdFile.exists() && result != null) {
LG.e(DownloadPicFromClient.class, "this.logoInfo.adImageUrl = " + this.logoInfo.adImageUrl);
saveCroppedImage(result, this.logoInfo.adImageUrl);
}
if (isFullBitmap) {
getFileCountAndName();
EventBus.getDefault().post("play advertisement");
}
}
}
private void saveCroppedImage(Bitmap bmp, String picUrl) {
File file = new File("/sdcard/LogoWidget");
if (!file.exists())
file.mkdir();
file = new File(("/sdcard/" + picUrl).trim());
String fileName = file.getName();
String mName = fileName.substring(0, fileName.lastIndexOf("."));
String sName = fileName.substring(fileName.lastIndexOf("."));
String newFilePath = LogoApplication.picPath + mName + sName;
file = new File(newFilePath);
if (fileIsExists(newFilePath)) {
} else {
try {
file.createNewFile();
FileOutputStream fos = new FileOutputStream(file);
bmp.compress(Bitmap.CompressFormat.JPEG, 50, fos);
fos.flush();
fos.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public void getFileCountAndName() {
getFiles(LogoApplication.picPath);
}
public boolean fileIsExists(String strFile) {
try {
File f = new File(strFile);
if (!f.exists()) {
return false;
}
} catch (Exception e) {
return false;
}
return true;
}
private void getFiles(String string) {
// TODO Auto-generated method stub
File file = new File(string);
File[] files = file.listFiles();
for (int j = 0; j < files.length; j++) {
String name = files[j].getName();
if (files[j].isDirectory()) {
String dirPath = files[j].toString().toLowerCase();
Log.d("shifuqiang", "dirPath" + dirPath);
getFiles(dirPath + "/");
} else if (files[j].isFile() & name.endsWith(".jpg") || name.endsWith(".png") || name.endsWith(".bmp") || name.endsWith(".gif") || name.endsWith(".jpeg")) {
Log.d("shifuqiang", "FileName===" + files[j].getName());
LogoApplication.picNameList.add(files[j].getName());
i++;
}
}
deletePicFromSDCard(LogoApplication.picNameList);
}
public void deletePicFromSDCard(List<String> picName) {
for (int i = 0; i < picName.size(); i++) {
boolean sdExitPic = false;
for (int j = 0; j < LogoApplication.tempLogoInfoList.size(); j++) {
if (LogoApplication.tempLogoInfoList.get(j).adImageUrl.contains((CharSequence) picName.get(i))) {
sdExitPic = true;
break;
}
}
if (!sdExitPic) {
deleteFileFromSDEx(picName.get(i));
}
}
}
public void deleteFileFromSDEx(String fileName) {
File deletefile = new File(LogoApplication.picPath + fileName);
deletefile.delete();
}
}
代码虽然有点长,也是当时不太规范,所以写的乱七八糟的,但是通过名字都能知道是什么意思就不多说了
下载完之后就去播放图片
public class LogoService extends Service {
private static final String TAG = "LogoService";
RemoteViews views;
List<PackageInfo> list;
PackageManager packageManager;
Context mcontext;
int playcount;
@Override
public void onCreate() {
super.onCreate();
views = new RemoteViews(getPackageName(), R.layout.adv_service_layout);
packageManager = this.getPackageManager();
mcontext = getApplicationContext();
}
@Override
public void onStart(Intent intent, int startId) {
super.onStart(intent, startId);
GetDataFromClient.getdataFromClient(getApplicationContext());
if (!EventBus.getDefault().isRegistered(this))
EventBus.getDefault().register(this);
if (null == views)
views = new RemoteViews(getPackageName(), R.layout.adv_service_layout);
}
public void onEventMainThread(String playAdvertisement) {
if (null == views)
views = new RemoteViews(getPackageName(), R.layout.adv_service_layout);
views.setImageViewResource(R.id.adv_imageview, R.drawable.define_head);
if (mHander.hasMessages(0))
mHander.removeCallbacksAndMessages(null);
LogoApplication.logoinfolist.clear();
for (int i = 0; i < LogoApplication.tempLogoInfoList.size(); i++) {
LogoApplication.logoinfolist.add(LogoApplication.tempLogoInfoList.get(i));
}
if (LogoApplication.logoinfolist.size() == 1) {
refreshWidget();
} else if (LogoApplication.logoinfolist.size() > 1) {
mHander.sendEmptyMessage(0);
}
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
super.onDestroy();
EventBus.getDefault().unregister(this);
mHander.removeCallbacksAndMessages(null);
startService(new Intent(this, LogoService.class));
}
Handler mHander = new Handler() {
public void handleMessage(Message msg) {
super.handleMessage(msg);
refreshWidget();
LG.e(LogoService.class, "handler post");
mHander.sendEmptyMessageDelayed(0, 5000);
}
};
public void getBitMapFromSDCard(String path, RemoteViews views) {
File mFile = new File(path);
if (mFile.exists()) {
Bitmap bitmap = BitmapFactory.decodeFile(path);
views.setImageViewBitmap(R.id.adv_imageview, bitmap);
}
}
public void refreshWidget() {
if (LogoApplication.logoinfolist == null
|| LogoApplication.logoinfolist.isEmpty())
return;
if (null == views)
views = new RemoteViews(getPackageName(), R.layout.adv_service_layout);
if (LogoApplication.logoinfolist.get(playcount
% LogoApplication.logoinfolist.size()).picbitmap != null) {
views.setImageViewBitmap(R.id.adv_imageview, LogoApplication.logoinfolist.get(playcount
% LogoApplication.logoinfolist.size()).picbitmap);
} else {
String sdPicPath = LogoApplication.picPath + LogoApplication.logoinfolist.get(playcount
% LogoApplication.logoinfolist.size()).downPicName;
getBitMapFromSDCard(sdPicPath, views);
}
list = packageManager.getInstalledPackages(0);
boolean hasadvpackage = false;
for (PackageInfo packageInfo : list) {
if (packageInfo.packageName
.equals(LogoApplication.logoinfolist.get(playcount
% LogoApplication.logoinfolist.size()).adAppActionPackageName)) {
hasadvpackage = true;
break;
}
}
Intent mintented = new Intent();
if (hasadvpackage) {
PackageManager packageManager = this.getPackageManager();
mintented = packageManager.getLaunchIntentForPackage("com.yuyu.android.pcam");
} else {
Uri uri = Uri.parse(LogoApplication.logoinfolist.get(playcount
% LogoApplication.logoinfolist.size()).adBrowserAction);
mintented.setAction(Intent.ACTION_VIEW);
mintented.setData(uri);
}
mintented.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED | Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
PendingIntent pendingIntent = PendingIntent.getActivity(
getApplicationContext(), 0, mintented, 0);
views.setOnClickPendingIntent(R.id.adv_imageview, pendingIntent);
AppWidgetManager appWidgetManager = AppWidgetManager
.getInstance(getApplicationContext());
ComponentName componentName = new ComponentName(
getApplicationContext(), LogoAppWidgetProvider.class);
appWidgetManager.updateAppWidget(componentName, views);
playcount++;
}
}
剩下的就是一些bean,接口类,和帮助类了
CheckWifiConnect.java
public static boolean isNetworkConnected(Context context) {
if (context != null) {
ConnectivityManager mConnectivityManager = (ConnectivityManager) context
.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo mNetworkInfo = mConnectivityManager
.getActiveNetworkInfo();
if (mNetworkInfo != null) {
return mNetworkInfo.isAvailable();
}
}
return false;
}
public static boolean isWifiConnected(Context context) {
if (context != null) {
ConnectivityManager mConnectivityManager = (ConnectivityManager) context
.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo mWiFiNetworkInfo = mConnectivityManager
.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
if (mWiFiNetworkInfo != null) {
return mWiFiNetworkInfo.isConnected();
}
}
return false;
}
public static boolean isMobileConnected(Context context) {
if (context != null) {
ConnectivityManager mConnectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo mMobileNetworkInfo = mConnectivityManager.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
if (mMobileNetworkInfo != null) {
return mMobileNetworkInfo.isConnected();
}
}
return false;
}
HttpResponseListener.java
public interface HttpResponseListener {
void httpResponse(String jsonObject);
void httpREsponseError(VolleyError error);
}
LogoInfo.java
public class LogoInfo {
String adId;
String adName;
String adSerialNumber;
String advertiserId;
String adStartTime;
String adEndTime;
String adAppActionPackageName;
String adAppActionClassName;
String adAppStoreAction;
String adBrowserAction;
String adImageUrl;
String adImageShowInterval;
String adState;
String adDurationTime;
String DelayedStartTime;
String DelayedEndTime;
public Bitmap picbitmap;
public String downPicName;
}
网络数据请求封装类VolleyRequest.java
public class VolleyRequest {
public StringRequest stringRequest;
public HttpResponseListener httpResponseListener;
public void setHttpResponseListener(
HttpResponseListener httpResponseListener) {
this.httpResponseListener = httpResponseListener;
}
public void RequestPost(String url, String tag) {
LogoApplication.getHttpQueues().cancelAll(tag);
stringRequest = new StringRequest(url,
new Response.Listener<String>() {
@Override
public void onResponse(String response) {
httpResponseListener.httpResponse(response);
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
httpResponseListener.httpREsponseError(error);
}
});
stringRequest.setTag(tag);
LogoApplication.getHttpQueues().add(stringRequest);
}
}