美文网首页
我的大学Android笔记

我的大学Android笔记

作者: 叶满林 | 来源:发表于2019-09-26 16:12 被阅读0次

    在大学期间,我的Android跌跌撞撞的学了一年。我上学时代对于知识的整理还是蛮痴迷的,可惜当时不会使用markdown(富文本让我头昏脑胀)。如今在利用晚上睡觉、工作之余把大学的Android用markdown整理了一遍。供学弟学妹们参考书使用。

    超长篇!!大量小白(学生)操作!!高手止步!!
    当然,后续笔记中,我会补充很多企业级写法、常用框架、底层代码、flutter、RN等,以供大家参考!

    第一节 基础布局


    • 0.常用属性
    layout_width[宽]、layout_height[高] 其属性包含(match_parent填充窗体、wrap_content包裹内容)
    layout_marginTop上外边距
    layout_weight(设置权重(要实施权重的方向不能设置为填充))
    
    • 1.线性布局(LinearLayout)
    它主要以水平与垂直的方式来显示界面控件。当控件水平排列时(显示从左到右),当控件垂直排列时,显示顺序从上到下。
    线性布局中有一个非常重要的属性orientation。用于控制排列方向。(两个值horizontal[水平]于vertical[垂直])
    
    如何让线形布局中的控件居中呢?
    layout_gravity属性只有根布局是LinearLayout的情况下才能使用。表示子布局在父布局中的显示方式:
    layout_gravity有以下几种值:
    center:居中(横向和纵向均居中)
    center_horizontal:水平居中
    center_vertical:垂直居中
    
    • 2.相对布局(RelateiveLayout)
    相对布局是通过相对定位的方式指定控件位置,在设计的时候要遵循控件之间的依赖关系。其内部的属性较多,比较常用的是以下几个
    layout_centerInParent位于父布局中央位置
    layout_centerVertical位于父布局垂直居中位置
    layout_centerHorizontal位于父布局水平居中位置
    layout_above当前控件位于某控件上方
    layout_below当前控件位于某控件下方
    layout_toLeftOf当前控件位于某控左侧
    layout_toRightOf当前控件位于某控右侧
    layout_alignBottom和某控件的底部对齐
    layout_alignParentBottom当前控件是否与父控件底部对齐
    
    • 3.帧布局(frameLayout)
    帧布局是最简单的一种布局模式,该布局为每一个控件都创造一个空白区域。安装先后顺序重叠摆放(先放入的显示在最底层)
    foreground属性设置容器前景(始终在所有子控件至上)
    
    • 4.表格布局(TableLayout)
    表格布局是以表格形式排列控件的,表格布局需要tableRow配合使用,每一行都由tableRow决定
    
    • 5.绝对布局(AbsoluteLayout)「已经废弃」

    • 6.网格布局(GridLayout)「android4.0出现」

    • 7.约束布局(ConstraintLayout)「维护太费劲」


    第二节 Android常用控件


    • 1.TextView 用于显示文字信息
    gravity="center"    居中显示
    
    • 2.EditText 继承于TextView进行可编辑操作(文本框)
    hint="提示"      //用于文本框提示
    maxLines="1"    //设置最大行数
    backgroud="@null"  //不设置会出现一道蜜汁下划线
    
    • 3.Button 按钮 响应点击事件
    /*
     *三种实现方式(java8以后lambda表达式也成为第四种大家较为常用的方式之一)
     */
    //1. 用onClick="click"标签 在对应的activity中实现该方法
        Button myBtn_one = (Button)findViewById(R.id.bt_one);
        public void click(View view){//参数很重要
            myBtn_one.setText(按钮已被点击);
        } 
            
    //2. 用匿名内部类实现
        myBtn_one.setOnClickListener(new View.OnClickListener(){
            public void onClick(View v){
                myBtn_one.setText(按钮已被点击);
            }
        })
                
    //3. 在当前Activity实现OnClickListener接口
        myBtn_one.setOnClickListener(this);
        public void onClick(View v){
            switch(v.getId){
                case R.id.bt_one:
                    break;
                default:
                    break;
            }
        }
    
    • 4.RadioButton单选按钮
    //RadioButton必须放到RadioGroup中去
        RadioGroup rg=(RadioGroup)findViewById(R.id.bt_two);
        rg.setOnClickedChangedListener(new RadioGroup.OnClickedChangedListener{
             public void onCheckedChanged(RadioGroup rg,int checkedId){
                  if(checkedId == R.id.rbtn){
                      //具体操作
                  }
             }
         })
    
    • 5.ImageView 视图控件
      可以从各种来源加载图像,并提供缩放、裁剪、着色等功能。
    backgroud="@drawable/bg"//拉伸
    src="@drawable/bg"//不拉伸
    

    第三节 常见对话框


    对话框是程序与用户交互的一种方式,通常用于显示当前程序提示信息以及相关说明,以小窗口形式展现。常见有以下几种:

    • 1.普通对话框

    链式调用:

    AlertDialog ad=new AlertDialog.Builder(this)
             .setTitle("Dialog对话框")//设置标题
             .setMessage("是否确定退出")//设置提示信息
             .setIcon(R.mipmap.ic_launcher)//设置图标
             .setPositiveButton("确定",null)//添加确定按钮
             .setNegetiveButton("取消",null)//设置取消按钮
             .create();
    ad.show();
    

    2.单选对话框

    AlertDialog ad=new AlertDialog.Builder(this)
             .setTitle("请选择性别")//设置标题
             .setIcon(R.mipmap.ic_launcher)//设置图标
             .setPositiveButton("确定",null)//添加确定按钮
             .setSingleChoiceItems(new String[]{"男","女"},0,new DialogInterFace.OnClickListener(){ 
                 /*参数0表示默认选择第一个,-1可表示没有默认选中*/
                  public void onClick(DialogInterFace Dialog,int which){
                  }
              })
             .create();
    ad.show();
    

    3.多选对话框

    AlertDialog ad=new AlertDialog.Builder(this)
             .setTitle("请选择兴趣爱好")//设置标题
             .setIcon(R.mipmap.ic_launcher)//设置图标
             .setPositiveButton("确定",null)//添加确定按钮
             .setMultiChoiceItems(new String[]{"旅游","美食","汽车","购物"},null,null)
             .create();
    ad.show();
    

    4.进度条对话框

    ProgressDialog dialog=new ProgressDialog(this);
    dialog.setTitle("进度条对话框");
    dialog.setIcon(R.mipmap.ic_launcher);
    dialog.setMessage("正在下载请稍后")
    dialog.setprogressStyle(ProgressDialog.STYLE_HORIZONTAL);//设置样式
    dialog.show;
    

    5.消息对话框
    Toast.makeText(this,"提示信息",Toast.LENGTH.LONG).show();

    6.自定义对话框
    自己做一个对话框my_dialog.xml,建一个类 继承系统的 DiaLlog.

    class MyDialog extends Dialog{
         private TextView tvMsg;
         private String dialogName;
         private Button btnOK;//确认按钮
         private Button btnCancel;//取消按钮
                    
         public MyDialog(Context context,String dialogName){
              super(context);
              this.DialogName=dialogName;
         }
         protected void onCreate(Bundle savedInstanceState){
              super.onCreate(savedInstanceState);
              requestWindFeature(Windos.FEATURE_NO_TITLE);//去处标题
              setContentView(R.layout_mydialog);//引入自定义的对话框布局文件
              tvMsg=(TextView)findViewByIdViewById(R.id.tv_msg);
              Button btnOK =(Button)findViewByIdViewById(R.id.tv_ok);
              Button btnCancel =(Button)findViewByIdViewById(R.id.tv_Cancel);
              vMsg.setText(dialogName);
              btnOK.setOnClickListener(new View.OnClickListener(){
                   public void onClick(View v){
                   }
              });
             btnCancel.setOnClickListener(new View.OnClickListener(){
                   public void onClick(View v){
                       dismiss();
                   }
             });
         }
    }
    

    调用:

    MyDialog myDialog=new MyDialog(this,"我是要提示的字");
    myDialog.show;
    

    第四节 view其他细节


    一、样式(一般作用在控件上)

    在res-->values-->styles.xml中:

    <style name="textStyle"><!--也可以继承(parent="")-->
        <item name="android:layout_width">match_parent</item>
    </style>
    

    使用的时候
    style="@style/textStyle"

    二、主题(一般作用在activity或者application上)

    在res-->values-->styles.xml中
    内容与样式相同
    使用的时候: 在清单文件AndroidManifest.xml
    <activity android:name=".MainActivity" android:theme="@style/textStyle">//加入该行

    三、国际化(别名 i18n)

    在res-->values-->创建string.xml文件、选择locale 选择相应国家然后编写属性(可以加多个国家)

    四、单元测试

    在项目创建之时,软件已经为我们创建了androidTest包与aoolication类,所有测试功能模块写入此类即可

    五、LogCat的使用
    六、debug调试

    F8走到下一行 绿色播放键 走到下一个断点, F7走入方法内部

    七、其他
    android焦点的概念 就相当于windows中的光标
    像你做登录程序的话,密码输入错误,焦点是不是要聚焦密码框好点,这样就不用鼠标去点密码框然后再输入密码,这样有利于用户体验。
    比如在一个界面上你点击按钮,那么焦点就聚集在这个按钮上。
    
    八、两种得到上下文的方法
    1.因为activity继承了activity所以可以用this
    2.直接用getApplicationContext()
    

    第五节 Android中的动画


    一.帧动画(Drawable Animation)【2.3不兼容(认为是耗时操作)】

    就是加载一系列的图片资源,在drawable下建立一个xml文件[例:dome.xml]

    <animation-list xmlns:android="http://schemas.android.com/apk/res/android" android:oneshot="true"> <!--是否执行一次 -->
          <item android:drawable="@drawable/rocket_thrust1" android:duration="200" />
          <item android:drawable="@drawable/rocket_thrust2" android:duration="200" />
          <item android:drawable="@drawable/rocket_thrust3" android:duration="200" />
    </animation-list>
    

    在显示页面

    ImageView rocketImage = (ImageView) findViewById(R.id.rocket_image);
    rocketImage.setBackgroundResource(R.drawable.dome);//设置背景
    rocketAnimation = (AnimationDrawable) rocketImage.getBackground();//加载类型
    rocketAnimation.start();//开启动画
    
    二.view动画(也叫补间动画)
    • 【1】透明AlphaAnim
    ImageView Image = (ImageView) findViewById(R.id.rocket_image);
    //1表示完全不透明,0表示完全透明
    AlphaAnimation aa = new AlphaAnimation(1.0f,0.0f)
    aa.setDuration(2000);//执行时间
    aa.setRepeatCount(1);//重复次数(不重复为0)
    aa.setRepeatMode(Animation.REVERSE);//动画效果
    Image.startAnimation(aa);
    
    • 【2】旋转rotateAnim
    //RotateAnimation ra=new RotateAnimation(0,360)
    RotateAnimation ra=new RotateAnimation(0,360,Animation.RELATIVE_TO_SELF,0.5f,RELATIVE_TO_SELF,0.5f);
    ra.setDuration(2000);//执行时间
    ra.setRepeatCount(1);//重复次数(不重复为0)
    ra.setRepeatMode(Animation.REVERSE);//动画效果
    Image.startAnimation(ra);
    
    • 【3】缩放scaleAnim
    ScaleAnimation sa=new ScaleAnimation(1f,2f,1f,2f,Animation.RELATIVE_TO_SELF,0.5f,Animation.RELATIVE_TO_SELF,0.5f)//放大(前四个参数)
    sa.setDuration(2000);//执行时间
    sa.setRepeatCount(1);//重复次数(不重复为0)
    sa.setRepeatMode(Animation.REVERSE);//动画效果
    Image.startAnimation(as);
    
    • 【4】位移translateAnim(不会改变真实位置)
    • 【5】一起用
      AnimationSet set =new AnimationSet(true)
      xml方式 定义补间动画
      res目录下创建anim文件夹,建立alpha文件
    <alpha xmlns:android="http://schemas.android.com/apk/res/android"
          android:fromAlpha="1.0f"
          android:toAlpha="0.0f"
          android:duration="3000"
          android:repeatCount="1"
          android:repeatMode="restart" />
    
    Animation animation = AnimationUtils.loadAnimation(getApplicationContext(), R.anim.anim);
    Image.startAnimation(animation);
    
    三.属性动画(真实的改变控件)
    ObjectAnimator oa=ObjectAnimator.ofFloat(iv."scaleY",0.1f,2,1,2);
    oa.setDuration(2000);
    oa.start();
    

    第六节 Android中Activity


    一个activity管理一个页面
    setContentView(R.layout.factivity);决定加载哪个布局

    一.activity的创建:

    (五个状态、六个方法)
    启动、运行、暂停、停止、销毁

    onCreate()创建时调用、onStart()即将可见时调用、onResum()获取焦点与用户交互时调用
    onPause()被覆盖或锁屏时调用、onStop()对用户不开见时调用、onRestart()从停止再启动时调用、onDestroy()销毁时调用
    
    二.android的任务栈

    一个应用对应一个任务栈(点开应用就会建立)
    当页面启动时,页面对应的activity进栈。
    按后退键,页面对应的activity就出栈
    用户操作的页面永远是栈顶页面

    三.activity的四种启动模式

    在清单文件中。每一个activity都对应一个<activity>标签、其中的android:launchMode声明了启动方式

    <activity android:name=".MainActivity" android:launchMode="standard">
    

    默认为standard(即标准启动):每一次启动activity就在任务栈顶创建一个新的实例。
    singleTop:创建检查任务栈栈顶,如果有实例就会复用(覆盖)该实例,不会创建新实例(浏览器书签)
    singleTask:创建检查整个任务栈,如果栈内出现相同activity即复用该实例,并把该activity之上的实例全部清空(保证只有实例存在,浏览器页面)
    singleInstance:会为实例单独创建任务栈(系统电话来电)

    四.意图(Intent)

    主要用于activity、server、发送广播
    根据开启组件的方式不同,意图被分为两种(显式意图、隐式意图)

    • 显式意图:可以通过名称开启、指定目标组件
    Intent intent=new Intent(this,MainActivity.class);
    //参数:上下文+目标activity的字节码文件(指定具体类名)
    startActivity(intent);
    
    • 隐式意图:通过指定action和category等属性,系统根据这些属性进行分析后寻找activity清单文件的意图过滤器:(action表示执行动作,category表示条件)
    <intent-filter>
       <action android:name="cn.yijiajia.hh" />
       <category android:name="android.intent.category.LAUNCHER"/>(.LAUNCHER表示启动页面;.DELAULT表示普通)
    </intent-filter>
    
    Intent intent=new Intent();
    intent.setAction("cn.yijiajia.hh");
    intent.addCategory("android.intent.category.DELAULT");
    startActivity(intent);
    

    使用时间(显示意图更安全)
    1.开启自己写的界面用显示意图
    2.开启其他应用的界面(大多数指系统应用)用隐式意图


    第七节 Activity操作


    一、Activity之间的跳转
    二、Activity之间数据传递

    1.打开网页:

    intent.setDate(Uri:parse("http://www.baidu.com"));
    startActivity(intent);
    

    2.传递信息:

    Intent intent=new Intent(this,MainActivity.class);
    intent.putExtra("date","你好");//背地里用map进行封装
    startActivity(intent);
                
    Intent intent=getIntent();
    String date =intent.getStringExtra("date");//    String date data=intent.getStringExtra("date","默认");
    

    3.数据的回传

    • 页面一
    Intent intent=new Intent(this,Activity2.class);
    startActivityForResult(intent,1);
    //使用startActivityForResult方法开启一个新的activity,第一个参数是intent对象,第二个参数是请求码,用于判断来源
    
    • 页面二
    Intent intent=new Intent();
    intent.putExtra("date","你好");
    setResult(1,intent);
    
    • 页面一
    protected void onActivityResult(int requestCode,int resultCode,Intent date){
    //本页面开启的页面关闭的时候执行(做数据回传的时候调用)[resultCode判断数据从哪来]
        super.onActivityResult(requestCode,resultCode,date);
        if(requestCode==1){
            if(resultCode==1){
                String string=data.getStringExtra("data")
            }
        }
    }
    

    4.关闭页面 finish();

    四、Activity的启动模式
    五、常见activity

    1.拨打电话

    Intent intent = new Inetent();
    intent.setAction(Intent.ACTION_CALL);
    intent.setDate(Uri.paese("tel:"+119));
    startActivity(intent);
    

    2.发短信

    SmsManager smsManager=SmsManager.getDefault();
    //1.一起发
    smsManager.sendTextMessage("电话号码",null,"短信内容",null,null);
    //2.分条发
    String text="短信内容";
    ArrayList<String> divide=smsManager.divideMessage(text);
    for (String s:divide){
        smsManager.sendTextMessage("电话号码",null,s,null,null);
    }
    

    第八节 二种数据存储格式


    一、XML解析
    • 1.DOM解析

    将XML文件中所有内容以DOM数形式存放在内存中,支持删除、修改等功能,缺点是消耗内存大。

    • 2.SAX解析

    逐行扫描XML文件,读取文件的同时即可以进行解析处理,不必等文件加载结束。缺点是无法进行增删改查

    • 3.PULL解析

    一个开源的JAVA项目既可以用于AndRoid应用,也可以用于JavaEE程序。Android中已经继承了PULL解析器

    • 天气预报
    <?xml version="1.0" encoding="utf-8"?>
        <infos>
            <city id="sh">
                <temp>20℃/30℃</temp>
                <weather>晴天多云</weather>
                <name>上海</name>
                <pm>80</pm>
                <wind>1级</wind>
            </city>
            <city id="bj">
                <temp>26℃/32℃</temp>
                <weather>晴天</weather>
                <name>北京</name>
                <pm>98</pm>
                <wind>3级</wind>
            </city>
        </infos>
    </xml>
    
    public static List<WeatherBean>getInfromXml(InputStream is)throws Exception{
        List<WeatherBean> weatherInfos=null;
        WeatherBean weatherBean=null;
        //获取pull解析器
        XmlPullParser parser=Xml.newPullParser();
        //告诉要解析的xml文件
        parser.setInput(is,"utf-8");
        //得到当前事件类型
        int type =parser.getEventType();
        //不到文件结尾 就一直解析
        while(type!=XmlPullParser.END_DOCUMENT){
            switch(type){
                case XmlPullParser.START_TAG ://解析的标签是开始标签
                    if("infos".equals(parser.getName())){
                        weatherInfos =new ArrayList<WeatherBean>();
                    }else if("city".equals(parser.getName())){
                        weatherBean=new weatherBean();  
                        String id= parser.getAttributeValue(0);
                        weatherBean.setId(id);
                    }else if("temp".equals(parser.getName())){
                        String temp= parser.getAttributeValue(0);
                        weatherBean.settemp(temp)
                    }
                    break;
                case XmlPullParser.END_TAG :
                    if("city".equals(parser.getName())){
                        weatherInfos.add(weatherBean);
                    }
                        break;
            }
            type=parser.next();                
        }
        return weatherInfos;
    }
    
    二、JSON数据

    JSON即JavaScript Object Notation (对象表示法),是一种轻量级的数据交换格式
    JSON是基于纯文本的数据格式、可以传播String、Number、Boolean类型的数据,也可以传输数组,或者Object对象
    JSON的扩展名为.json
    JSON分为JSON对象和JSON数组两种数据结构

    例子

    {"name":"zhangsan" "address":{"city":"bejing" "postcode":100096}}
    {"name":"zhangsan" "hobby":["羽毛球" "篮球"]}
    

    JSON解析

    {"name":"zhangsan","age":27,"married":true}
    [16,2,26]
    
    //解析对象
    JSONObject jsonObj = new JSONObject(json1);
    String name= jsonObj.optString("name");
    int age =jsonObj.optInt("age");
    //解析数组
    JSONObject jsonObj = new JSONObject(json1);
    for(int i=0;i<jsonArray.length();i++){
        int age =jsonArray.optInt(i);
    }
    //注意:optXXX()比getXXX方法更安全,不会抛出异常,得不到返回null或者0
    

    2.用Gson库解析对象

    //对象
    Gson gson=new Gson();
    Person person =gson.fromJson(json1,Person.class);
    //数组
    Gson gson=new Gson();
    Type listType = new TypeToken<List<Integer>>(){}.getType();
    List<Integer>ages =gson.fromJson(json2,listType);
    

    ················


    第九节 Android中的五种数据存储方式


    Android中有五种数据存储方式,它们分别是:
    1.文件存储
    2.SharedPreferences 存储简单配置信息(xml文件)
    3.SQLiet数据库
    4.ContentProvider(内容提供者) 可以将数据共享给其他应用
    5.网络存储

    一、文件存储的简介
    • 文件存储是Android中最基本的一种存储方式,它分成两种存储类型 内部存储、外部存储

    内部存储写入

    String fileName="data.txt";
    String content="helloworld";
    FileOutput fos;
    try{
        fos =openFileOutput(fileName,MODE_PRIVATE);
        fos.write(content.getBytes());
        fos.close;
    }catch(Exception e){
        e.printStackTrace();
    }
    

    外部存储

    String state=Environment.getExternalStorageState();
    if(stare.equals(Environment.MEDIA_MOUNTED)){//判断sd卡是否可用
        File SDPath=Environment.getExternalStorageStateDirectory();
        File file=new File(SDPath,"date.text");
        String date="HelloWorld";
        FileOutputStream fos;
        try{
            fos= new FileOutputStream(file);
            fos.write(data.getBytes());
            fos.close;
        }catch(Exception e){
            e.printStackTrace();
        }
    
    • QQ保存实战
    //1.得到控件的值
    String number=etText.getTex().toString().trim();//trim可以去除前后空格
    //2.检查用户名密码是否为空
    if(TextUtils.isEmpty(number)){}//为空返回true
    //3.文件保存重新一个类
    public class FileSaveQQ{
        //写入
        public static boolean save(Context context,String number,String password){
            try{
            //首先得到数据流
                FileOutputStream fos=content.openFileOutput("data.txt",content.MODE_PRIVATE);
                //把数据写到文件中
                fos.write((number+":"+password).getBytes());
                fos.close;
                return true;
            }catch(){}
        }
        //从文件中读取
        public static Map<String,String> get(Context context){
            try{
                //首先得到数据流
                FileOutputStream fis=content.openFileInput("data.txt");
                byte[] buffer=new byte[fis.available];
                fis.resd(buffer);
                Map<String,String>  userMap =new HashMap<>();
                String content=new String(buffer);
                String[] info=content.split(":");
                userMap.put("number",info[0]);
                userMap.put("password",info[1]);
                fis.close;
            }catch(){}
        }
    }            
        //保存密码的数据回显
        Map<String,String> userInfo = FileSaveQQ.get(this);
        if(userInfo!=null){
            etNumber.setText(userInfo.get("number"));
            etpassword.setText(userInfo.get("password"));
        }
    
    二、SharedPreferences

    SharedPreferences是Android平台一个轻量级的存储类
    用于存储配置参数、如:用户名、密码等
    通过key/value(键值对)的形式将数据保存在Xml文件中
    value的值,只能是float、int、long、boolean、String StringSet类型数据
    使用方法
    保存:

    SharedPreferences sp=getSharedPreferences("data",MODE_PRIVATE);【保存成data.xml】
    SharedPreferences.editor editor=sp.edit();
    editor.putString("name","创智博客");
    editor.putInt("age",8);
    editor.commit();
    

    获取:

    SharedPreferences sp=getSharedPreferences("data",MODE_PRIVATE);
    String date =sp.getString("name","");
    
    三、SQLite数据库的操作与事务
    • 1.相关简介
      SQLiet是一个轻量级数据库,占用资源非常低。在内存中只需要占用几百KB的存储空间。
      SQLiet是遵循ACID的关系型数据库管理系统,ACID是指数据库事务正确执行的四个基本要素 (原子性、一致性、隔离性、持久性)
      SQLiet保存数据时,支持NULL(零)、INTEGER(整数)、REAL(浮点数字)、TEXT(字符串文本)、BLOB(二进制对象)五种类型

    • 2.创建数据库的方法
      只需要继承SQLiteOpenHelper即可

    public class MyHelper extends SQLiteOpenHelper{
        public MyHelper (Context context){
            super(context,"itcast.db",null,2);//上下文、数据库文件名、游标工厂、版本
        }
        //第一次创建时候调用
        public void onCreate(SQLietDatebase db){
            db.execSQL("CREATE TABLE information(id INTEGER PRIMARY KEY AUTOINCREMENT,name VARCHAR(20),price INTEGER)");
        }
        //当实况版本号增加时候调用
        public void onUpgrade(SQLietDatebase db,int oldVersion,int newVersion){
        }
    }
    

    添加数据

    public void intsert(String name,String price){
        SQLiteDatebase db=MyHelper.getWritableDatabase();
        ContentValues values= new ContentVables();
        values.put("name",name);
        values.put("price",price);
        long id =db.insert("information",null,values);//表名、sql语句不允许插入空行、表示values(固定类,底层用map实现)
        db.close();
    }
    

    修改数据

    public int update(String name,String price){
        SQLiteDatebase db=MyHelper.getWritableDatabase();
        ContentVables values = new ContentValues();
        values.put("price",price);
        int number  =db.update("information",value,"name=?",new String[]{name});
        db.close();
        return number;
    }
    

    删除方法

    public int delete(long id){
        SQLiteDatebase db= MyHelper.getWritableDatabas();
        int number =db.delete("information","id=?",new String[]{id+""});
        db.close;
        return number;
    }
    

    查询方法

    //cursor是一个bean类
    public boolean find(long id){
        SQLiteDatebase db=MyHelper.getReadableDatebase();
        Cursor cursor=db.query("information",null,"id=?",new String[]{id+""},null,null,null);
        boolean result = cursor.moreToNext();
        cursor.close();
        db.close();
        return result;
    }
    

    查询所有

    public boolean find(long id){
        SQLiteDatebase db=MyHelper.getReadableDatebase();
        Cursor cursor=db.query("information",null,null,null,null,null);
        if(cursor.getCount()==0){
            //就是说没有数据
            Toast.makeText(this,"什么都没有",Toast.LENGTH_LONG).show;
        }else{
            cursor.moveToFrist();//把第一行数据取出来
            Toast.makeText(this,cursor.getString(1),Toast.LENGTH_LONG).show;
        }
        //当然你可以这样子把所有数据都拿出来
        while(cursor.moreToNext()){
            mTvShow.append("\n"+"name"+cursor.getString(1))
        }
        cursor.close;
        db.close;
    }
    
    • 3.事务处理
    PersonSQLiteOpenHelper helper= new PersonSQLiteOpenHelper(getContext());
    SQLietDatebase db =helper.getWritableDatabas();
    db.beginTransaction();
    db.beginTransaction();
    try{
        db.execSQL("update person set account =account -1000 where name = ?",new Object[]{"zhangsan"});
        db.execSQL("update person set account =account +1000 where name = ?",new Object[]{"lisi"});
        db.setTrabsactionSuccessful();
    }catch(Exception E){
        Log.i("事务处理失败",e.toString);
    }finally{
        db.endTransaction();
        db.close;
    }
    

    第十节 android中的Broadcast


    一、Broadcast Receiver(广播接收者)
    • 1.广播接受者介绍:

    1.Android系统中内置了很多广播(手机开发完成、电池电量过低都会发送)
    2.为了监听来自系统或者程序的广播时间,Android通过了Broadcast Receiver组件
    3.一个广播事件,可以有多个接收者处理

    • 2.BroadcastReceiver的使用

    1.创建BroadcastReceiver对象
    2.创建好以后记得注册
    3.静态注册(既是以后不开应用,系统都会帮你创建广播)

    <receiver
        android:name=".MyReceiver"
        android:enabled="true"
        android:exported="true">
    </receiver>
    

    动态注册(只有应用打开的时候才接受,注意需要注销)

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //实例化广播
        myReceiver= new MyReceiver();
        //实例化过滤器,并设置要接收的广播
        String action="android.provider.Telephony.SMS_RECEIVED";
        //创建意图过滤器对象
        IntentFilter intentFilter=new IntentFilter(action);
        registerReceiver(myReceiver,intentFilter);
    }
    
    protected void onDestroy() {
        super.onDestroy();
        //注销
        unregisterReceiver(myReceiver);
    }
    

    练习题.电话拦截器——保存电话:

    SharedPreferences sp=getSharedPreferences("data",MODE_PRIVATE);
    SharedPreferences.Editor editor=sp.edit();
    editor.putString("name","你好");
    editor.commit();
    获取:
    SharedPreferences sp=getSharedPreferences("data",MODE_PRIVATE);
    String date =sp.getString("name","");
    新的API
    getResultDate();//得到电话
    setResultDate(null);//修改电话
    

    修改电话,需要在清单文件中声明

    <receiver
        <intent-filter>
            <action android:name="android.intent.action.NEW_OUTGOING_CALL"></action>
        </intent-filter>
    </receiver>
    

    修改电话,涉及到打电话权限
    <uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS"/>

    二、自定义广播

    1.当自定义广播发送消息时,会存储到公共消息区中,而公共消息区如果存在对应的广播接受者,就会及时接受到这条消息

    2.拯救史迪仔

    Intent intent=new Intent();
    //定义广播的事件类型
    intent.setAction("help_Stitch");
    //发送广播
    sendBroadcast(intent)
    

    在控制台输出代码
    Log.i("BroadcastReceiver","我收到了");
    当然接受者要写相应的拦截器

    <intent-filter>
        <action android:name="help_Stitch"></action>
    </intent-filter>
    
    三、广播的类型

    1.无序广播:完全异步执行,发送广播时所有监听该广播的接收者会同时收到消息

        Intent intent=new Intent();
        intent.setAction("help_Stitch");
        intent.putExtra("data","鬼子进村了");
        sendBroadcast(intent);
    

    2.有序广播:安装接收者的优先级,只有一个广播接收后,执行完相应逻辑,才会继续传播。(可以被拦截)
    优先级设定:

    <receiver>
        <intent-filter 
            android:name=""
            android:priority="" //值越大,优先级越高(相同级别,先创建先收到)
        >
    </receiver>
    

    发送广播

    Intent intent=new Intent();
    //定义广播的事件类型
    intent.setAction("help_Stitch");
    //发送广播
    sendOrderedBroadcast(intent,null);//第二个是权限,不需要则设置为null
    

    接收广播

    • 拦截
      abortBroadcast();
    • 修改
      setResultData("上面发了500斤大米");
    • 得到数据
      getResultData()

    3.写入一定会被某个接收者的广播

    sendOrderedBroadcast(intent,null,new final(),null,0,"发1000斤大米",null);
    //myReceiver即使等级很低,即使被拦截,依然会被final接收(final不需要配置)
    

    四、广播打开activity

    Intent intent=new Intent(this,Activity2.class);
    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    content.startActivity(intent);
    

    第十一节 android中的server


    startService一旦开启就要手动关闭,而bingService()与Actity组件绑定 不求同年同月同日但求同年同月同日死

    一、服务的创建
    • 1.服务可以看做是一个没有界面的Activity。比如音乐的播放

    特点:在后台长期运行

    • 2.服务的创建
    二、服务的声明周期
    • 1.和activity一样创建与销毁
    • 2.服务的开启方式有两种

    (1)通过startService()方式启动

    通过startService()方式启动,需要自身调用stopSelf()方法或其他组件调用stopService()方法服务才能停止
    onCreate()-》onStartCommand()-》Service running-》上面-》onDestroy()
    

    (2)通过bindService()方式启动

    通过bindService()方式启动,需要调用onUnbind方法解除绑定才能销毁
    onCreate()-》onBind()-》Service running-》上面-》onDestroy()
    
    三、服务的启动方式

    案例1.
    通过startService:特点:与开启者没有关系。既是启动组件被销毁,服务依然运行。
    onStartCommand()可以执行多次
    需要在Service中写onCreate()、onStartCommand()、onDestroy()方法; onBind()不用,返回null

    //开启:
    Intent intent =new Intent(this,MyServer.class);
    startService(intent);
    //关闭:
    Intent intent =new Intent(this,MyServer.class);
    stopService(intent);
    

    案例2.
    通过bingService()
    需要在Service中写onCreate()、onUnbind()方法;||onBind()方法绑定(返回一个IBinder数据类型)、onUnbind()解绑 onBind()不能多次执行
    需一个内部类继承Binder(已经实现了IBinder接口)
    //通过该对象可以间接的访问服务(在里面可以调用该服务的方法)
    class MyBinder extends Binder{
    }
    //IBinder是夸进程访问

    开启:
    bindServer(intent,conn,flags);||//意图(指明要开启哪一个),ServiceConnection用于监听调用者与service的连接状态,指明连接时是否自动创建service
    成员变量MyConn myconn;
    在某个方法内
    
    {
        if(myconn==null){
            myconn=new MyConn();
        }
        Intent intent =new Intent(this,MyServer.class);
        bindServer(intent,myconn,BIND_ABOVE_CLIENT);
    }
    //在Activity中创建一个内部类
    private class MyConn implements ServiceConnection{
    //当服务连接的时候,调用该方法,
    public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
        MyService.MyBinder myBinder=(MyService.MyBinder)iBinder;
        log.i("MainActivity","服务成功绑定")
    }
    //当服务失去连接的时候调用该方法
    public void onServiceDisconnected(ComponentName componentName) {
    }
             
    //关闭:用onUnbind
    if(myconn!=null){
        unbindService(myconn);
        myconn==null
    }
    
    四、通信方式

    本地通信(运行在自己应用的服务)
    远程服务通信(运行在其他应用的服务)【AIDL】
    android interface Definition language;

    • 1.先把interface 文件后缀改成aidl[Stub使用进程间通信IPC]
    • 2.服务类中间人mybind直接继承stub
    • 3.在本地创建一个一模一样的包 一模一样的.aidl文件
    • 4.在获取的时候不使用iservice=(Iservice)iBinder;而是 iservice=stub.asInterface(server);
    五、音乐播放器
    MediaPlayer mediaPlayer=new MediaPlayer();
    //指定音频文件
    mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
    mediaPlayer.setDataSource("dizhi");
    mediaPlayer.prepare();//准备播
    mediaPlayer.start();//开始播
    if(mediaPlayer.isplaying())//判断在不在播放
    mediaPlayer.stop;
    mediaPlayer.release();
    mediaPlayer=null;
    
    六、进程概念【一个进程含有多个线程】

    四大组件都运行在主线程中(换句话说 四大组件都运行在主线程中)
    系统尽可能长时间的维持进程的操作,
    五种进程的优先级

    • 1.前台进程(正在调用onResum()方法)
    • 2.可视进程(用户可见,影响用户看得见)
    • 3.服务进程(通过通过startService()方式启动)【一般不会杀到这里】
    • 4.后台进程(activity进行了onstop()方法)
    • 5.空进程(不维持任何激活组件)[有时不杀死,提高速度]
    七、通过特定的接口 暴露想暴露的方法
    • 1.定义一个接口 把自己想暴露的方法暴露在接口中
    • 2.定义的中间人实现接口
    • 3.在获取中间人对象时mybinder
    八、混合方式开启服务(既想长期运行 又想调用里面的方法)

    startserver让服务运行
    在服务类中创建中间人mybind继承Binder
    mybind方法实现接口类
    服务类onBind方法返回刚才创建的类
    在actity中创建myconn实现ServiceConnection类 然后new出来
    然后bindService(intent,myconn,BIND_AUTO_CREATE);
    调用unbindserver解绑服务


    第十二节 android中的内容提供者contentProvider


    一、内容提供者(contentProvider)

    内容提供者是android的四大组件之一,它是不同应用程序之间进行数据共享的标准API
    ContentResolver类可以访问ContentPrivider中共享数据
    他们主要是通过ContentProvider 与ContentResolver两个组件

    • 1.ContentResolver提供了一系列的增删改查方法对数据进行操作,并将这些方法以uri的形式对外通过数据
    • 2.uri为内容提供者中的数据建立了唯一标识符。主要由3部分构成
    1.scheme部分:content://是标准前缀,不能被修改
    2.authority部分:创建内容提供者指定的authorities属性值,通常采用程序包名的方式命名
    3.path部分:/person 代表资源或数据,可以动态改变
    

    例:content://cn.itcast.mycontentprovider/person

    二、内容提供者的创建{在日志中搜索Pub}

    创建:
    new->Other->Content Provider
    URI Authorities 通过哪一个uri可以访问该内容提供者 (一般用包名 cn.itcast.mycontentprovider)
    Exported:是否暴露给别人
    Enabled:是否允许系统自动创建
    其中几个方法
    getType:获取媒体类型
    需要在清单文件中声明
    例子:(这里以查询为例)

    public class MyContentProvider extends ContentProvider {
        private static final UriMatcher sUriMatcher=new UriMatcher(UriMatcher.NO_MATCH);//不匹配返回-1
        private static final int QUERYSUCCSEE=0;
        private static final int INSERTSUCCSEE=1;
        private MyHelper myHelper;
        public MyContentProvider() {
            sUriMatcher.addURI("henan.com.provider","query",QUERYSUCCSEE);
            sUriMatcher.addURI("henan.com.provider","insert",INSERTSUCCSEE);
        }
        
        @Override
        public boolean onCreate() {
            myHelper = new MyHelper(getContext());
            return false;
        }
        
        @Override
        public int delete(Uri uri, String selection, String[] selectionArgs) {
            throw new UnsupportedOperationException("Not yet implemented");
        }
        
        @Override
        public String getType(Uri uri) {
            throw new UnsupportedOperationException("Not yet implemented");
        }
        
        @Override
        public Uri insert(Uri uri, ContentValues values) {
            int code = sUriMatcher.match(uri);
            if (code==INSERTSUCCSEE){
                SQLiteDatabase myDatabase = myHelper.getReadableDatabase();
                long insert=myDatabase.insert("info",null,values);
                Uri uri1=Uri.parse("com.henan.insert/"+insert);
                return uri1;
            }else {
                return null;
            }
        }
    
        @Override
        public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
            int code = sUriMatcher.match(uri);
            if (code==QUERYSUCCSEE){
                SQLiteDatabase myDatabase = myHelper.getReadableDatabase();
                Cursor query = myDatabase.query("info", projection, selection, selectionArgs, null, null, sortOrder);
                myDatabase.close()
                //这里cursor不用关,但是数据库要关
                return query;
            }else {
                return null;
            }
        }
    
        @Override
        public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
            throw new UnsupportedOperationException("Not yet implemented");
        }
    }
    
    三、内容解析者

    查询

    Uri uri = Uri.parse("content://henan.com.provider/query");
    ContentResolver contentResolver= getContentResolver();//获取ContentResolver对象
    Cursor cursor=contentResolver.query(uri,new String[]{"name","age"},null,null,null);//条件、条件参数、排序
    while (cursor.moveToNext()){
        String name=cursor.getString(1);
        int age=cursor.getInt(2);
    }
    cursor.close();
    

    插入

    Uri uri = Uri.parse("content://henan.com.provider/insert");
    ContentValues contentValues=new ContentValues();
    contentValues.put("name","张三");
    contentValues.put("password","123");
    ContentResolver contentResolver= getContentResolver();//获取ContentResolver对象
    Uri uri=contentResolver.insert(uri,contentValues);
    
    四、查看短信案例
    五、内容观察者ContentObserver

    1.内容观察者是用来指定Uri所代表的数据。当ContentObserver观察到指定Uri代表的数据发生变化时,就会触发onChange()方法,在该方法中使用ContentProvider可查询数据变化
    2.要使用ContentObserver观察数据变化,就必须在ContentProvider的delete()、insert()、update()方法中调用ContentResover的notifyChange()方法;
    假设B程序调用A程序

    
    /*
     *A程序:ContentProvider暴露数据并调用ContentResolver的notifyChange()方法
     *      当程序发生变化是,A向信息中心发生消息
     *B程序:使用ContentResolver操作A程序的数据
     *C程序:注册ContentObserver
     *     观察消息中心的消息,通过消息观察A程序的数据变化
     *     当观察到变化的数据触发onChange()方法
     */
    
    //ContentObserver的两个常用方法:
    public ContentObserver(Handler handler){}
    //ContentObserver的派生类都需要调用该构造方法,参数可以是主线程Handler,也可以是其他handler对象
    public void onChange(boolean selfChange){}
    //当观察者Uri代表的数据发生变化时,会触发该方法。在该方法中使用ContentResovler可以查询到变化数据
    Uri uri = Uri.parse("content://cn.itcast.mycontentprovider/person");//一定要注意首字母大写其余小写
    ContentResolver contentResolver= getContentResolver();//获取ContentResolver对象
    contentResolver.registerContentObserver(uri,true,MyObserver(new Handler()));//第二个参数:是否精确匹配uri true只匹配该uri false匹配其派生类 第三个参数:ContentObserver实例 
    
    六、常用的几个系统表

    data表:datal存所有人联系的信息 mimetype_id区分是什么信息 raw_contact_id:存放有多少条信息
    raw_contacts:mimetype表


    第十三节 初步http协议


    一、http协议:

    超文本传输协议

    二、HttpURLConnection的基本用法
    URL url=new URL("http://www.itcast.cn");
    HttpURLConnection conn=(HttpURLConnection)url.openConnection();
    conn.setRequestMethod("GET");
    conn.setConnectTimeout(5000);//连接超时时间
    InputStream is=conn.getInputStream();
    conn.disconnect();
    
    三、GET和POST请求方式
    String path = "http://xx.xxx.xx.xxx:80/web/LoginServlet?username="+URLEncoder.encode("zhangsan")+"&password="+URLEncoder.encode("123");
    URL url=new URL(path);
    HttpURLConnection conn=(HttpURLConnection)url.openConnection();
    

    第十四节 多线程初步


    一、多线程编程

    android的主线程不能进行耗时操作(4.0以后强制,主线程也没这个义务)
    打印线程名称方法:
    Thread.currentThread().getName();(Android的主线程就是UI线程,只有UI线程才可以更新ui)

    开启多线程的方法一:

    第一步:new Thread(){}
    第二步:new Thread(){}.stare()
    第三步:new Thread(){public void run(){};}.stare()
    

    开启多线程的方法二:(基本上用第一种,第二种是在特殊方法中使用)

    new Runnable(){}
    new Runnable(){public void run(){};}
    
    二、handle机制

    主线程 含handler,可以告诉系统更新ui
    handler的作用是发消息和处理消息
    looper是从消息队列里取消息
    (该模型十分重要)

    1.以下是更新ui的方法(该方法小白使用,存在内存泄漏风险)

    Handler handler=new Handler(){
    //该方法在UI线程执行
        @Override
        public void handleMessage(Message msg) {
            String s=(String)msg.obj;
            view.setText(s);
        }
    }
    
    new Thread(){
        @Override
        public void run() {
            Message msg=new Message();
            String content="内容";
            msg.obj=content;
            handler.sendMessage(msg);//发送一条消息,数据放到msg里(子线程)handleMessage方法便会执行
        }
    }.start();
    

    图片查看器

    new Thread(){
        try{
            //获取访问图片路径
            String path=et_view.getText().toString().trim();
            //创建URL路径
            URL url=new URL(path);
            //获取httpurlconnection
            HttpURLConnection  conn=(HttpURLConnection)url.openConnection();
            //设置请求方式
            conn.setRequestMethod("GET");
            //设置超时时间
            conn.setConnectTimeout(5000)
            //获取服务器返回状态码
            int code=conn.getResponseCode();
            if(code == 200){//200代表成功 404代表没有找到
                //获取图片数据(基本上都是以流的形式接收)
                InputStream in=conn.getInputStream();
                //通过位图工厂获取位图
                Bitmap bitmap=BitmapFactory.decodeStream(in);
                //把位图显示到iv上
                Message msg= Message.obtain();//使用msg的静态方法 可以减少对对象的创建
                msg.obj=bitmap;
                handler.sendMessage(msg);
             }
        }
    }.start();
    
    三、缓存机制
    //缓存图片,谷歌给我们提供了一个缓存目录getCacheDir() //创建缓存目录[类似于 getFilesDir()//创建file目录]
    File file=new File(getCacheDir(),"Beautiful.png")
    if(file.exists()&&file.length()>0){
        Bitmap cacheBitmap=BitmapFactory.decodeFile(file.getAbsolutePath());//
        Message msg=Message.obtain();
        msg.obj=cacheBitmap;
        handler.sendMessage(msg)
    }else{
        //第一次
    }
    
    四、cache目录和filedir目录区别

    cache可以被用户手动清除掉缓存(用户可以清楚)
    file可以被用户手动清除掉data

    五、runOnUiThread();

    作用:在主线程中会立即执行 在子线程中会交给主线程执行

    runOnUiThread(new Runnable(){
        @Override
        public void run() {
            view.setText("xxx");
        }
    });
    
    六、常见的API

    下面的方法不能更新ui(当然可以用runOnUiThread())【大部分在企业中是没办法用的,有兴趣的同学可以学习线程池】
    第一个:handler

    //2秒后执行run方法
    new Handler().postDelayed(new Runnable(){
        public void run(){
            syso("哈哈哈")
        }
    },2000)
    

    第二个:time

    //5秒后进行run方法
    Timer timer =new Timer();
    TimerTask task=new TimerTask(){
       public void run(){
           syso("呵呵呵")
       }
    };
    timer.schedule(task,5000)[也可以是timer.schedule(task,5000,1000)]
         
    //销毁方法
    timer.cancel();
    task.cancel();
    
    七、将字符流转换成string的方法
    public String inputStream2String(InputStream is)   throws IOException{
        BufferedReader reader = new BufferedReader(new InputStreamReader(is));
        StringBuilder sb = new StringBuilder();
        String line = null;
        try {
            while ((line = reader.readLine()) != null) {
                sb.append(line + "\n");
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                is.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return sb.toString();
    }
    
    八、服务器的逻辑
    public void androidlogin() {
    /*使用servletActionContext对象拿request与Response都很简单*/
    HttpServletRequest request=ServletActionContext.getRequest();
    String phone=request.getParameter("phone");
    String password=request.getParameter("password");
    System.out.println(phone);
    HttpServletResponse response=ServletActionContext.getResponse();
    response.setContentType("text/plain; charset=utf-8");
    PrintWriter out;
    try {
        out = response.getWriter();
        out.print("登录成功");
        out.flush();
            out.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    
    九、HttpURLConnection的get与post客户端逻辑
    public void click1(View view) {
        String name=name_edit.getText().toString().trim();
        String password=password_edit.getText().toString().trim();
        final String path="http://117.34.240.61:8080/AndroidServiceDome2/user_androidlogin.action?phone="+name+"&password="+password;
        new Thread(){
            @Override
            public void run() {
                try{
                    URL url=new URL(path);
                    HttpURLConnection conn=(HttpURLConnection)url.openConnection();
                    conn.setRequestMethod("GET");
                    conn.setConnectTimeout(5000);
                    int code=conn.getResponseCode();
                    if(code == 200) {//200代表成功 404代表没有找到
                        InputStream inputStream = conn.getInputStream();
                        Util util=new Util();
                        String S =util.inputStream2String(inputStream);
                        //因為不可以在子線程展示ui所以
                        showToast(S);
                    }
                }catch (Exception e){
                }
            }
        }.start();
    }
    
    public void click2(View view) {
        final String name=name_edit.getText().toString().trim();
        final String password=password_edit.getText().toString().trim();
        final String path="http://117.34.240.61:8080/AndroidServiceDome2/user_androidlogin.action";
        new Thread(){
            @Override
            public void run() {
                try{
                    String data="phone="+name+"&password="+password;
                    URL url=new URL(path);
                    HttpURLConnection conn=(HttpURLConnection)url.openConnection();
                    conn.setRequestMethod("POST");
                    conn.setConnectTimeout(5000);
                    conn.setRequestProperty("Content-Type","application/x-www-form-urlencoded");
                    conn.setRequestProperty("Content-Length",data.length()+"");
                    conn.setDoOutput(true);
                    conn.getOutputStream().write(data.getBytes());
                    int code=conn.getResponseCode();
                    if(code == 200) {//200代表成功 404代表没有找到
                        InputStream inputStream = conn.getInputStream();
                        Util util=new Util();
                        String S =util.inputStream2String(inputStream);
                        //因為不可以在子線程展示ui所以
                        showToast(S);
                    }
                }catch (Exception e){
                }
            }
        }.start();
    }
    
    十、httpclient(使用直接子类Defaulthttpcliet)【该方法已经过时】
    DefaultHttpClient client = new DefaultHttpClient();
    HttpGet get = new HttpGet(path);
    HttpResponse response = client.execute(get);
    int code = response.getStatusLine().getStatusCode();
    if(code == 200){
        InputStream inputStream=response.getEntity().getContent();
        showToast(content);
    }
    DefaultHttpClient client = new DefaultHttpClient();
    HttpPost post = new HttpPost(path);
    List<NameValuePair> lists= new ArrayList<NameValuePair>();
    BasicNameValuePair nameValuePair = new BasicNameValuePair("phone",name);
    BasicNameValuePair passwordValuePair = new BasicNameValuePair("password",password);
    lists.add(nameValuePair);
    lists.add(passwordValuePair);
    URLEncodedFormEntity entity = new URLEncodedFormEntity(lists);
    post.setEntity(entity);
    HttpResponse response = client.execute(post);
    int code = response.getStatusLine().getStatusCode();
    if(code == 200){
        InputStream inputStream=response.getEntity().getContent();
        showToast(content);
    }
    
    十一、retrofit

    下载包

    //retrofit
    compile 'com.squareup.retrofit2:retrofit:2.1.0' 
    compile 'com.squareup.retrofit2:converter-gson:2.1.0'
    
    十二、多线程加速下载

    1.注意

    • 不是线程越多下载越快
    • 下载速度受服务器带宽的影响

    2.多线程下载步骤
    [1]获取文件大小

    int length=conn.getContentLength()//得到字节长度
    runningThread = threadCount;
    

    [2]在客户端创建一个大小和服务器一模一样的文件提前申请好空间

    RandomAccessFile rafAccessFile = new RandomAccessFile("dome.exe","rw");
    rafAccessFile.setLength(length);
    //[2.1]确定每个线程下载的开始位置与结束位置
    int blockSize =length/threadCount;//提前声明好有几个线程
    for(int i=0; i<theadCount;i++){
        int startIndex = i*blockSize;
        int endIndex=(i+1)*blockSize-1;
        if(i==threadCount-1){
            endIndex=length-1;
            syso("线程"+i+"理论下载的位置"+startIndex+"-----"+endIndex)
            //开启线程
            DownLoadThread  downLoadThread = new DownLoadThread(startIndex,endIndex,i);
            downLoadThread.start();
         }
    }
    

    [3]开多个线程去下载文件

    //这里单独抽取一下
    private static class DownLoadThread extends Thread{
        private int startIndex;
        private int endIndex;
        private int threadId;
        
        public DownLoadThread (int startIndex,int endIndex,int threadId){
            this.startIndex=startIndex;
            this.endIndex=endIndex;
            this.threadId=threadId;
        }
        
        public void run(){
            try{
                URL url=new URL(path);
                HttpURLConnection conn=(HttpURLConnection)url.openConnection();
                conn.setRequestMethod("GET");
                conn.setConnectTimeout(5000);
                                
                //再次下载要先看看上一次是不是没下完、
                File file =new File(threadId+".txt")
                if(file.exists()&&file.length()>0){
                    FileInputStream fis =new FileInputStream(file);
                    BufferedReader bufr =new BufferedReader(new InputStreamReader(fis));
                    String lastPositionn=bufr.readLine();
                    int lastPosition=Integer.parseInt(lastPositionn);
                    startIndex=lastPosition;
                    syso("线程"+threadId+"真实下载的位置"+startIndex+"-----"+endIndex)
                    fis.close;
                 }
                 //[3.1]设置一个请求头Range
                 conn.setRequestProperty("Range","bytes="+startIndex+"-"+endIndex);
                 int code=conn.getResponseCode();
                 if(code == 200) {//200代表成功 404代表没有找到
                    //创建随机文件读写对象
                    RandomAccessFile raf = new RandomAccessFile("dome.exe","rw");
                    ref.seek(startIndex);
                    InputStream inputStream = conn.getInputStream();
                    //把内容写到文件中
                    int len=-1;
                    /*****断点续传(把当前进度用文件存起来)****/
                    int total=0;//代表当前下载的大小
                    byte[] buffer=new byte[2014*1024];//定义缓冲区的大小
                    while((len = in.read(buffer))!=-1){
                        raf.write(buffer,0,len);
                        total +=len;
                        int currentThreadPosition=startIndex+total;
                        /*该方式不安全*/
                        //File file = new File(threadId+".txt")
                        //FileOutputStream fos = new FileOutputStream(file);
                        //fos.write(String.valueOf(currentThreadPosition).getBytes());
                        //fos.close;
                        RandomAccessFile raff =new RandomAccessFile(threadId+".txt","rws");raff.write(String.valueOf(currentThreadPosition).getBytes());
                        raff.close;
                    }
                raf.close();
                syso("线程id:"+threadId+"加载完毕")
                //把txt文件删除(之前声明一个runningThread 代表当前正在运行的线程)
                synchronized(DownLoadThread.class){//线程锁
                    runningThread--;
                    if(runningThread==0){
                    //说明执行完毕
                        for(int i=0;i<threadCount;i++){
                            File deletFile=new File(i+".txt");
                            delteFile.delete();
                        }
                    }
                }
            }catch (Exception e){
                e.printStackTrace();
            }    
        }
        public static String getFilenam(String path){
            int start =path.lastIndexOf("/")+1;
            return path.substring(start);
        }
    }
    

    [4]知道每个线程什么时候下载完毕将文件拼接起来即可


    第十五节 多媒体初步


    一、计算机表示图形的几种方式

    bmp:以高质量保存
    jpg:以良好质量保存
    png:以高质量保存(png与jpg差不多 只不过压缩算法不一样,png压缩算法更好)
    图片大小的计算公式:(图片总像素 X 每一个像素的大小)
    单色: 只有两种颜色(要么是黑要么是白) 每一个像素只要长度是1的二进制位表示(一个像素占1/8个byte)
    16色: 每个像素最多可以表示16种颜色 0000-1111 只需要使用长度为4的二进制表示(一个像素占1/2个byte)
    256色: 每个像素最多可以表示256种颜色 0000 0000-1111 1111 只需要使用长度为8的二进制表示(一个像素占1个byte)
    24位: 每个像素最多可以表示1600万种颜色 RGB组合 一个像素占3byte(RGB各占一个byte)
    在android中采用png,采用的是arpg一个像素四个byte

    二、缩放加载大图片
    Bitmap bitmap=BitmapFactory.decodeFile("/mnt/sdcard/dog.jpg")
    imageView.setImageBitmap()
    

    (oom内存溢出异常,因为默认给每个应用就分配16m空间,而图片加载申请内存与图片大小有关 与真实大小无关)

    正确方法:

    • 1.获取图片分辨
    • 2.获取手机分辨率
    • 3.计算缩放比(宽除以宽,高除以高,然后按照大的缩放)
    //获取手机宽与高
    WindowManager wm = (WindowManager)getSystemService(WINDOW_SERVICE);
    //第一种过时
    int height = wm.getDefaultDisplay().getHeight();
    int width = wm.getDefaultDisplay().getWidth();
    //第二种
    Point point = new Point();
    wm.getDefaultDisplay().getSize(point);
    int height1 = point.x;
    int width1 = point.y;
    //加载图片信息
    //创建一个位图工厂创建一个参数
    BitmapFactory.Options options=new BitmapFactory.Options();
    //解码器不去真正的解析位图 但是还能够获取图片的宽与高信息
    options.inJustDecodeBounds =true;
    BitmapFactory.decodeFile("/mnt/sdcard/dog.jpg",options);
    int imgw=options.outWidth;
    int imgh=options.outHeight;
    //计算缩放比
    int scale=(imgw/height)>=(imgh/height)?(imgw/height):(imgh/height);
    //但是不能小于1
    if (scale<1){
            scale=1;
    }
    options.inSampleSize=scale;
    //加载图片
    options.inJustDecodeBounds =false;
    Bitmap bitmap = BitmapFactory.decodeFile("/mnt/sdcard/dog.jpg", options);
                    imageView.setImageBitmap(bitmap);
    
    三、创建原图副本
    //把普通照片转化成bitmap
    Bitmap srcBitmap=BitmapFactory.decodeResource(getResources(),R.drawable.ic_launcher_background);
    //创建了一个与原图一样的空白的白纸
    Bitmap copyBitmap = Bitmap.createBitmap(srcBitmap.getWidth(), srcBitmap.getHeight(), srcBitmap.getConfig());
    //用画笔画一个与原图一样的图
    //1.拿画笔
    Paint paint=new Paint();
    //2.拿画布并把把画布铺在copy图上
    Canvas canvas=new Canvas(copyBitmap);
    //3.画图
    canvas.drawBitmap(srcBitmap,new Matrix(),paint);
    //已经画好的图修改(一次修改一个像素)
    copyBitmap.setPixel(20,20, Color.BLUE);
    
    四、图形处理的api

    旋转

    //1.拿画笔
    Paint paint=new Paint();
    //2.拿画布并把把画布铺在copy图上
    Canvas canvas=new Canvas(copyBitmap);
    Matrix matrix = new Matrix();
    //旋转角度,基于什么中心点           matrix.setRotate(20,copyBitmap.getWidth()/2,copyBitmap.getHeight()/2);
    canvas.drawBitmap(srcBitmap,matrix,paint);
    

    缩放

    //缩放比例(水平,竖直)
    matrix.setScale(0.5f,0.4f);
    

    平移

    //水平,竖直
    matrix.setTranslate(30,0);
    

    镜面(旋转平移组合)

    matrix.setScale(-1f,0);
    //使用post是在修改的基础上修改
    matrix.postTranslate(copyBitmap.getWidth(),0);
    

    倒影

    matrix.setScale(1f,-1f);
    matrix.postTranslate(0,copyBitmap.getHeight());
    
    五、使用mediaplayer播放音频文件(mediaPlayer只能播放mp4或者3gp格式)
    MediaPlayer mediaPlayer=new MediaPlayer();
    try {
        mediaPlayer.setDataSource("/mnt/sdcard/dog.mp3");
        mediaPlayer.prepare();
        mediaPlayer.start();
    } catch (IOException e) {
        e.printStackTrace();
    }
    mediaPlayer.stop();
    
    六、surfaceview介绍(控件)

    他是一个重量级控件
    维护两个线程A、加载数据 B、显示数据 可以直接更新ui

    View scroll = findViewById(R.id.scrollView1);
    SurfaceHolder handler = (SurfaceHolder)scroll.getHandler();
    MediaPlayer mediaPlayer = new MediaPlayer();
    try {
        mediaPlayer.setDataSource("/mnt/sdcard/dog.mp4");
        mediaPlayer.prepareAsync();
        mediaPlayer.setDisplay(handler);
        mediaPlayer.start();
    } catch (IOException e) {
        e.printStackTrace();
    }
    
    七、VideoView控件介绍
    VideoView videoView = findViewById(R.id.video_view);
    videoView.setVideoPath("/mnt/sdcard/dog.mp4");
    videoView.start();
    
    八、vitamio框架
    九、照相与录像

    第十六节 Fragment入门


    一、fragment入门 [最低11版本(即3.0)]

    它总是被嵌入到activity当中,生命周期被activity影响

    • 1.ViewGroup可以有自己的孩子
    • 2.view 没有自己的孩子

    通过 onCreateView这个方法可以加载fragmen自己的布局
    第一种加载fragment方式

    <fragment
        android:layout_width="0dp"
        android:layout_weight="1"
        android:layout_height="match_parent"
        android:id="@+id/addfragment_first"
        android:name="dome813.henan.com.fragmentdome.Fragment1"
    />
    <fragment
        android:layout_width="0dp"
        android:layout_weight="1"
        android:layout_height="match_parent"
        android:id="@+id/addfragment_second"
        android:name="dome813.henan.com.fragmentdome.Fragment2"
    />
    
    public class Fragment2 extends Fragment {
        //第一次调UI的时候执行该方法 加载fragment自己的控件
        public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) {
        //通过打气筒将布局转化成view
            View view = inflater.inflate(R.layout.fragmentlayout2,null);
            return view;
        }
    }
    

    第二种加载fragment方式(动态加载)

    FragmentManager fragmentManager = getFragmentManager();
    FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
    String state = null;
    if (state=="横屏"){
        fragmentTransaction.replace(android.R.id.content,new Fragment1());
    }else{
        fragmentTransaction.replace(android.R.id.content,new Fragment2());
    }
    fragmentTransaction.commit();
    

    3.fragment的xml中 不能用onClick方法点击,只能通过id方式 setOnClickListener
    4.兼容11版本以下的 就要使V4包

    二、fragment的生命周期
    onAttach()
        onCreate()
            onCreateView()//第一次画ui 必须重新
                onActivityCreated()//准备view 已初始化
                    onStart()
                        onResum()
                        onPause()
                    onStop()
            onDestroyView()
        onDestroy()//回收内存
    onDetach
    
    三、fragment之间的通信 (通过activity)
    public class Fragment1 extends Fragment {
        //第一次调UI的时候执行该方法 加载fragment自己的控件
        public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) {
        //通过打气筒将布局转化成view
            View view = inflater.inflate(R.layout.fragmentlayout1,null);
            view.findViewById(R.id.button1).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Fragment2 fragment2 =(Fragment2)getActivity().getFragmentManager().findFragmentByTag("massage1");
             }
        });
        return view;
        }
    }
    public class MainActivity extends AppCompatActivity {
        @Override
        protected void onCreate(Bundle savedInstanceState) {
        .....
            if (state=="横屏"){
                fragmentTransaction.replace(android.R.id.content,new Fragment1(),"message1");
            else{
                fragmentTransaction.replace(android.R.id.content,new Fragment2(),"message2");
            }
            fragmentTransaction.commit();
        }
    }
    

    相关文章

      网友评论

          本文标题:我的大学Android笔记

          本文链接:https://www.haomeiwen.com/subject/ywteyctx.html