原文再续书接上一回,昨天我们把那个与服务器端的交互以及解析xml的内容给搭建出来啦,那么今天我们就来完成一下下载新版的apk并安装的逻辑写一下
既然要下载apk,那么肯定是另开一个线程下载的啦,所以我们在这里就新建一个类啦
com.xiaobin.security.engine.downloadtask
<font color="#333333"><font face="arial">package com.xiaobin.security.engine;
import java.io.file;
import java.io.fileoutputstream;
import java.io.inputstream;
import java.net.httpurlconnection;
import java.net.url;
import android.app.progressdialog;
public class downloadtask
{
public static file getfile(string path, string filepath, progressdialog progressdialog) throws exception
{
url url = new url(path);
httpurlconnection httpurlconnection = (httpurlconnection) url.openconnection();
httpurlconnection.setconnecttimeout(2000);
httpurlconnection.setrequestmethod("get");
if(httpurlconnection.getresponsecode() == 200)
{
int total = httpurlconnection.getcontentlength();
progressdialog.setmax(total);
inputstream is = httpurlconnection.getinputstream();
file file = new file(filepath);
fileoutputstream fos = new fileoutputstream(file);
byte[] buffer = new byte[1024];
int len;
int process = 0;
while((len = is.read(buffer)) != -1)
{
fos.write(buffer, 0, len);
process += len;
progressdialog.setprogress(process);
}
fos.flush();
fos.close();
is.close();
return file;
}
return null;
}
}
</font></font>
复制代码
好啦,那个写好了,从服务器里面拿到一个最新版的apk之后,我们就要在splashactivity里面写一些安装的逻辑啦,还有一个内部类,用来启动另一个线程下载 com.xiaobin.security.ui.splashactivity
package com.xiaobin.security.ui;
import android.annotation.suppresslint;
import android.app.activity;
import android.app.alertdialog;
import android.content.dialoginterface;
import android.content.intent;
import android.content.pm.packageinfo;
import android.content.pm.packagemanager;
import android.content.pm.packagemanager.namenotfoundexception;
import android.net.uri;
import android.os.bundle;
import android.os.environment;
import android.os.handler;
import android.os.message;
import android.util.log;
import android.view.window;
import android.view.windowmanager;
import android.view.animation.alphaanimation;
import android.widget.linearlayout;
import android.widget.textview;
import android.widget.toast;
import com.xiaobin.security.r;
import com.xiaobin.security.domain.updateinfo;
import com.xiaobin.security.engine.downloadtask;
import com.xiaobin.security.engine.updateinfoservice;
public class splashactivity extends activity
private textview tv_version;
private linearlayout ll;
private progressdialog progressdialog;
private updateinfo info;
private string version;
private static final string tag = "security";
@suppresslint("handlerleak")
private handler handler = new handler()
public void handlemessage(message msg)
if(isneedupdate(version))
showupdatedialog();
};
};
@override
protected void oncreate(bundle savedinstancestate)
super.oncreate(savedinstancestate);
requestwindowfeature(window.feature_no_title);
setcontentview(r.layout.splash);
getwindow().setflags(windowmanager.layoutparams.flag_fullscreen, windowmanager.layoutparams.flag_fullscreen);
tv_version = (textview) findviewbyid(r.id.tv_splash_version);
version = getversion();
tv_version.settext("版本号 " + version);
ll = (linearlayout) findviewbyid(r.id.ll_splash_main);
alphaanimation alphaanimation = new alphaanimation(0.0f, 1.0f);
alphaanimation.setduration(2000);
ll.startanimation(alphaanimation);
progressdialog = new progressdialog(this);
progressdialog.setprogressstyle(progressdialog.style_horizontal);
progressdialog.setmessage("正在下载...");
new thread()
public void run()
try
{
sleep(3000);
handler.sendemptymessage(0);
}
catch (interruptedexception e)
e.printstacktrace();
};
}.start();
private void showupdatedialog()
alertdialog.builder builder = new alertdialog.builder(this);
builder.seticon(android.r.drawable.ic_dialog_info);
builder.settitle("升级提醒");
builder.setmessage(info.getdescription());
builder.setcancelable(false);
builder.setpositivebutton("确定", new dialoginterface.onclicklistener()
@override
public void onclick(dialoginterface dialog, int which)
if(environment.getexternalstoragestate().equals(environment.media_mounted))
file dir = new file(environment.getexternalstoragedirectory(), "/security/update");
if(!dir.exists())
{
dir.mkdirs();
}
string apkpath = environment.getexternalstoragedirectory() + "/security/update/new.apk";
updatetask task = new updatetask(info.geturl(), apkpath);
progressdialog.show();
new thread(task).start();
else
toast.maketext(splashactivity.this, "sd卡不可用,请插入sd卡", toast.length_short).show();
loadmainui();
});
builder.setnegativebutton("取消", new dialoginterface.onclicklistener()
loadmainui();
builder.create().show();
private boolean isneedupdate(string version)
updateinfoservice updateinfoservice = new updateinfoservice(this);
try
info = updateinfoservice.getupdateinfo(r.string.serverurl);
string v = info.getversion();
if(v.equals(version))
log.i(tag, "当前版本:" + version);
log.i(tag, "最新版本:" + v);
return false;
else
log.i(tag, "需要更新");
return true;
catch (exception e)
e.printstacktrace();
toast.maketext(this, "获取更新信息异常,请稍后再试", toast.length_short).show();
loadmainui();
return false;
private string getversion()
packagemanager packagemanager = getpackagemanager();
packageinfo packageinfo = packagemanager.getpackageinfo(getpackagename(), 0);
return packageinfo.versionname;
catch (namenotfoundexception e)
return "版本号未知";
private void loadmainui()
intent intent = new intent(this, mainactivity.class);
startactivity(intent);
finish();
/**
* 安装apk
* @param file 要安装的apk的目录
*/
private void install(file file)
intent intent = new intent();
intent.setaction(intent.action_view);
intent.setdataandtype(uri.fromfile(file), "application/vnd.android.package-archive");
//===========================================================================================
* 下载的线程
*
class updatetask implements runnable
private string path;
private string filepath;
public updatetask(string path, string filepath)
this.path = path;
this.filepath = filepath;
@override
public void run()
try
file file = downloadtask.getfile(path, filepath, progressdialog);
progressdialog.dismiss();
install(file);
catch (exception e)
e.printstacktrace();
toast.maketext(splashactivity.this, "更新失败", toast.length_short).show();
ps:上面那个com.xiaobin.security.ui.splashactivity类里面的那个handler是我为让用户清楚看到那个启动界面而设置的,不然,因为都是在同一个局域网里面,一下子就会完成那个更新的判断的啦,如果不用更新,那就会看不到那个启动界面的啦,所以为了我们能够看到那个界面,我让它休眠了2秒钟,才进行与服务器更新的,所以有什么不明白的也可以问一下
就这样子,我们就把启动界面时候,从服务器获取最新版的内容,然后提示用户是不是要更新的处理弄好啦! 既然启动界面弄好啦,那么,我们接下来,肯定是要做我们最重要的主界面啦 我们的主界面用到的是一个叫gridview的控件,它需要一个adapter,所以我们也要新建一个adapter的类 下面是主界面的布局文件
<?xml version="1.0" encoding="utf-8"?>
<linearlayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<linearlayout
android:layout_width="match_parent"
android:layout_height="40dip"
android:gravity="center_vertical|center_horizontal"
android:background="@drawable/title_background"
android:orientation="vertical">
<textview
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textcolor="@android:color/white"
android:textsize="22sp"
android:text="@string/main"/>
</linearlayout>
<gridview
android:id="@+id/gv_main"
android:layout_height="match_parent"
android:verticalspacing="8dip"
android:numcolumns="2" />
</linearlayout>
下面是adapter类的代码com.xiaobin.security.adapter.mainuiadapter
package com.xiaobin.security.adapter;
import android.content.context;
import android.content.sharedpreferences;
import android.view.layoutinflater;
import android.view.view;
import android.view.viewgroup;
import android.widget.baseadapter;
import android.widget.imageview;
public class mainuiadapter extends baseadapter
private static final string[] names = new string[] {"手机防盗", "通讯卫士", "软件管理", "流量管理", "任务管理", "手机杀毒",
"系统优化", "高级工具", "设置中心"};
private static final int[] icons = new int[] {r.drawable.widget01, r.drawable.widget02, r.drawable.widget03,
r.drawable.widget04, r.drawable.widget05, r.drawable.widget06, r.drawable.widget07,
r.drawable.widget08, r.drawable.widget09};
//声明成静态,起到一定的优化作用,关于adapter还有别的优化方法的,有机会我们再说
private static imageview imageview;
private static textview textview;
private context context;
private layoutinflater inflater;
private sharedpreferences sp;
public mainuiadapter(context context)
this.context = context;
inflater = layoutinflater.from(this.context);
sp = context.getsharedpreferences("config", context.mode_private);
public int getcount()
return names.length;
public object getitem(int position)
return position;
public long getitemid(int position)
public view getview(int position, view convertview, viewgroup parent)
view view = inflater.inflate(r.layout.main_item, null);
imageview = (imageview) view.findviewbyid(r.id.iv_main_icon);
textview = (textview) view.findviewbyid(r.id.tv_main_name);
imageview.setimageresource(icons[position]);
textview.settext(names[position]);
if(position == 0)
string name = sp.getstring("lostname", "");
if(!name.equals(""))
textview.settext(name);
return view;
adapter也写好啦,那么接下来,肯定就是我们的主界面啦com.xiaobin.security.ui.mainactivity
import com.xiaobin.security.adapter.mainuiadapter;
import android.content.sharedpreferences.editor;
import android.widget.adapterview;
import android.widget.edittext;
import android.widget.adapterview.onitemlongclicklistener;
import android.widget.gridview;
import android.widget.adapterview.onitemclicklistener;
public class mainactivity extends activity implements onitemclicklistener
private gridview gridview;
private mainuiadapter adapter ;
setcontentview(r.layout.main);
sp = this.getsharedpreferences("config", context.mode_private);
gridview = (gridview) findviewbyid(r.id.gv_main);
adapter = new mainuiadapter(this);
gridview.setadapter(adapter);
gridview.setonitemclicklistener(this);
gridview.setonitemlongclicklistener(new onitemlongclicklistener()
public boolean onitemlongclick(adapterview<?> parent, final view view, int position, long id)
if(position == 0) //这个是因为,如果我们的手机被盗了,用户一看到第一个手机防盗,那样肯定会先卸载我们的程序的,所以我们在手机防盗这个item里面,设置了一个重命名的功能
alertdialog.builder builder = new alertdialog.builder(mainactivity.this);
builder.settitle("设置");
builder.setmessage("请输入要理性的名称");
final edittext et = new edittext(mainactivity.this);
et.sethint("新名称");
builder.setview(et);
builder.setpositivebutton(android.r.string.ok, new dialoginterface.onclicklistener()
@override
public void onclick(dialoginterface dialog, int which)
{
string name = et.gettext().tostring();
if(name.equals(""))
{
toast.maketext(mainactivity.this, "输入内容不能为空", toast.length_short).show();
}
else
editor editor = sp.edit();
editor.putstring("lostname", name);
editor.commit();
textview tv = (textview) view.findviewbyid(r.id.tv_main_name);
tv.settext(name);
adapter.notifydatasetchanged();
}
});
builder.setnegativebutton(android.r.string.cancel, new dialoginterface.onclicklistener()
// todo auto-generated method stub
builder.create().show();
public void onitemclick(adapterview<?> parent, view view, int position, long id)
switch(position)
case 0 : //手机防盗
break;
case 1 : //通讯卫士
case 2 : //软件管理
case 3 : //流量管理
case 4 : //任务管理
case 5 : //手机杀毒
case 6 : //系统优化
case 7 : //高级工具
case 8 : //设置中心
default :
上面的那个重命名的功能,是我们把重新命名的名字,存放到一个sharedpreferences里面的,然后下一次启动的时候,就先检查里面有没有对应的值,没有就用默认的,有就用用户自己命名的 好啦,今天的代码基本上写得差不多的啦,现在只剩下添加权限啦,因为要读取sd卡,所以要添加相应的权限
<uses-permission android:name="android.permission.mount_unmount_filesystems" />
<uses-permission android:name="android.permission.write_external_storage"/>
现在就可以测试啦,记得要把服务器打开喔,还要昨天说的那个服务器的目录下面放一个apk喔,并把那个update.xml修改成与现在这个版本不一致的喔,不然不会更新的,不明白的可以看看下面的图
注意一下名称的对应 好啦,今天就说到这里啦
mb, 下载次数: 1115)