原文再續書接上一回,昨天我們把那個與伺服器端的互動以及解析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)