继上篇博客,我接下来做的是一个九宫格界面,但是对之前的Splash页面我还有要说的就是,当出现网络异常、json解析异常或者没有更新的时候,我们都必须要跳转到我们的主页面,因为Splash页面仅是展示一下我们的开发的品牌和版本信息,我们没有必要因为网络没有接通等一些异常,就让用户使用不了我们的软件。所以我们应该做的 是当出现这些异常的时候,我们要用Toast提示一下用户到底出现了什么异常。所以在之前的代码基础上我增加了红色的代码。
上篇博客当我们检查到新版本的时候,我们来下载这个安装包。以及显示下载的进度。下面我来展示一下效果图:
package com.itcast.mobilesafe58.activity; import java.io.File; import java.io.IOException; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; import org.json.JSONException; import org.json.JSONObject; import com.itcast.mobilesafe58.utils.StreamUtils; import com.itcast.mobilesafe58.utils.ToastUtils; import com.lidroid.xutils.HttpUtils; import com.lidroid.xutils.exception.HttpException; import com.lidroid.xutils.http.ResponseInfo; import com.lidroid.xutils.http.callback.RequestCallBack; import android.os.Bundle; import android.os.Environment; import android.os.Handler; import android.os.Message; import android.app.Activity; import android.app.AlertDialog; import android.content.DialogInterface; import android.content.DialogInterface.OnClickListener; import android.content.Intent; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.view.Menu; import android.view.View; import android.widget.TextView; import android.widget.Toast; /* * 展示品牌---->初始化数据---->检查版本---->校验合法性 */ public class SplashActivity extends Activity { private static final int UPDATE_DIALOG = 1;//更新提醒 private static final int NETWORK_ERROR = 2;//网络异常 private static final int JSON_ERROR = 3;//数据解析失败 private static final int URL_ERROR = 4;//网络异常 private static final int ENTER_HOME = 5;//跳转主页面 //控件初始化 private TextView tvVersion; private TextView tvProgress; //服务器的返回值 private String mVersionName;//成员变量 private int mVersionCode; private String mDescription; private String mDownloadUrl; //消息传递 private Handler mHandler = new Handler(){ public void handleMessage(android.os.Message msg) { switch (msg.what) { case UPDATE_DIALOG: showUpdateDialog(); break; case NETWORK_ERROR: ToastUtils.showToast(getApplicationContext(), "网络异常"); enterHome(); break; case JSON_ERROR: ToastUtils.showToast(getApplicationContext(), "数据解析失败"); enterHome(); break; case URL_ERROR: ToastUtils.showToast(getApplicationContext(), "网络连接异常"); enterHome(); break; case ENTER_HOME: enterHome(); default: break; } }; }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_splash); tvVersion = (TextView)findViewById(R.id.tv_version); tvProgress = (TextView)findViewById(R.id.tv_progress); tvVersion.setText("版本名:"+getVersionName()); checkVersion();//检查版本 } /* * 检查版本更新 */ private void checkVersion() { // TODO Auto-generated method stub new Thread(){ long startTime = System.currentTimeMillis();//开始时间 Message msg = Message.obtain();//获取消息 public void run(){ try { // URL url = new URL("http://10.0.2.2:8080/versionCode.json"); HttpURLConnection conn = (HttpURLConnection)url.openConnection(); conn.setConnectTimeout(2000);//连接网络超时 conn.setReadTimeout(2000);//读取超时 conn.setRequestMethod("GET");//访问方法 conn.connect();//连接网络 int responseCode = conn.getResponseCode(); if(responseCode == 200){ String result = StreamUtils.streamToString(conn.getInputStream()); System.out.println("访问成功--->"+result); //json数据解析 JSONObject jo = new JSONObject(result); mVersionName = jo.getString("versionName"); mVersionCode = jo.getInt("versionCode"); mDescription = jo.getString("description"); mDownloadUrl = jo.getString("downloadUrl"); System.out.println("versionCode--->"+mVersionCode); if (getVersionCode()<mVersionCode) {//如果软件的版本与网络中的版本号不一致,提示用户更新版本 System.out.println("有新版本!!!"); msg.what = UPDATE_DIALOG; }else{ System.out.println("没有新版本!!!"); //跳转到主页面 msg.what = ENTER_HOME; } } } catch (MalformedURLException e) { //url异常 // TODO Auto-generated catch block msg.what = URL_ERROR; e.printStackTrace(); } catch (IOException e) { //网络异常 // TODO Auto-generated catch block msg.what = NETWORK_ERROR; e.printStackTrace(); }catch (JSONException e) { //json异常 // TODO Auto-generated catch block e.printStackTrace(); msg.what = JSON_ERROR; }finally{ long endTime = System.currentTimeMillis();//访问网络结束时间 long timeUsed = endTime - startTime;//访问网络总的用时 if (timeUsed<2000) {//如果访问网络的时间小于2秒,就展示闪屏页面。目的是凑够两秒,来展示软件的品牌。 try { Thread.sleep(2000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } mHandler.sendMessage(msg);//发送消息 } } }.start(); } /* * 用于提醒用户更新的提示窗 */ protected void showUpdateDialog() { // TODO Auto-generated method stub AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setTitle("发现新版本:"+mVersionName); builder.setMessage(mDescription);//新版本的描述 builder.setPositiveButton("立即升级", new OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { // TODO Auto-generated method stub System.out.println("发现新版本"); downloadApk(); } }); builder.setNegativeButton("以后再说", new OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { // TODO Auto-generated method stub enterHome(); } }); builder.show(); } /* * 下载安装包 */ protected void downloadApk(){ String target = Environment.getExternalStorageDirectory().getAbsolutePath()+"/mobilesafe.apk"; tvProgress.setVisibility(View.VISIBLE); HttpUtils utils = new HttpUtils(); utils.download(mDownloadUrl, target, new RequestCallBack<File>() { //下载成功 @Override public void onSuccess(ResponseInfo<File> responseInfo) { // TODO Auto-generated method stub System.out.println("下载成功!!!!"); File result = responseInfo.result; tvProgress.setVisibility(View.GONE); enterHome(); } /* * 正在下载 * total 文件总大小 * current 当前下载的大小 * isUploading 是否正在上传 * (non-Javadoc) * @see com.lidroid.xutils.http.callback.RequestCallBack#onLoading(long, long, boolean) */ public void onLoading(long total, long current, boolean isUploading) { // TODO Auto-generated method stub super.onLoading(total, current, isUploading); // int percent = (int) ((current*100)/total); tvProgress.setText("下载进度:"+percent+"%"); } //下载失败 @Override public void onFailure(HttpException error, String msg) { // TODO Auto-generated method stub System.out.println("下载失败!!!!"); //ToastUtils.showToast(getApplicationContext(),"下载失败!!"); error.printStackTrace(); } }); } /* * 获取版本名 */ private String getVersionName() { // TODO Auto-generated method stub //获取包管理器 PackageManager pm = getPackageManager(); try { PackageInfo packageInfo = pm.getPackageInfo(getPackageName(), 0); int versionCode = packageInfo.versionCode;//获取版本号 String versionName = packageInfo.versionName;//获取版本名 System.out.println("versionName"+versionName+",versionCode"+versionCode); return versionName; } catch (NameNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } return ""; } /* * 获取版本号 */ private int getVersionCode() { // TODO Auto-generated method stub //获取包管理器 PackageManager pm = getPackageManager(); try { PackageInfo packageInfo = pm.getPackageInfo(getPackageName(), 0); int versionCode = packageInfo.versionCode;//获取版本号 return versionCode; } catch (NameNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } return 0; } //跳转到主页面 private void enterHome(){ startActivity(new Intent(this,HomeActivity.class));//开启的新的页面 finish();//结束原来的页面 } }
当我们运行程序的时候就会发现,我们的Splash页面展示的时间太短暂,为了更好的让Splash页面的功能能够体现我们让跳转页面的时间慢一点,这样我们就可以展示一下我们的品牌。但是如果用户的网速特别慢打开软件都需要花费很长时间,我们就没有必要让用户看我们的页面了。这样的话就需要我们来计算一下开始进入程序的时间,以及结束的时间,当用时小于2秒时,我们就让剩下的时间看一会闪屏页面。否则就直接跳转到主页面。所以我在我的程序中添加了一下的代码:上面程序的粉红色部分
好了,上篇的博客补充完毕。接下来介绍一下我做的九宫格页面。先把效果展示一下:
我们做九宫格经常用到的一个控件就是GridView,下面我把我的布局文件写在下面,这样的话可以更好的讲解一下九宫格当中的特殊属性:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:background="@color/white" android:orientation="vertical" > <TextView android:id="@+id/tv_title" android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center" android:background="#8866FF00" android:textColor="#000" android:textSize="30sp" android:text="功能列表" /> <GridView android:id="@+id/gv_home" android:layout_width="wrap_content" android:layout_height="wrap_content" android:verticalSpacing="15dp" //这是定义每一行和每一行之间的间隔 android:numColumns="3"> //这是定义一行有几个图片 </GridView> </LinearLayout>
下面是第一个功能模块-----》手机防盗功能的开发,当用户第一次点击手机防盗的时候会弹出一个设置密码的对话框,实现的效果图是:
实现代码是:
package com.itcast.mobilesafe58.activity; import com.itcast.mobilesafe58.utils.ToastUtils; import android.os.Bundle; import android.app.Activity; import android.app.AlertDialog; import android.app.AlertDialog.Builder; import android.app.Application; import android.content.Intent; import android.text.TextUtils; import android.view.Menu; import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.BaseAdapter; import android.widget.Button; import android.widget.EditText; import android.widget.GridView; import android.widget.ImageView; import android.widget.TextView; public class HomeActivity extends Activity { private GridView gvHome; //把需要添加的文字写在一个数组当中 private String[] mHomeList = new String[]{"手机防盗","通讯卫士", "软件管家","病毒查杀","缓存清理","进程管理","流量统计","高级工具","设置中心"};
//把需要添加的图片放在一个数组当中 private int[] mImageIds = new int[]{R.drawable.shi04xi, R.drawable.qi08ta,R.drawable.qi06ta,R.drawable.qi07ta, R.drawable.qi07ta,R.drawable.qi08ta,R.drawable.qi09ta, R.drawable.qi08ta,R.drawable.qi09ta}; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_home); gvHome = (GridView)findViewById(R.id.gv_home); gvHome.setAdapter(new HomeAdapter());//与ListView极其相似 //设置条目的点击事件 gvHome.setOnItemClickListener(new OnItemClickListener() { //parent代表gridview,view代表每个条目的view对象,position代表每个条目的位置 @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { // TODO Auto-generated method stub switch (position) { case 0://手机防盗 showSafeDialog(); break; case 1://通讯卫士 break; case 2://软件管家 break; case 3://病毒查杀 break; case 4://缓存清理 break; case 5://进程管理 break; case 6://流量统计 break; case 7://高级工具 break; case 8://设置中心 break; default: break; } } }); } /* * 密码弹窗 */ protected void showSafeDialog() { // TODO Auto-generated method stub //弹出设置密码的对话框 showSetUpPswdDialog(); } /* * 设置密码弹窗 */ private void showSetUpPswdDialog() { // TODO Auto-generated method stub AlertDialog.Builder builder = new AlertDialog.Builder(this); final AlertDialog dialog = builder.create();//创建dialog对象 View view = View.inflate(this, R.layout.dialog_set_password, null); dialog.setView(view, 0, 0, 0, 0);//给dialog设置自定义的布局,强制把上下左右边距设置为0,为了兼容2.x版本 final EditText etPassword = (EditText)view.findViewById(R.id.et_password); final EditText etPasswordConfirm = (EditText)view.findViewById(R.id.et_password_confirm); Button btn_OK = (Button)view.findViewById(R.id.btn_ok); Button btn_cancel = (Button)view.findViewById(R.id.btn_cancel); btn_OK.setOnClickListener(new OnClickListener() { /* * 判断两次输入的密码是否为空,两次输入的密码是否一致 * (non-Javadoc) * @see android.view.View.OnClickListener#onClick(android.view.View) */ @Override public void onClick(View v) { // TODO Auto-generated method stub String password = etPassword.getText().toString().trim(); String passwordConfirm = etPasswordConfirm.getText().toString().trim(); if (TextUtils.isEmpty(password)&&TextUtils.isEmpty(passwordConfirm)) { ToastUtils.showToast(getApplicationContext(), "输入框不能为空"); }else{ if (password .equals(passwordConfirm)) { ToastUtils.showToast(getApplicationContext(), "登录成功"); dialog.dismiss();//隐藏弹窗 HomeActivity.this.startActivity(new Intent(getApplicationContext(),LostAndFindActivity.class)); }else{ ToastUtils.showToast(getApplicationContext(), "两次输入的密码不一致!"); } } } private void startActivity(Application application, Class<LostAndFindActivity> class1) { // TODO Auto-generated method stub } }); btn_cancel.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub } }); dialog.show(); } /* * 九宫格数据适配器 */ class HomeAdapter extends BaseAdapter{ //得到item的个数 @Override public int getCount() { // TODO Auto-generated method stub return mHomeList.length; } //根据位置获取对象 @Override public String getItem(int position) { // TODO Auto-generated method stub return mHomeList[position]; } // @Override public long getItemId(int position) { // TODO Auto-generated method stub return position; } //初始化每一个item的布局 @Override public View getView(int position, View convertView, ViewGroup parent) { // TODO Auto-generated method stub View view = View.inflate(getApplicationContext(), R.layout.list_item_home, null); ImageView ivHome = (ImageView)view.findViewById(R.id.iv_home); TextView tvHome = (TextView) view.findViewById(R.id.tv_home); tvHome.setText(mHomeList[position]); ivHome.setImageResource(mImageIds[position]); return view; } } }