編輯:關於Android編程
demo的邏輯過程:
1.進入程序
2.檢查是否有版本更新,如果有則詢問用戶是否更新,否則維持原狀
3.檢測當前網絡狀態並且詢問用戶是否進行版本更新,如果是則進行更新,否則維持原狀
4.切換網絡,當當前網絡為wifi時,檢查版本更新,重復2、3.
結構:

CommonAsyncTask:執行網絡請求操作
ConnectionUrl:記錄要請求的IP地址
NetworkHelp:網絡輔助類
upDateAppUtil:更新版本類
MainActivity:UI及執行界面
客戶端:
MainActivity:
public class MainActivity extends Activity {
//接收網絡請求返回回調
private ListenerImpl mListenerImpl;
private ProgressDialog m_progressDlg;
private static final String TAG = "MainActivity";
private Dialog dialogs;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
m_progressDlg = new ProgressDialog(this);
m_progressDlg.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
// 設置ProgressDialog 的進度條是否不明確 false 就是不設置為不明確
m_progressDlg.setIndeterminate(false);
Log.d(TAG,"ONCREATE");
//注冊廣播接收器
registerReceiver();
//綁定網絡數據回調接收器
initListener();
// //獲取服務器版本
// updateAppUtil.getServerVersion(this);
}
protected void onStart(){
super.onStart();
Log.d(TAG, "ONSTART");
}
/**
* 網絡數據回調
*/
public void initListener() {
mListenerImpl = null;
mListenerImpl = ListenerImpl.getInstance();
mListenerImpl.setOnListener(new Listener() {
@Override
public void receiveData(T data) {
Log.d(TAG, data.toString());
dealAfterResponse((String) data);
}
});
}
/**
* 解析忘了數據
* @param s
*/
private void dealAfterResponse(String s) {
try {
JSONObject object;
object = new JSONObject(s);
if (object.getInt("Success")==200) {
//版本需要更新操作
if (object.getInt("appVersion")!= updateAppUtil.getAppVersion(this)){
Log.d(TAG, "not same");
if (NetworkHelp.isWifi(this)){
if (dialogs==null)
showDialog("有版本更新,是否更新版本");
}
else {
if (dialogs==null)
showDialog("有版本更新,當前不在wifi狀態,是否更新版本");
}
}
//版本不需要更新操作
else{
Log.d(TAG, "same");
}
}
} catch (JSONException e) {
e.printStackTrace();
}
}
/**
* 接收網絡狀態廣播消息
*/
public class MyReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
ConnectivityManager connectivityManager=(ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo mobNetInfo=connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
NetworkInfo wifiNetInfo=connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
if (!mobNetInfo.isConnected() && !wifiNetInfo.isConnected()) {
Toast.makeText(context, "網絡狀態不可用", Toast.LENGTH_SHORT).show();
}else {
dialogs=null;
//獲取服務器版本
Log.d(TAG,"MyReceiver");
updateAppUtil.getServerVersion(context);
}
} //如果無網絡連接activeInfo為null
}
/**
* 提示框
* @param str
*/
public void showDialog(String str){
dialogs = new AlertDialog.Builder(this).setTitle("軟件更新").setMessage(str)
// 設置內容
.setPositiveButton("更新",// 設置確定按鈕
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog,
int which) {
m_progressDlg.setTitle("正在下載");
m_progressDlg.setMessage("請稍候...");
updateAppUtil.downNewApp(ConnectionUrl.GET_SERVER_IP, m_progressDlg);
updateAppUtil.getAllFiles(new File("/sdcard/newApp"));
}
})
.setNegativeButton("暫不更新",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog,
int whichButton) {
dialogs.dismiss();
}
}).create();// 創建
// 顯示對話框
dialogs.show();
}
/**
* 注冊廣播接收器
*/
private void registerReceiver(){
IntentFilter filter=new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
MyReceiver myReceiver=new MyReceiver();
this.registerReceiver(myReceiver, filter);
}
protected void onDestroy(){
super.onDestroy();
Log.d(TAG,"ONDESTORY");
}
protected void onPause(){
super.onPause();
Log.d(TAG,"ONPAUSE");
if (isFinishing()){
Log.d(TAG,"ONONON");
}
}
}
該類主要工作是注冊了一個網絡狀態改變的廣播接收器,當網絡狀態改變的時候就會執行不同的操作,但是經過這個demo發現他並非改變時才會發送廣播,進入app後也會發送廣播:
if (!mobNetInfo.isConnected() && !wifiNetInfo.isConnected()) {
Toast.makeText(context, "網絡狀態不可用", Toast.LENGTH_SHORT).show();
}else {
dialogs=null;
//獲取服務器版本
Log.d(TAG,"MyReceiver");
updateAppUtil.getServerVersion(context);
}
updateAppUtil.getServerVersion(context);
該類還有一個工作是注冊了一個回調,接收服務器返回的版本號並且調用dealAfterResponse方法解析:
public void initListener() {
mListenerImpl = null;
mListenerImpl = ListenerImpl.getInstance();
mListenerImpl.setOnListener(new Listener() {
@Override
public void receiveData(T data) {
Log.d(TAG, data.toString());
dealAfterResponse((String) data);
}
});
}
調用getAppVersion能夠獲取當前app的版本號,版本號不同就會詢問是否更新,判斷不同的網絡狀態,彈出不同內容的提示框——showDialog():
if (object.getInt("appVersion")!= updateAppUtil.getAppVersion(this)){
Log.d(TAG, "not same");
if (NetworkHelp.isWifi(this)){
if (dialogs==null)
showDialog("有版本更新,是否更新版本");
}
else {
if (dialogs==null)
showDialog("有版本更新,當前不在wifi狀態,是否更新版本");
}
}
//版本不需要更新操作
else{
Log.d(TAG, "same");
}
點確定後調用以下方法下載並且安裝新版本app:
updateAppUtil.downNewApp(ConnectionUrl.GET_SERVER_IP, m_progressDlg);
updateAppUtil
該類封裝了一些更新app版本要用到的一些方法。
public class updateAppUtil {
private static Context mContext;
private static ProgressDialog progressDialog;
private static final String DIRECTORY_NAME = "/newApp";
private static final String File_NAME = "NewVersion.apk";
private static final String TAG = "updateAppUtil";
/**
* 獲取本app版本號
* @param context
* @return
*/
public static int getAppVersion(Context context) {
mContext =context;
int verCode = -1;
try {
//對應AndroidManifest.xml裡的package部分
verCode = context.getPackageManager().getPackageInfo(
"com.test.tangjiarao.versionupdate", 0).versionCode;
} catch (PackageManager.NameNotFoundException e) {
Log.e("msg", e.getMessage());
}
return verCode;
}
/**
* 獲取服務器的版本號
* @param context
*/
public static void getServerVersion(Context context){
Log.d(TAG,"getServerVersion");
new CommonAsyncTask(context).execute("get", ConnectionUrl.GET_SERVER_IP);
}
/**
* 創建文件路徑
*/
public static File getDirectory(){
File file = new File(Environment.getExternalStorageDirectory() + DIRECTORY_NAME);
//如果該路徑不存在,則創建文件夾
if (!file.exists()) {
file.mkdir();
}
return file;
}
/**
* 獲取目標路徑下的文件
* @param root
*/
public static void getAllFiles(File root){
File files[] = root.listFiles();
if(files != null)
for(File f:files){
if(f.isDirectory()){
getAllFiles(f);
}
else{
Log.d(TAG, f.getName());
}
}
}
/**
* 下載app
* @param path
* @param mProgressDialog
*/
public static void downNewApp(String path,ProgressDialog mProgressDialog) {
progressDialog =mProgressDialog;
progressDialog.show();
new Thread() {
public void run() {
URL url = null;
FileOutputStream fos = null;
BufferedInputStream bis = null;
HttpURLConnection connection = null;
try {
url = new URL(ConnectionUrl.DOWN_NEW_APP);
connection = (HttpURLConnection) url.openConnection();
//不能獲取服務器響應
if (HttpURLConnection.HTTP_OK != connection.getResponseCode()) {
Message message = Message.obtain();
message.what = 1;
handler.sendMessage(message);
}
//不存在sd卡
else if (Environment.getExternalStorageState()
.equals(Environment.MEDIA_UNMOUNTED)){
Message message=Message.obtain();
message.what=2;
handler.sendMessage(message);
}
//滿足上兩個條件
else{
//獲取網絡輸入流
bis = new BufferedInputStream(connection.getInputStream());
//文件大小
int length = connection.getContentLength();
progressDialog.setMax((int)length);
//緩沖區大小
byte[] buf = new byte[10];
int size =0;
//獲取存儲文件的路徑,在該路徑下新建一個文件為寫入流作准備
File cfile = new File(getDirectory().getPath(), File_NAME);
//如果不存在則新建文件
if (!cfile.exists()) {
cfile.createNewFile();
}
//將流與文件綁定
fos = new FileOutputStream(cfile);
//記錄進度條
int count=0;
//保存文件
while ((size = bis.read(buf)) != -1) {
fos.write(buf, 0, size);
count += size;
if (length > 0) {
progressDialog.setProgress(count);
}
}
Log.d("JSON",count+"");
Log.d("JSON","HAHA"+cfile.getAbsolutePath()+cfile.getName());
Bundle bundle=new Bundle();
Message message=Message.obtain();
message.what=3;
bundle.putString("msg", cfile.getAbsolutePath());
message.setData(bundle);
handler.sendMessage(message);
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
if (fos!= null) {
fos.close();
}
if (bis != null) {
bis.close();
}
if (connection!= null) {
connection.disconnect();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}.start();
}
private static Handler handler = new Handler() {
public void handleMessage(android.os.Message msg) {
switch (msg.what) {
case 1:
Toast.makeText(mContext, "網絡狀態不可用", Toast.LENGTH_SHORT).show();
Log.d(TAG, "網絡不通");
break;
case 2:
Toast.makeText(mContext, "請插入SD卡", Toast.LENGTH_SHORT).show();
Log.d(TAG, "沒有sd卡");
break;
case 3:
Bundle bundle = msg.getData();
String fileName = bundle.getString("msg");
installAPK(fileName,mContext);
Log.d(TAG, "已經下載");
break;
default:
break;
}
};
};
/**
* 安裝app
* @param fileName
* @param mContext
*/
private static void installAPK(String fileName,Context mContext){
File file =new File(fileName);
if(!file.exists()){
return;
}
Intent intent=new Intent();
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setAction(Intent.ACTION_VIEW);
Log.d(TAG,"AA"+"file://"+file.toString());
//"file://"+file.toString()下載的app的路徑
intent.setDataAndType(Uri.parse("file://"+file.toString()), "application/vnd.android.package-archive");
mContext.startActivity(intent);
}
}
CommonAsyncTask
public class CommonAsyncTask extends AsyncTask{ //顯示UI的組件 private Context mContext; //回調 private ListenerImpl listener; //調用標識 private String flag; //訪問url private String url; private String httpFuntion; //post傳參 private Map parameters; private final String TAG="CommonAsyncTask"; public CommonAsyncTask(Context mContext){ this.mContext = mContext; } //onPreExecute方法用於在執行後台任務前做一些操作 protected void onPreExecute() { super.onPreExecute(); Log.i(TAG, "onPreExecute() called"); if (!(NetworkHelp.isConnected(mContext))) { Toast.makeText(mContext, "網絡狀態不可用", Toast.LENGTH_SHORT).show(); return; } } //doInBackground方法內部執行後台任務,不可在此方法內修改UI @Override protected String doInBackground(String... params) { //get方法或者post方法的標識 httpFuntion= params[0]; url = params[1]; if(httpFuntion.equals("post")){ // flag =params[2]; // parameters = new HashMap<>(); // switch (flag) { // case "text" : // // parameters.put("account", params[3]); // break; // } return NetworkHelp.sendDataByPost(parameters, "utf-8", url); } else{ return NetworkHelp.getDataByGet("utf-8", url); } } //onProgressUpdate方法用於更新進度信息 @Override protected void onProgressUpdate(Integer... progresses) { Log.i(TAG, "onProgressUpdate(Progress... progresses) called"); } //onPostExecute方法用於在執行完後台任務後更新UI,顯示結果 @Override protected void onPostExecute(String result) { Log.i(TAG, "onPostExecute(Result result) called"); super.onPostExecute(result); //獲取返回數據後給MainActivity listener = null; listener = ListenerImpl.getInstance(); listener.transferData(result); clear(); } @Override protected void onCancelled() { Log.i(TAG, "onCancelled() called"); } protected void clear(){ parameters = null; flag = null; url = null; httpFuntion = null; } }
NetWorkHelp
public class NetworkHelp {
private static final String TAG ="NetworkHelp";
private static final int TIMEOUT_MILLIONS = 8000;
/**
* 判斷網絡是否連接
*
* @param context
* @return
*
*/
public static boolean isConnected(Context context)
{
ConnectivityManager connectivity = (ConnectivityManager) context
.getSystemService(Context.CONNECTIVITY_SERVICE);
if (null != connectivity)
{
NetworkInfo info = connectivity.getActiveNetworkInfo();
if (null != info && info.isConnected())
{
if (info.getState() == NetworkInfo.State.CONNECTED)
{
return true;
}
}
}
return false;
}
/**
* 判斷是否是wifi連接
*/
public static boolean isWifi(Context context)
{
ConnectivityManager connectivity = (ConnectivityManager) context
.getSystemService(Context.CONNECTIVITY_SERVICE);
if (connectivity == null)
return false;
return connectivity.getActiveNetworkInfo().getType() == ConnectivityManager.TYPE_WIFI;
}
/**
* Get funtion
* @param encode
* @param path
* @return
*/
public static String getDataByGet(String encode, String path){
URL url =null;
HttpURLConnection connection =null;
InputStream inptStream =null;
int responseCode;
try {
url = new URL(path);
connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
connection.setReadTimeout(TIMEOUT_MILLIONS);
connection.setConnectTimeout(TIMEOUT_MILLIONS);
connection.setDoInput(true);
connection.setUseCaches(false);
responseCode = connection.getResponseCode();
if(responseCode == HttpURLConnection.HTTP_OK) {
inptStream = connection.getInputStream();
Log.d(TAG,"GET FUNCTION OK");
return dealResponseResult(inptStream,encode);
}
} catch (IOException e) {
return "err: " + e.getMessage().toString();
} finally {
try {
if (connection != null) {
connection.disconnect();
}
if (inptStream != null) {
inptStream.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return "";
}
public static String sendDataByPost(Map params, String encode, String path) {
URL url=null;
HttpURLConnection connection = null;
OutputStream outputStream = null;
InputStream inputStream = null;
int responseCode;
byte [] data = getRequestData(params, encode).toString().getBytes();
try {
url = new URL(path);
connection = (HttpURLConnection)url.openConnection();
connection.setRequestMethod("POST");
connection.setConnectTimeout(TIMEOUT_MILLIONS);
connection.setReadTimeout(TIMEOUT_MILLIONS);
connection.setDoInput(true);
connection.setDoOutput(true);
connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
connection.setRequestProperty("Content-Length", String.valueOf(data.length));
outputStream = connection.getOutputStream();
outputStream.write(data, 0, data.length);
responseCode = connection.getResponseCode();
if (responseCode == 200) {
Log.d(TAG,"POST FUNCTION OK");
inputStream = connection.getInputStream();
return dealResponseResult(inputStream, encode);
}
} catch (Exception e) {
} finally {
try {
if (outputStream != null) {
outputStream.close();
}
if (inputStream != null) {
inputStream.close();
}
if (connection != null) {
connection.disconnect();
}
} catch (Exception e) {
e.printStackTrace();
}
}
return "";
}
public static StringBuffer getRequestData(Map params, String encode) {
StringBuffer buffer = new StringBuffer();
try {
for (Map.Entry entry : params.entrySet()) {
buffer.append(entry.getKey())
.append("=")
.append(URLEncoder.encode(entry.getValue(), encode))
.append("&");
}
buffer.deleteCharAt(buffer.length() - 1);
} catch (Exception e) {
e.printStackTrace();
}
return buffer;
}
public static String dealResponseResult(InputStream inputStream, String encode) {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
byte [] data = new byte[1024];
int lenngth = 0;
try {
while ((lenngth = inputStream.read(data)) != -1) {
byteArrayOutputStream.write(data, 0, lenngth);
}
return new String(byteArrayOutputStream.toByteArray(), encode);
} catch (Exception e) {
e.printStackTrace();
}
return "";
}
}
ConnectionUrl
public class ConnectionUrl { //獲取版本號IP public static String GET_SERVER_IP = "http://192.168.0.62:3000/getVersion"; //下載app IP public static String DOWN_NEW_APP = "http://192.168.0.62:3000/updateApp"; }
var express = require('express'); var router = express.Router(); /* GET home page. */ router.get('/updateApp', function(req, res, next) { ///Users/tangjiarao/version2.apk是該版本2apk在你計算機中的路徑 res.download("/Users/tangjiarao/version2.apk","version2"); }); router.get('/getVersion', function(req, res, next) { //返回版本號 res.json({"Success":200,"appVersion":2}); }); module.exports = router;
演示:
進入程序界面&不更新&更新
安裝&更新完成
問題:進入版本1app調用一次getServerVersion()調用一次,而更新版本2後,進入app捕抓不了mainActivy生命周期動作,並且調用兩次getServerVersion()方法。
進入版本1app:
下載版本2後:
猜測:是否是因為廣播接收器沒有注銷?
Android 使用內置的Camera應用程序捕獲圖像
本Demo的實現效果是調用手機上已安裝的照相機來實現拍照的功能,拍好的照片以ImageView形式展示。 目的:學習手機調用安裝的相機照相,對大的圖片處理有所認識,這裡主
Android高手之路之Android中Intent傳遞對象的兩種方法Serializable,Parcelable
Android中的傳遞有兩個方法,一個是Serializable,另一個是Parcelable。 Serializable是J2SE本身就支持的。而Parc
已有Android工程集成ReactNative頁面
React Native出自Facebook之手, 而且剛剛更新了文檔, 差一點我就放棄它了, 然而又撈了回來, 相比其他, 畢竟還是大公司大品牌有保障. 不多說了, 想
Android中與ViewRoot相關的一些概念
1、View和ViewRootViewRoot從名稱上來理解似乎是“View樹的根”,這很容易讓人產生誤解。因為ViewRoot並不屬於View樹