android基础入门

历史

  1. 2008年推出android1.0。
  2. 2011年10月,发布android4.0

概要

android系统架构

4层架构,5块区域
1. linux内核层
基于linux2.6内核,提供底层的驱动。
2. 系统运行库层
通过C/C++库提供主要特性支持。如sqlite,opengl,webkit,android运行时库(包括dalvik虚拟机)
3. 应用框架层
为应用程序提供api
4. 应用层
所有安装在手机上的应用程序,包括系统自带的。

搭建开发环境

需要的软件

  1. jdk
  2. android sdk
  3. android studio

分析android程序

android studio基本项目结构
  1. app/build
    app模块build编译输出的目录
  2. app/build.gradle
    app模块的gradle编译文件
  3. app/app.iml
    app模块的配置文件
  4. app/proguard-rules.pro
    app模块proguard文件
  5. build.gradle
    项目的gradle编译文件
  6. settings.gradle
    定义项目包含哪些模块
  7. gradlew
    编译脚本,可以在命令行执行打包
  8. local.properties
    配置SDK/NDK
  9. MyApplication.iml
    项目的配置文件
  10. External Libraries
    项目依赖的Lib, 编译时自动下载的
  11. app/main/java
    源码目录
  12. app/main/res
    资源文件目录
核心文件解析
  1. AndroidManifest.xml
    1. 注册activity,设置主活动。
  2. Activity的java源文件
    1. 继承自Activity。
    2. 设置各阶段的业务代码
  3. res目录
    1. res/layout目录
      存放所有的布局文件
    2. res/mip*
      用来存放图片
    3. res/menu
      用来放菜单文件
    4. res/values
      用来存放字符串
      如何引用资源:
  4. 代码中用R.string.string_name
  5. xml中用@string/string_name
使用日志

android中的日志工具类是Log(android.util.Log),提供了如下几种方法:
1. Log.v()
最琐碎,意义最小的日志
2. Log.d()
调试信息
3. Log.i()
info,打印一些比较重要的数据
4. Log.w()
警告信息
5. Log.e()
错误信息

活动(Activity)

包含用户界面的组件,主要用于和用户进行交互。一个应用程序中可以包含0个或者多个活动。

创建活动
  1. 新建一个类,继承自Activity,并重写onCreate()方法。
public class FirstActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }
}

2.创建布局文件

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
    <Button
    android:id="@+id/button_1"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:text="Button 1"
    />
</LinearLayout>

3.修改Activity代码

public class FirstActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.first_layout);
    }
}

4.在AndroidManifest文件中注册activity

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.activitytest"  >
    <application
    android:allowBackup="true"
    android:icon="@drawable/ic_launcher"
    android:label="@string/app_name"
    android:theme="@style/AppTheme" >
        <activity
        android:name=".FirstActivity"
        android:label="This is FirstActivity" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" /><!--设置项目入口-->
                <category android:name="android.intent.category.LAUNCHER" /><!--设置为启动程序-->
            </intent-filter>
        </activity>
    </application>
</manifest>

5.销毁Activity,修改button对应的事件。

Button b1 = (Button)findViewById(R.id.t1);
b1.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        finish();
    }
});

目的(Intent)

使用显式intent

通过intent启动另一个activity。

button1.setOnClickListener(new OnClickListener() {
    @Override
    public void onClick(View v) {
        Intent intent = new Intent(FirstActivity.this, SecondActivity.class);
        startActivity(intent);
    }
});
使用隐式intent

1.通过activity标签的intent-filter指定当前activity可以响应的action和category。Action为系统中已经定义的一系列常用动作。Category属性用于指定当前动作(Action)被执行的环境。

<activity android:name=".SecondActivity" >
    <intent-filter>
        <action android:name="com.example.activitytest.ACTION_START" /><!-- 自定义的action-->
        <category android:name="android.intent.category.DEFAULT" /><!--必须加上这个,否则下面无法直接使用自定的action-->
    </intent-filter>
</activity>

2.修改按钮的点击事件。

button1.setOnClickListener(new OnClickListener() {
    @Override
    public void onClick(View v) {
        Intent intent = new Intent("com.example.activitytest.ACTION_START");
        startActivity(intent);
    }
});
更多隐式intent的用法

调用系统浏览器访问一个网页。

button1.setOnClickListener(new OnClickListener() {
    @Override
    public void onClick(View v) {
        Intent intent = new Intent(Intent.ACTION_VIEW);
        intent.setData(Uri.parse("http://www.baidu.com"));
        startActivity(intent);
    }
});

ACTION_VIEW是android系统内置的动作。

向下一个活动传递数据

intent提供了一系列putExtra()方法的重载,用来暂存需要传递的数据。启动另一个intent后,从intent中取出数据即可。
传递方:

button1.setOnClickListener(new OnClickListener() {
    @Override
    public void onClick(View v) {
        String data = "Hello SecondActivity";
        Intent intent = new Intent(FirstActivity.this, SecondActivity.class);
        intent.putExtra("extra_data", data);
        startActivity(intent);
    }
});

接收方

public class SecondActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.second_layout);
        Intent intent = getIntent();
        String data = intent.getStringExtra("extra_data");
        Log.d("SecondActivity", data);
    }
}

这里的getStringExtra可以用getIntExtra(),getBooleanExtra()等方法代替。

返回数据给上一个活动

接收方

button1.setOnClickListener(new OnClickListener() {
    @Override
    public void onClick(View v) {
        Intent intent = new Intent(FirstActivity.this, SecondActivity.class);
        startActivityForResult(intent, 1);
    }
});
....
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    switch (requestCode) {
        case 1:
            if (resultCode == RESULT_OK) {
                String returnedData = data.getStringExtra("data_return");
                Log.d("FirstActivity", returnedData);
            }
        break;
        default:
    }
}

startActivityForResult的第二个整数用来唯一标识一次请求,传递方处理完数据后会传回给onActivityResult作为第一个参数。onActivityResult函数的第二个参数为返回码,用来判断处理是否成功,第三个参数为携带详细数据的intent。处理时一般先检查requestCode,判断数据来源。
传递方

public class SecondActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.second_layout);
        Button button2 = (Button) findViewById(R.id.button_2);
        button2.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
            Intent intent = new Intent();
            intent.putExtra("data_return", "Hello FirstActivity");
            setResult(RESULT_OK, intent);
            finish();
            }
        });
    }
}

setResult的值一般只使用RESULT_OK或RESULT_CANCLED。

活动的生命周期
返回栈

Android是用任务来管理活动。一个任务就是一组存放在栈里的活动的集合,称作返回栈。栈后进先出,默认启动的新活动位于栈顶,当按下back键或者调用finish()方法时,栈顶活动出栈,前一个活动处于栈顶,并显示给用户。

活动状态

每个活动生命周期中会有4种状态。
1.运行状态
当一个活动位于返回栈的栈顶时,处于运行状态
2.暂停状态
活动不再处于栈顶位置,但是仍然可见。内存极低时,有可能被系统回收资源。
3.停止状态
不处于栈顶,并且完全不可见。有可能被系统回收资源。
4.销毁状态
活动从返回栈移除后。系统最倾向于回收这类活动的资源。

活动的生存期

activity类定义了七个回调方法,覆盖了活动生命周期的每个环节。
1.onCreate()
活动第一次创建时调用,一般用来完成初始化等操作。
2.onStart()
在活动由不可见变成可见时调用
3.onResume()
在活动准备好和用户进行交互时调用。此时活动一定处于运行状态。
4.onPause()
在系统准备启动或者恢复另一个活动时调用。通常用来释放资源和保存数据。
5.onStop()
在活动完全不可见时调用。
6.onRestart()
在活动由停止变成运行状态前调用。

活动回收前的数据保存

activity提供了一个onSaveInstanceState()回调方法,保证一定在活动被回收之前调用。可以通过这个方法来保存数据。
1.保存数据

@Override
protected void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    String tempData = "Something you just typed";
    outState.putString("data_key", tempData);
}

2.提取数据

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    Log.d(TAG, "onCreate");
    requestWindowFeature(Window.FEATURE_NO_TITLE);
    setContentView(R.layout.activity_main);
    if (savedInstanceState != null) {
        String tempData = savedInstanceState.getString("data_key");
        Log.d(TAG, tempData);
    }
......
}
活动的启动模式

1.standard
默认模式,每次都会重新创建活动,并放在栈顶。同一个activity会出现多个实例。
2.singleTop
创建活动时如果发现该活动已经是栈顶,则直接返回。
3.singleTask
如果返回栈里有该活动,则直接返回。
4.singleInstance
新建一个返回栈来管理该活动。
5.退出程序的做法
使用队列,将所有activity出队列。

public class ActivityCollector {
    public static List<Activity> activities = new ArrayList<Activity>();
    public static void addActivity(Activity activity) {
        activities.add(activity);
    }
    public static void removeActivity(Activity activity) {
        activities.remove(activity);
    }
    public static void finishAll() {
        for (Activity activity : activities) {
            if (!activity.isFinishing()) {
                activity.finish();
            }
        }
    }
}

分别在oncreate和ondestroy中调用方法。

public class BaseActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.d("BaseActivity", getClass().getSimpleName());
        ActivityCollector.addActivity(this);
    }
    @Override
    protected void onDestroy() {
        super.onDestroy();
        ActivityCollector.removeActivity(this);
    }
}

如果需要退出程序,调用ActivityCollector.finishAll()即可。

public class ThirdActivity extends BaseActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.d("ThirdActivity", "Task id is " + getTaskId());
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.third_layout);
        Button button3 = (Button) findViewById(R.id.button_3);
        button3.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                ActivityCollector.finishAll();
            }
        });
    }
}

UI开发

常用android控件

1.textview

<TextView
android:id="@+id/text_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="This is TextView" />

2.button

<Button
android:id="@+id/button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Button" />

3.edittext

<EditText
android:id="@+id/edit_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
/>

4.imageview显示图片

<ImageView
android:id="@+id/image_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_launcher"
/>

5.progressbar进度条

<ProgressBar
android:id="@+id/progress_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
/>

6.alertdialog弹出对话框

AlertDialog.Builder dialog = new AlertDialog.Builder(MainActivity.this);
dialog.setTitle("This is Dialog");
dialog.setMessage("Something important.");
dialog.setCancelable(false);
dialog.setPositiveButton("OK", new DialogInterface.
OnClickListener() {
    @Override
    public void onClick(DialogInterface dialog, int which) {
}
});
dialog.setNegativeButton("Cancel", new DialogInterface.
OnClickListener() {
    @Override
    public void onClick(DialogInterface dialog, int which) {
    }
});
dialog.show();
break;

7.progressdialog缓冲对话框

ProgressDialog progressDialog = new ProgressDialog
(MainActivity.this);
progressDialog.setTitle("This is ProgressDialog");
progressDialog.setMessage("Loading...");
progressDialog.setCancelable(true);
progressDialog.show();

3)

四种基本布局

1.linearlayout
线性布局,垂直或者水平方向布局。

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal" >
......
</LinearLayout>

2.relativelayout
相对布局。指定它们相对于其父元素或兄弟元素的位置。

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
    <Button
    android:id="@+id/button1"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignParentLeft="true"
    android:layout_alignParentTop="true"
    android:text="Button 1" />
    <Button
    android:id="@+id/button2"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignParentRight="true"
    android:layout_alignParentTop="true"
    android:text="Button 2" />
    ...
</RelativeLayout>

3.framelayout
所有控件都放在左上角。

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button"
/>
<ImageView
android:id="@+id/image_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_launcher"
/>
</FrameLayout>

4.tablelayout
使用表格的方式来排列控件。

<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<TableRow>
<TextView
android:layout_height="wrap_content"
android:text="Account:" />
<EditText
android:id="@+id/account"
android:layout_height="wrap_content"
android:hint="Input your account" />
</TableRow>
...
</TableLayout>

自定义控件

所有控件继承自view,所有布局继承自viewgroup。
view是android最基本的UI组件,可以在屏幕上绘制一块矩形区域并响应这块区域的各种事件,所有的控件都是在view的基础上添加了各自特有的功能。
viewgroup是一种特殊的view,可以包含很多子view和子viewgroup,是一个用于放置控件和布局的容器。

引入布局

为了避免布局文件大量重复。
1.创建一个布局文件

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/title_bg" >
<Button
android:id="@+id/title_back"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_margin="5dip"
android:background="@drawable/back_bg"
android:text="Back"
android:textColor="#fff" />
</LinearLayout>

2.在需要的地方导入布局文件

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<include layout="@layout/title" />
</LinearLayout>
自定义控件

1.新建控件类

public class TitleLayout extends LinearLayout {
    public TitleLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
        LayoutInflater.from(context).inflate(R.layout.title, this);
        Button titleBack = (Button) findViewById(R.id.title_back);
        Button titleEdit = (Button) findViewById(R.id.title_edit);
        titleBack.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                ((Activity) getContext()).finish();
            }
        });
        titleEdit.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(getContext(), "You clicked Edit button",
                Toast.LENGTH_SHORT).show();
            }
        });
    }
}

2.在布局文件中使用新建的控件。

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<com.example.uicustomviews.TitleLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
></com.example.uicustomviews.TitleLayout>
</LinearLayout>
单位和尺寸

px表示像素,pt表示磅(1/72英寸)都会收到分辨率的影响。所以google引入了dp和sp。
dp是密度无关像素的意思,也称dip,在不同密度的屏幕中显示比例保持一致。
sp表示可伸缩像素,和dp概念一样,解决了文字大小适配问题。

android碎片

主要是用来处理大屏幕的访问问题,比如在平板上使用碎片显示更多的内容。

全局大喇叭

android中每个应用程序都可以对自己感兴趣的广播进行注册。

广播的类型

1.标准广播
是一种完全一部执行的广播,广播发出后,所有的广播接收器几乎同时收到广播消息,没有先后顺序,无法被截断。
2.有序广播
是同步执行的广播,发出后同一时刻只会有一个广播接收器能收到这条广播消息,该接收器的逻辑执行完毕后,广播继续传递。可以截断正在传递的广播。

接受系统的广播

1.动态注册广播
新建一个类,继承自BroadcastReceiver,并重写父类的onreceive()方法。oncreate中使用registerReceiver进行注册,在ondestroy方法中调用unregisterreceiver方法取消注册。动态注册的广播一定要取消注册。

public class MainActivity extends Activity {
    private IntentFilter intentFilter;
    private NetworkChangeReceiver networkChangeReceiver;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        intentFilter = new IntentFilter();
        intentFilter.addAction("android.net.conn.CONNECTIVITY_CHANGE");
        networkChangeReceiver = new NetworkChangeReceiver();
        registerReceiver(networkChangeReceiver, intentFilter);
    }
    @Override
    protected void onDestroy() {
        super.onDestroy();
        unregisterReceiver(networkChangeReceiver);
    }
    class NetworkChangeReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
        Toast.makeText(context, "network changes",
        Toast.LENGTH_SHORT).show();
        }
    }
}

2.静态注册实现开机启动
动态注册的问题在于必需要启动后才能接受到广播。静态注册可以在程序未启动时接收广播。
1)新建类,继承自BootCompleteReceiver。

public class BootCompleteReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        Toast.makeText(context, "Boot Complete", Toast.LENGTH_LONG).show();
    }
}

2)在AndroidManifest.xml 中将这个广播接收器的类名注册进去。
这里出现了新的标签,所有静态注册的广播接收器都在这里进行注册。别忘了还要申请相应的权限。

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.broadcasttest"
android:versionCode="1"
android:versionName="1.0" >
    ......
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
    <application
    android:allowBackup="true"
    android:icon="@drawable/ic_launcher"
    android:label="@string/app_name"
    android:theme="@style/AppTheme" >
    ......
        <receiver android:name=".BootCompleteReceiver" >
            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED" />
            </intent-filter>
        </receiver>
    </application>
</manifest>
发送自定义的广播

1.发送标准广播

Intent intent = new Intent("com.example.broadcasttest.MY_BROADCAST");
sendBroadcast(intent);

2.发送有序广播

Intent intent = new Intent("com.example.broadcasttest.MY_BROADCAST");
sendOrderedBroadcast(intent, null);

阻止有序广播继续传播

public class MyBroadcastReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        Toast.makeText(context, "received in MyBroadcastReceive",Toast.LENGTH_SHORT).show();
        abortBroadcast();
    }
}

3.使用本地广播
android引入了一套本地广播机制,所发出的广播只能在应用程序内部进行传递,并且本地广播接收器也只能接收来自本应用程序发出的广播,避免了安全性的问题。
区别:使用LocalBroadcastManager获取实例,发送和注册广播接收器时均使用该实例的方法。

localBroadcastManager = LocalBroadcastManager.getInstance(this);
// 获取实例
...
intentFilter = new IntentFilter();
intentFilter.addAction("com.example.broadcasttest.LOCAL_BROADCAST");
localReceiver = new LocalReceiver();
localBroadcastManager.registerReceiver(localReceiver, intentFilter);
// 注册本地广播监听器
...
Intent intent = new Intent("com.example.broadcasttest.LOCAL_BROADCAST");
localBroadcastManager.sendBroadcast(intent); // 发送本地广播
...
localBroadcastManager.unregisterReceiver(localReceiver);//注销广播
...
class LocalReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        Toast.makeText(context, "received local broadcast",
        Toast.LENGTH_SHORT).show();
    }
}

数据存储全方案

android提供了3种方式用于简单地实现数据持久化功能。
1.文件存储
2.sharedpreference存储
3.数据库存储

文件存储

写文件

context类提供了一个openFileOutput方法,接收2个参数。
1.文件名,不包含路径。文件默认存储到/data/data/”package-name”/files/目录下。
2.模式。MODE_PRIVATE 和 MODE_APPEND。覆盖写和追加写。

FileOutputStream out = null;
BufferedWriter writer = null;
try {
    out = openFileOutput("data", Context.MODE_PRIVATE);
    writer = new BufferedWriter(new OutputStreamWriter(out));
    writer.write(data);
} catch (IOException e) {
    e.printStackTrace();
}
读文件
FileInputStream in = null;
BufferedReader reader = null;
StringBuilder content = new StringBuilder();
try {
    in = openFileInput("data");
    reader = new BufferedReader(new InputStreamReader(in));
    String line = "";
    while ((line = reader.readLine()) != null) {
        content.append(line);
    }
} catch (IOException e) {
    e.printStackTrace();
} finally {
    if (reader != null) {
        try {
            reader.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
return content.toString();

SharedPreferences存储

使用键值的方式来存储数据。SharedPreferences文件都是存放在/data/data/”package-name”/shared_prefs/目录下的,以xml格式进行管理。
三种获取SharedPreferences对象的方法
1.context类的getSharedPreferences()方法
第一个参数指定文件名。
第二个参数指定操作模式,MODE_PRIVATE 和MODE_MULTI_PROCESS。MODE_PRIVATE 是默认的操作模式,和直接传入 0 效果是相同的,表示只有当前的应用程序才可以对这个SharedPreferences 文件进行读写。 MODE_MULTI_PROCESS 则一般是用于会有多个进程中对同一个 SharedPreferences 文件进行读写的情况。
2.Activity 类中的 getPreferences()方法
只接收一个参数,指定操作模式。文件名默认为当前活动的类名。
3.PreferenceManager 类中的 getDefaultSharedPreferences()方法
只接收一个参数,指定操作模式。文件名默认为当前应用程序包名。

写入

1.调用SharedPreferences对象的edit方法获取Editor对象。
2.向edit对象添加数据
3.调用commit方法提交数据,完成存储。

SharedPreferences.Editor editor =getSharedPreferences("data",
MODE_PRIVATE).edit();
editor.putString("name", "Tom");
editor.putInt("age", 28);
editor.putBoolean("married", false);
editor.commit();
读取
SharedPreferences pref = getSharedPreferences("data",MODE_PRIVATE);
String name = pref.getString("name", "");
int age = pref.getInt("age", 0);
boolean married = pref.getBoolean("married", false);
Log.d("MainActivity", "name is " + name);
Log.d("MainActivity", "age is " + age);
Log.d("MainActivity", "married is " + married);

sqlite数据库存储

SharedPreferences存储只适用于保存一些简单的数据,当需要进行大量复杂的存储时,需要使用sqlite。
数据库文件会存放在/data/data/”package-name”/databases/目录下。
1.创建数据库
1)新建类,继承自SQLiteOpenHelper,重写oncreate和onupgrade方法。
oncreate方法只会在创建数据库时执行一次,onupgrade在每次修改数据库版本号后执行一次。
SQLiteOpenHelper 构造方法中接收四个参数,
第一个参数是 Context,
第二个参数是数据库名,
第三个参数允许我们在查询数据的时候返回一个自定义的 Cursor,一般都是传入 null。
第四个参数表示当前数据库的版本号,可用于对数据库进行升级操作。(新建或者修改表等操作后,增加该值。)

public class MyDatabaseHelper extends SQLiteOpenHelper {
    public static final String CREATE_BOOK = "create table book ("
                                                                            + "id integer primary key autoincrement, "
                                                                            + "author text, "
                                                                            + "price real, "
                                                                            + "pages integer, "
                                                                            + "name text)";
    private Context mContext;
    public MyDatabaseHelper(Context context, String name, CursorFactory factory, int version) {
        super(context, name, factory, version);
        mContext = context;
    }
    @Override
    public void onCreate(SQLiteDatabase db) {
        db.execSQL(CREATE_BOOK);
        Toast.makeText(mContext, "Create succeeded", Toast.LENGTH_SHORT).show();
    }
    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
    db.execSQL("drop table if exists Book");
    onCreate(db);
    }
}

2)调用该类,创建库。

private MyDatabaseHelper dbHelper;
dbHelper = new MyDatabaseHelper(this, "BookStore.db", null, 2);
Button createDatabase = (Button) findViewById(R.id.create_database);
createDatabase.setOnClickListener(new OnClickListener() {
    @Override
    public void onClick(View v) {
    dbHelper.getWritableDatabase();
    }
});

2.插入数据

private MyDatabaseHelper dbHelper;
dbHelper = new MyDatabaseHelper(this, "BookStore.db", null, 2);
...
SQLiteDatabase db = dbHelper.getWritableDatabase();
ContentValues values = new ContentValues();
// 开始组装第一条数据
values.put("name", "The Da Vinci Code");
values.put("author", "Dan Brown");
values.put("pages", 454);
values.put("price", 16.96);
db.insert("Book", null, values); // 插入第一条数据
values.clear();
// 开始组装第二条数据
values.put("name", "The Lost Symbol");
values.put("author", "Dan Brown");
values.put("pages", 510);
values.put("price", 19.95);
db.insert("Book", null, values); // 插入第二条数据

3.更新数据

values.put("price", 10.99);
db.update("Book", values, "name = ?", new String[] { "The DaVinci Code" });

4.删除数据

SQLiteDatabase db = dbHelper.getWritableDatabase();
db.delete("Book", "pages > ?", new String[] { "500" });

5.查询数据
query参数详情:
1)表名
2)需要查询的列
3)指定where的约束条件
4)为where中占位符提供具体的值
5)指定需要group by的列
6)对group by后的结果进一步约束
7)指定查询结果的排序方式

SQLiteDatabase db = dbHelper.getWritableDatabase();
// 查询Book表中所有的数据
Cursor cursor = db.query("Book", null, null, null, null, null, null);
if (cursor.moveToFirst()) {
    do {
        // 遍历Cursor对象,取出数据并打印
        String name = cursor.getString(cursor.getColumnIndex("name"));
        String author = cursor.getString(cursor.getColumnIndex("author"));
        int pages = cursor.getInt(cursor.getColumnIndex("pages"));
        double price = cursor.getDouble(cursor.getColumnIndex("price"));
        Log.d("MainActivity", "book name is " + name);
        Log.d("MainActivity", "book author is " + author);
        Log.d("MainActivity", "book pages is " + pages);
        Log.d("MainActivity", "book price is " + price);
    } while (cursor.moveToNext());
}
cursor.close();

6.使用sql操作数据库

SQLiteDatabase db = dbHelper.getWritableDatabase();
db.execSQL("insert into Book (name, author, pages, price) values(?, ?, ?, ?)",new String[] { "The Lost Symbol", "Dan Brown", "510", "19.95" });
db.rawQuery("select * from Book", null);

7.使用事务

SQLiteDatabase db = dbHelper.getWritableDatabase();
db.beginTransaction(); // 开启事务
....
db.endTransaction(); // 结束事务

跨程序共享数据

内容提供器

主要用于在不同应用程序之间实现数据共享的功能。
1.现有的内容提供器
android系统自带的电话薄等程序都提供了类似的访问接口。
内容 URI 是内容提供器中数据的唯一标识符,由两部分组成:权限(authority)和路径(path)。
权限是用于区分不同的应用程序,为了避免冲突,都会采用程序包名的方式来进行命名。比如某个程序的包名是 com.example.app,那么该程序对应的权限就可以命名为com.example.app.provider。
路径则是用于对同一应用程序中不同的表做区分的,通常都会添加到权限的后面。
最后,还需要在字符串的头部加上协议声明。
1)声明权限

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.contactstest"
android:versionCode="1"
android:versionName="1.0" >
    ......
    <uses-permission android:name="android.permission.READ_CONTACTS" />
    ......
</manifest>

2)获取数据

Cursor cursor = null;
// 查询联系人数据
cursor = getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,null, null, null, null);
while (cursor.moveToNext()) {
    // 获取联系人姓名
    String displayName = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
    // 获取联系人手机号
    String number = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
    contactsList.add(displayName + "\n" + number);
}
cursor.close();

2.创建自己的内容提供器
1)新建一个类,继承自ContentProvider,重写6个抽象方法。

public class MyProvider extends ContentProvider {
    @Override
    public boolean onCreate() {
        return false;
    }
    @Override
    public Cursor query(Uri uri, String[] projection, String selection,String[] selectionArgs, String sortOrder) {
        return null;
    }
    @Override
    public Uri insert(Uri uri, ContentValues values) {
        return null;
    }
    @Override
    public int update(Uri uri, ContentValues values, String selection,String[] selectionArgs) {
        return 0;
    }
    @Override
    public int delete(Uri uri, String selection, String[] selectionArgs) {
        return 0;
    }
    @Override
    public String getType(Uri uri) {
        return null;
    }
}

运用手机多媒体

1.使用通知

NotificationManager manager = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
Notification notification = new Notification(R.drawable.ic_launcher, "This is ticker text", System.currentTimeMillis()); //第一个参数指定图片,第二个指定ticker内容,第三个指定通知创建时间
....
Intent intent = new Intent(this,NotificationActivity.class);
PendingIntent pi = PendingIntent.getActivity(this, 0, intent,PendingIntent.FLAG_CANCEL_CURRENT);//创建延迟intent
....
Uri soundUri = Uri.fromFile(new File("/system/media/audio/ringtones/Basic_tone.ogg"));
notification.sound = soundUri;//让通知发生的时候播放一段音频
notification.setLatestEventInfo(this, "This is content title","This is content text", pi);//第二个参数指定标题,第三个指定内容,第四个
manager.notify(1, notification);

2.接收和发送短信
使用intent和系统提供的功能进行交互
3.调用摄像头和相册

File outputImage = new File(Environment.
getExternalStorageDirectory(), "tempImage.jpg");
try {
    if (outputImage.exists()) {
        outputImage.delete();
    }
    outputImage.createNewFile();
} catch (IOException e) {
    e.printStackTrace();
}
imageUri = Uri.fromFile(outputImage);
Intent intent = new Intent("android.media.action. IMAGE_CAPTURE");
intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
startActivityForResult(intent, TAKE_PHOTO); // 启动相机程序

4.播放多媒体文件(音频和视频)

后台服务

服务的生命周期

1.context调用startService方法,服务启动。
2.如果服务未创建过,oncreate方法执行。
3.执行onStartCommand方法
4.服务处理完毕,调用stopService或者stopSelf方法。
5.ondestroy方法执行
注意,只有服务取消绑定后才能被销毁。

context.startService() -> onCreate() -> onStart() -> Service running -> context.stopService() -> onDestroy() -> Service stop

服务的基本使用

1)定义server

public class MyService extends Service {
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
    @Override
    public void onCreate() {
        super.onCreate();
    }
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        return super.onStartCommand(intent, flags, startId);
    }
    @Override
    public void onDestroy() {
        super.onDestroy();
    }
}

2)修改 AndroidManifest.xml文件

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.servicetest"
android:versionCode="1"
android:versionName="1.0" >
......
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
......
<service android:name=".MyService" >
</service>
</application>
</manifest>

3)启动服务

Intent startIntent = new Intent(this, MyService.class);
startService(startIntent); // 启动服务

4)停止服务

Intent stopIntent = new Intent(this, MyService.class);
stopService(stopIntent); // 停止服务

活动与服务通信

1)server类中新建binder类的子类

public class MyService extends Service {
    private DownloadBinder mBinder = new DownloadBinder();
    class DownloadBinder extends Binder {
        public void startDownload() {
            Log.d("MyService", "startDownload executed");
        }
        public int getProgress() {
            Log.d("MyService", "getProgress executed");
            return 0;
        }
    }
    @Override
    public IBinder onBind(Intent intent) {
        return mBinder;
    }
    ......
}

2)定义一个connection类。提供一个ServiceConnection的实现,用以监控与服务Service间的连接情况。

private ServiceConnection connection = new ServiceConnection() {
    @Override
    public void onServiceDisconnected(ComponentName name) {
    }
    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
        downloadBinder = (MyService.DownloadBinder) service;
        downloadBinder.startDownload();
        downloadBinder.getProgress();
    }
};

3)绑定服务
bindService()无返回值,但系统在客户端与服务端连接之间,会调用在ServiceConnect对象中的onServiceConnected()方法

Intent bindIntent = new Intent(this, MyService.class);
bindService(bindIntent, connection, BIND_AUTO_CREATE); // 绑定服务

前台服务

在通知栏显示服务进程,避免因内存不足导致进程关闭。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值