Android复习

本文全面介绍了Android开发中的核心概念和技术,包括日志工具的使用、活动生命周期管理、UI布局设计、碎片管理、广播接收器的创建与使用、持久化技术如SQLite数据库及SharedPreferences的运用、内容提供器的工作原理以及多媒体和服务的相关知识。
摘要由CSDN通过智能技术生成

Android复习

一.日志工具(Log)

Log.v():用于打印那些最为琐碎的,意义最小的日志信息。对应级别:verbose
Log.d() :打印调试信息。对应级别:debug
Log.i():打印比较重要的信息。对应级别:info
Log.w():打印警告信息。对应级别:warn
Log.e():打印程序中的错误信息。对应级别:error

String TAG=“test”;
Log.d(TAG,"打印调试信息");

二.活动(Activity)

1.使用Toast提醒消息:

Toast.makeText(MainActivity.this,"通知消息",Toast.LENTH_SHORT).show();

2.使用Intent在活动之间穿梭(实现页面跳转)

//显式Intent
Intent intent=new Intent(FirstActivity.this,SecondActivity.this);
startActivity(intent);
//隐式Intent
//在注册文件manifest.xml中声明需要跳转的界面的action和category
//每个Intent只能指定一个action,能指定多个category
<activity android:name=".SeconActivity">
	<intent-filter>
		<action android:name="com.example.activitytest.ACTION_ATART">
		<category android:name="android.intent.category.DEFAULT">
		<category android:name="com.example.activitytest.MY_CATEGORY">
	</intent-filter>
</activity>
//在主界面有:
Intent intent=new Intent("com.example.activitytest.ACTION_ATART");
intent.addCategory("com.example.activitytest.MY_CATEGORY");//使用代码添加category时,必须在mannifest里面注册
startActivity(intent);
//使用Intent打开网页
Intent intent=new Intent(Intent.ACTION_VIEW);//Intent.ACTION_VIEW是android内置的一个动作
intent.setData(Uri.parse("http://www.baidu.com"));
startActivity(intent);
//使用Intent拨打电话
//必须加tel:
//geo显示地理协议
Intent intent=new Intent(Intent.ACTION_DIAL);
intent.setData(Uri.parse("tel:10086"));
startActivity(intent);
//使用Intent发短信
Uri uri=Uri.parse("smsto:10086");
Intent intent new Intent(intent.ACTION_SENDTO,uri);
intent.putExtra("sms_body","Hello");
startActivity(intent);

3.使用Intent传递数据

从FirstActivity传值到SecondActivity
//传递数据使用putExtra()方法
Intent intent=new Intent(FirstActivity.this,SecondActivity.class);
intent.putExtra("extra_data","data");//第一个参数是键名,第二个参数是键值(真正传递的数据)
startActivity(intent);
//接收数据
Intent intent=getIntent();//通过getIntent()方法获取用于启动SecondActivity的Intent
String data=intent.getStringExtra("extra_data");//传递的整形则是getIntExtra(),布尔型则是getBooleanExtra()
从SecondActivity回传数据到FirstActivity
//在FirstActivity中有:
Intent intent=new Intent(FirstActivity.this,SecondActivity.class);
startActivityForResult(intent,1);//第二个参数是请求码,必须唯一
//在SecondActivity中有:
Intent intent=new Intent();
intent.putExtra("data_return","hello FirstActivity");
setResult(RESULT_OK,intent);//第一个参数是回调码
finish();//销毁当前活动
//在FirstActivity中书写获取回调码的后续逻辑
//直接输入onActivityResult
@Override
protected void onActivityResult(int requstCode,int resultCode,Intent data){
	switch(requstCode){
		case 1:
				if(resultCode==RESULT_OK){
					String returnData=data.getStringExtra("data_return");
				}
				break;
		default:
	}
}

4.使用Bundle和序列化类传递数据

使用Bundle传递数据

//在FirstActivity中有
Intent intent=new Intent(FirstActivity.this,SecondActivity.class);
Bundle bundle=new Bundle();
bundle.putExtra("userNo","001");
bundle.putExtra("userName","CSL");
intent.putExtra(bundle);
startActivity(intent);
//在SecondActivity获取数据
Bundle bundle=this.getIntent().getExtras();
String userNo=bundle.getString("userNo");

序列化类传递数据

//
public class UserInfo implements Serializable{
	private String userNo;
	private String userName;
	public String getUserNo(){return userNo;}
	public String setUserNo(String userNo){this.userNo=userNo;}
	public String getUserName(){return userName;}
	public String setUserName(String userName){this.userName=userName;}
}
//在FirstActicity录入数据
UserInfo user=new UserInfo();
user.setUserno("001");
user.setUserName("CSL");
intent.putExtra("user",user);
startActivity(intent);
//在SecondActivity获取数据
UserInfo user=(UserInfo)this.getIntent().getSerializableExtra("user")

5.活动的生命周期

Android是使用任务(Task)来管理活动的,一个任务就是一组存放在栈里的活动的集合,这个栈也被称为返回栈(Back
Stack)。在默认情况下,每当启动一个新的活动,它会在Back
Stack中入栈,并处于栈顶的位置。当按下Back键或者调用finish()方法时,处于栈顶的活动会出栈,使得前一个入栈的活动处于栈顶。系统总是会显示处于栈顶的活动。

4.1活动状态:

每个活动在其生命周期最多可能有4种状态

  • 01.运行状态

    当一个活动处于Back Stack的栈顶时,该活动就处于运行状态。

  • 02.暂停状态

    当一个活动不再处于栈顶位置,但仍然可见时,这时活动就进入了暂停状态。在内存低的情况下,不能系统killed(杀死)

  • 03.停止状态

    当一个活动不再处于栈顶位置,并且完全不可见的时候,就进入了停止状态。在内存低的情况下,能系统killed(杀死)

  • 04.销毁状态

    当一个活动从返回栈中移除后就变成了销毁状态。

4.2活动的生存期:

7个回调方法

  • onCreate()
  • onStart()
  • onResume()
  • onPause()
  • onStop()
  • onDestroy()
  • onRestart()
    活动的生命周期及其回调方法
4.3Android的四种启动模式

指定启动模式:在注册文件中在标签中通过android:launchMode属性选择启动模式

  • standard模式:Activity的默认启动方式,每启动一个Activity就会在栈顶创建一个新的实例

  • singleTop模式:判断要启动的Activity实例是否位于栈顶,如果位于栈顶则直接复用,否则创建新的实例singleTop模式

  • singleTask模式:系统首先检查栈中是否存在当前Activity实例,如果存在则直接使用,并把当前Activity之上的所有实例全部出栈singleTask模式

  • singleInstance模式:启动一个新的任务战来管理Activity实例,无论从哪个任务战中启动该Activity,该实例在整个系统中只有一个singleInstance模式

三.UI布局及控件

1.五种常见布局

  • 线性布局:以水平或者垂直方向排列
  • 相对布局:通过相对定位排列
  • 帧布局:开辟空白区域,帧里的控件(层)叠加,帧布局的大小由内部最大控件决定
  • 表格布局:表格形式排列。配合TableRow使用
  • 网格布局:与表格类似以行列排列
  • 绝对布局:通过x,y坐标排列

2.常用单位

  • px:像素
  • pt:磅数
  • dp:基于屏幕密度的抽象单位
  • sp:可伸缩像素,推荐设置文字大小时使用

3.控件

控件太多,属性等详情查找资料即可

3.1创建自定义控件
3.2ListView

见碎片Fragment新闻例子处

4.常见对话框

//普通对话框
//声明对象并创建对话框
final AlertDialog alertDialog=new AlertDialog.Builder(MainActivity.this).create();
//设置相关信息
alertDialog.setTitle("对话框");
alertDialog.setMessage("是否确定退出?");
alertDialog.setIcon(R.mipmap.ic_launcher);
//显示对话框
alertDialog.show();      
//单选对话框
new AlertDialog.Builder(MainActivity.this)
       .setTitle("请选择性别")//设置选项内容,0标识默认选中第一项
       .setSingleChoiceItems(new String[]{"男", "女"}, 0,
          		new DialogInterface.OnClickListener() {
                  	@Override//建立监听,允许被点击
                         public void onClick(DialogInterface dialog, int which) {
                                        
                                    }
                                }).setPositiveButton("确定",null)
          .show();
//多选对话框
new AlertDialog.Builder(MainActivity.this)
        .setMultiChoiceItems(new String[]{"旅游","美食","汽车","宠物"},null,null)
        .setPositiveButton("确定",null)
        .show();
//进度条对话框
final ProgressDialog progressDialog;
progressDialog=new ProgressDialog(MainActivity.this);
progressDialog.setTitle("进度条对话框");
progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
progressDialog.show();

四.碎片(Fragment)

1.新闻例子(静态添加Fragment和ListView的用法)

静态添加Fragment是通过布局文件添加

以新闻布局为例
当手机横屏时,布局为左边新闻列表,右边新闻详情,竖屏时,为双页模式

//新闻类
class News{
    public int nID;
    public int picture;
    public String title;
    public String content;
    public String Source;
    public String Time;
    public News(String title,String content,String source,String Time,int picture,int nID){
        this.title=title;
        this.content=content;
        this.Source=source;
        this.Time=Time;
        this.picture=picture;
        this.nID=nID;
    }

    public int getPicture() { return picture; }

    public String getContent() {
        return content;
    }

    public String getSource() {
        return Source;
    }

    public String getTime() {
        return Time;
    }

    public String getTitle() {
        return title;
    }

    public int getnID() { return nID; }
}

创建布局文件和Fragment:
创建两个Fragment(新闻列表碎片:ListFragment,新闻详情碎片:DetailFragment)
创建Fragment

创建新闻列表Fragment(使用了ListView控件)
首先在fragment_list.xml里写一个listview布局

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

    <ListView
        android:id="@+id/listview"
        android:layout_width="match_parent"
        android:layout_height="match_parent"></ListView>
</LinearLayout>

为每个ListView里面每列写布局:item.xml(此处为一个新建的单独的布局文件)

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/news"
android:layout_width="match_parent"
android:layout_height="100dp"
android:layout_margin="5dp"
android:orientation="horizontal">

<ImageView
    android:id="@+id/news_picture"
    android:layout_width="99dp"
    android:layout_height="99dp"
    android:src="@mipmap/ic_launcher"></ImageView>

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="99dp"
    android:orientation="vertical">
    <TextView
        android:id="@+id/news_title"
        android:text="新闻标题新闻标题"
        android:textSize="20sp"
        android:textStyle="bold"
        android:textColor="#000000"
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:gravity="center_vertical"></TextView>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="49dp"
        android:layout_weight="2"
        android:orientation="horizontal">
        <TextView
            android:id="@+id/news_source"
            android:text="来源:新华网"
            android:layout_weight="1"
            android:textSize="15sp"
            android:textColor="#000000"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:gravity="center_vertical"></TextView>

        <TextView
            android:id="@+id/news_time"
            android:text="时间:2020/09/28"
            android:layout_weight="1"
            android:textSize="15sp"
            android:textColor="#000000"
            android:layout_width="match_parent"
            android:layout_height="20dp"
            android:gravity="center_vertical"></TextView></LinearLayout>
</LinearLayout>

</LinearLayout>

现在写新闻详情的Fragmment,detail_fragment.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout android:layout_height="match_parent"
    android:layout_width="match_parent"
    android:orientation="vertical"
    android:layout_margin="10dp"
    xmlns:android="http://schemas.android.com/apk/res/android">

    <LinearLayout
        android:layout_width="match_parent"
        android:orientation="vertical"
        android:layout_height="100dp">

        <TextView
            android:id="@+id/news_title"
            android:text="新闻标题新闻标题"
            android:textSize="30sp"
            android:textStyle="bold"
            android:textColor="#000000"
            android:layout_width="match_parent"
            android:layout_height="70dp"
            android:gravity="center"></TextView>

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="30dp"
            android:layout_weight="2"
            android:orientation="horizontal">
            <TextView
                android:id="@+id/news_source"
                android:text="来源:新华网"
                android:layout_weight="1"
                android:textSize="15sp"
                android:textColor="#000000"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:gravity="left|center_vertical"></TextView>

            <TextView
                android:id="@+id/news_time"
                android:text="时间:2020/09/28"
                android:layout_weight="1"
                android:textSize="15sp"
                android:textColor="#000000"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:gravity="right|center_vertical"></TextView></LinearLayout></LinearLayout>

    <View
        android:background="#000000"
        android:layout_width="match_parent"
        android:layout_height="1dp"></View>

    <TextView
        android:id="@+id/news_content"
        android:text="新闻内容新闻内容……"
        android:textColor="#000000"
        android:textSize="20sp"
        android:layout_width="match_parent"
        android:layout_height="match_parent"></TextView></LinearLayout>

碎片写完后,开始写布局
由于分横竖屏,横屏和竖屏对应的布局不一样,故有两个main_activity,xml文件
首先竖屏布局:

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

    <fragment
        android:id="@+id/fragmentList"
        android:name="com.example.labfourfragment.ListFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    </fragment>
</LinearLayout>

创建横屏界面的方法:
在layout目录旁再创建一个同级别的layout-land目录,将activity_list.xml布局文件复制到layout-land中即可
故land\main_activity.xml如下:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal"
    android:layout_weight="5"
    xmlns:android="http://schemas.android.com/apk/res/android">
    <fragment
        android:id="@+id/fragmentList"
        android:layout_weight="2"
        android:name="com.example.labfourfragment.ListFragment"
        android:layout_width="0dp"
        android:layout_height="match_parent"></fragment>

    <fragment
        android:id="@+id/fragment_content"
        android:layout_weight="3"
        android:name="com.example.labfourfragment.DetailFragment"
        android:layout_width="0dp"
        android:layout_height="match_parent">
    </fragment></LinearLayout>

对于detail_activity.xml有:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
xmlns:android="http://schemas.android.com/apk/res/android">

<fragment
    android:id="@+id/fragment_content"
    android:name="com.example.labfourfragment.DetailFragment"
    android:layout_width="match_parent"
    android:layout_height="match_parent"></fragment>
</LinearLayout>

布局文件全部创建完毕,在.java文件中写逻辑:
写碎片的逻辑,新闻列表碎片(ListFragment.java)如下:

public class ListFragment extends Fragment {

    public ListFragment() {
        // Required empty public constructor
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        return inflater.inflate(R.layout.fragment_list, container, false);
    }

}

新闻详情碎片(DetailFragment.java):

public class DetailFragment extends Fragment {
    public DetailFragment() {
        // Required empty public constructor
    }
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
       View view=inflater.inflate(R.layout.fragment_detail,container,false);
       return view;
    }

    public void refresh(String news_title, Object news_content, Object news_sourse, Object news_time){
        View v=getView().findViewById(R.id.fragment_content);
        v.setVisibility(View.VISIBLE);
        TextView news_Title=(TextView)v.findViewById(R.id.news_title);
        TextView news_Content=(TextView)v.findViewById(R.id.news_content);
        TextView news_Sourse=(TextView)v.findViewById(R.id.news_source);
        TextView news_Time=(TextView)v.findViewById(R.id.news_time);

        news_Title.setText(news_title);
        news_Content.setText((CharSequence) news_content);
        news_Sourse.setText((CharSequence) news_sourse);
        news_Time.setText((CharSequence) news_time);
    }
}

竖屏时,点击新闻跳转到新闻详情界面,故DetailActivity逻辑如下:

public class DetailActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_detail);
        //获取数据
        Intent intent=getIntent();
        TextView DetailNewsContent=findViewById(R.id.news_content);
        TextView DetailNewsTitle=findViewById(R.id.news_title);
        TextView DetailNewsSource=findViewById(R.id.news_source);
        TextView DetailNewsTime=findViewById(R.id.news_time);

        DetailNewsContent.setText(intent.getStringExtra("newsContent"));
        DetailNewsTitle.setText(intent.getStringExtra("newsTitle"));
        DetailNewsSource.setText(intent.getStringExtra("newsSourse"));
        DetailNewsTime.setText(intent.getStringExtra("newsTime"));

    }
}

MainActivity.java:

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR);
        setContentView(R.layout.activity_main);

        //新闻信息:
        final News[] news=new News[2];
        news[0]=new News("西南石油大学新生军训","新生冬季军训","swpu","2020/10/07",R.mipmap.swpu,31062101);
        news[1]=new News("西南石油大学冬季运动会","计科院学生积极参与","swpu","2020/10/18",R.mipmap.swpu_head,31062101);

        final ListView listView=findViewById(R.id.listview);
        //创建一个list集合
        final List<Map<String,Object>> listItems=new ArrayList<Map<String,Object>>();
        //通过for循环将图片id和列表项文字放在Map中,并添加到List集合中
        for(int i=0;i<2;i++){
            Map<String,Object>map=new HashMap<String, Object>();//实例化map对象
            map.put("图标",news[i].getPicture());
            map.put("标题",news[i].getTitle());
            map.put("来源",news[i].getSource());
            map.put("时间",news[i].getTime());
            map.put("内容",news[i].getContent());
            listItems.add(map);
        }

        SimpleAdapter adapter=new SimpleAdapter(this,listItems,R.layout.listview,
                new String[]{"图标","标题","来源","时间","内容"},
                new int[]{R.id.news_picture,R.id.news_title,R.id.news_source,R.id.news_time,R.id.news_content});
        listView.setAdapter(adapter);
        //判断横竖屏
        Configuration mConfiguration = MainActivity.this.getResources().getConfiguration();
        int ori = mConfiguration.orientation;
        if (ori == mConfiguration.ORIENTATION_LANDSCAPE) {
            listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
                @Override
                public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                    Map<String,Object>map=(Map<String, Object>)parent.getItemAtPosition(position);
                    String Title=String.valueOf(map.get("标题"));
                    String Content= String.valueOf(map.get("内容"));
                    String Sourse= String.valueOf(map.get("来源"));
                    String Time= String.valueOf(map.get("时间"));
                    DetailFragment fragment=(DetailFragment)getSupportFragmentManager().findFragmentById(R.id.fragment_content);
                    fragment.refresh(Title,Content,Sourse,Time);
                }
            });
        } else if (ori == mConfiguration.ORIENTATION_PORTRAIT) {
            listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
                @Override
                public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                    Map<String,Object>map=(Map<String, Object>)parent.getItemAtPosition(position);
                    String Title=String.valueOf(map.get("标题"));
                    String Content= String.valueOf(map.get("内容"));
                    String Sourse= String.valueOf(map.get("来源"));
                    String Time= String.valueOf(map.get("时间"));
                    Intent intent=new Intent();
                    intent.setClassName(MainActivity.this,"com.example.labfourfragment.DetailActivity");
                    intent.putExtra("newsTitle",Title);
                    intent.putExtra("newsContent",Content);
                    intent.putExtra("newsSourse",Sourse);
                    intent.putExtra("newsTime",Time);
                    startActivity(intent);
                }
            });

        }

    }
}

2.动态添加Fragment

先创建一个MyFragment碎片,然后在.java文件中:
无需在布局文件中添加标签

public class Main2Activity extends AppCompatActivity {

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

        MyFragment fragment=new MyFragment();
        FragmentManager fm=getSupportFragmentManager();//获取FragmentManager实例
        FragmentTransaction beginTransaction=fm.beginTransaction();//获取FragmTransaction实例
        beginTransaction.add(R.id.main2_activity,fragment);//添加一个Fragment,向布局文件main2_activity添加碎片
        beginTransaction.commit();
    }
}

Fragment 的返回

public class Main2Activity extends AppCompatActivity {

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

        MyFragment fragment=new MyFragment();
        FragmentManager fm=getSupportFragmentManager();//获取FragmentManager实例
        FragmentTransaction beginTransaction=fm.beginTransaction();//获取FragmTransaction实例
//        beginTransaction.add(R.id.main2_activity,fragment);//添加一个Fragment,向布局文件main2_activity添加碎片
//        beginTransaction.commit();
        //Fragment的返回,返回上一个碎片,直到没有碎片为止
        beginTransaction.replace(R.id.main2_activity,fragment);
        beginTransaction.addToBackStack(null);
        beginTransaction.commit();
    }
}

3.Fragment和Activity之间的通信

在碎片中获取碎片实例
在这里插入图片描述
得到碎片实例后,活动即可调用碎片中的方法,如:在活动中操作碎片的控件在碎片中获取活动实例:
MainActivity activity=(MainActivity)getActivity();
得到活动实例后,即可调用任何活动中的方法:
MainActivity acticity=(MianActivity)getActivity();
Textview tv=(TextView)activity.findViewById(R.id.show_text);

4.碎片的生命周期

  • Fragment不能独立存在必须嵌入到Activity中使用,所以Fragment生命周期直接受所在Activity影响。
  • 当Activity暂停时,它拥有的所有Fragment都暂停,当Activity销 毁时,它拥有的所有Fragment都被销毁。
    Fragment的生命周期

五.广播(Broadcast Receiver)

为了监听来自系统或者应用程序的广播事件,Android系统提供了BroadcastReceiver(广播接收者)组件
当Android系统产生一个广播事件时,可以有多个对应的广播接收者接受并处理

广播的类型:有序广播+无序(标准)广播
有序广播:完全异步执行,发送广播时所有监听这个广播的广播接收者都会收到此消息,但是接受的顺序不确定
无序广播:按照接收者的优先级接收,只有一个广播接收者能接收消息,在此广播接收者逻辑执行完毕之后,才会继续传递

5.1创建广播接收者

com.example.review–>New–>Other–>Broadcast Receiver
其中属性Exportd属性表示是否允许这个广播接收者接收本程序以外的广播,Enabled属性表示是否启用这个广播接收者
勾选上述两个属性,点击finish完成创建

5.2静态注册广播(例子:提示开机成功)

首先在manifest中注册,注册权限use-permission和intent-filter中的action:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.review">
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"></uses-permission>
    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"></uses-permission>

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <receiver
            android:name=".MyBroadcastReceiver"
            android:enabled="true"
            android:exported="true">
            <intent-filter>
                <!--此广播接收者接收的特定广播类型:下面是开机自启动服务-->
                <action android:name="android.intent.action.RECEIVE_BOOT_COMPLETED"></action>
            </intent-filter>
        </receiver>

        <activity android:name=".Main2Activity" />
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

5.3动态注册广播

 private MyBroadcastReceiver myBroadcastReceiver;
 private IntentFilter intentFilter;
 ...
 //在onCreate方法里有:
  Intent intent = new Intent("android.intent.action.RECEIVE_BOOT_COMPLETED");
  intent.putExtra("MyBroadMessage","send message");
 //打开另一服务
  intent.setComponent(new ComponentName("com.example.broadcastreceiver","com.example.broadcastreceiver.MyBroadcastReceiver"));
  sendBroadcast(intent);
//在onDestroy方法中:(必须取消注册)
  unregisterReceiver(myBroadcastReceiver);

5.4自定义广播

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

发送标准广播:
Intent intent2=new Intent();
intent2.setAction(“在注册文件中的filter的name”);
sendBroadcast(intent2);

发送有序广播
Intent intent2=new Intent();
intent2.setAction(“在注册文件中的filter的name”);
sendOrderedBroadcast(intent2,null);

首先new一个Broadcast Receiver,然后写注册文件
自定义一个Filter的名字,记住它,后面会用:

 <receiver
      android:name=".MyReceiver"
      android:enabled="true"
      android:exported="true">
      <intent-filter>
        	<action android:name="MyReceiver"></action>
            </intent-filter>
 </receiver>

书写发出广播:

  Button button=findViewById(R.id.button1);
  button.setOnClickListener(new View.OnClickListener() {
       @Override
       public void onClick(View v) {
           Intent intent1=new Intent("MyReceiver");
           //变量以及变量对应的值
           intent1.putExtra("extraKey","CustomValue");
           intent1.setComponent(new ComponentName("com.example.broadcastreceiver","com.example.broadcastreceiver.MyReceiver"));
           sendBroadcast(intent1);
            }
        });

书写接收广播:

public void onReceive(Context context, Intent intent) {
        if(intent.getAction().equals("MyBroadcast")){
            String msg=intent.getStringExtra("extraKey");
            Log.d("MyBroadcastReceiver", "extraKey:"+msg);
        }
    }

5.5有序广播的优先级

在filter中增加priority属性,数值越大,优先级越高。若两者优先级相同,则先注册的广播接收者优先级高:

< intent-filter android:priority=“100”>
< action android:name=“MyReceiver”>< /action>
< /intent-filter>

在广播中:

//可截断广播,优先级低的接收器无法接收
public void onReceive(Context context, Intent intent) {
abortBroadcast();
}

5.6本地广播

androidx.localbroadcastmanager.content.LocalBroadcastManager
1.广播注册:动态注册方式
2.广播接收器定义:与全局广播一样,继承BroadcastReceiver并重写onReceiver方法
3.广播注册/注销:
使用LocalBroadcastManager下的registerReceiver方法注册
使用LocalBroadcastManager下的unRegisterReceiver方法注销
4.广播发送:
1)创建LocalBroadcastManager实例
LocalBroadcastManager lbc = LocalBroadcastManager.getInstance(this);
2)创建Intent实例,并指定广播的action
Intent intent = new Intent(“com.example.broadcast.LOCAL_BROADCAST”);
3)使用LocalBroadcastManager的sendBroadcast()方法发送
lbc. sendBroadcast(intent);

六.持久化技术(SQLite和SharedPreference)

持久化技术:将内存中的数据存入持久化存储设备中,如:硬盘

  1. 文件流/字节序列:使用文件流存储为文件
  2. 键值对:存储和传输结构简单的数据,如:单个变量或简单序列
    HTTP请求数据(数据传输)、Android SharedPreferences等
  3. 对象:面向对象编程中,内存中的数据以对象形式存在——对象持久化;对象包含所属类名、属性名、属性值等,理想的存储介质是数据库、JSON字串、XML文档等
    3.1 数据库:将数据库表映射到对象的持久层框架
    Java技术:Hibernate、MyBatis
    微软技术:Entity Framework、Linq
    3.2. JSON和XML:将对象与JSON字串/XML文档相互转换,通常用于对象的文件化存储和远程传输
    JSON字串的序列化/反序列化
    XML文档的序列化/反序列化

1.文件存储

文件存储是Android中最基本的一种数据存储方式,它与Java中的文件存储类似,都是通过I/O流的形式把数据存储到文档中。

文件存储分为内部存储和外部存储

内部存储
将应用程序中的数据以文件方式存储到设备的内部,当创建的应用程序被卸载时,其内部存储文件也随之被删除。

外部存储
是将文件存储到一些外部设备上,例如SD卡或者设备内嵌的存储卡,属于永久性的存储方式。

1.1内部存储的写入和读取

找书写的内部文件:
点击搜索图标(放大镜),输入File Explorer,回车,打开文件:data/data/com.example.项目的名字/files,书写的data文件就在这下面

//内部存储的写入
String fileName="data.txt";
String content="helloworld";
FileOutputStream fos;
try{
   fos=openFileOutput(fileName,MODE_PRIVATE);
   fos.write(content.getBytes());
   fos.close();
   }catch (Exception e){
   e.printStackTrace();
}

内部文件的读取

 //内部储存的读取
 String content1="";
 FileInputStream fis;
 try{
      fis=openFileInput("data.txt");
      byte[]buffer=new byte[fis.available()];
      fis.read(buffer);
      content1=new String(buffer);
      Log.d("Review",content1);
      fis.close();
}catch (Exception e){
      e.printStackTrace();
}
1.2外部文件的存入和读取

由于操作SD卡中的数据属于系统中比较关键的信息,因此需要在清单文件的< manifest>节点中添加SD卡的读写权限

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

外部文件的写入:

String state = Environment.getExternalStorageState();
        if (state.equals(Environment.MEDIA_MOUNTED)) {
            File SDPath = Environment.getExternalStorageDirectory();
            File file = new File(SDPath, "data.txt");
            String data = "HelloWorld";
            FileOutputStream fos;
            try {
            //将数据存储到SD卡中
                fos = new FileOutputStream(file);
                fos.write(data.getBytes());
                fos.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

外部文件的读取:

//获取外部设备判断外部设备是否可用获取SD卡目录
        String state = Environment.getExternalStorageState();
        if (state.equals(Environment.MEDIA_MOUNTED)) {
            File SDPath = Environment.getExternalStorageDirectory();
            File file = new File(SDPath, "data.txt");
            FileInputStream fis;
            try {
                //获取指定文件对应的输入流,将其包装成BufferReader读取文件
                fis = new FileInputStream(file);
                BufferedReader br = new BufferedReader(new InputStreamReader(fis));
                String data = br.readLine();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

2.SharedPreference

  • SharedPreferences是Android平台上一个轻量级的存储类。

  • 用于存储应用程序的配置参数,如用户名、密码等。

  • 通过key/value(键值对)的形式将数据保存在XML文件中。

  • value值只能是float、int、long、boolean、String、StringSet类型数据

***例子:***使用SharedPreferences保存已看过的新闻ID,下次再进入时,以灰色显示(详情见综合例子)
存储数据:
SharedPreferences对象只能获取数据,必须通过SharedPreferences的Editor对象来操作数据
注意:
操作完数据后,一定要调用commit()方法提交数据,否则所有操作不生效。

//获取SP对象,data表示文件名,MODE_PRIVATE表示文件操作类型
SharedPreferences sp = getSharedPreferences("data",MODE_PRIVATE);
SharedPreferences.Editor editor = sp.edit();//获取编辑器
editor.putString(“name”, “西南石油大学");//存入数据
editor.putInt("age", 61);//存入数据
editor.commit(); //提交修改

获取数据:
通过SharedPreferences对象的getXXX()方法来实现获取:
注意:
getXXX()方法第二个参数为缺省值,如果SharedPreferences中不存在该key,将返回缺省值。例如getString(“name”,””),若name不存在则key就返回空字符串。

SharedPreferences sp = getSharedPreferences("data",MODE_PRIVATE);
String data = sp.getString("name","");    

注意事项:

  • 获取数据的key值与存入数据的key值数据类型要一致,否则查找不到指定数据。
  • 保存SharedPreferences的key值时,使用静态变量保存,以免操作时写错,如private final String key = “itcast”。

3.SQLite

  • SQLite是一个轻量级数据库,占用资源非常低,在内存中只需要占用几百KB的存储空间。
  • SQLite是遵守ACID的关系型数据库管理系统,ACID是指数据库事务正确执行的四个基本要素。原子性-A,一致性-C,隔离性-I,持久性-D
  • SQLite保存数据时,支持NULL(零)、INTEGER(整数)、REAL(浮点数字)、TEXT(字符串文本)和BLOB(二进制对象)五种数据类型。
3.1数据库的创建
public class MyHelper extends SQLiteOpenHelper {
    public MyHelper(Context context) {
        super(context, “test.db", null, 2);
    }
    //第一次创建时调用,用于初始化表结构
	public void onCreate(SQLiteDatabase db) {
    db.execSQL("CREATE TABLE information(_id INTEGER PRIMARY 
                KEY AUTOINCREMENT, name VARCHAR(20), price INTEGER)");
    }
    // 当数据库的版本号增加时调用
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
    }
}

3.2添加数据
public void insert(String name,String price) {
		//获取可读写对象SQLiteDatabase
        SQLiteDatabase db = helper.getWritableDatabase();
        //创建ContentValue对象,并将数据添加到ContentValues对象中
        ContentValues values = new ContentValues();
        values.put("name", name);
        values.put("price", price);
        //调用insert()方法将数据添加到数据库中
        long id = db.insert("information",null,values);
        db.close();
    }
3.3修改数据
    public int update(String name, String price) {
    SQLiteDatabase db = helper.getWritableDatabase();
    //创建ContentValue对象,并将修改的数据添加到ContentValues对象中
    ContentValues values = new ContentValues();
    values.put("price", price);
    //调用update()方法修改数据
    int number = db.update("information", values, " name =?", new        	String[]{name});
    db.close();
    return number; }

3.4删除数据
    public int delete(long id){
        SQLiteDatabase db = helper.getWritableDatabase();
        int number = db.delete("information", "_id=?", new String[]{id+""});
        db.close();
        return number;
    }
3.5查询数据
    public boolean find(long id){
        SQLiteDatabase db = helper.getReadableDatabase();
        //调用query()方法查询数据库中的数据,返回一个行数集合Cursor
        Cursor cursor = db.query("information", null, "_id=?", new
                String[]{id+""}, null, null, null);
        boolean result = cursor.moveToNext();
        cursor.close();
        db.close();
        return result;
    }
3.6另外的写法
//添加
db.execSQL(“insert into tblStu(name,age) values(?,?),new Object[]{1,值2})
//修改
db.execSQL(“update tblStu set name=?  and age =?),new Object[]{1,值2})
//删除
db.execSQL(“delete from  tblStu where num=?,new Object[]{})
//查询
Cursor cusor=db.rawQuery(“select * from tblStu where stuNo=?,new String[]{})

3.7事务
SQLiteDatabase db = helper. getWritableDatabase();
db.beginTransaction();
db.execSQL(..)
db.execSQL(..)
db.setTransactionSuccessful();
db.endTransaction() ;
db.close();

4.综合例子(实验报告6,SharedPreference和SQLite)

MainActivity:

public class MainActivity extends AppCompatActivity {

    MyHelper myHelper=new MyHelper(MainActivity.this);
    SQLiteDatabase db;
    ContentValues values;
    private static final String TAG="Test";

    //记录新闻详情浏览时间
    static long starttime=0;
    static long endtime=0;

    //记录新闻被点击的行号
    String number;
    //用于承装浏览过的新闻ID
    final static List<String> lstID=new ArrayList<String>();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR);
        setContentView(R.layout.activity_main);


        //向数据库中录入数据
        News news;
        news=new News(0,"title","content","source","time");
        insert(news.getnID(),news.getTitle(),news.getContent(),news.getSource(),news.getTime());

        //初始化新闻列表
        db=myHelper.getReadableDatabase();
        final ListView listView=findViewById(R.id.listview);
        final List<Map<String,String>> listItems=new ArrayList<Map<String,String>>();
        //查询数据库中数据,将数据库数据填入新闻列表
        Cursor cursor=db.query("NewsTable",null,null,null,null,null,null);
        while(cursor.moveToNext()){
            Map<String,String>map=new HashMap<>();
            map.put("ID",cursor.getString(cursor.getColumnIndex("nID")));
            map.put("标题",cursor.getString(cursor.getColumnIndex("Title")));
            map.put("内容",cursor.getString(cursor.getColumnIndex("Content")));
            map.put("来源",cursor.getString(cursor.getColumnIndex("Source")));
            map.put("时间",cursor.getString(cursor.getColumnIndex("time")));
            listItems.add(map);
        }
        //创建适配器
        SimpleAdapter adapter=new SimpleAdapter(this,listItems,R.layout.items,
                new String[]{"标题","来源","时间","内容"},
                new int[]{R.id.news_title,R.id.news_source,R.id.news_time,R.id.news_content});
        //设置适配器
        listView.setAdapter(adapter);

        //判断横竖屏:
        Configuration mConfiguration = MainActivity.this.getResources().getConfiguration();
        int ori=mConfiguration.orientation;
        if(ori==mConfiguration.ORIENTATION_LANDSCAPE){//横屏时:
            //点击事件:
            listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
                @Override
                public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                    Map<String,String>map=(Map<String, String>)parent.getItemAtPosition(position);
                    //获取点击位置的ID
                    number=String.valueOf(position);
                    String Title=map.get("标题");
                    String Content= map.get("内容");
                    String Sourse= map.get("来源");
                    String Time= map.get("时间");
                    DetailFragment fragment=(DetailFragment)getSupportFragmentManager().findFragmentById(R.id.fragment_content);
                    fragment.refresh(Title,Content,Sourse,Time);
                }
            });
        }
        else if(ori==mConfiguration.ORIENTATION_PORTRAIT){//竖屏时:
           //点击事件:
            listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
                @Override
                public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                    Map<String,String>map=(Map<String, String>)parent.getItemAtPosition(position);
                    //获取点击位置的ID
                    number=String.valueOf(position);
                    String Title=map.get("标题");
                    String Content= map.get("内容");
                    String Sourse= map.get("来源");
                    String Time= map.get("时间");

                    Intent intent=new Intent();
                    intent.setClassName(MainActivity.this,"com.example.labsixsqlite.DetailActivity");
                    intent.putExtra("newsTitle",Title);
                    intent.putExtra("newsContent",Content);
                    intent.putExtra("newsSourse",Sourse);
                    intent.putExtra("newsTime",Time);
                    startActivity(intent);
                }
            });
        }

    }

    //向数据库中增加数据
    public void insert(int nID,String Title,String Content,String Source,String time){
        //获取可读写SQLiteDatabase对象
        db = myHelper.getReadableDatabase();
        values=new ContentValues();
        for(int i=0;i<6;i++){
            values.put("nID",nID+i);
            values.put("Title",Title+i);
            values.put("Content",Content+i);
            values.put("Source",Source+i);
            values.put("time",time+i);
            //调用Inset方法将数据添加到数据库中
            db.insert("NewsTable",null,values);
            values.clear();
        }
    }

    @Override
    protected void onRestart() {
        super.onRestart();
        endtime=System.currentTimeMillis();
        getALRead();
        changeClolor();
    }

    @Override
    protected void onDestroy() {//退出应用时,关闭数据库连接
        super.onDestroy();
        if(db!=null){
            db.close();
        }
    }

    private void getALRead()
    {
        //达到规定阅读时间,将新闻ID存入文件
        if((endtime-starttime)/1000>3){
            Log.d(TAG,"duration:"+(endtime-starttime)/1000);
            SharedPreferences.Editor editor=getSharedPreferences("AlRead",MODE_PRIVATE).edit();
            lstID.add(number);
            Log.d(TAG,"存入lstID中的新闻ID:"+number);
            //将已读新闻ID转化为字符串保存
            String str="";
            for(int i=0;i<lstID.size();i++){
                str+=lstID.get(i)+",";
            }
            editor.putString("ID",str);
            Log.d(TAG,"达到阅读时间的所有新闻ID:"+str);
            editor.apply();
        }
    }

    private void changeClolor(){
        File alRead=new File("data/data/com.example.labsixsqlite/shared_prefs","AlRead.xml");
        if(alRead.exists()){
            SharedPreferences pref=getSharedPreferences("AlRead",MODE_PRIVATE);
            String str=pref.getString("ID","");
            //将字符串以","分割为字符数组sstr
            String[] sstr=str.split(",");
            //将lstAlRead中的新闻ID
            for(int i=0;i<sstr.length;i++){
                //获取item的layout的index
                ListView listView= findViewById(R.id.listview);
                LinearLayout layout=(LinearLayout)listView.getChildAt(Integer.parseInt(sstr[i]));
                TextView textView=layout.findViewById(R.id.news_title);
                textView.setTextColor(Color.RED);
            }
        }
    }
}



public class DetailFragment extends Fragment {

    String TAG="DetailFragment";
    long starttime=0;

    public DetailFragment() {
        // Required empty public constructor
    }
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        Log.d(TAG,"onCreateView");
        View view=inflater.inflate(R.layout.fragment_detail,container,false);
        return view;
    }

    public void refresh(String news_title, Object news_content, Object news_sourse, Object news_time){
        View v=getView().findViewById(R.id.fragment_content);
        v.setVisibility(View.VISIBLE);

        TextView news_Title= v.findViewById(R.id.news_title);
        TextView news_Content= v.findViewById(R.id.news_content);
        TextView news_Sourse= v.findViewById(R.id.news_source);
        TextView news_Time= v.findViewById(R.id.news_time);

        news_Title.setText(news_title);
        news_Content.setText((CharSequence) news_content);
        news_Sourse.setText((CharSequence) news_sourse);
        news_Time.setText((CharSequence) news_time);
    }

    
    @Override
    public void onStart() {
        super.onStart();
        starttime=System.currentTimeMillis();
        MainActivity.starttime=starttime;
        Log.d(TAG,"onStart");
    }
    
}
public class DetailActivity extends AppCompatActivity {
    long starttime=0;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_detail);
        //获取数据
        Intent intent=getIntent();
        TextView DetailNewsContent=findViewById(R.id.news_content);
        TextView DetailNewsTitle=findViewById(R.id.news_title);
        TextView DetailNewsSource=findViewById(R.id.news_source);
        TextView DetailNewsTime=findViewById(R.id.news_time);

        DetailNewsContent.setText(intent.getStringExtra("newsContent"));
        DetailNewsTitle.setText(intent.getStringExtra("newsTitle"));
        DetailNewsSource.setText(intent.getStringExtra("newsSourse"));
        DetailNewsTime.setText(intent.getStringExtra("newsTime"));
    }
    @Override
    protected void onStart() {
        super.onStart();
        starttime=System.currentTimeMillis();
        MainActivity.starttime=starttime;
    }
}
public class MyHelper extends SQLiteOpenHelper {
    public MyHelper(Context context){ super(context,"NewsTable.db",null,2); }
    @Override
    //第一次创建时调用,用于初始化表结构
    //创建新闻数据库,包含新闻表
    //第一次加载时能创建数据库及表
    public void onCreate(SQLiteDatabase db) {
        db.execSQL("Create table  NewsTable(" +
                "nID integer primary key autoincrement," +
                "Title text," +
                "Content text," +
                "Source text," +
                "time text)");
    }
    @Override
    //当数据库的版本号增加时调用
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

    }
}

七.跨程序共享数据-内容提供器(Content Provider)

Android系统四大组件:Activity+Service+BroadCast+Content Provider

  • 内容提供者(ContentProvider)是Android系统四大组件之一,它是不同应用程序之间进行数据共享的标准API,通过ContentResolver类可以访问ContentProvider中共享的数据。
    工作原理:
    ContentProvider的工作原理
  • ContentResolver
  • ContentResolver提供一系列增删改查的方法对数据进行操作,并且这些方法以Uri的形式对外提供数据。
  • Uri为内容提供者中的数据建立了唯一标识符。它主要由三部分组成,scheme、authorities和path。

1.运行时权限(运行时授权)

  • 数据共享涉及到权限问题

  • 权限种类:

一般权限:不会威胁隐私的权限

危险权限:威胁到隐私的权限,仅对此类权限进行运行时授权
特殊权限:很少使用

  • Android管理权限的方式是通过权限注册

在AndroidManifest.xml中注册,这样在APP安装时会提示用户权限

< use-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
  • 同时为了防止一些刚需软件在安装时提示权限过多,导致用户无法拒绝的现象出现,Android在6.0以后增加了运行时权限功能

  • 运行时权限

用户不需要在安装时一次性授权所有权限,而是在用到该功能时选择是否授权,这样就使得用户可以在拒绝一部分功能后,仍然可以使用APP的其他功能
运行时授权仅针对危险权限

1.1拨打电话例子:

6.0版本以下:
注册权限–>编写代码

<use-permission android:name="android.permission.CALL_PHONE" />
Intent intent = new Intent(Intent.ACTION_CALL);
intent.setData(Uri.parse("tel:10086"));
startActivity(intent);

6.0以上版本
判断是否已运行时授权:

//检查CALL_PHONE权限是否曾被授权
if(ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.CALL_PHONE) !=  PackageManager.PERMISSION_GRANTED)
{
       //打开请求授权框,用户可以看到一个CALL_PHONE的请求授权对话框;
       //可在框中选择授权、拒绝,或直接关闭对话框
       //1是请求码
        ActivityCompat.requestPermissions(MainActivity.this,  new
                String[]{Manifest.permission.CALL_PHONE}, 1); 
}
else{
        call();    //如果有权限,则执行call()方法
}

是否接受运行时授权

    public void onRequestPermissionResult(int requestCode, String[] permissions, int[] grantResults){
        switch(requestCode){
            case 1:
                if(grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED){
                    call();
                }
                else{
                    Toast.makeText(MainActivity.this, "You denied the permission", Toast.LENGTH_LONG).show();
                }
                break;
            default:
        }
    }

执行动作:

public void call(){
        Intent intent = new Intent(Intent.ACTION_CALL);
        intent.setData(Uri.parse("tel:10086"));
        startActivity(intent);
    }

2.访问其他程序数据

访问内容提供者:

//获取相应操作的Uri,Uri.Parse()方法将字符串转化成Uri对象
Uri uri = Uri.parse("content://cn.itcast.mycontentprovider/person");
//获取ContentResolver对象
ContentResolver resolver = context.getContentResolver();
//通过ContentResolver对象查询数据
Cursor cursor = resolver.query(uri, new String[] { "address", "date","type", "body" },
        null, null, null);
while (cursor.moveToNext()) {
        String address = cursor.getString(0);
        long date = cursor.getLong(1);
        int type = cursor.getInt(2);
        String body = cursor.getString(3);
        }
        cursor.close();

3.内容观察者的使用

创建内容提供者步骤:

  • 在程序包名处点击右键选择【New】–>【Other】–>【Content Provider】选项

  • 输入内容提供者的Class Name(名称)和URI Authorities(唯一标识,通常使用包名)

  • 点击【Finish】按钮创建完成

创建完成后,Android Studio会在注册文件中对内容提供者进行注册

3.1内容提供者概述

内容提供者封装在ContentProvider中,该类是一个抽象类,包含了6个抽象方法,必须全部重写

  • onCreate():内容提供器初始化时调用,通常用于数据库的创建、升级等操作。
  • query():查询数据
  • insert():插入数据
  • update():修改数据
  • delete():删除数据
  • getType():根据URI返回MIME类型
  • MIME用于在网络传输中定义资源类型
3.2内容提供者Uri
  • 内容访问者(ContentResolver)通过URI访问内容提供器(ContentProvider)

  • 格式:content://包名/表名/id,如:content://com.example.provider/table1/1

  • 通配符:表名和id都可用通配符表达

  • *:表示任意长度的任意字符

  • #:表示任意长度的数字

  • 如:content://com.example.provider/* 匹配任意表的内容

  • content://com.example.provider/table1/# 匹配table1表的任意行数据

八.多媒体(Notification,Camera,Album,MediaPlayer)

九.服务(Service)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值