Android学习笔记

文章目录

2月5号

1. 目标

掌握Android UI设计之布局管理器

2. 学习笔记

2.1 UI 组件

  • TextView
  • Botton
  • RadioBotton
  • EditView
  • ImageView
  • RecyclerView
2.2 布局管理器

2.2.1 线性布局
最常用属性
属性属性属性
android:idandroid:layout_widthandroid:layout_height
android:backgroundandroid:layout_marginandroid:layout_padding
android:orientationandroid:gravityandroid:layout_weight
上机操作
	<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:layout_margin="20dp"
    tools:context=".MainActivity">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="200dp"
        android:text="15521139529"
        android:gravity="center"
        ></TextView>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:orientation="horizontal">
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="密码"
            android:layout_marginRight="10dp"
            android:gravity="center"></TextView>
        <EditText
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:hint="请填写微信密码"
            android:inputType="textPassword"
            android:maxLines="1"
            ></EditText>
    </LinearLayout>

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="用短信验证码登录"
        android:textColor="	#7D9EC0"></TextView>

    <Button
        android:layout_width="match_parent"
        android:layout_height="60dp"
        android:text="登录"
        android:layout_marginTop="20dp"></Button>
	</LinearLayout>

运行结果:
运行效果图

2.2.2 相对布局
最常用的属性
属性作用
android:layout_toLeftOf在谁的左边
android:layout_toRightOf在谁的右边
android:layout_above在谁的上边
android:layout_below在谁的下边
android:layout_alignBottom跟谁的底部对齐
android:layout_alignParentBottom跟父控件底部对齐
android:layout_centerInParent在父组件的中间
上机操作

代码:

	<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_margin="20dp"
    android:id="@+id/relative"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/text1"
        android:layout_width="match_parent"
        android:layout_height="100dp"
        android:text="15521139529"
        android:gravity="center"></TextView>

    <RelativeLayout
        android:id="@+id/relative1"
        android:layout_below="@+id/text1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
        <TextView
            android:id="@+id/text2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="密码"
            android:layout_centerVertical="true">
        </TextView>
        <EditText
            android:id="@+id/edit_text"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="请输入微信密码"
            android:layout_toRightOf="@+id/text2"
            android:gravity="center"
            android:inputType="textPassword"
            ></EditText>
    </RelativeLayout>

    <TextView
        android:id="@+id/text3"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="使用验证码登陆"
        android:layout_below="@+id/relative1"
        android:layout_alignParentLeft="true"
        android:textColor="	#7D9EC0"
        ></TextView>

    <Button
        android:id="@+id/bottom1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="登录"
        android:layout_marginTop="40dp"
        android:padding="20dp"
        android:layout_below="@id/text3">
    </Button>

    <RelativeLayout
        android:id="@+id/bottom"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:layout_alignParentBottom="true"
        android:gravity="center">
        <TextView
            android:id="@+id/text_bottom1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="找回密码"
            android:textColor="	#7D9EC0"
            android:layout_toLeftOf="@+id/text_bottom2"
            ></TextView>

        <TextView
            android:id="@+id/text_bottom2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:layout_marginLeft="10dp"
            android:layout_marginRight="10dp"
            android:text="紧急冻结"
            android:textColor="	#7D9EC0"></TextView>

        <TextView
            android:id="@+id/text_bottom3"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="微信安全中心"
            android:textColor="	#7D9EC0"
            android:layout_toRightOf="@id/text_bottom2"></TextView>
    </RelativeLayout>
	</RelativeLayout>

运行结果:
微信登录界面相对布局

2月6号

1. 学习目标

掌握一下组件的常见使用方法

  1. TextView
  2. Button
  3. EditView

2. 学习笔记

2.1 TextView

2.1.1 掌握的要点
  1. 设置文字的大小 颜色
  2. 文字太长显示不下时使用
  3. 文字 + icon
  4. 中划线 下划线
  5. 跑马灯效果
2.1.2 解决方法
  1. textColor 设置字体颜色, TextSize 设置字体大小, 注意这里使用的单位时sp
  2. maxLine 限制文字在一行中显示, ellipsize 设置缺省的显示格式, 选择 end 就好
  3. drawableRight 即可在文字右边添加一个图片, 得事先准备好图片, 再添加一个点击
    监听事件即可实现一些想 筛选 的功能
  4. 添加中划线和下划线在java文件中设置, 代码如下:
	private TextView mTv4;
	mTv4 = findViewById(R.id.tv_4);
	mTv4.getPaint().setFlags(Paint.STRIKE_THRU_TEXT_FLAG); // 添加中划线
	mTv4.getPaint().setAntiAlias(true); // 去除锯齿
	
	private TextView mTv5;
	mTv5 = findViewById(R.id.tv_5);
	mTv5.getPaint().setFlags(Paint.UNDERLINE_TEXT_FLAG); // 添加下划线
	mTv5.getPaint().setAntiAlias(true); // 去除锯齿
  1. 跑马灯的实现, 要靠以下几个属性来设置
	android:singleLine="true"
	android:ellipsize="marquee"
	android:marqueeRepeatLimit="marquee_forever"
	android:focusable="true"
	android:focusableInTouchMode="true"

2.2 Button

2.2.1 要点
  1. 按钮大小 颜色 的设置
  2. 自定义按钮背景
  3. 自定义按压效果
  4. 点击事件
2.2.2 解决方法
  1. TextView ,因为Button继承于TextView
  2. 通过新建drawable resouce file 来自定义背景, 常见的有直角 圆角 描边, 代码如下:
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">
    <solid
        android:color="#FFCC00"/> // 填充颜色
    <corners
        android:radius="10dp"/> // 圆角
</shape>

<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">
    <stroke
        android:width="2dp"
        android:color="#FFCC00"/> // 描边
    <corners
        android:radius="10dp"/> //圆角
</shape>
  1. 同理, 自定义按压效果, 代码如下:
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_pressed="true"> // 按下去
        <shape>
            <solid android:color="#00BB25"/> // 填充颜色
            <corners android:radius="10dp"/> // 圆角
        </shape>
    </item>

    <item android:state_pressed="false"> // 没有按下去
        <shape>
            <solid android:color="#00DD2C"/>
            <corners android:radius="10dp"/>
        </shape>
    </item>
</selector>
  1. 方法一: 在布局文件中添加 onClick 属性, 其值为自定义的一个方法名字, 然后在 Activity 中定义并实现该方法, 代码如下:
	android:onClick="showToast"

    public void showToast(View view) {
        Toast.makeText(this, "点击了一下按钮4", Toast.LENGTH_LONG).show();
    }

方法二 (推荐) : 直接在 Activity 中获取控件, 新建监听事件来实现, 代码如下:

	private Button mBtn3;
	 
	mBtn3 = findViewById(R.id.btn_3);
	mBtn3.setOnClickListener(new View.OnClickListener() {
		@Override
		public void onClick(View v) {
			Toast.makeText(ButtonActivity.this, "点击了一下按钮3", Toast.LENGTH_LONG).show();
		}
	});

2.3 EditText

2.3.1 要点
  1. 常用属性
  2. 监听事件
2.3.2 解决方法
  1. 属性
常用属性作用
hint提示语
inputType输入类型
  1. 监听事件, 监听 text 值改变前, 中, 后
		mEditText1 = findViewById(R.id.et_1);
        mEditText1.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {

            }

            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {
                Log.d("useName", s.toString());

            }

            @Override
            public void afterTextChanged(Editable s) {

            }
        });

2月7号

1. 学习目标

掌握以下控件的常见用法:

  1. RadioButton
  2. CheckBox
  3. ImageView
  4. ListView
  5. GridView
  6. ScrollView

2. 学习笔记


2.1 RadioButtonRadioGroup

2.1.1 要点
  1. 常用属性
  2. 自定义样式
  3. 监听事件
2.1.2 解决方法
  1. 如果是一组, 则需要使用 RadioGroud 包含多个 * RadioButton* 来实现多选一, 常见属性:
属性作用
checked默认情况下是否选中
orientation选项摆放方向, 水平或者垂直
button设置勾选按钮的样式, 可以设置为 @null 来隐藏, 然后使用自定义的图案
  1. 同其他自定义样式一样, 新建 drawable resouce file , 设置 background 的值为新建文件名就好, 代码如下:
	android:button="@null"
	android:background="@drawable/rb_rb_2"
	
	<selector xmlns:android="http://schemas.android.com/apk/res/android">
	    <item android:state_checked="true">
	        <shape>
	            <solid android:color="#00BB25"/>
	            <corners android:radius="10dp"/>
	        </shape>
	    </item>
	
	    <item android:state_checked="false">
	        <shape>
	            <stroke
	                android:width="2dp"
	                android:color="#00BB25"/>
	            <corners android:radius="10dp"/>
	        </shape>
	    </item>
	</selector>
  1. 代码如下:
	private RadioGroup mRg1;
	
        mRg1 = findViewById(R.id.rg_1);
        mRg1.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(RadioGroup group, int checkedId) {
                RadioButton radioButton = group.findViewById(checkedId);
                Toast.makeText(RadioButtonActivity.this, radioButton.getText(), Toast.LENGTH_SHORT).show();
            }
        });

2.2 CheckBox

多个 CheckBox 就是一组选择几项, 即复选的 RadioGroup

2.1.1 要点
  1. 常用属性
  2. 自定义样式
  3. 监听事件
2.1.2 解决方法
  1. RaidoBox
  2. RaidoBox , 代码如下:
	<selector xmlns:android="http://schemas.android.com/apk/res/android">
	    <item android:state_checked="true" android:drawable="@drawable/checkbox_checked"/>
	    <item android:state_checked="false" android:drawable="@drawable/checkmark_unchecked"/>
	</selector>
  1. 监听的方法也跟 RadioGrounp 差不多, 代码如下
    private CheckBox mCb5, mCb6;
    
        mCb5 = findViewById(R.id.cb_21);
        mCb6 = findViewById(R.id.cb_22);
        mCb5.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                Toast.makeText(CheckBoxActivity.this, isChecked?"checked":"unchecked", Toast.LENGTH_SHORT).show();
            }
        });
        mCb6.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                Toast.makeText(CheckBoxActivity.this, isChecked?"checked":"unchecked", Toast.LENGTH_SHORT).show();
            }
        });

2.3 ImageView

2.3.1 要点
  1. 常用属性
  2. 加载网络图片
2.3.2 方法
  1. 常见属性
属性作用
src图片资源的位置
scaleType图片适配视图的类型
scaleType值效果
fitXY拉伸长和宽, 使图片撑满整个 ImageView
fitCenter等比缩放, 是图片完整展示在 ImageView 中
centerCrop等比缩放, 使图片撑满整个 ImageView
  1. 加载开源包, 直接去 GitHub 官网搜索所需要的包, 按照其说明指引进行操作, 就可以调用相关功能了, 代码如下
	// 加载开源包, 将对应的内容复制粘贴到 *build.gradle(Moudle:app)* 的相应位置, 然后点击同步即可 
	
	repositories {
	    mavenCentral()
	    google()
	}
	
	dependencies {
	    implementation 'com.github.bumptech.glide:glide:4.11.0'
	    annotationProcessor 'com.github.bumptech.glide:compiler:4.11.0'
	}
	
	// 使用开源包, 加载网络图片
	
	private ImageView mIv4;
	
		mIv4 = findViewById(R.id.iv_4); 
		Glide.with(this).load("https://i0.hdslb.com/bfs/archive/058056424b94c3ff8c1facc940f48ce3bfe423a5.jpg@1100w_484h_1c_100q.jpg").into(mIv4);

2.4 ListView

2.4.1 常用xml属性
属性作用
listSelector设置选择的效果, 可以自定义drawable文件来实现点击效果
divider设置item间的分割线的样式
dividerHeight设置分割线的宽度
2.4.2 列表的生成
  1. 新建一个布局文件, 设计一个 item 的布局
	<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
	    android:orientation="horizontal"
	    android:layout_width="match_parent"
	    android:layout_height="match_parent"
	    android:layout_margin="10dp">
	
	    <ImageView
	        android:id="@+id/iv"
	        android:layout_width="150dp"
	        android:layout_height="100dp"
	        android:background="@color/colorBlack"
	        android:scaleType="fitXY"/>
	
	    <LinearLayout
	        android:id="@+id/ll"
	        android:layout_width="match_parent"
	        android:layout_height="100dp"
	        android:orientation="vertical"
	        android:paddingLeft="10dp">
	
	        <TextView
	            android:id="@+id/tv_tittle"
	            android:layout_width="wrap_content"
	            android:layout_height="wrap_content"
	            android:text="橡皮擦"
	            android:textSize="20sp"
	            android:textColor="@color/colorBlack"/>
	        <TextView
	            android:id="@+id/tv_date"
	            android:layout_width="wrap_content"
	            android:layout_height="wrap_content"
	            android:text="2020-02-07"
	            android:textSize="18sp"
	            android:textColor="@color/colorGray"
	            android:layout_marginTop="5dp"/>
	        <TextView
	            android:id="@+id/tv_details"
	            android:layout_width="wrap_content"
	            android:layout_height="wrap_content"
	            android:text="这是介绍, 橡皮擦擦铅笔迹!"
	            android:textSize="19sp"
	            android:layout_marginTop="5dp"
	            android:textColor="@color/colorGray"/>
	    </LinearLayout>
	    
	</LinearLayout>
  1. 这里的内容需要了解一下几个知识
    1. 菜鸟教程: 加载布局的系统服务 LayoutInflater
    2. 需要实现 BaseAdapter 类的 getView() 方法
    3. setTag()getTag() 方法
public class MyListAdapter extends BaseAdapter {

    private Context mContext;
    private LayoutInflater mLayoutInflater;

    public MyListAdapter(Context context) {
        this.mContext = context;
        mLayoutInflater = LayoutInflater.from(context); // 获取布局填充器
    }
    @Override
    public int getCount() {
        return 10;
    }

    @Override
    public Object getItem(int position) {
        return null;
    }

    @Override
    public long getItemId(int position) {
        return 0;
    }

    static class ViewHolder {
        public ImageView imageView;
        public TextView tvTittle, tvDate, tvDetails;
    }
    @Override
    // 列表每一行长什么样子, 这个方法可以得到
    public View getView(int position, View convertView, ViewGroup parent) {

        ViewHolder viewHolder = null;

        if (convertView == null) { // 如果当前 item 是空的, 则新建一个convertView, 更新viewHolder, 并放到缓存区
            // convertView 是一个item View, 将R.layout.layout_list_item填充到一个view得到convertView
            convertView = mLayoutInflater.inflate(R.layout.layout_list_item, null);
            // viewHolder 是管理一个 item 上的所有控件的类对象
            viewHolder = new ViewHolder();
            viewHolder.imageView = convertView.findViewById(R.id.iv);
            viewHolder.tvTittle = convertView.findViewById(R.id.tv_tittle);
            viewHolder.tvDate = convertView.findViewById(R.id.tv_date);
            viewHolder.tvDetails = convertView.findViewById(R.id.tv_details);
            // 将 viewHolder 放到缓存区
            convertView.setTag(viewHolder);
        } else { // 如果当前 item 不是空的, 则直接从缓存区取来就好
            viewHolder = (ViewHolder)convertView.getTag();
        }
        // 给控件赋值, 会覆盖 xml 文件中的初始值
        viewHolder.tvTittle.setText("这是标题");
        viewHolder.tvDate.setText("2022-02-22");
        viewHolder.tvDetails.setText("这是内容喔!");
        Glide.with(mContext).load("https://i0.hdslb.com/bfs/archive/058056424b94c3ff8c1facc940f48ce3bfe423a5.jpg@1100w_484h_1c_100q.jpg").into(viewHolder.imageView);

        return convertView;
    }
}


private ListView mLv1;

	mLv1 = findViewById(R.id.lv_1);
	mLv1.setAdapter(new MyListAdapter(ListViewActivity.this));
2.4.3 监听事件
  1. 点击
        mLv1.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                Toast.makeText(ListViewActivity.this, "position" + position, Toast.LENGTH_SHORT).show();
            }
        });
  1. 长按
        mLv1.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
            @Override
            public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
                Toast.makeText(ListViewActivity.this, "position" + position, Toast.LENGTH_SHORT).show();
                return true;
            }
        });

2.5 GridView

2.5.1 常用 xml 属性

也有 ListView 的许多属性, 还有以下这些:

属性作用
numColumns多少列
horizontalSpacing水平间距
verticalSpacing竖直间距
2.5.2 Adapter

ListView , 代码如下:

  1. 新建一个布局文件, 设计一个 item 的布局
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_margin="10dp">

    <ImageView
        android:id="@+id/iv_image"
        android:layout_width="match_parent"
        android:layout_height="100dp"
        android:background="@color/colorPink"
        android:scaleType="centerCrop"/>

    <TextView
        android:id="@+id/tv_name"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="name"
        android:gravity="center"/>

</LinearLayout>
  1. 自定义 MyGridViewAdapter
public class MyGridViewAdapter extends BaseAdapter {

    private Context mContext;
    private LayoutInflater mLayoutInflater;

    public MyGridViewAdapter(Context context){
        this.mContext = context;
        mLayoutInflater = LayoutInflater.from(context);
    }

    static class ViewHolder{
        public ImageView mImageView;
        public TextView mTextView;
    }

    @Override
    public int getCount() {
        return 10;
    }

    @Override
    public Object getItem(int position) {
        return null;
    }

    @Override
    public long getItemId(int position) {
        return 0;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolder viewHolder = null;
        if (convertView == null) {
            convertView = mLayoutInflater.inflate(R.layout.layout_grid_item, null);
            viewHolder = new ViewHolder();
            viewHolder.mImageView = convertView.findViewById(R.id.iv_image);
            viewHolder.mTextView = convertView.findViewById(R.id.tv_name);
            convertView.setTag(viewHolder);
            convertView.setTag(viewHolder);
        } else {
            viewHolder = (ViewHolder) convertView.getTag();
        }
        viewHolder.mTextView.setText("JoJo");
        Glide.with(mContext).load("https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1581092772754&di=252dc3a97008701c0c654df1cb070f42&imgtype=0&src=http%3A%2F%2Fi2.hdslb.com%2Fbfs%2Farchive%2F23cd383165745a6fdc4ddc06ecc31e5cee91f91c.jpg").into(viewHolder.mImageView);
        return convertView;
    }
}

	private GridView mGv1
        mGv1 = findViewById(R.id.gv);
        mGv1.setAdapter(new MyGridViewAdapter(GridViewActivity.this));
  1. 监听事件
    ListView
	    // 单次点击
    mGv1.setOnItemClickListener(new AdapterView.OnItemClickListener() {
        @Override
        public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
            Toast.makeText(GridViewActivity.this, "点击了图片" + position, Toast.LENGTH_SHORT).show();
        }
    });

    // 长按
    mGv1.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
        @Override
        public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
            Toast.makeText(GridViewActivity.this, "长按了图片" + position, Toast.LENGTH_SHORT).show();
            return true;
        }
  	});

2.6 ScrollView

当控件太多, 手机屏幕放不下时, 就可以使用 ScrollView 来实现滚动功能

2.6.1 使用

将需要滚动的布局放在 ScrollView 里面就好, 注意里面只能放一个元素, 竖直滚动用 ScrollView , 水平滚动用 HorizontalScrollView

<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:app="http://schemas.android.com/apk/res-auto"
  xmlns:tools="http://schemas.android.com/tools"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  tools:context=".ScrollViewActivity">
  <LinearLayout
      android:id="@+id/sv_ll_1"
      android:layout_width="match_parent"
      android:layout_height="match_parent"
      android:orientation="vertical"
      android:layout_margin="5dp">
      <TextView
          android:layout_width="match_parent"
          android:layout_height="150dp"
          android:text="\(@^0^@)/"
          android:textSize="30sp"
          android:gravity="center"
          android:background="@color/colorPink"/>
      <TextView
          android:layout_width="match_parent"
          android:layout_height="150dp"
          android:text="\(@^0^@)/"
          android:textSize="30sp"
          android:gravity="center"
          android:background="@color/colorPink"
          android:layout_marginTop="10dp"/>
      <TextView
          android:layout_width="match_parent"
          android:layout_height="150dp"
          android:text="\(@^0^@)/"
          android:textSize="30sp"
          android:gravity="center"
          android:background="@color/colorPink"
          android:layout_marginTop="10dp"/>
      <TextView
          android:layout_width="match_parent"
          android:layout_height="150dp"
          android:text="\(@^0^@)/"
          android:textSize="30sp"
          android:gravity="center"
          android:background="@color/colorPink"
          android:layout_marginTop="10dp"/>
      <HorizontalScrollView
          android:layout_width="match_parent"
          android:layout_height="match_parent">
          <LinearLayout
              android:layout_width="match_parent"
              android:layout_height="match_parent"
              android:orientation="horizontal">
              <TextView
                  android:layout_width="200dp"
                  android:layout_height="150dp"
                  android:text="\(@^0^@)/"
                  android:textSize="30sp"
                  android:gravity="center"
                  android:background="@color/colorPink"
                  android:layout_marginTop="10dp"/>

              <TextView
                  android:layout_width="200dp"
                  android:layout_height="150dp"
                  android:layout_marginTop="10dp"
                  android:background="@color/colorPink"
                  android:gravity="center"
                  android:text="\(@^0^@)/"
                  android:textSize="30sp"
                  android:layout_marginLeft="10dp"/>

              <TextView
                  android:layout_width="200dp"
                  android:layout_height="150dp"
                  android:text="\(@^0^@)/"
                  android:textSize="30sp"
                  android:gravity="center"
                  android:background="@color/colorPink"
                  android:layout_marginTop="10dp"
                  android:layout_marginLeft="10dp"/>
          </LinearLayout>
      </HorizontalScrollView>

  </LinearLayout>

</ScrollView>

2月8号

1. 学习目标

RecycleView

2. 学习笔记


2.1 RecyclerView

2.1.1 简述 RecyclerView
  1. 可以它被用来代替ListView和GridView, 灵活地实现大数据集的展示
  2. 列表、网格和瀑布流等形式。
  3. viewHoldwer能够实现多元的item,例如微信聊天界面有文字、图片和地址信息等多元item。

2.1.2 导入 Recyclerview 库的依赖

三种方法

2.1.3 实现竖直列表功能

  1. 设置 布局管理器:有三种布局管理器,这里用 LinearLayoutManager
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(HorRecyclerViewActivity.this); // 创建布局管理器对象
mRv.setLayoutManager(linearLayoutManager); // 为RecyclerView控件设置布局管理器
  1. 设置 适配器
mRvHor.setAdapter(new HorAdapter(HorRecyclerViewActivity.this, new HorAdapter.OnItemClickListener() {
            @Override
            public void onClick(int pos) {
                Toast.makeText(HorRecyclerViewActivity.this, "点击了" + pos, Toast.LENGTH_SHORT).show();
            }
        }));
2.1.3.1 具体实现
  1. 布局文件准备:一个 activity 的布局文件,还有一个 item 布局文件
// activity的布局文件
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".recyclerview.RecyclerViewActivity"
    android:layout_margin="10dp">

    <Button
        android:id="@+id/btn_linear"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="列表视图"/>
        
</LinearLayout>

// item布局文件
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <TextView
        android:id="@+id/tv_tittle"
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:textSize="20sp"
        android:textColor="@color/colorBlack"
        android:gravity="center"
        android:background="@color/colorWhite"/>
        
</LinearLayout>
  1. 实现适配器
public class LinearAdapter extends RecyclerView.Adapter<LinearAdapter.LinearViewHolder> {

    private Context mContext;

    public LinearAdapter(Context context) {
        this.mContext = context;
    }

    @NonNull
    @Override
    /**
     * 创建 ViewHolder, 是用来实现复用功能的
     */
    public LinearAdapter.LinearViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        return new LinearViewHolder(LayoutInflater.from(mContext).inflate(R.layout.layout_linear_item, parent, false));
    }

    @Override
    /**
     * 是用来设置数据的,当item划入屏幕时,就会调用此方法,来改变数据
     */
    public void onBindViewHolder(@NonNull LinearAdapter.LinearViewHolder holder, final int position) {

        holder.mTv.setText("设置holder的值");
    }

    @Override
    /**
     * 是用来获取item个数的,实际开发是要获取List的长度
     */
    public int getItemCount() {
        return 30;
    }

    /**
     * 自定义ViewHolder的类型,并将此类型代替所有的泛型
     */
    class LinearViewHolder extends RecyclerView.ViewHolder {

        private TextView mTv;

        public LinearViewHolder(@NonNull View itemView) {
            super(itemView);
            mTv = itemView.findViewById(R.id.tv_tittle);
        }
    }

}
  1. 使用适配器
public class LinearRecyclerViewActivity extends AppCompatActivity {

    private RecyclerView mRvMain;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_linear_recycler_view);
        mRvMain = findViewById(R.id.rv_main);
        mRvMain.setLayoutManager(new LinearLayoutManager(LinearRecyclerViewActivity.this)); // 设置布局管理器, 有三种线性、表格和瀑布流
        mRvMain.setAdapter(new LinearAdapter(LinearRecyclerViewActivity.this);
    }

}
2.1.3.2 实现分割线

使用 addItemDecoration 来实现分割线

public class LinearRecyclerViewActivity extends AppCompatActivity {

    private RecyclerView mRvMain;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_linear_recycler_view);
        mRvMain = findViewById(R.id.rv_main);
        mRvMain.setLayoutManager(new LinearLayoutManager(LinearRecyclerViewActivity.this)); // 设置布局管理器, 有三种线性、表格和瀑布流
        mRvMain.setAdapter(new LinearAdapter(LinearRecyclerViewActivity.thi);
        mRvMain.addItemDecoration(new MyDecoration());
    }

    /**
     * 实现分割线的作用
     */
    class MyDecoration extends RecyclerView.ItemDecoration {
        @Override
        public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
            super.getItemOffsets(outRect, view, parent, state);
            outRect.set(0, 0, 0, getResources().getDimensionPixelOffset(R.dimen.dividerHeight));
        }
    }
}
2.1.3.3 监听事件
  1. 方法一:直接在 onBindViewHolder() 方法中新建监听事件即可。
    @Override
    /**
     * 是用来设置数据的,当item划入屏幕时,就会调用此方法,来改变数据或设置监听(第一种方法)
     */
    public void onBindViewHolder(@NonNull LinearAdapter.LinearViewHolder holder, final int position) {

        holder.mTv.setText("设置holder的值");
        holder.mTv.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(mContext, "点击了" + position, Toast.LENGTH_SHORT).show();
            }
        });
    }
  1. 方法二:使用接口,在自定义的适配器中定义监听事件的接口,实例化适配器时重写接口的点击方法,实现监听事件。
// 适配器的代码
public class LinearAdapter extends RecyclerView.Adapter<LinearAdapter.LinearViewHolder> {

    private Context mContext;
    private OnItemClickListener mOnItemClickListener; // 声明接口

    public LinearAdapter(Context context, OnItemClickListener onItemClickListener) {
        this.mContext = context;
        this.mOnItemClickListener = onItemClickListener; // 初始化接口
    }

    @NonNull
    @Override
    /**
     * 创建 ViewHolder, 是用来复用的
     */
    public LinearAdapter.LinearViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        return new LinearViewHolder(LayoutInflater.from(mContext).inflate(R.layout.layout_linear_item, parent, false));
    }

    @Override
    /**
     * 是用来设置数据的,当item划入屏幕时,就会调用此方法,来改变数据或设置监听(第一种方法)
     */
    public void onBindViewHolder(@NonNull LinearAdapter.LinearViewHolder holder, final int position) {

        holder.mTv.setText("设置holder的值");
        holder.mTv.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
            // 接口方法的调用,实例化后重写该方法,即最终重写后的方法在此处调用
                mOnItemClickListener.onClick(position); 
            }
        });
    }

    @Override
    /**
     * 是用来获取item个数的,实际开发是要获取List的长度
     */
    public int getItemCount() {
        return 30;
    }

    /**
     * 自定义ViewHolder的类型,并将此类型代替所有的泛型
     */
    class LinearViewHolder extends RecyclerView.ViewHolder {

        private TextView mTv;

        public LinearViewHolder(@NonNull View itemView) {
            super(itemView);
            mTv = itemView.findViewById(R.id.tv_tittle);
        }
    }

    /**
     * 写一个接口实现第二种设置监听的方法
     * 即实例化这个类,就得实现这个接口,重写方法,而该方法又是在onBindViewHolder()方法中调用的。
     * 如此一来,只要重写方法中添加一个监听事件就可以实现,但item出现在屏幕时,就可以为该item添加一个监听事件。
     */
    public interface OnItemClickListener {
        void onClick(int pos);
    }
}

// activity的代码
public class LinearRecyclerViewActivity extends AppCompatActivity {

    private RecyclerView mRvMain;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_linear_recycler_view);
        mRvMain = findViewById(R.id.rv_main);
        mRvMain.setLayoutManager(new LinearLayoutManager(LinearRecyclerViewActivity.this)); // 设置布局管理器, 有三种线性、表格和瀑布流
        mRvMain.setAdapter(new LinearAdapter(LinearRecyclerViewActivity.this, new LinearAdapter.OnItemClickListener() {
            @Override
            public void onClick(int pos) {
                Toast.makeText(LinearRecyclerViewActivity.this, "点击了" + pos, Toast.LENGTH_SHORT).show();
            }
        }));
    }
}

2.1.4 水平滚动

只需要设置线性布局的方向就好了

LinearLayoutManager linearLayoutManager = new LinearLayoutManager(HorRecyclerViewActivity.this);
linearLayoutManager.setOrientation(LinearLayoutManager.HORIZONTAL); // 设置滚动方向
mRvHor.setLayoutManager(linearLayoutManager);
mRvHor.setAdapter(new HorAdapter(HorRecyclerViewActivity.this, new HorAdapter.OnItemClickListener() {
    @Override
    public void onClick(int pos) {
        Toast.makeText(HorRecyclerViewActivity.this, "点击了" + pos, Toast.LENGTH_SHORT).show();
    }
}));

2.1.5 网格布局

得使用表格布局管理器 GridLayoutManager
new GridLayoutManager(GridRecyclerViewActivity.this, 3);

public class GridRecyclerViewActivity extends AppCompatActivity {

    private RecyclerView mRvGrid;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_grid_recycler_view);
        mRvGrid = findViewById(R.id.rv_grid);
        GridLayoutManager gridLayoutManager = new GridLayoutManager(GridRecyclerViewActivity.this, 3); // 3列
        mRvGrid.setLayoutManager(gridLayoutManager);
        mRvGrid.setAdapter(new GridAdapter(GridRecyclerViewActivity.this, new GridAdapter.OnItemClickListener() {
            @Override
            public void onClick(int pos) {
                Toast.makeText(GridRecyclerViewActivity.this, "点击了" + pos, Toast.LENGTH_SHORT).show();
            }
        }));

    }
}

2.1.5 瀑布流

得使用表格布局管理器 StaggeredGridLayoutManager
new StaggeredGridLayoutManager(2,StaggeredGridLayoutManager.VERTICAL);

public class StaggeredRecyclerViewActivity extends AppCompatActivity {

    private RecyclerView mRvSta;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_staggered_recycler_view);
        mRvSta = findViewById(R.id.rv_staggered);
        StaggeredGridLayoutManager staggeredGridLayoutManager = new StaggeredGridLayoutManager(2,StaggeredGridLayoutManager.VERTICAL);
        mRvSta.setLayoutManager(staggeredGridLayoutManager);
        mRvSta.setAdapter(new StaggeredAdapter(StaggeredRecyclerViewActivity.this, new StaggeredAdapter.OnItemClickListener() {
            @Override
            public void onClick(int pos) {
                Toast.makeText(StaggeredRecyclerViewActivity.this, "点击了" + pos, Toast.LENGTH_SHORT).show();
            }
        }));
        mRvSta.addItemDecoration(new MyItemDecoration());
    }
}

2.1.6 实现多种item展示

就是自定义Adapter的ViewHolder要求多种类型,可以通过重写getItemViewType(int position)方法,根据不同的信息返回不同的item类型。接下来ViewHolder的创建和onBindViewHolder方法中的具体操作都根据item类型来操作。

public class MulVHAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {

    private Context mContext;
    private OnItemClickListener mOnItemClickListener;

    public MulVHAdapter(Context context, OnItemClickListener onItemClickListener) {
        this.mContext = context;
        this.mOnItemClickListener = onItemClickListener;
    }

    @Override
    /**
     * 根据iitem的位置,判断item的类型
     * return 0: 奇数, item是Text类型
     * return 1: 偶数,item是Iamge类型
     */
    public int getItemViewType(int position) {
        int flag;
        if(position % 2 == 0){
            flag = 1;
        } else {
            flag = 0;
        }
        return flag;
    }

    @NonNull
    @Override
    /**
     * 根据item的类型,创建对应的ViewHolder
     */
    public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        RecyclerView.ViewHolder viewHolder = null;
        if(viewType == 0) { // Text类型
            viewHolder = new MyViewHolderText(LayoutInflater.from(mContext).inflate(R.layout.layout_mvh_text_item, parent, false));
        } else { // Image类型
            viewHolder = new MyViewHolderImage(LayoutInflater.from(mContext).inflate(R.layout.layout_mvh_image_item, parent, false));
        }
        return viewHolder;
    }

    @Override
    /**
     * 根据item的类型,进行不同的操作
     */
    public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, final int position) {
        if(getItemViewType(position) == 0) {
            ((MyViewHolderText)holder).mTv.setText("我是文本");
            ((MyViewHolderText)holder).mTv.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    mOnItemClickListener.onClick(position);
                }
            });
        } else {
            ((MyViewHolderImage)holder).mIv.setImageResource(R.drawable.pikaqiu);
            ((MyViewHolderImage)holder).mIv.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    mOnItemClickListener.onClick(position);
                }
            });
        }
    }

    @Override
    /**
     * 是用来获取item个数的,实际开发是要获取List的长度
     */
    public int getItemCount() {
        return 30;
    }

    /**
     * 自定义ViewHolder的类型1, Text类型
     */
    class MyViewHolderText extends RecyclerView.ViewHolder {

        private TextView mTv;

        public MyViewHolderText(@NonNull View itemView) {
            super(itemView);
            mTv = itemView.findViewById(R.id.tv_mvh);
        }
    }

    /**
     * 自定义ViewHolder的类型2,Image类型
     */
    class MyViewHolderImage extends RecyclerView.ViewHolder {

        private ImageView mIv;

        public MyViewHolderImage(@NonNull View itemView) {
            super(itemView);
            mIv = itemView.findViewById(R.id.iv_mvh);
        }
    }

    /**
     * 写一个接口实现第二种设置监听的方法
     * 即实例化这个类,就得实现这个接口。如此一来,就可以
     */
    public interface OnItemClickListener {
        void onClick(int pos);
    }
}

2月9号

1. 学习目标

  1. WebView
  2. Toast
  3. AlertDialog

2. 学习笔记


2.1 WebView

加载网页

  • 加载 URL(网络或者本地assets文件夹下的html文件)
  • 加载 HTML 代码
  • Native 和 JavaScript 的相互调用
2.1.1 加载本地html文件

需要在main文件夹下新建一个assete文件夹,把html文件放在这个文件夹下,使用以下代码进行加载。
mWvMain.loadUrl("file:///android_asset/test.html");

2.1.2 加载网页

分两步走:

  • 设置JavaScript支持:mWvMain.getSettings().setJavaScriptEnabled(true);
  • 调用加载方法:mWvMain.loadUrl("https://m.baidu.com");
2.1.3 WebViewClient

用于处理各种通知、请求事件。为一个webView设置 WebViewClient mWvMain.setWebViewClient(new MyWebViewClient());其中,MyWebViewClient() 是自定义的继承于 WebViewClient 的类,重写以下方法:

  • 使加载的URL界面保留在当前的 WebView
	@Override
    public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
        return false;
    }
  • 监听界面加载开始时
	@Override
	public void onPageStarted(WebView view, String url, Bitmap favicon) {
	    super.onPageStarted(view, url, favicon);
	    Log.d("WebView", "Page Started");
	}
  • 监听界面加载结束时
    @Override
    public void onPageFinished(WebView view, String url) {
        super.onPageFinished(view, url);
        Log.d("WebView", "Page Finished");
    }
2.1.4 WebChromClient

WebViewClient , 只不过 WebChromClient 是处理对话框、网站图标、网站title、加载进度等。
为一个 WebView 设置一个WebChromClientmWvMain.setWebChromeClient(new MyWebChromeClient());

    public class MyWebChromeClient extends WebChromeClient {
        @Override
        public void onProgressChanged(WebView view, int newProgress) {
            super.onProgressChanged(view, newProgress);
        }

        @Override
        public void onReceivedTitle(WebView view, String title) {
            super.onReceivedTitle(view, title);
            setTitle(title);
        }
    }
2.1.4 浏览中的返回键

进入URL界面时,若不对返回键进行设置,则返回键会直接退出URL界面。实现返回键为回到上一个URL界面,秩序重写监听方法 onKeyDown(int keyCode, KeyEvent event) 即可,代码如下:

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if(keyCode == KeyEvent.KEYCODE_BACK && mWvMain.canGoBack()) {
            mWvMain.goBack();
            return true;
        }
        return super.onKeyDown(keyCode, event);
    }
2.1.5 综合代码
public class WebViewActivity extends AppCompatActivity {

    private WebView mWvMain;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_web_view);
        mWvMain = findViewById(R.id.wv);
        // 加载本地html文件
//        mWvMain.loadUrl("file:///android_asset/test.html");
        // 加载网络URL
        mWvMain.getSettings().setJavaScriptEnabled(true); // 设置支持
        mWvMain.setWebViewClient(new MyWebViewClient()); // 处理各种通知、请求事件
        mWvMain.setWebChromeClient(new MyWebChromeClient()); // 处理对话框、网站图标、网站title、加载进度等
        mWvMain.loadUrl("https://m.baidu.com"); //
    }

    public class MyWebViewClient extends WebViewClient {
        @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
        /**
         * 返回true终止加载URL,返回false在WebView中加载URL
         */
        @Override
        public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
            return false;
        }

        @Override
        public void onPageStarted(WebView view, String url, Bitmap favicon) {
            super.onPageStarted(view, url, favicon);
            Log.d("WebView", "Page Started");
        }

        @Override
        public void onPageFinished(WebView view, String url) {
            super.onPageFinished(view, url);
            Log.d("WebView", "Page Finished");
        }
    }

    public class MyWebChromeClient extends WebChromeClient {
        @Override
        public void onProgressChanged(WebView view, int newProgress) {
            super.onProgressChanged(view, newProgress);
        }

        @Override
        public void onReceivedTitle(WebView view, String title) {
            super.onReceivedTitle(view, title);
            setTitle(title);
        }
    }

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if(keyCode == KeyEvent.KEYCODE_BACK && mWvMain.canGoBack()) {
            mWvMain.goBack();
            return true;
        }
        return super.onKeyDown(keyCode, event);
    }
}

2.2 Toast

是一个消息弹窗提示组件

  1. 默认调用: Toast.makeText(getApplicationContext(), "Toast", Toast.LENGTH_SHORT).show();
  2. 调整位置: toastCenter.setGravity(Gravity.CENTER, 0, 0);
  3. 自定义图案: toastCustom.setView(view);
switch (v.getId()){
    case R.id.btn_toast_1: // 默认情况
        Toast.makeText(getApplicationContext(), "Toast", Toast.LENGTH_SHORT).show();
        break;
    case R.id.btn_toast_2: // 调整位置
        Toast toastCenter = Toast.makeText(getApplicationContext(), "Toast", Toast.LENGTH_SHORT);
        toastCenter.setGravity(Gravity.CENTER, 0, 0);
        toastCenter.show(); ;
    case R.id.btn_toast_3: // 自定义图案
        Toast toastCustom = new Toast(ToastActivity.this);
        View view = LayoutInflater.from(ToastActivity.this).inflate(R.layout.layout_toast_item, null);
        ImageView imageView = view.findViewById(R.id.iv_toast);
        TextView textView = view.findViewById(R.id.tv_toast);
        imageView.setImageResource(R.drawable.icon_smile);
        textView.setText("我是一个Toast");
        toastCustom.setView(view);
        toastCustom.setDuration(Toast.LENGTH_SHORT);
        toastCustom.show();
        break;
}

2.3 AlertDialog

弹出一个消息对话框. 使用构建器来管理, 具体方法可以看构建器里面的方法介绍, 新建构建器: AlertDialog.Builder builder5 = new AlertDialog.Builder(DialogActivity.this);
实现5种情况的对话框

switch (v.getId()) {
    case R.id.btn_dialog_1:
        AlertDialog.Builder builder1 = new AlertDialog.Builder(DialogActivity.this);
        builder1.setTitle("请回答").setMessage("我帅不帅?").setIcon(R.drawable.icon_smile)
                .setPositiveButton("帅呆了", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        Toast.makeText(DialogActivity.this, "有眼光", Toast.LENGTH_SHORT).show();
                    }
                }).setNegativeButton("一般", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                Toast.makeText(DialogActivity.this, "Fuck", Toast.LENGTH_SHORT).show();
            }
        }).setNeutralButton("还行", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                Toast.makeText(DialogActivity.this, "你再想想", Toast.LENGTH_SHORT).show();
            }
        }).show();
        break;
    case R.id.btn_dialog_2:
        final String[] array2 = new String[]{"boy", "girl"};
        AlertDialog.Builder builder2 = new AlertDialog.Builder(DialogActivity.this);
        builder2.setTitle("What's your sex?").setItems(array2, new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                Toast.makeText(DialogActivity.this, array2[which], Toast.LENGTH_SHORT).show();
            }
        }).show();
        break;
    case R.id.btn_dialog_3: // 单选
        final String[] array3 = new String[]{"boy", "girl"};
        AlertDialog.Builder builder3 = new AlertDialog.Builder(DialogActivity.this);
        builder3.setTitle("What's your sex?").setSingleChoiceItems(array3, 1, new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                Toast.makeText(DialogActivity.this, array3[which], Toast.LENGTH_SHORT).show();
            }
        }).show();
        break;
    case R.id.btn_dialog_4: // 多选
        final String[] array4 = new String[]{"boy", "girl", "I don't know!"};
        boolean[] isSelected = new boolean[]{false, false, true};
        AlertDialog.Builder builder4 = new AlertDialog.Builder(DialogActivity.this);
        builder4.setTitle("What's your sex?").setMultiChoiceItems(array4, isSelected, new DialogInterface.OnMultiChoiceClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which, boolean isChecked) {
                Toast.makeText(DialogActivity.this, array4[which], Toast.LENGTH_SHORT).show();
            }
        }).setPositiveButton("确定", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                Toast.makeText(DialogActivity.this, "确定", Toast.LENGTH_SHORT).show();
            }
        }).setNegativeButton("取消", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                Toast.makeText(DialogActivity.this, "取消", Toast.LENGTH_SHORT).show();
            }
        }).show();
        break;
    case R.id.btn_dialog_5: // 自定义View
        AlertDialog.Builder builder5 = new AlertDialog.Builder(DialogActivity.this);
        View view = LayoutInflater.from(DialogActivity.this).inflate(R.layout.layout_dialog, null);
        builder5.setView(view).setTitle("请先登录").show();
        break;
}

2月10号

1. 学习任务

  1. ProgressBarProgressDialog
  2. 自定义 Dialog
  3. PopupWindow

2. 学习笔记

2.1 PressingDialogPressingBar

前者是进度条, 后者是进度对话框, 在API26就已经弃用了, 这里不学了, 也挺简单的
下面列举出几种样式的进度条, 也可以 自定义样式, 这里不说自定义样式了, 需要时候再搜索就好.

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:layout_margin="10dp">

    <ProgressBar
        android:id="@+id/rb_def"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:visibility="visible"/>
    <ProgressBar
        android:id="@+id/rb_style_1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        style="@android:style/Widget.ProgressBar"
        android:layout_marginTop="10dp"/>
    <ProgressBar
        android:id="@+id/rb_style_2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        style="@android:style/Widget.ProgressBar.Horizontal"
        android:progress="10"
        android:secondaryProgress="30"
        android:layout_marginTop="10dp"/>
    <ProgressBar
        android:id="@+id/rb_style_3"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        style="@android:style/Widget.Holo.ProgressBar.Horizontal"
        android:progress="20"
        android:secondaryProgress="30"
        android:layout_marginTop="10dp"/>
    <ProgressBar
        android:id="@+id/rb_style_4"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        style="@android:style/Widget.DeviceDefault.ProgressBar.Horizontal"
        android:progress="20"
        android:secondaryProgress="30"
        android:layout_marginTop="10dp"/>
        
</LinearLayout>

写都写了, 还是将代码附上来吧

mBtnProgressDialog1.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        ProgressDialog progressDialog = new ProgressDialog(ProgressActivity.this);
        progressDialog.setTitle("请稍等");
        progressDialog.setMessage("正在加载");
        progressDialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
            @Override
            public void onCancel(DialogInterface dialog) {
                Toast.makeText(ProgressActivity.this, "加载完成", Toast.LENGTH_SHORT).show();
            }
        });
        progressDialog.setCancelable(false); // 不允许返回, 当加载完成时才能可以调用progressDialog.setCancelable(true); 来取消加载
        progressDialog.setCancelable(true);
        progressDialog.show();
    }
});

2.2 自定义 Dialog

  1. 自定义一个类 CustomDialog 继承于 Dialog
  2. 重写 onCreate() 方法, 对应上一个 CustomDialog 布局文件, 获取布局文件上的各个控件, 并为每一个控件设置存储数据的变量, 并写出它们的 setter()getter() 方法.
  3. 让这个自定义的类 CustomDialog 实现接口 View.OnClickListener , 为相关的控件设置点击事件监听, 重写 onClick() 方法, 在 onClick() 方法中调用在 CustomDialog 中自定义的接口的方法, 如此一来, 就可以用 CustomDialog 的实例传入自定义接口, 同时重写自定义接口的方法

自定义类 CustomDialog 代码如下:

public class CustomDialog extends Dialog implements View.OnClickListener{

    private TextView mTvTittle, mTvMassage, mTvPositive, mTvNegative;
    private String tittle, massage, positive, negative;
    private IOnNegativeListener negativeListener;
    private IOnPositiveListener positiveListener;

    public CustomDialog(@NonNull Context context) {
        super(context);
    }

    public CustomDialog(@NonNull Context context, int themeResId) {
        super(context, themeResId);
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.layout_custom_dialog);
        mTvTittle = findViewById(R.id.tv_tittle);
        mTvMassage = findViewById(R.id.tv_massage);
        mTvPositive = findViewById(R.id.tv_positive);
        mTvNegative = findViewById(R.id.tv_negative);
        if (!TextUtils.isEmpty(tittle)) {
            mTvTittle.setText(tittle);
        }
        if (!TextUtils.isEmpty(massage)) {
            mTvMassage.setText(massage);
        }
        if (!TextUtils.isEmpty(positive)) {
            mTvPositive.setText(positive);
        }
        if (!TextUtils.isEmpty(negative)) {
            mTvNegative.setText(negative);
        }
        mTvPositive.setOnClickListener(this);
        mTvNegative.setOnClickListener(this);
    }


    public String getTittle() {
        return tittle;
    }


    public CustomDialog setTittle(String tittle) {
        this.tittle = tittle;
        return this;
    }

    public String getMassage() {
        return massage;
    }

    public CustomDialog setMassage(String massage) {
        this.massage = massage;
        return this;
    }

    public String getPositive() {
        return positive;
    }

    public CustomDialog setPositive(String positive, IOnPositiveListener positiveListener) {
        this.positive = positive;
        this.positiveListener = positiveListener;
        return this;
    }

    public String getNegative() {
        return negative;
    }

    public CustomDialog setNegative(String negative, IOnNegativeListener negativeListener) {
        this.negative = negative;
        this.negativeListener = negativeListener;
        return this;
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()){
            case R.id.tv_positive:
                positiveListener.positive(this);
                break;
            case R.id.tv_negative:
                negativeListener.negative(this);
                break;
        }
    }

    public interface IOnPositiveListener {
        void positive(CustomDialog customDialog);
    }

    public  interface IOnNegativeListener {
        void negative(CustomDialog customDialog);
    }
}

布局文件的代码

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    android:background="@drawable/layout_dialog">

    <TextView
        android:id="@+id/tv_tittle"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="提示"
        android:textSize="20sp"
        android:gravity="center"
        android:textColor="@color/colorGray"
        android:layout_margin="20dp"/>

    <TextView
        android:id="@+id/tv_massage"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="确定删除?"
        android:textSize="20sp"
        android:gravity="center"
        android:textColor="@color/colorBlack"
        android:layout_margin="20dp"/>

    <View
        android:layout_width="match_parent"
        android:layout_height="1dp"
        android:background="@color/colorLightGray"
        android:layout_marginTop="20dp"/>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:orientation="horizontal">

        <TextView
            android:id="@+id/tv_positive"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:text="确定"
            android:textSize="20sp"
            android:textColor="@color/colorLightGrayishBlue"
            android:gravity="center"
            android:layout_weight="1"/>
        <View
            android:layout_width="1dp"
            android:layout_height="match_parent"
            android:background="@color/colorLightGray"/>
        <TextView
            android:id="@+id/tv_negative"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:text="取消"
            android:textSize="20dp"
            android:textColor="@color/colorLightGrayishBlue"
            android:gravity="center"
            android:layout_weight="1"/>
    </LinearLayout>

</LinearLayout>

使用自定义类 CustomDialog

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_custom_dialog);
    mBtnCustomDialog1 = findViewById(R.id.btn_custom_dialog_1);
    mBtnCustomDialog1.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            CustomDialog customDialog = new CustomDialog(CustomDialogActivity.this);
            customDialog.setTittle("提示").setMassage("你确定删除吗?").setPositive("确定", new CustomDialog.IOnPositiveListener() {
                @Override
                public void positive(CustomDialog customDialog) {

                }
            }).setNegative("取消", new CustomDialog.IOnNegativeListener() {
                @Override
                public void negative(CustomDialog customDialog) {

                }
            }).show();
        }
    });
}

2.3 PopupWindow

它是一个容器, 可以把View放到里面去, 通过设计监听, 可以点弹出View

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_popup_window);
        mBtnPop = findViewById(R.id.btn_pop);
        mBtnPop.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                View view = getLayoutInflater().inflate(R.layout.layout_pop, null);
                mPop = new PopupWindow(view, mBtnPop.getWidth(), ViewGroup.LayoutParams.WRAP_CONTENT);
                mPop.setOutsideTouchable(true);
                mPop.setFocusable(true);
//                mPop.setAnimationStyle();
                mPop.showAsDropDown(mBtnPop);
                final TextView textView = view.findViewById(R.id.tv_1);
                textView.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        Toast.makeText(PopupWindowActivity.this, textView.getText(), Toast.LENGTH_SHORT).show();
                        mPop.dismiss();
                        //do something
                    }
                });

            }
        });
    }

布局文件

// R.layout.layout_pop 布局文件
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent" android:layout_margin="5dp">

    <TextView
        android:id="@+id/tv_1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="苹果"
        android:gravity="center"
        android:padding="5dp"/>
    <View
        android:layout_width="match_parent"
        android:layout_height="1dp"
        android:background="@color/colorGray"/>
    <TextView
        android:id="@+id/tv_2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="雪梨"
        android:gravity="center"
        android:padding="5dp"/>
    <View
        android:layout_width="match_parent"
        android:layout_height="1dp"
        android:background="@color/colorGray"/>
    <TextView
        android:id="@+id/tv_3"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="香蕉"
        android:gravity="center"
        android:padding="5dp"/>

</LinearLayout>

2月11号

1. 学习目标

  1. Activity
  2. Fragmen

2. 学习笔记


2.1 Activity

2.1.1 何为 Activity?

Activity主要是用来做控制的,它可以选择要显示的View,也可以从View中获取数据然后把数据传给Model层进行处理,最后再来显示出处理结果。

2.1.2 新建 Avtivity 分三步
  1. 创建类继承于 Activity 类或其子类, 如: public class UIActivity extends AppCompatActivity { ...
  2. AndroidManifest 文件中声明, 如: <activity android:name=".UIActivity" />
  3. 创建布局文件, 并在重写的 onCreate() 方法中设置, 如: setContentView(R.layout.activity_ui);(通常情况下得需要这一步, 但并非必须的)
2.1.3 在 AndroidManifest 中设置 Avtivity 的相关属性
属性作用
label设置最顶端一栏, 也就是action bar 的文本内容
theme设置主题, 可以在 application 标签内设置, 这样就会运用到全部的activity中去
screenOrientation方向, 竖屏或者横屏, 或者全屏
intent-filter这个标签可以设置启动项
2.1.4 Activity 的生命周期

在这里插入图片描述
打印日志, 查看生命周期如何运行的

public class LifeCycleActivity extends AppCompatActivity {

    private String eTag = "LifeCycle";
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_life_cycle);
        Log.e(eTag, "onCreate");
    }

    @Override
    protected void onStart() {
        super.onStart();
        Log.e(eTag, "onStart");
    }

    @Override
    protected void onResume() {
        super.onResume();
        Log.e(eTag, "onResume");
    }

    @Override
    protected void onPause() {
        super.onPause();
        Log.e(eTag, "onPause");
    }

    @Override
    protected void onStop() {
        super.onStop();
        Log.e(eTag, "onStop");
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        Log.e(eTag, "onDestroy");
    }
}
2.1.5 Activity 的跳转

一般用显式1就好了, 其他的要看得懂

  1. 显式跳转 Activity , 四种方式:2
// 方式一
// 第一个参数: 当前Activity. 第二个参数: 目标 Activity
Intent intent = new Intent(JumpActivity.this, TargetActivity.class); 
startActivity(intent);

// 方式二
Intent intent = new Intent();
intent.setClass(JumpActivity.this, TargetActivity.class);
startActivity(intent);

// 方式三
Intent intent = new Intent();
intent.setClassName(JumpActivity.this, "com.example.learningandroid.activity.jump.TargetActivity");
startActivity(intent);

// 方式四
Intent intent = new Intent();
intent.setComponent(new ComponentName(JumpActivity.this, "com.example.learningandroid.activity.jump.TargetActivity"));
startActivity(intent);
  1. 隐式跳转 Activity

需要在 AndroidManifest 文件的目标 Activity内增加一个标签, 具体如下:

// 第一个字符串随便起, 对应好就行, 第二个字符串得是DEFAULT
<intent-filter>
    <action android:name="android.intent.action.jumpto" />

    <category android:name="android.intent.category.DEFAULT" />
</intent-filter>

然后就可以使用显式跳转了

Intent intent = new Intent();
intent.setAction("android.intent.action.jumpto");
startActivity(intent);
2.1.6 Activity 的数据传递
  1. put: 使用键值对Bundle, 把要传的值 put 进去, 然后调用 intentputExtras() 方法将 Bundle 传过去
Intent intent = new Intent(JumpActivity.this, TargetActivity.class);
Bundle bundle = new Bundle();
bundle.putString("name", "阿笑");
bundle.putInt("old", 18);
intent.putExtras(bundle);
  1. get, 调用 getIntent() 方法获取 Intent对象, 再调用 getExtras(); 方法获取传过来的 Bundle 对象, 再调用get方法就可以获取传过来的数据了
Bundle bundle = getIntent().getExtras();
mTv.setText(bundle.getString("name") + bundle.getInt("old"));
  1. startActivityForResult()setResult
    为了满足这样一个求: 跳转到另外一个 Activity , 处理完数据后回到原 Activity , 同时返回数据. 这就需要上述的两个方法
// 当前Activity中:
// 跳转 *Activity* 要用这个方法了
startActivityForResult(intent, 0);
// 同时要重写onActivityResult()方法以获取传回来的数据, 数据在data种
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    Toast.makeText(JumpActivity.this, data.getExtras().getString("content"), Toast.LENGTH_LONG).show();
}
// 目标Activity中:
// 设置该按钮, 点击后回到原来的 *Activity*, 并调用 *setResult()*  方法传回数据, 和 *finish()* 方法关闭当前的 *Activity*
mBtnBack.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        Intent intent = new Intent();
        Bundle bundle1 = new Bundle();
        bundle1.putString("content", "I'm back!");
        intent.putExtras(bundle1);
        setResult(Activity.RESULT_OK, intent);
        finish();
    }
});
2.1.7 Activity 的4种启动模式

Android 的 Activity 是由栈管理的, 每启动一个 Activity 就会被放进栈种, 按返回键, 就会从栈顶移除一个 Activity .
AndroidManifest 文件种可以设置启动模式: android:launchMode, 可以设置任务栈名称: android:taskAffinity, 这相当于一个新的任务栈了, 这之后的都往这里放了.
有四种启动模式:可以参考 图解4种启动模式

  • standar : 标准模式, 默认. 每启动一个 Activity 就会创建一个新的实例 (一直往上堆)
  • singleTop : Task栈顶复用模式. 当要启动的 Activity 位于栈顶, 则不会创建实例, 而是复用这个栈顶的 Activity , 并且它的 onNewIntent() 方法会被调用. 如果目标 Activity 不在栈顶, 则跟标准模式一样 (最上面的重复就复用它)
  • singleTask : Task栈内复用模式. 当要启动的 Activity 位于栈内, 则不会创建实例, 而是复用这个栈顶的 Activity , 并且它的 onNewIntent() 方法会被调用. 同时位于该 Activity 上方的全部被清除. 如果目标 Activity 不在栈内, 则跟标准模式一样 (里面重复就复用它, 并且通过清除使它成为最上面的)
  • singleIstance : 全局单例模式. 一个任务栈里只有一个 Activity , 并且全局复用

2.2 Fragment 碎片

2.2.1 何为 Fragment

碎片(Fragment)是一种可以嵌入在活动当中的UI片段,它能让程序更加合理和充分地利用大屏幕的空间,因而在平板上应用的非常广泛。虽然碎片对你来说应该是个全新的概念,但我相信你学习起来应该毫不费力,因为它和活动实在是太像了,同样都能包含布局,同样都有自己的生命周期。你甚至可以将碎片理解成一个迷你型的活动,虽然这个迷你型的活动有可能和普通的活动是一样大的。
emmm…觉得会用不上, 就先不学了

二月12日

1.学习目标

  1. 书写4种事件监听的实现方式
  2. 理解基于回调的事件处理机制
  3. Handler消息处理

2. 学习笔记

2.1 4种事件监听的实现方式

要点: 监听器的创建由许多种方式, 可以直接匿名内部类, 也可以写个类, 再实例化它来使用, 还可以让事件源所在的类实现监听接口, 然后直接用本类来创建监听器, 更是可以通过外部自定义监听器创建的类, 然后实例它来实现, 所以就由以下4种方法来设置事件监听

public class EventActivity extends AppCompatActivity implements View.OnClickListener {
    private Button mBtnToast;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_event);
        mBtnToast = findViewById(R.id.btn_toast);
        // 方式一: 内部类
//        mBtnToast.setOnClickListener(new OnClick());

        // 方式二: 匿名内部类
//        mBtnToast.setOnClickListener(new View.OnClickListener() {
//            @Override
//            public void onClick(View v) {
//                Toast.makeText(EventActivity.this, "匿名内部类实现事件监听", Toast.LENGTH_SHORT).show();
//            }
//        });

        // 方式三: 通过事件源所在的类来实现事件监听
//        mBtnToast.setOnClickListener(EventActivity.this);

        // 方式四: 通过外部类来实现
        mBtnToast.setOnClickListener(new MyListener(this));
    }

    @Override
    public void onClick(View v) {
        Toast.makeText(EventActivity.this, "通过事件源所在的类来实现事件监听", Toast.LENGTH_SHORT).show();
    }

    private class OnClick implements View.OnClickListener {
        @Override
        public void onClick(View v) {
            Toast.makeText(EventActivity.this, "内部类实现事件监听", Toast.LENGTH_SHORT).show();
        }
    }
}
 
 public class MyListener implements View.OnClickListener {

    private Activity activity;

    public MyListener(Activity activity) {
        this.activity = activity;
    }
    @Override
    public void onClick(View v) {
        Toast.makeText(this.activity, "通过外部类来实现", Toast.LENGTH_SHORT).show();
    }
}

当然, 还有第五种方式, 也就是通过布局文件设置 android:onClick=“方法名” ,并在类中实现这个方法, 注意访问限制符是 public , 参数是也可以实现
android:onClick="show"

public void show(View v) {
    Toast.makeText(EventActivity.this, "通过布局文件来实现", Toast.LENGTH_SHORT).show();
}

注意 : 监听器最终起作用的是最后建立的.

2.2 基于回调的事件处理机制

  • 事件的处理是由内向外依次传播的, 只有监听返回值是 true, 事件处理才会终止, 不然会一直往外传播.
  • 如果由设立了事件监听器, 那么就从监听器开始, 然后再由内往外传
  • 所谓的 由内往外传 是指 : 比如一个Button控件的触发事件的处理, 就需要从最里边的触发方法开始调用, 依次往外.

2.3 Handler消息处理

利用 Handler 实现需求 : 在某一 Activity 停留3秒后跳转到另外一个 Activity

mHandler = new Handler();
        mHandler.postDelayed(new Runnable() {
            @Override
            public void run() {
                Intent intent = new Intent();
                intent.setClass(HandlerActivity.this, ButtonActivity.class);
                startActivity(intent);
            } 
        }, 3000);

Handler 可以实现上述功能, 但一般不拿来这么用, 一般会结合新建的线程, 进行线程之间的通信:

mHandler = new Handler() { // 主线程
    @Override
    public void handleMessage(@NonNull Message msg) {
        super.handleMessage(msg);
        switch (msg.what) { // 根据不同的消息进行不一样的操作
            case 1 :
                Toast.makeText(HandlerActivity.this, "线程通讯成功", Toast.LENGTH_SHORT).show();
                break;
            default :
        }
    }
};

// 新建一个线程
new Thread(){
    @Override
    public void run() {
        super.run();
        Message message = new Message();
        message.what = 1; // 消息识别标识
        mHandler.sendMessage(message); // Handler发送消息
    }
}.start();

二月13日

1. 学习目标

  1. SharePreference轻量数据处理
  2. Android 存储概念
  3. File 内部存储
  4. File 外部存储
  5. BroadcastReceiver

2. 学习笔记

2.1 SharePreference轻量数据处理

  • 数据读取用 : SharePreference
  • 数据存储用 : SharePreference.Editor
  1. 存储数据 : mEditor.putString("content", mEtInputContent.getText().toString()); mEditor.apply();
  2. 读取数据 : mSharedPreferences.getString("content", "no content")
    例子:
public class SharedPreferencesActivity extends AppCompatActivity {

    private EditText mEtInputContent;
    private Button mBtnSave, mBtnShow;
    private TextView mTvShow;
    private SharedPreferences mSharedPreferences; // 用来读轻量的数据
    private SharedPreferences.Editor mEditor; // 用来写轻量的数据

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_shared_preferences);

        mEtInputContent = findViewById(R.id.et_input_content);
        mBtnSave = findViewById(R.id.btn_save_data);
        mBtnShow = findViewById(R.id.btn_show_data);
        mTvShow = findViewById(R.id.tv_show_content);

        mSharedPreferences = getSharedPreferences("data", MODE_PRIVATE);
        mEditor = mSharedPreferences.edit();

        mBtnSave.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
            	// putString(), 键值对的形式存数据
                mEditor.putString("content", mEtInputContent.getText().toString());
                mEditor.apply();

            }
        });

        mBtnShow.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
            	// getString(), 取数据
                mTvShow.setText(mSharedPreferences.getString("content", "no content"));
            }
        });
    }
}

2.2 Android 存储概念

参考资料 : 五大数据存储

2.3 File内部存储

  1. 数据存储分三步
    1. 打开输出流 : fileOutputStream = openFileOutput(mFILENAME, MODE_PRIVATE)
    2. 写入数据 : fileOutputStream.write(content.getBytes())
    3. 关闭输出流 : fileOutputStream.close();
  2. 读取数据分三步
    1. 打开输入流 : fileInputStream = openFileInput(mFILENAME);
    2. 读取数据 : fileInputStream.read(buff)
    3. 关闭输出流 : fileInputStream.close();
  3. 综合代码:
public class FileActivity extends AppCompatActivity {

    private EditText mEtInputContent;
    private Button mBtnSave, mBtnShow;
    private TextView mTvShow;
    private final String mFILENAME = "test.txt";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_file);

        mEtInputContent = findViewById(R.id.et_input_content);
        mBtnSave = findViewById(R.id.btn_save_data);
        mBtnShow = findViewById(R.id.btn_show_data);
        mTvShow = findViewById(R.id.tv_show_content);


        mBtnSave.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                save(mEtInputContent.getText().toString());
            }
        });

        mBtnShow.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mTvShow.setText(read());
            }
        });
    }

    // 存储数据
    private void save(String content) {
        FileOutputStream fileOutputStream = null;
        try {
            fileOutputStream = openFileOutput(mFILENAME, MODE_PRIVATE);
            fileOutputStream.write(content.getBytes());
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (fileOutputStream != null) {
                try {
                    fileOutputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    // 读取数据
    private String read() {
        FileInputStream fileInputStream = null;
        try {
            fileInputStream = openFileInput(mFILENAME);
            byte[] buff = new byte[1024];
            StringBuilder stringBuilder = new StringBuilder(""); // 一个可变长字符串
            int len = 0;
            while ((len = fileInputStream.read(buff)) > 0) {
                stringBuilder.append(new String(buff, 0, len));
            }
            return  stringBuilder.toString();
        }catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (fileInputStream != null) {
                try {
                    fileInputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return null;
    }
}

2.4 File外部存储

外部存储的访问需要设置权限以及动态申请权限, 首先得再 AndroidManifest 文件中申请权限 : <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>, 然后得动态申请用户的权限:

String[] permissions = new String[]{Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE};
List<String> mUnPermissionList = new ArrayList<>();

// private ImageView welcomeImg = null;
private static final int PERMISSION_REQUEST = 1;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    checkPermission();
    setContentView(R.layout.activity_main);
}

// 检查权限
private void checkPermission() {
    mUnPermissionList.clear();

    //判断哪些权限未授予
    for (int i = 0; i < permissions.length; i++) {
        if (ContextCompat.checkSelfPermission(this, permissions[i]) != PackageManager.PERMISSION_GRANTED) {
            mUnPermissionList.add(permissions[i]);
        }
    }
    /**
     * 判断是否为空
     */
    if (mUnPermissionList.isEmpty()) {//未授予的权限为空,表示都授予了

    } else {//请求权限方法
        String[] permissions = mUnPermissionList.toArray(new String[mUnPermissionList.size()]);//将List转为数组
        ActivityCompat.requestPermissions(MainActivity.this, permissions, PERMISSION_REQUEST);
    }
}

/**
 * 响应授权
 * 这里不管用户是否拒绝,都进入首页,不再重复申请权限
 */
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    switch (requestCode) {
        case PERMISSION_REQUEST:

            break;
        default:
            super.onRequestPermissionsResult(requestCode, permissions, grantResults);
            break;
    }
}

其余部分与内部存储相比, 就只是多了一步, 即最先得创建文件.

  1. 数据存储分四步
    1. 创建文件类对象 :
    // 创建文件夹对象
    File dir = new File(Environment.getExternalStorageDirectory(), "axiao");
    if (!dir.exists()) { // 如果该文件夹不存在的话就创建目标文件夹
        dir.mkdirs();
    }
    //  创建文件对象
    File file = new File(dir, mFILENAME);
    if (!file.exists()) { // 如果该文件不存在的话就目标创建文件
        file.createNewFile();
    }
    
    1. 创建输出流对象 : fileOutputStream = new FileOutputStream(file); // 创建一个通向目标文件的输出流
    2. 写文件 : fileOutputStream.write(content.getBytes());
    3. 关闭输出流对象 : fileOutputStream.close();
  2. 数据读取分四步
    1. 创建文件类对象 : File file = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + "axiao", mFILENAME);
    2. 创建输入流对象 : fileInputStream = new FileInputStream(file);
    3. 读取数据 : fileInputStream.read(buff)
    4. 关闭输入流对象 : fileInputStream.close();
  3. 综合代码
public class FileActivity extends AppCompatActivity {

    private EditText mEtInput;
    private Button mBtnSave, mBtnShow;
    private TextView mTvShow;
    private final String mFILENAME = "test.txt";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_file);

        mEtInput = findViewById(R.id.et_input);
        mBtnSave = findViewById(R.id.btn_save_data);
        mBtnShow = findViewById(R.id.btn_show_data);
        mTvShow = findViewById(R.id.tv_show_content);


        mBtnSave.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                save(mEtInput.getText().toString());
            }
        });

        mBtnShow.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mTvShow.setText(read());
            }
        });
    }

    // 存储数据
    private void save(String content) {
        FileOutputStream fileOutputStream = null;
        try {
            // 内部存储
//            fileOutputStream = openFileOutput(mFILENAME, MODE_PRIVATE);
            // 外部存储
            // 创建文件夹对象
            File dir = new File(Environment.getExternalStorageDirectory(), "axiao");
            if (!dir.exists()) { // 如果该文件夹不存在的话就创建目标文件夹
                dir.mkdirs();
            }
            //  创建文件对象
            File file = new File(dir, mFILENAME);
            if (!file.exists()) { // 如果该文件不存在的话就目标创建文件
                file.createNewFile();
            }
            fileOutputStream = new FileOutputStream(file); // 创建一个通向目标文件的输出流

            fileOutputStream.write(content.getBytes());
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (fileOutputStream != null) {
                try {
                    fileOutputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

2.5 BroadcastReceiver

一般不常用…要用再说, 自己写代码时出现一个问题, 广播成功发送了, 并且广播也成功注册了, 但是收不到广播, 最后查明原因是: 我发送广播的时刻, 接收广播的Activity的 onDestroy() 方法已经调用了, 也就是已经销毁了, 故我再进去的时候还是没有之前的数据, 即没有接收到广播. 于是吸取教训: 运用广播的时候, 一般是之前的 Activity 发送广播, 而在它之后的 Activity 来接受广播, 这样才能保证发送广播的时刻, 接收广播的 Activity 也存在.
广播的使用很简单, 就分为四个部分:

  1. 发送广播 : LocalBroadcastManager.getInstance(context).sendBroadcast(new Intent("com.test.action"));
  2. 注册广播 : LocalBroadcastManager.getInstance(context).registerReceiver(deviceEventReceiver, intentFilter);
  3. 注销广播 : 为了防止内存泄漏, 这一步骤一般放在接收 ActivityonDestroy() 方法中 : LocalBroadcastManager.getInstance(context).unregisterReceiver(deviceEventReceiver)

以下代码参考自 火龙映天

Intent intent = new Intent("com.test.action");
LocalBroadcastManager.getInstance(context).sendBroadcast(intent);

接收广播:
//注册广播
private void registerDeviceEventReceiver() {
    IntentFilter intentFilter = new IntentFilter();
    intentFilter.addAction("com.test.action");
    LocalBroadcastManager.getInstance(context).registerReceiver(deviceEventReceiver, intentFilter);
}
//注销广播
private void unregisterDeviceEventReceiver() {
    LocalBroadcastManager.getInstance(context).unregisterReceiver(deviceEventReceiver);
}
//广播接收器
private BroadcastReceiver deviceEventReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        if (intent.getAction() == null) {
            return;
        }
        if ("com.test.action".equals(intent.getAction())) {
            //TODO: 逻辑处理
        }
    }
};
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值