手机安全卫士01

01.  项目介绍

02.  SVN的使用

03.  代码的包结构

 1.按照模块 组织代码的包结构 ;各个模块之间的业务是独立;

      办公软件www.itheima.com

             ----开会  com.itheima.meeting

             ----发工资       com.itheima.money

             ----出差    com.itheima.travel

 

       风行网

            -----播放器    com.funshion.android.player

            -----下载模块 com.funshion.android.download

            -----联网 com.funshion.android.network

 2.按照类型组织代码的包结构

       -----界面 com.itheima.activity

       ----自定义界面      com.itheima.ui

       ----业务逻辑  com.itheima.engine- 联网

       ----持久化      com.itheima.db

                            com.itheima.db.dao

       ----后台服务  com.itheima.service

       ----接收广播  com.itheima.receiver

       ----公共API接口 com.itheima.utils

04.工程的创建

创建工程时最好不要选择最大版本,防止以后Android新版本无法安装(maxSdkVersion)

05.  splash页面UI完成

  (1)提交工程到版本库

      a.在版本库中新建一个库,拷贝URl

      b.找出mobilesafe工程的路径,把工程文件夹右键检出,使库的URL与工程的绝对路径相对应

      c.打开工程文件夹,把问号文件(除了自动生成的svn,bin,gen)添加到本地库,然后提交到服务器

  (2)splash界面的作用

      a.用来展现产品的Logo;

      b.应用程序初始化的操作;

      c.检查应用程序的版本;

      d.检查当前应用程序是否合法注册

  (3)配置文件中的版本信息

      a.  android:versionCode="1"   :int类型            ,android:versionName="1.0"    :string类型

  (4)动态的到版本信息(即配置文件中的版本)

      a.程序运行会自动生成一个apk,包含配置文件


<span style="font-size:14px;">  
	/**
	 * 得到应用程序的版本名称
	 */

	private String getVersionName() {
		// 用来管理手机的APK
		PackageManager pm = getPackageManager();

		try {
			// 得到知道APK的功能清单文件
			PackageInfo info = pm.getPackageInfo(getPackageName(), 0);
			return info.versionName;
		} catch (NameNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			return "";
		}

	}
</span>

06.  升级的原理

 1.在服务器配置,下载的apk和版本信息(json-------版本号,版本描述,版本下载链接)

 2.升级原理


07.连接服务器获取更新信息

1、到webservice里去写json文件:updata.json

2、Anddroid工程添加联网权限:android.permission.INTERNET

3、在子线程中请求服务器代码checkVersion()。

4,   请求网络的代码:        把url封装到value目录下,创建一个xml文件

5.   参照一个解析流的类StreamTools.java  :把字节流转换成字符串

6.   解析JSON

7.   用Handler更新信息

8、写延迟2秒进入主页面代码

	/**
	 * 检查是否有新版本,如果有就升级
	 */
	private void checkUpdate() {

		new Thread() {
			public void run() {
				// URLhttp://192.168.1.254:8080/updateinfo.html

				Message mes = Message.obtain();
				long startTime = System.currentTimeMillis();     //睡两秒,防止一闪而过,记录当前时间
				try {

					URL url = new URL(getString(R.string.serverurl));//放在values新建一个xml文件,便于改变
					// 联网
					HttpURLConnection conn = (HttpURLConnection) url
							.openConnection();
					conn.setRequestMethod("GET");//请求方法
					conn.setConnectTimeout(4000);//链接超时
					int code = conn.getResponseCode();//响应吗
					if (code == 200) {
						// 联网成功
						InputStream is = conn.getInputStream();
						// 把流转成String
						String result = StreamTools.readFromStream(is);
						Log.i(TAG, "联网成功了" + result);
						// json解析
						JSONObject obj = new JSONObject(result);
						// 得到服务器的版本信息
						String version = (String) obj.get("version");

						description = (String) obj.get("description");
						apkurl = (String) obj.get("apkurl");

						// 校验是否有新版本
						if (getVersionName().equals(version)) {//当前的版本与服务器版本
							// 版本一致,没有新版本,进入主页面
							mes.what = ENTER_HOME;
						} else {
							// 有新版本,弹出一升级对话框
							mes.what = SHOW_UPDATE_DIALOG;

						}

					}

				} catch (MalformedURLException e) {
					// TODO Auto-generated catch block
					mes.what = URL_ERROR;
					e.printStackTrace();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					mes.what = NETWORK_ERROR;
					e.printStackTrace();
				} catch (JSONException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
					mes.what = JSON_ERROR;
				} finally {

					long endTime = System.currentTimeMillis(); //结束时间
					// 我们花了多少时间
					long dTime = endTime - startTime;
					// 2000
					if (dTime < 2000) {
						try {
							Thread.sleep(2000 - dTime);
						} catch (InterruptedException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}
					}

					handler.sendMessage(mes);
				}

			};
		}.start();

	}

9、创建主页面HomeActivity和布局文件

10、添加AlphaAnimation动画效果:   activity间切换效果     (oncreat());

		AlphaAnimation aa = new AlphaAnimation(0.2f, 1.0f);   //  界面切换动画,朦胧转成清晰
		aa.setDuration(500);
		findViewById(R.id.rl_root_splash).startAnimation(aa);

11. 提示升级对话框--------升级安装

   (1)工具包  afinal.jar

/**
	 * 弹出升级对话框
	 */
	protected void showUpdateDialog() {
		//this = Activity.this
		AlertDialog.Builder builder = new Builder(SplashActivity.this);
		builder.setTitle("提示升级");
//		builder.setCancelable(false);//强制升级
		builder.setOnCancelListener(new OnCancelListener() {  //监听取消
			
			@Override
			public void onCancel(DialogInterface dialog) {
				// TODO Auto-generated method stub
				//进入主页面
				enterHome();
				dialog.dismiss();
				
			}
		});
		builder.setMessage(description);
		builder.setPositiveButton("立刻升级", new OnClickListener() {

			@Override
			public void onClick(DialogInterface dialog, int which) {
				// 下载APK,并且替换安装
				if (Environment.getExternalStorageState().equals(
						Environment.MEDIA_MOUNTED)) {
					// sdcard存在
					// afnal
					FinalHttp finalhttp = new FinalHttp();   //外部包
					finalhttp.download(apkurl, Environment
							.getExternalStorageDirectory().getAbsolutePath()+"/mobilesafe2.0.apk",
							new AjaxCallBack<File>() {

								@Override
								public void onFailure(Throwable t, int errorNo,           //下载失败
										String strMsg) {
									t.printStackTrace();
									Toast.makeText(getApplicationContext(), "下载失败", 1).show();
									super.onFailure(t, errorNo, strMsg);
								}

								@Override
								public void onLoading(long count, long current) {        //下载中
									// TODO Auto-generated method stub
									super.onLoading(count, current);
									tv_update_info.setVisibility(View.VISIBLE);
									//当前下载百分比
									int progress = (int) (current * 100 / count);
									tv_update_info.setText("下载进度:"+progress+"%");
								}

								@Override
								public void onSuccess(File t) {                      //下载完成
									// TODO Auto-generated method stub
									super.onSuccess(t);                     
									installAPK(t);                           //下载完成后安装
								}
								/**
								 * 安装APK
								 * @param t
								 */
								private void installAPK(File t) {
                                                                  //调用系统的安装
								  Intent intent = new Intent();
								  intent.setAction("android.intent.action.VIEW");
								  intent.addCategory("android.intent.category.DEFAULT");
								  intent.setDataAndType(Uri.fromFile(t), "application/vnd.android.package-archive");
								  
								  startActivity(intent);
								  
								}
								
							
							});
				} else {
					Toast.makeText(getApplicationContext(), "没有sdcard,请安装上在试",
							0).show();
					return;
				}

			}
		});
		builder.setNegativeButton("下次再说", new OnClickListener() {

			@Override
			public void onClick(DialogInterface dialog, int which) {
				// TODO Auto-generated method stub
				dialog.dismiss();
				enterHome();// 进入主页面
			}
		});
		builder.show();

	}
08.应用程序的签名

 (1)在Android手机里不允许有两个应用程序有相同的包名;

     假设A应用的包名:com.itheima.mobilesafeA;

     A应用已经在系统中存在了。

    这个时候再去安装一个应用B ,他的报名也叫con.itheima.mobilesafeA

    系统就会去检查这两应用的签名是否相同。如果相同,B会把A给覆盖安装掉;

    如果不相同 B安装失败;

   要想自动安装成功,必须保证应用程序不同版本的签名完成一样。

(2)正在开发的应用会根据电脑开发环境产生默认签名,工程路径-----bin目录-----apk

(3)签名方式:导出应--------------------用已存在的密钥or创建新的密钥

09.Splash界面的细节

(1)显示4.0的样式:方式是去掉功能清单里的Activity对应的android:theme

    放到application里面;------------------------改一下系统代码

(2)当splash页面弹出升级提示框,过滤点击返回的是两种方式:

    提示框不能取消-------------------------------强制升级//  一般不用

    监听返回键和触摸对话框以外地方

10.两种上下文的区别

 对话框是Activity的一部分。

  对话框是挂载在Activity上面的 。

  如果Activity不存在,对话框就不能被创建。

 

  Activity 实际上是应用程序context上下文的一个子集。

 

  子类有的东西父类不一定有

  父类有的东西子类一定有

 

  getApplicationContext();生命周期长,只要应用还存活它就存在;

  this 生命周期短,只要Activity不存在了,系统就会回收; 

 

  其中:getBaseContext(),getApplication(),getApplicationContext();

  都不能放在AlertDialog做上下文;

 

  getApplicationContext() 使用场景是比如频繁需要操作的数据库

 

  推荐用法:Activity.this

11. 应用程序主界面
(1)滚动的TextView---------------------------------自定义一个TextView

      创建一个类class继承TextView

import android.content.Context;
import android.util.AttributeSet;
import android.view.ViewDebug.ExportedProperty;
import android.widget.TextView;

/*
 * 自定一个TextView 一出生就有焦点
 */
public class FocusedTextView extends TextView {

	public FocusedTextView(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
		// TODO Auto-generated constructor stub
	}

	public FocusedTextView(Context context, AttributeSet attrs) {
		super(context, attrs);
		// TODO Auto-generated constructor stub
	}

	public FocusedTextView(Context context) {
		super(context);
		// TODO Auto-generated constructor stub
	}
	
	/**
	 * 当前并没有焦点,我只是欺骗了Android系统
	 */
	@Override
	@ExportedProperty(category = "focus")
	public boolean isFocused() {
		return true;
	}
	
	
使用:

 <com.itheima.mobilesafe.ui.FocusedTextView
        android:singleLine="true"
        android:ellipsize="marquee"
        android:textSize="18sp"
        android:text="最新的手机卫士,快来下载啊,下载送好吃的,最新的手机卫士,快来下载啊,下载送好吃的"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content" />
总界面:

public class HomeActivity extends Activity {
	
	private GridView list_home;
	private MyAdapter adapter;
	private static String [] names = {
		"手机防盗","通讯卫士","软件管理",
		"进程管理","流量统计","手机杀毒",
		"缓存清理","高级工具","设置中心"
		
	};
	
	private static int[] ids = {
		R.drawable.safe,R.drawable.callmsgsafe,R.drawable.app,
		R.drawable.taskmanager,R.drawable.netmanager,R.drawable.trojan,
		R.drawable.sysoptimize,R.drawable.atools,R.drawable.settings
		
	};
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		// TODO Auto-generated method stub
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_home);
		list_home = (GridView) findViewById(R.id.list_home);
		adapter = new MyAdapter();
		list_home.setAdapter(adapter);
		list_home.setOnItemClickListener(new OnItemClickListener() {

			@Override
			public void onItemClick(AdapterView<?> parent, View view,
					int position, long id) {
				switch (position) {
				case 8://进入设置中心
					Intent intent = new Intent(HomeActivity.this,SettingActivity.class);
					startActivity(intent);
					
					break;

				default:
					break;
				}
				
			}
		});
	}
	
	
	private class MyAdapter extends BaseAdapter{

		@Override
		public int getCount() {
			// TODO Auto-generated method stub
			return names.length;
		}
		
		@Override
		public View getView(int position, View convertView, ViewGroup parent) {
			// TODO Auto-generated method stub
			View view = View.inflate(HomeActivity.this, R.layout.list_item_home, null);
			ImageView iv_item = (ImageView) view.findViewById(R.id.iv_item);
			TextView tv_item = (TextView) view.findViewById(R.id.tv_item);
			
			tv_item.setText(names[position]);
			iv_item.setImageResource(ids[position]);
			return view;
		}

		@Override
		public Object getItem(int position) {
			// TODO Auto-generated method stub
			return null;
		}

		@Override
		public long getItemId(int position) {
			// TODO Auto-generated method stub
			return 0;
		}

		
		
	}

}

----------------------------------------------------------------------设置中心-------------------------------------------------------------------------------------

12. 自定义组合控件
   (1)把一组控件封装起来重用

        创建一个新的布局文件xml,和一个继承布局的Java类

布局:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="fill_parent"
        android:layout_height="68dip" >

        <TextView
            android:id="@+id/tv_title"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="10dip"
            android:layout_marginTop="8dip"
            android:text="设置是否自动更新"
            android:textColor="#000000"
            android:textSize="20sp" />

        <TextView
            android:id="@+id/tv_desc"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_below="@id/tv_title"
            android:layout_marginLeft="10dip"
            android:text="自动更新已经关闭"
            android:textColor="#88000000"
            android:textSize="18sp" />

        <CheckBox
            android:clickable="false"
            android:focusable="false"
            android:id="@+id/cb_status"
            android:layout_marginRight="10dip"
            android:layout_centerVertical="true"
            android:layout_alignParentRight="true"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />
        
        <View  
            android:layout_marginLeft="5dip"
            android:layout_marginRight="5dip"
            android:layout_alignParentBottom="true"
            android:background="#000000"
            android:layout_width="fill_parent"
            android:layout_height="0.2dip"/>
    </RelativeLayout>
继承布局的java类

import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.widget.CheckBox;
import android.widget.RelativeLayout;
import android.widget.TextView;

import com.itheima.mobilesafe.R;

/**
 * 我们自定义的组合控件,它里面有两个TextView ,还有一个CheckBox,还有一个View
 * @author Administrator
 *
 */
public class SettingItemView extends RelativeLayout {
	
	private CheckBox cb_status;
	private TextView tv_desc;
	private TextView tv_title;
	
	/**
	 * 初始化布局文件
	 * @param context
	 */
	private void iniView(Context context) {
		
		//把一个布局文件---》View 并且加载在SettingItemView
		View.inflate(context, R.layout.setting_item_view, this);
		cb_status = (CheckBox) this.findViewById(R.id.cb_status);
		tv_desc = (TextView) this.findViewById(R.id.tv_desc);
		tv_title = (TextView) this.findViewById(R.id.tv_title);
		
	}

	public SettingItemView(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
		iniView(context);
	}

	public SettingItemView(Context context, AttributeSet attrs) {
		super(context, attrs);
		iniView(context);
	}

	

	public SettingItemView(Context context) {
		super(context);
		iniView(context);
	}
	
	/**
	 * 校验组合控件是否选中
	 */
	
	public boolean isChecked(){
		return cb_status.isChecked();
	}
	
	/**
	 * 设置组合控件的状态
	 */
	
	public void setChecked(boolean checked){
		cb_status.setChecked(checked);
	}
	
	/**
	 * 设置 组合控件的描述信息
	 */
	
	public void setDesc(String text){
		tv_desc.setText(text);
	}
	
	

}
布局使用

    <com.itheima.mobilesafe.ui.SettingItemView
        android:id="@+id/siv_update"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" >
    </com.itheima.mobilesafe.ui.SettingItemView>

代码使用

public class SettingActivity extends Activity {
	private SettingItemView siv_update;
	private SharedPreferences sp;
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_setting);
		sp = getSharedPreferences("config", MODE_PRIVATE);
		siv_update = (SettingItemView) findViewById(R.id.siv_update);
		
		boolean update = sp.getBoolean("update", false);
		if(update){
			//自动升级已经开启
			siv_update.setChecked(true);
			siv_update.setDesc("自动升级已经开启");
		}else{
			//自动升级已经关闭
			siv_update.setChecked(false);
			siv_update.setDesc("自动升级已经关闭");
		}
		siv_update.setOnClickListener(new OnClickListener() {
			
			@Override
			public void onClick(View v) {
				Editor editor = sp.edit();
				//判断是否有选中
				//已经打开自动升级了
				if(siv_update.isChecked()){
					siv_update.setChecked(false);
					siv_update.setDesc("自动升级已经关闭");
					editor.putBoolean("update", false);
					
				}else{
					//没有打开自动升级
					siv_update.setChecked(true);
					siv_update.setDesc("自动升级已经开启");
					editor.putBoolean("update", true);
				}
				editor.commit();
			}
		});
	}

}

(2)保存配置数据用  SharedPreferences

(3)演示并处理CheckBox的点击事件---解决方案:禁用点击事件;

      Android:clickable=”false”

      Android:focusable=”false”

(4)记录选中状态,并在进入的时候读取保存的状态

(5)在SplashActivity根据是否开启升级而相应的是否升级

(6)延迟两秒进入主页面的代码

//停留2秒后进入主页面;
			handler.postDelayed(new Runnable() {
				
				@Override
				public void run() {
					enterHome();
				}
			}, 2000);


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值