android之ListPreference的用法_PreferenceActivity用法
首先,我们明确,preference是和数据存储相关的。
其次,它能帮助我们方便的进行数据存储!为什么这个地方一定要强调下方便的这个词呢?原因是,我们可以根本就不使用,我们有另外的N种办法可以实现同样的功能!它的出现,相当于为我们提供了一个方便的工具,当然了,这个工具并不是必须的。
preference都应用在什么场景呢?
这得从android对preference的实现说起,实际上,preference所存储的数据最后都会以xml文件格式的形式进行保存,而且其只能 保存一些基本格式的数据。例如string/boolean……。该xml文件存放的位置在data/data/你应用的包名/shared_prefs 文件夹下。
种种的限制与实现机制表明了,preference非常适合于参数设置功能。实际上,它也确实是干这个的,我们通过使用preference可以迅速的将某些值保存进xml文件中,然后我们可以读取这些设置信息进行相应的操作。
为了简化与preference相关的应用开发,android为我们提供了一系列的api来帮助我们。主要有PreferenceActivity,ListPreference,EditTextPreference,CheckBoxPreference,RingtonePreference
下面我们简单的介绍下ListPreference的用法:
我们选择了山东,然后该页面就会自动关闭,并且和山东所对应的值也已经写入了后台的xml文件中。
java代码:
[java] view plain copy
- package jason.demo;
- import android.os.Bundle;
- import android.preference.ListPreference;
- import android.preference.PreferenceActivity;
- import android.preference.PreferenceManager;
- import android.util.Log;
- /**
- * @description 有关首选项preferences的研究
- * 继承了PreferenceActivity,我们可以方便的对preference进行操作。
- * 例如可以通过getPreferenceManager获取首选项管理器
- * 那,我们可不可以不继承PreferenceActivity呢?当然可以,实际上Activity类中
- * 就有个SharedPreferences getSharedPreferences(String name, int mode)方法呢,我们通过它
- * 也可以对preference进行操作。当然了,如果我们不继承PreferenceActivity的话,那么我们就要手动的
- * 对数据进行保存了。而不是跟现在一样,会自动的根据你的选择项进行数据保存。
- * 那么,preference在这里是怎么样进行自动保存的呢,答案很简单,那就是在addPreferencesFromResource方法的具体实现中!
- */
- public class MyPreferencesActivity extends PreferenceActivity {
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- addPreferencesFromResource(R.xml.mylistpreference);
- /**
- * getPreferenceManager返回首选项管理器对象
- */
- PreferenceManager manager = getPreferenceManager();
- // 根据android:key中指定的名称(相当于id)来获取首选项
- ListPreference listPreference = (ListPreference) manager.findPreference("myListPreference");
- Log.i("存储的值为", ""+listPreference.getValue());
- }
- }
res/xml/mylistperference.xml布局文件
[html] view plain copy
- <?xml version="1.0" encoding="utf-8"?>
- <!--
- 对于该文件需要注意以下几点
- 第一:位置。该文件的位置是在res/xml/下的。
- 第二:格式,PreferenceScreen为根标签,ListPreference为子标签
- 第三:标签属性含义
- android:key 唯一标识符,和android:id相类似,PreferenceManager可以以其为参数通过findPreference获取指定的preference
- android:title 整个屏幕的标题
- android:summary 选项的简单说明
- android:entries 弹出的对话框中,列表显示的文本内容,注意哦,这里指定的是一个数组
- android:entryValues 与android:entries相对应的值
- android:defaultValue 当对应值不存在时的默认值
- android:dialogTitle 弹出的对话框中的标题信息
- -->
- <PreferenceScreen
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:key="screen_list"
- android:title="标题"
- android:summary="说明摘要"
- >
- <ListPreference
- android:key="myListPreference"
- android:title="标题"
- android:summary="说明摘要"
- android:entries="@array/list_entries"
- android:entryValues="@array/list_entries_value"
- android:dialogTitle="dialogTitle"
- android:defaultValue="@array/list_entries_value2"
- ></ListPreference>
- </PreferenceScreen>
res/values/arrays.xml文件,为上面的文件提供数据
[html] view plain copy
- <?xml version="1.0" encoding="utf-8"?>
- <resources>
- <string-array name="list_entries">
- <item>山东</item>
- <item>福建</item>
- <item>北京</item>
- <item>河北</item>
- </string-array>
- <string-array name="list_entries_value">
- <item>shandong1</item>
- <item>fujian1</item>
- <item>beijing1</item>
- <item>hebei1</item>
- </string-array>
- <string-array name="list_entries_value2">
- <item>shandong2</item>
- <item>fujian2</item>
- <item>beijing2</item>
- <item>hebei2</item>
- </string-array>
- </resources>
当我们运行,并选择了福建时,我们可以查看在shared_prefes下的xml文件如下:
[html] view plain copy
- <?xml version='1.0' encoding='utf-8' standalone='yes' ?>
- <map>
- <string name="myListPreference">fujian1</string>
- </map>
===================================================
android之android.intent.category.DEFAULT的用途和使用
1、要弄清楚这个问题,首先需要弄明白什么是implicit(隐藏) intent什么是explicit(明确) intent。
Explicit Intent明确的指定了要启动的Acitivity ,比如以下Java代码:
[java] view plain copy
- Intent intent= new Intent(this, B.class);
Implicit Intent没有明确的指定要启动哪个Activity ,而是通过设置一些Intent Filter来让系统去筛选合适的Acitivity去启动。
2、intent到底发给哪个activity,需要进行三个匹配,一个是action,一个是category,一个是data。
理论上来说,如果intent不指定category,那么无论intent filter的内容是什么都应该是匹配的。但是,如果是implicit intent,android默认给加上一个CATEGORY_DEFAULT,这样的话如果intent filter中没有android.intent.category.DEFAULT这个category的话,匹配测试就会失败。所以,如果你的 activity支持接收implicit intent的话就一定要在intent filter中加入android.intent.category.DEFAULT。
例外情况是:
[java] view plain copy
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
中没有必要加入android.intent.category.DEFAULT,当然加入也没有问题。这个是应用启动默认的第一个启动的activity(每个应用有那么多activity,总得有一个是第一个启动的吧)
如果自己定义的某个Activity要通过隐式启动,在AndroidManifast.xm那么必须加上android.intent.category.DEFAULT,否则不起作用
除此之外,category的用途还有很多
比如做个桌面,按home键时启动自己做的应用
[html] view plain copy
- <activity
- android:name=".MainActivity"
- android:label="@string/app_name" >
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER"/>
- <category android:name="android.intent.category.HOME" />
- </intent-filter>
- </activity>
在intent中是如何配置那三个匹配数据的呢,也简单一说
也就是说,在不直接指定要跳转的Activity的时候,为Intent提供一些相关的参数,让其自动去和AndroidManifest.xml中已有的Activity去匹配
IntentFilter在xml中的三個主要的参数:action,categary,data。
我们通过Intent的构造函数或者Intent提供的方法可以指定这个三个参数:
[java] view plain copy
- intent.setAction(action);intent.setData(data);intent.addCategory(category);
- intent.setAction(action);
- intent.setData(data);
- intent.addCategory(category);
=======================================================================
android之View的启动过程
程序里调用了onSizeChanged方法进行了一些设置,不知道onSizeChanged是在什么时候启动的,所以研究了一下View的启动流程
代码如下:
[java] view plain copy
- public class TestView extends View {
- public TestView(Context context) {
- super(context);
- Log.d("mDebug", "TestView context");
- }
- public TestView(Context context, AttributeSet attrs) {
- super(context, attrs);
- Log.d("mDebug", "TestView context, attrs="+attrs.getAttributeValue(0));
- }
- public TestView(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
- Log.d("mDebug", "TestView context,attrs,defStyle attrs="+attrs.getAttributeValue(0));
- }
- @Override
- protected void onDraw(Canvas canvas) {
- super.onDraw(canvas);
- Log.d("mDebug", "onDraw");
- }
- @Override
- protected void onFinishInflate() {
- super.onFinishInflate();
- Log.d("mDebug", "onFinishInflate");
- }
- @Override
- protected void onSizeChanged(int w, int h, int oldw, int oldh) {
- super.onSizeChanged(w, h, oldw, oldh);
- Log.d("mDebug", "onSizeChanged,w="+w+",h="+h+",oldw="+oldw+",oldh="+oldh);
- }
- }
输出如下:
[java] view plain copy
- 22:23:03.587: D/mDebug(9715): TestView context, attrs=@2131034112
- 22:23:03.597: D/mDebug(9715): onFinishInflate
- 22:23:03.667: D/mDebug(9715): onSizeChanged,w=720,h=1080,oldw=0,oldh=0
- 22:23:03.727: D/mDebug(9715): onDraw
- 22:23:03.757: D/mDebug(9715): onDraw
很显然,onSizeChanged的启动时间在onDraw之前
=========================================================================
android之ListView的Adapter使用
在做一个小练习的时候,又遇到了Adapter,才发现以前没有对它进行过记录
现在介绍一下:
其实Adapter就是数据和视图之间的桥梁,数据在adapter中做处理,然后显示到ListView上面
Adapter有很多种,有ArrayAdapter<T>, BaseAdapter, CursorAdapter, HeaderViewListAdapter, ListAdapter,ResourceCursorAdapter, SimpleAdapter, SimpleCursorAdapter, SpinnerAdapter, WrapperListAdapter.
这里就以ArrayAdapter<T>为例来介绍
我自己写的一个例子:
有两个类,一个是主界面Activity,用来处理输入和显示,效果图在最下面,可以翻到最后看一下,布局如下:
[html] view plain copy
- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- >
- <LinearLayout
- android:orientation="horizontal"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- >
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="Name:"
- />
- <EditText android:id="@+id/name"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- />
- </LinearLayout>
- <LinearLayout
- android:orientation="horizontal"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- >
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="Address:"
- />
- <EditText android:id="@+id/addr"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- />
- </LinearLayout>
- <Button android:id="@+id/save"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:text="Save"
- />
- </LinearLayout>
java代码如下:
[java] view plain copy
- public class LunchList extends Activity {
- List<Restaurant> model=new ArrayList<Restaurant>();
- ArrayAdapter<Restaurant> adapter=null;
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- Button save=(Button)findViewById(R.id.save);
- save.setOnClickListener(onSave);
- ListView list=(ListView)findViewById(R.id.restaurants);
- adapter=new ArrayAdapter<Restaurant>(this,android.R.layout.simple_list_item_1,model);//这行代码在下面解释
- list.setAdapter(adapter);//为ListView设置我们配置好的适配器
- }
- private View.OnClickListener onSave=new View.OnClickListener() {
- public void onClick(View v) {
- Restaurant r=new Restaurant();
- EditText name=(EditText)findViewById(R.id.name);
- EditText address=(EditText)findViewById(R.id.addr);
- r.setName(name.getText().toString());
- r.setAddress(address.getText().toString());
- RadioGroup types=(RadioGroup)findViewById(R.id.types);
- switch (types.getCheckedRadioButtonId()) {
- case R.id.sit_down:
- r.setType("sit_down");
- break;
- case R.id.take_out:
- r.setType("take_out");
- break;
- case R.id.delivery:
- r.setType("delivery");
- break;
- }
- adapter.add(r);//每个增加的条目都会添加到适配器里面
- }
- };
- }
针对上面的进行解释:
1. 适配器的作用是数据和视图之间的桥梁
2. 这个小例子是要显示一个数组,我们就用ArrayAdapter,数组适配器,数据的数据类型<>是Restaurant类型的(下面的定义),数据的数据类型还可以是其他的包括对象类型的
3. adapter=new ArrayAdapter<Restaurant>(this, android.R.layout.simple_list_item_1, model);
这段代码是创建一个数组适配器的代码,里面有三个参数,第一个参数是上下文,就是当前的Activity, 第二个参数是android sdk中自己内置的一个布局,它里面只有一个TextView,这个参数是表明我们数组中每一条数据的布局是这个view,就是将每一条数据都显示在这个view上面;第三个参数就是我们要显示的数据,这个数据是以List<Restaurant>的形式存在的,当然我们在设置的时候这个数组里面还没有数据,数据时候来调用adapter.add(r);加入进去的.
listView会根据这三个参数,遍历adapterData里面的每一条数据,读出一条,显示到第二个参数对应的布局中,这样就形成了我们看到的listView.
其实就是两个EditText和一个RadioGroup,用来采集输入的数据,然后存储到下面这个类里面:
[java] view plain copy
- package apt.tutorial;
- public class Restaurant {
- private String name="";
- private String address="";
- private String type="";
- public String getName() {
- return(name);
- }
- public void setName(String name) {
- this.name=name;
- }
- public String getAddress() {
- return(address);
- }
- public void setAddress(String address) {
- this.address=address;
- }
- public String getType() {
- return(type);
- }
- public void setType(String type) {
- this.type=type;
- }
- public String toString() {
- return(getName());
- }
- }
每增加一个存储,就会在ListView里面显示出来一个
执行之后效果图如下:
如果还是不很明白,下面这个网上的代码段更加清晰:
[java] view plain copy
- package com.cz.list.demo;
- import android.app.Activity;
- import android.os.Bundle;
- import android.widget.ArrayAdapter;
- import android.widget.ListView;
- public class ArrayListDemo extends Activity {
- private ListView listView;
- private String[] adapterData;
- /** Called when the activity is first created. */
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.array_list_layout);
- /* 找到这个listView */
- listView = (ListView) findViewById(R.id.array_list);
- /* 我们要在listView上面显示的数据,放到一个数组中 */
- adapterData = new String[] { "Afghanistan", "Albania", "Algeria",
- "American Samoa", "Andorra", "Angola", "Anguilla",
- "Antarctica", "Antigua and Barbuda", "Argentina", "Armenia",
- "Aruba", "Australia", "Austria", "Azerbaijan", "Bahrain",
- "Bangladesh", "Barbados", "Belarus", "Belgium", "Belize",
- "Benin", "Bermuda", "Bhutan", "Bolivia",
- "Bosnia and Herzegovina", "Botswana", "Bouvet Island" };
- /* 下面就是对适配器进行配置了 */
- ArrayAdapter<String> arrayAdapter = new ArrayAdapter<String>( ArrayListDemo.this, android.R.layout.simple_list_item_1, adapterData);
- /* 设置ListView的Adapter */
- listView.setAdapter(arrayAdapter);
- }
- }
///
android之ArrayAdapter的重写
昨天介绍了ArrayAdapter的使用,今天介绍一下更加实用的一点,对它进行重写,满足自己的个性化设计需要.
ArrayAdapter(数组适配器)一般用于显示一行文本信息,所以比较容易。
[java] view plain copy
- public ArrayAdapter(Context context,int textViewResourceId, List<T> objects)
上面的这行代码来装配数据,要装配这些数据就需要一个连接ListView视图对象和数组数据的适配器来做两者的适配工作,ArrayAdapter的构造需要三个参数,依次为this,布局文件(注意这里的布局文件描述的是列表的每一行的布局),数据源(一个List集合)。同时用setAdapter()将ListView和Adapter绑定。
例子一:可以用来简单的显示一条文字
[java] view plain copy
- package jason.demo14;
- import java.util.ArrayList;
- import android.app.Activity;
- import android.os.Bundle;
- import android.widget.ArrayAdapter;
- import android.widget.ListView;
- public class Demo13Activity extends Activity {
- private ListView lv;
- private ArrayList<String> list = new ArrayList<String>();
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- lv = (ListView)findViewById(R.id.listview);
- ArrayAdapter<String> adapter = new ArrayAdapter<String>(
- this,
- android.R.layout.simple_expandable_list_item_1,
- getData());
- lv.setAdapter(adapter);
- }
- private ArrayList<String> getData()
- {
- list.add("180平米的房子");
- list.add("一个勤劳漂亮的老婆");
- list.add("一辆宝马");
- list.add("一个强壮且永不生病的身体");
- list.add("一个喜欢的事业");
- return list;
- }
- }
- <span style="font-family:Arial;background-color:#ffffff;"></span>
注意:这里的android.R.layout.simple_expandable_list_item_1是系统内置布局,样式就是如下
[java] view plain copy
- <span style="font-size:18px;">例子二:这个例子可以增加一个ImageView,但是在设置ArrayAdapter的时候需要增加这个自定义的布局</span>
[java] view plain copy
- public ArrayAdapter(Context context, int resource, int textViewResourceId, List<T> objects)
上面的第一个参数是上下文,一般为this。第二个参数是自定义的布局文件,比如下面的就是R.layout.list_item。第三个参数是布局中用来显示文字的TextView的id,第四个参数是数据集合,跟例一一样
[html] view plain copy
- <?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="horizontal" >
- <ImageView
- android:id="@+id/img"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:src="@drawable/ic_launcher"
- />
- <TextView
- android:id="@+id/tv"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- />
- </LinearLayout>
Activity的java代码:
[java] view plain copy
- package jason.demo14;
- import java.util.ArrayList;
- import android.app.Activity;
- import android.os.Bundle;
- import android.widget.ArrayAdapter;
- import android.widget.ListView;
- public class Demo13Activity extends Activity {
- private ListView lv;
- private ArrayList<String> list = new ArrayList<String>();
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- lv = (ListView)findViewById(R.id.listview);
- ArrayAdapter<String> adapter = new ArrayAdapter<String>(
- this,
- R.layout.list_item,//区别就在这一行和下一行,这里是自己定义的布局文件,
- R.id.tv,//这是R.layout.list_item中TextView的ID,用来确定把添加进来的数据显示在哪个位置
- getData());
- lv.setAdapter(adapter);
- }
- private ArrayList<String> getData()
- {
- list.add("180平米的房子");
- list.add("一个勤劳漂亮的老婆");
- list.add("一辆宝马");
- list.add("一个强壮且永不生病的身体");
- list.add("一个喜欢的事业");
- return list;
- }
- }
效果如下:
例子3:实现更复杂的效果:
这就需要重写getView方法了,
1. 自定义列表样式
image_item.xml
[html] view plain copy
- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:orientation="horizontal">
- <ImageView
- android:id="@+id/item_thumbnail"
- android:layout_height="48dip"
- android:layout_width="48dip"
- />
- <TextView
- android:id="@+id/item_file_name"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textAppearance="?android:attr/textAppearanceLarge"
- android:minHeight="?android:attr/listPreferredItemHeight"
- android:gravity="center_vertical"
- android:paddingLeft="5dip"
- />
- </LinearLayout>
2. 自定义ArrayAdapter
[java] view plain copy
- public class ImageListAdapter extends ArrayAdapter<File>{
- private int resource;
- public ImageListAdapter(Context context, int resourceId, List<File> objects) {
- super(context, resourceId, objects);
- // 记录下来稍后使用
- resource = resourceId;
- }
- public View getView(int position, View convertView, ViewGroup parent) {
- LinearLayout imageListView;
- // 获取数据
- File file = getItem(position);
- String fileName = file.getName();
- Bitmap bitmap = getBitmapFromFile(file);
- // 系统显示列表时,首先实例化一个适配器(这里将实例化自定义的适配器)。
- // 当手动完成适配时,必须手动映射数据,这需要重写getView()方法。
- // 系统在绘制列表的每一行的时候将调用此方法。
- // getView()有三个参数,
- // position表示将显示的是第几行,
- // covertView是从布局文件中inflate来的布局。
- // 我们用LayoutInflater的方法将定义好的image_item.xml文件提取成View实例用来显示。
- // 然后将xml文件中的各个组件实例化(简单的findViewById()方法)。
- // 这样便可以将数据对应到各个组件上了。
- //
- if(convertView == null) {
- imageListView = new LinearLayout(getContext());
- LayoutInflater inflater = (LayoutInflater)getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- inflater.inflate(resource, imageListView, true);//把image_item.xml布局解析到LinearLayout里面
- } else {
- imageListView = (LinearLayout)convertView;
- }
- // 获取控件,填充数据
- ImageView imageView = (ImageView) imageListView.findViewById(R.id.item_thumbnail);
- TextView textView = (TextView) imageListView.findViewById(R.id.item_file_name);
- textView.setText(fileName);
- imageView.setImageBitmap(bitmap);
- return imageListView;
- }
- // 从文件获取Bitmap用于填充
- private Bitmap getBitmapFromFile(File file) {
- Bitmap bitmap = BitmapFactory.decodeFile(file.getAbsolutePath());
- return bitmap;
- }
- }
3. 绑定数据
[java] view plain copy
- private void bindFilesToList(File[] files) {
- List<File> fileList = new ArrayList<File>();
- for(File file : files) {
- fileList.add(file);
- }
- ImageListAdapter adapter = new ImageListAdapter(ImageFilesListActivity.this,
- R.layout.image_item,
- fileList);
- setListAdapter(adapter);
- }
基本就是这样了
/
对于List的初始化还是有些讲究的.
List是一个接口,这个一看文档便知,所以对它初始化不能new List,而应该使用ArrayList或者LinkList(这些实例化了List接口),
[java] view plain copy
- List<T> list = new ArrayList<T>();
而且,如果你确定List里面存放的数据类型,可以直接初始化为这种List,
[java] view plain copy
- List<String> list = new LinkedList<String>();
这样能够快速的处理,存取数据就不用再进行类型转换,直接是String就行了,
如果在初始化时是这样的,
[java] view plain copy
- List<Object> list = new LinkedList<Object>();
那么在存储时就能存储各种类型的数据了,int,String,Map,甚至是你自己定义的class都可以.
当然这样在存取时候是要进行类型转换的,效率会低一些.
还有,关于空指针错误真的是很困扰人的一件事情,所以最好的解决方式就是在使用前 一定要保证完成正确的初始化.
///
android之通过Button的监听器往adapter中添加数据时出错
本来源代码如下:
[java] view plain copy
- List<Restaurant> model; //自定义的一个List数据,存储的是自定义的类 LunchListAdapter adapter;//自定义的一个ListView的适配器
- ......//省略
- class onSavaLis implements OnClickListener{ //Button save的监听器,点击之后往model里面添加数据
- Restaurant r = new Restaurant();//②
- @Override
- public void onClick(View v) {
- r.setName(name.getText().toString());
- r.setAddress(addr.getText().toString());
- switch (types.getCheckedRadioButtonId()) {
- case R.id.take_out:
- r.setType(TAKE_OUT);
- break;
- case R.id.sit_down:
- r.setType(SIT_DOWN);
- break;
- case R.id.delivery:
- r.setType(DELIVERY);
- break;
- }
- model.add(r);//①
- }
- }
问题是,点击存储之后,在如果①处采用的是adapter.add(r);
那么ListView里面展示出来的item全都是最后存进去的那个,而且在点击item之后,从model里面输出来的内容也都是一样的,
如果①处采用的是model.add(r);
那么ListView里面展示出来的item是正确的,刚好是你存储的内容的顺序,但是点击item之后,从model里面读取出来的内容跟上面一样,全都是最后存进去的数据,
想来想去也没怎么弄明白,最后我把②那行代码放到了onClick里面定义,这样之后不管①出用哪种方式,显示和输出的结果都是正确的.
暂时想到的就是在②处定义的r可能model里面之前加入的数据都覆盖了,但是还是有点糊涂,先记下这么个印象,望高手赐教.
fragment 特点
- Fragment可以作为Activity界面的一部分组成出现;
- 可以在一个Activity中同时出现多个Fragment,并且一个Fragment也可以在多个Activity中使用;
- 在Activity运行过程中,可以添加、移除或者替换Fragment;
- Fragment可以响应自己的输入事件,并且有自己的生命周期,它们的生命周期会受宿主Activity的生命周期影响。
//
requestWindowFeature可以设置的值有:
1.DEFAULT_FEATURES:系统默认状态,一般不需要指定
2.FEATURE_CONTEXT_MENU:启用ContextMenu,默认该项已启用,一般无需指定
3.FEATURE_CUSTOM_TITLE:自定义标题。当需要自定义标题时必须指定。如:标题是一个按钮时
4.FEATURE_INDETERMINATE_PROGRESS:不确定的进度
5.FEATURE_LEFT_ICON:标题栏左侧的图标
6.FEATURE_NO_TITLE:无标题
7.FEATURE_OPTIONS_PANEL:启用“选项面板”功能,默认已启用。
8.FEATURE_PROGRESS:进度指示器功能
9.FEATURE_RIGHT_ICON:标题栏右侧的图标
代码如下
[java] view plain copy
- package jason.my;
- import android.app.Activity;
- import android.os.Bundle;
- import android.os.Handler;
- import android.os.Message;
- import android.view.Window;
- import android.view.WindowManager;
- public class WindowFeatureDemoActivity extends Activity {
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- // requestWindowFeature();的取值
- // 1.DEFAULT_FEATURES:系统默认状态,一般不需要指定
- // 2.FEATURE_CONTEXT_MENU:启用ContextMenu,默认该项已启用,一般无需指定
- // 3.FEATURE_CUSTOM_TITLE:自定义标题。当需要自定义标题时必须指定。如:标题是一个按钮时
- // 4.FEATURE_INDETERMINATE_PROGRESS:不确定的进度
- // 5.FEATURE_LEFT_ICON:标题栏左侧的图标
- // 6.FEATURE_NO_TITLE:无标题
- // 7.FEATURE_OPTIONS_PANEL:启用“选项面板”功能,默认已启用。
- // 8.FEATURE_PROGRESS:进度指示器功能
- // 9.FEATURE_RIGHT_ICON:标题栏右侧的图标
- // showFEATURE_INDETERMINATE_PROGRESS();
- // showFEATURE_CUSTOM_TITLE();
- // showFEATURE_LEFT_ICON();
- // showFEATURE_NO_TITLE();
- showFEATURE_PROGRESS();
- }
- private void showFEATURE_INDETERMINATE_PROGRESS() {
- requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
- setContentView(R.layout.main);
- getWindow().setFeatureInt(Window.FEATURE_INDETERMINATE_PROGRESS, R.layout.progress);
- // 必须得加上否则显示不出效果 可以通过这个在以后设置显示或隐藏
- setProgressBarIndeterminateVisibility(true);
- }
- private void showFEATURE_CUSTOM_TITLE() {
- // 自定义标题。当需要自定义标题时必须指定。如:标题是一个按钮时
- requestWindowFeature(Window.FEATURE_CUSTOM_TITLE);
- setContentView(R.layout.main);
- getWindow().setFeatureInt(Window.FEATURE_CUSTOM_TITLE, R.layout.customtitle);
- }
- private void showFEATURE_LEFT_ICON()
- {
- requestWindowFeature(Window.FEATURE_LEFT_ICON);
- setContentView(R.layout.main);
- getWindow().setFeatureDrawableResource(Window.FEATURE_LEFT_ICON, R.drawable.icon);
- }
- private void showFEATURE_NO_TITLE()
- {
- requestWindowFeature(Window.FEATURE_NO_TITLE);
- setContentView(R.layout.main);
- // 加上这句设置为全屏 不加则只隐藏title
- getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
- WindowManager.LayoutParams.FLAG_FULLSCREEN);
- }
- private void showFEATURE_PROGRESS()
- {
- requestWindowFeature(Window.FEATURE_PROGRESS);
- setProgressBarVisibility(true);
- setContentView(R.layout.main);
- setTitle("");
- getWindow().setFeatureInt(Window.FEATURE_PROGRESS, Window.PROGRESS_VISIBILITY_ON);
- // 通过线程来改变ProgressBar的值
- new Thread(new Runnable() {
- public void run() {
- for (int i = 0; i < 10; i++) {
- try {
- Thread.sleep(1000);
- Message m = new Message();
- m.what = (i + 1) * 20;
- WindowFeatureDemoActivity.this.myMessageHandler.sendMessage(m);
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- }
- }).start();
- }
- Handler myMessageHandler = new Handler() {
- // @Override
- public void handleMessage(Message msg) {
- // 设置标题栏中前景的一个进度条进度值
- setProgress(100 * msg.what);
- // 设置标题栏中后面的一个进度条进度值
- setSecondaryProgress(100 * msg.what + 10);
- super.handleMessage(msg);
- }
- };
- }
/
android之存储篇_SharedPreferences存储方式
SharedPreferences是一种轻型的数据存储方式,它的本质是基于XML文件存储key-value键值对数据,通常用来存储一些简单的配置信息。其存储位置在/data/data/<包名>/shared_prefs目录下。SharedPreferences对象本身只能获取数据而不支持存储和修改,存储修改是通过Editor对象实现。实现SharedPreferences存储的步骤如下:
一、根据Context获取SharedPreferences对象
二、利用edit()方法获取Editor对象。
三、通过Editor对象存储key-value键值对数据。
四、通过commit()方法提交数据。
具体实现代码如下:
[java] view plain copy
- public class MainActivity extends Activity {
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- //获取SharedPreferences对象
- Context ctx = MainActivity.this;
- SharedPreferences sp = ctx.getSharedPreferences("SP", MODE_PRIVATE);
- //存入数据
- Editor editor = sp.edit();
- editor.putString("STRING_KEY", "string");
- editor.putInt("INT_KEY", 0);
- editor.putBoolean("BOOLEAN_KEY", true);
- editor.commit();
- //返回STRING_KEY的值
- Log.d("SP", sp.getString("STRING_KEY", "none"));
- //如果NOT_EXIST不存在,则返回值为"none"
- Log.d("SP", sp.getString("NOT_EXIST", "none"));
- }
- }
这段代码执行过后,即在/data/data/com.test/shared_prefs目录下生成了一个SP.xml文件,一个应用可以创建多个这样的xml文件。如图所示:
SP.xml文件的具体内容如下:
[html] view plain copy
- <?xml version='1.0' encoding='utf-8' standalone='yes' ?>
- <map>
- <string name="STRING_KEY">string</string>
- <int name="INT_KEY" value="0" />
- <boolean name="BOOLEAN_KEY" value="true" />
- </map>
在程序代码中,通过getXXX方法,可以方便的获得对应Key的Value值,如果key值错误或者此key无对应value值,SharedPreferences提供了一个赋予默认值的机会,以此保证程序的健壮性。如下图运行结果中因为并无值为"NOT_EXIST"的Key,所以Log打印出的是其默认值:“none”。在访问一个不存在key值这个过程中,并无任何异常抛出。
SharedPreferences对象与SQLite数据库相比,免去了创建数据库,创建表,写SQL语句等诸多操作,相对而言更加方便,简洁。但是SharedPreferences也有其自身缺陷,比如其职能存储boolean,int,float,long和String五种简单的数据类型,比如其无法进行条件查询等。所以不论SharedPreferences的数据存储操作是如何简单,它也只能是存储方式的一种补充,而无法完全替代如SQLite数据库这样的其他数据存储方式。
///
android之存储篇_ContentProvider存储
ContentProvider是安卓平台中,在不同应用程序之间实现数据共享的一种机制。一个应用程序如果需要让别的程序可以操作自己的数据,即可采用这种机制。并且此种方式忽略了底层的数据存储实现,ContentProvider提供了一种统一的通过Uri实现数据操作的方式。其步骤为:
1. 在当前应用程序中定义一个ContentProvider。
2. 在当前应用程序的AndroidManifest.xml中注册此ContentProvider
3. 其他应用程序通过ContentResolver和Uri来获取此ContentProvider的数据。
ContentResolver提供了诸如insert(), delete(), query()和update()之类的方法。用于实现对ContentProvider中数据的存取操作。
Uri是一个通用资源标志符,将其分为A,B,C,D 4个部分:
A:无法改变的标准前缀,包括;"content://"、"tel://"等。当前缀是"content://"时,说明通过一个Content Provider控制这些数据
B:URI的标识,它通过authorities属性声明,用于定义了是哪个ContentProvider提供这些数据。对于第三方应用程序,为了保证URI标识的唯一性,它必须是一个完整的、小写的 类名。例如;"content://com.test.data.myprovider"
C:路径,可以近似的理解为需要操作的数据库中表的名字,如:"content://hx.android.text.myprovider/name"中的name
D:如果URI中包含表示需要获取的记录的ID;则就返回该id对应的数据,如果没有ID,就表示返回全部;
下面通过是代码示例,演示一下如何在应用之间相互获取数据。
在应用程序A中,继承ContProvider类,并重写其中方法.
[java] view plain copy
- public class MyProvider extends ContentProvider{
- @Override
- public int delete(Uri uri, String selection, String[] selectionArgs) {
- // TODO Auto-generated method stub
- return 0;
- }
- @Override
- public String getType(Uri uri) {
- // TODO Auto-generated method stub
- return null;
- }
- @Override
- public Uri insert(Uri uri, ContentValues values) {
- return null;
- }
- //在Create中初始化一个数据库
- @Override
- public boolean onCreate() {
- SQLiteDatabase db = this.getContext().openOrCreateDatabase("test_db.db3", Context.MODE_PRIVATE, null);
- db.execSQL("create table tab(_id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL)");
- ContentValues values = new ContentValues();
- values.put("name", "test");
- db.insert("tab", "_id", values);
- db.close();
- return true;
- }
- //实现query方法
- @Override
- public Cursor query(Uri uri, String[] projection, String selection,
- String[] selectionArgs, String sortOrder) {
- SQLiteDatabase db = this.getContext().openOrCreateDatabase("test_db.db3", Context.MODE_PRIVATE, null);
- Cursor c = db.query("tab", null, null, null, null, null,null);
- return c;
- }
- @Override
- public int update(Uri uri, ContentValues values, String selection,
- String[] selectionArgs) {
- // TODO Auto-generated method stub
- return 0;
- }
- }
在其AndroidManifest.xml中声明此ContentProvider,其中authorities属性定义了此ContentProvider的Uri标识。
[html] view plain copy
- <provider android:name=".MyProvider" android:authorities="com.test.MyProvider"/>
在应用程序B中,通过ContentResolver获取程序A的ContentProvider中的数据。
[java] view plain copy
- public class MainActivity extends Activity {
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- //获取上下文
- Context ctx = MainActivity.this;
- //获取ContentResolver对象
- ContentResolver resolver = ctx.getContentResolver();
- //获取Uri对象
- Uri uri = Uri.parse("content://com.test.MyProvider");
- //获取数据
- Cursor c = resolver.query(uri, null, null, null, null);
- c.moveToFirst();
- for(int i=0; i<c.getCount(); i++){
- int index = c.getColumnIndexOrThrow("name");
- String src = c.getString(index);
- Log.d("", src);
- c.moveToNext();
- }
- }
- }
应用程序B的运行结果如下,从此图可以发现我们在程序B中成功的获取到了程序A中的数据:
再观察两个应用程序的结构,如下图,其中红框是应用程序A的程序结构,可以清楚看到其有一个名为“test_db.db3”的数据库,蓝框是应用程序B的程序结构,其并没有任何数据库用于存储数据。由此图,可以确定应用程序B中查询出来的数据结果是来自于应用程序A。
以上就是ContentProvider的使用方式,这种存储方式相比SQLite和SharedPreferences,其复杂性是显而易见的,但是在处处可见“云”的今天,程序间的数据交互需求令ContentProvider存储机制变成必不可少的一部分。
以上示例代码只是为了展示ContentProvider的使用,所以程序代码中有诸多不合理的地方并未进行处理
///
android之activity中onSaveInstanceState和onRestoreInstanceState触发时机
onSaveInstanceState的调用遵循一个重要原则,即当系统“未经你许可”时销毁了你的activity,则onSaveInstanceState会被系统调用,这是系统的责任,因为它必须要提供一个机会让你保存你的数据(当然你不保存那就随便你了)。onRestoreInstanceState被调用的前提是,activity A“确实”被系统销毁了
android错误之Unable to resolve target 'Google Inc.:Google APIs:6'
修改目录下的project.property文件内容为
target=Google Inc.:Google APIs:16(在这里他本来可能是其他版本号,不用管它,只需要改成你所导入的包的版本就行,
比如我这里已经导入就是api16而他的本来版本是6)
/
Android开发中Intent用法总结
Android使用Intent来"封装"程序的"调用意图",不管程序想启动什么组件,启动一个Activity也好,一个service也好,或者一个Broadcast Receiver也好,Android统一使用Intent对象来封装这种"启动意图"。
Intent还是应用程序组件之间通信的重要媒介,两个Activity把需要交换的数据封装成Bundle对象,然后使用Intent来携带Bundle对象,这样就实现了两个Activity之间的数据交换。
Intent存在以下几个属性:Component,Action,Category,Data,Type,Extra,Flag七个属性,其中Component属性用来指定需要启动的目标组件,Extra属性用于携带需要交换的数据。
下面对Intent对象做详细的介绍:
1. Intent的Component属性
Component是用来指定启动目标组件的属性,标准的启动代码如下:
1 2 3 4 |
|
以上代码用来标准的创建ComponentName对象,进而调用Intent对象的setComponent()函数来为Intent设定相应的componentName,最后调用startAcitvity函数启动一个新的Activity。
实际上,当需要为Intent设定Component属性的时候,Intent已经为我们提供了一个简单的构造器,使用方法如下(我们经常使用的方式):
复制代码代码如下:
Intent intent = new Intent(firstActivity.this,senondActivity.class);
值得一提的是,在secondActivity组件中,可以使用getIntent()方法取得调用次组件的Intent对象,进而,getXXX方法在这里就可以各种使用了。
2. Intent 的Action与Category属性
Action和Category属性都是普通的字符串,其中Action代表了抽象出来的"动作",Category属性用来和Action属性配合使用,表达出要启动某组件的意图。
具有<intent-filter…/>标签的Activity均有可能会被启动。
比如:
1 2 3 4 5 6 |
|
这样的代码并没有具体指出要启动哪个Activity,这样就脱离了"硬编码",但是具体要启动哪个Activity呢,这将取决于Activity配置文件中的<intent-filter…/>标签。
<intent-filter…/>是AndroidManifest.xml文件中<activity…/>元素的子元素,需要做的,就是给你实际需要相应这个意图的Activity添加<intent-filter…/>标签,在<intent-filter…/>下,存在着三种标签:1.<action…/>2.<category…/>3.<data…/>,其中指定android:name属性之后,这个activity便具有了相应上面意图的属性了。
对于上面的意图,则添加这样的代码(当然要在<intent-filter…/>标签下):
复制代码代码如下:
<action android:name = "org.someaction.SOME_ACTION"/>
需要一提的是:一个activity对象最多只能包含一个action属性,程序调用setAction(Stringstr)来设定Action的属性值;而一个Activity可以有多个Category属性,程序可以调用addCategory(String str)来添加Category属性。当程序创建Intent的时候,创建的Intent属性自动启动属性值为Intent.CATEGORY_DEFAULT常量,其值为"android.intent.category.DEFAULT",所以,在配置某个Activity属性的时候<categoryandroid:name = "andrid.intent.category.DEFAULT ">是可以添加到配置文件当中的。
实际上Android内部提供了大量的标准的Action和Category常量。
总结如下:
Action常量 | 对应的android:name 设定 | 简单说明 |
ACTION_MAIN | Android.intent.action.MAIN | 应用程序入口 |
ACTION_VIEW | Android.intent.action.VIEW | 显示指定数据 |
ACTION_ATTACH_DATA | Android.intent.action.ATTACH_DATA | 指定某模块数据被附加的地方 |
ACTION_EDIT | Android.intent.action.EDIT | 编辑指定数据 |
ACTION_PICK | Android.intent.action.PICK | 从列表中选择某项并返回所选数据 |
ACTION_CHOOSER | Android.intent.action.CHOOSER | 显示一个Activity选择器 |
ACTION_GET_CONTENT | Android.intent.action.GET_CONTENT | 让用户选择数据,并返回所选 |
ACTION_DIAL | Android.intent.action.DIAL | 显示拨号面板 |
ACTION_SEND | Android.intent.action.SEND | 直接发送数据 |
ACTION_SENDTO | Android.intent.action.SENDTO | 直接发送消息 |
ACTION_ANSWER | Android.intent.action.ANSWER | 应答电话 |
ACTION_INSERT | Android.intent.action.INSERT | 插入数据 |
ACTION_DELETE | Android.intent.action.DELETE | 删除数据 |
ACTION_RUN | Android.intent.action.RUN | 运行数据 |
ACTION_SYNC | Android.intent.action.SYNC | 执行数据同步 |
ACTION_PICK_ACTIVITY | Android.intent.action.PICK_ACTIVITY | 用于选择activity |
ACTION_SEARCH | Android.intent.action.SEARCH | 执行搜索 |
ACTION_WEB_SEARCH | Android.intent.action. WEB_SEARCH | 直径web搜索 |
ACTION_ FACTORY_TEST | Android.intent.action.FACTORY_TEST | 工厂测试入口点 |
这里仅仅摘录一些,如果想了解全部的ACTION,可以直接查看Android的标准API中有关Intent的说明部分。
3. Intent中的Data和Type属性
采用几个例子来说明Data的用法:
在一个button的OnClick()方法中添加下面代码:
1 2 3 4 5 |
|
此方法中将会使得按钮启动人人网。
当然一下代码是简便的写法:
1 2 3 |
|
上面的为其更详细的设定方法。
4. Intent的Extra属性
Intent属性通常用来用于在多个Activity之间进行数据交换,Intent的Extra属性值应该是一个Bundle对象,他可以输入多个key-value对,这样就可以通过Intent在不同的Activity之间进行相应的数据交换了。
Intent提供的方法有如下几个:
putExtra(Bundledata) getExtras()
putXXX(Stringkey XXX data) getXXX(String key)
putSerializable(Stringkey, Serializable data) 对应的有
getSerializable(Stringkey, Serializable data)
在课件中已经给出了添加键值对的相关代码,这里就不在重复了。
总结:
Android应用总是要借助Intent来实现需要启动的某个组件,Intent就是这种"启动意图"的封装形式,这种意图并没有和任何程序组件耦合,通过这种方式即可以很好的提供了程序的可扩展性和可维护性,其中<intent-filter/>的配置是程序组件最为重要的标签
android之知识点小结一
Manifest.xml文件中的一些代码作用:
[html] view plain copy
- <activity android:name=".LunchList"
- android:label="@string/app_name">
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- <intent-filter>
- <action android:name="android.intent.action.SEARCH" />
- <category android:name="android.intent.category.DEFAULT" />
- </intent-filter>
- <meta-data android:name="android.app.searchable"
- android:resource="@xml/searchable" />
- <meta-data android:name="android.app.default_searchable"
- android:value=".LunchList" />
- </activity>
在上面这段代码中,
[html] view plain copy
- <intent-filter>
- <action android:name="android.intent.action.SEARCH" />
- <category android:name="android.intent.category.DEFAULT" />
- </intent-filter>
这个是注册的隐式Intent的过滤器,第二行表示过滤带有搜索action的intent,第三行是必须要添加的(自定义的Activity如果要通过隐式intent启动,则必须添加)
[html] view plain copy
- <meta-data android:name="android.app.searchable"
- android:resource="@xml/searchable" />
这个是在使用默认的搜索框架是,给搜索框设置的布局,第一行name是给定的,第二行resource就是你给自己的搜索框设置的外观布局,一般放在res/xml里
[html] view plain copy
- <meta-data android:name="android.app.default_searchable"
- android:value=".LunchList" />
这个也是和搜索相关,上面两个是通过intent_filter过滤接收到intent,以及接收到intent之后显示出来的搜索框的布局,但那样只是在你注册了meta-data节点的activity里面才能执行搜索,如果想要在任意一个activity里面都能启动搜索框架,就要加上这个,这个第一行也是给定的,第二行则用来指定是由哪一个activity响应并执行搜索和显示搜索结果.
[html] view plain copy
- <receiver android:name=".AppWidget"
- android:label="@string/app_name"
- android:icon="@drawable/icon">
- <intent-filter>
- <action android:name="android.appwidget.action.APPWIDGET_UPDATE"/>
- <category android:name="android.intent.category.DEFAULT" />
- </intent-filter>
- <meta-data
- android:name="android.appwidget.provider"
- android:resource="@xml/widget_provider" />
- </receiver>
这段代码中:注册的是一个Widget,其中第二行是widget的标题,第三行是它的图标,
[html] view plain copy
- <intent-filter>
- <action android:name="android.appwidget.action.APPWIDGET_UPDATE"/>
- <category android:name="android.intent.category.DEFAULT" />
- </intent-filter>
这个跟最上面的类似,就是注册了intent的过滤器,过滤widget的更新action,第三行在上面解释过了,这里的更新actiong是放在隐式intent里面的,所以要加上第三行
[html] view plain copy
- <meta-data
- android:name="android.appwidget.provider"
- android:resource="@xml/widget_provider" />
这个则是对widget的参数配置,第二行是指定的,第三行就是我们自定义的widget参数,放在res/xml下,这里的配置如下:res/xml/widget_provider.xml
[html] view plain copy
- <appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
- android:minWidth="300dip"
- android:minHeight="79dip"
- android:updatePeriodMillis="1800000"
- android:initialLayout="@layout/widget"
- />
二三四行分别是宽高和更新频率,第五行则是该widget的具体布局,布局方式与layout里的其他布局方式一样:res/layout/widget.xml
[html] view plain copy
- <?xml version="1.0" encoding="utf-8"?>
- <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:background="@drawable/widget_frame"
- >
- <TextView android:id="@+id/name"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_centerVertical="true"
- android:layout_alignParentLeft="true"
- android:layout_toLeftOf="@+id/next"
- android:textSize="10pt"
- android:textColor="#FFFFFFFF"
- />
- <ImageButton android:id="@+id/next"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_centerVertical="true"
- android:layout_alignParentRight="true"
- android:src="@drawable/ff"
- />
- </RelativeLayout>
///
android之知识点小结二
SharedPreferences的使用:
在这里也是偏向于使用android自带的SharedPreferences管理机制,简要说明使用流程,备忘:
首先在主activity里面初始化SharedPreferences,
[java] view plain copy
- SharedPreferences prefs=null;
- ...
- @Override
- public void onCreate(Bundle savedInstanceState) {
- ...
- prefs=PreferenceManager.getDefaultSharedPreferences(this);
- ...
- /*注册SharedPreferences的监听器,一旦SharedPreferences发生变化,则触发监听器,进行一些操作,比如这里是通过SharedPreferences设置列表的排序方式,一旦排序方式的设置改变,则*SharedPreferences的存储内容改变,则触发监听器,进行列表的重新初始化
- */
- prefs.registerOnSharedPreferenceChangeListener(prefListener);
- ...
- }
- .
- .
- .
- private SharedPreferences.OnSharedPreferenceChangeListener prefListener=
- new SharedPreferences.OnSharedPreferenceChangeListener() {
- public void onSharedPreferenceChanged(SharedPreferences sharedPrefs, String key) {
- if (key.equals("sort_order")) {//这里就是监听器的具体操作,通过判断是某一个SharedPreferences的变化,进行相应操作
- initList();//重新初始化列表
- }
- }
- };.
- .
- private void initList() {
- ...
- model=helper.getAll(where, prefs.getString("sort_order", "name"));
- //在这里需要通过prefs.getString("sort_order", "name")获取SharedPreferences中存取的具体内容,即采取何种排列方式,如果结果为空,则返回"name",按姓名排序
- ...
- }
上面则完成了对SharedPreferences的一系列操作,从初始化和注册监听器,监听变化,以及变化后做出相应操作,
那么是如何唤出SharedPreferences的设置界面,并且存储是如何实现的呢,
这里采用的是
[java] view plain copy
- if (item.getItemId()==R.id.prefs) {
- startActivity(new Intent(this, EditPreferences.class));
- }
就是在菜单里加一个prefs设置选项,点击它则启动定义的SharedPreferences设置界面,这个界面就直接继承PreferenceActivity,可以方便高效的实现Preference的存储和管理.代码如下:
[java] view plain copy
- public class EditPreferences extends PreferenceActivity {
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- addPreferencesFromResource(R.xml.preferences);//这个方法的实现就内置了SharedPreferences的存储方法,所以无需我们自己再去存储SharedPreferences
- }
- }
代码是很简单的,只需要addPreferencesFromResource(R.xml.preferences);这个设置显示界面就可以了,
界面代码res/xml/preferences.xml:
[html] view plain copy
- <PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
- <ListPreference
- android:key="sort_order"
- android:title="Sort Order"
- android:summary="Choose the order the list uses"
- android:entries="@array/sort_names"
- android:entryValues="@array/sort_clauses"
- android:dialogTitle="Choose a sort order" />
- </PreferenceScreen>
整个界面是一个PreferenceScreen,第二行,是一个ListPreference,key就相当于id,也是键值对的key,实际存储之后就是一个键值对的键,在前面的initList里面
[java] view plain copy
- model=helper.getAll(where, prefs.getString("sort_order", "name"));
我们就是用prefs.getString("sort_order","name");去获取内容的,很明显这里用到的就是key,
title就是ListPreference的标题,summary是简单说明用法,效果如下,显示位置很明显就体会到其用途了.
再有就是所显示的具体内容了,ListPreference里的选项是从哪里来的呢,来自
android:entries="@array/sort_names"
这个数组定义了要显示的内容,而下一行
android:entryValues="@array/sort_clauses"
这行定义了对应着你所选的选项,存储到SharedPreferences里面的内容,整个数组的资源代码如下
[html] view plain copy
- <?xml version="1.0" encoding="utf-8"?>
- <resources>
- <string-array name="sort_names">
- <item>By Name, Ascending</item>
- <item>By Name, Descending</item>
- <item>By Type</item>
- <item>By Address, Ascending</item>
- <item>By Address, Descending</item>
- </string-array>
- <string-array name="sort_clauses">
- <item>name ASC</item>
- <item>name DESC</item>
- <item>type, name ASC</item>
- <item>address ASC</item>
- <item>address DESC</item>
- </string-array>
- </resources>
比如我们在选择时,选择了第一个By Name, Ascending,那么系统自动帮你把name ASC存储到SharedPreferences里面,即
所存储的这条SharedPreferences为(SharedPreferences的存储方式就是xml文件的形式存储)
<string name="sort_order">name ASC</string>
那么在看前面的这行代码
[java] view plain copy
- model=helper.getAll(where, prefs.getString("sort_order", "name"));
很明显,这个prefs所获取到的内容就是"name ASC",这行代码其实就是把参数传递到数据库帮助类里用来获取内容,而这个获取到的SharedPreferences就是设置的排序方式
//
android之存储篇_存储方式总览
作为一个完成的应用程序,数据存储操作是必不可少的。因此,Android系统一共提供了四种数据存储方式。分别是:SharePreference、SQLite、Content Provider和File。由于Android系统中,数据基本都是私有的的,都是存放于“data/data/程序包名”目录下,所以要实现数据共享,正确方式是使用Content Provider。
SQLite: SQLite是一个轻量级的数据库,支持基本SQL语法,是常被采用的一种数据存储方式。Android为此数据库提供了一个名为SQLiteDatabase的类,封装了一些操作数据库的API。
SharedPreference: 除SQLite数据库外,另一种常用的数据存储方式,其本质就是一个xml文件,常用于存储较简单的参数设置。
File: 即常说的文件(I/O)存储方法,常用语存储大数量的数据,但是缺点是更新数据将是一件困难的事情。
ContentProvider: Android系统中能实现所有应用程序共享的一种数据存储方式,由于数据通常在各应用间的是互相私密的,所以此存储方式较少使用,但是其又是必不可少的一种存储方式。例如音频,视频,图片和通讯录,一般都可以采用此种方式进行存储。每个Content Provider都会对外提供一个公共的URI(包装成Uri对象),如果应用程序有数据需要共享时,就需要使用Content Provider为这些数据定义一个URI,然后其他的应用程序就通过Content Provider传入这个URI来对数据进行操作。
PS: URI由3个部分组成:"content://"、数据的路径、标识ID(可选)。
//
android之IntentFilter的用法android.intent.action.TIME_TICK在manifest.xml不起作用
在模仿一个天气预报的widget时候,用到了IntentFilter,感觉在manifest.xml注册的receiver跟用代码写registerReceiver()的效果应该是相同的,于是想证明一下,就写了如下一段程序:
MainActivity:
public class MainActivity extends AppCompatActivity {
/*
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
*/
public static final int UPDATE = 000;
TextView xml;
TextView java;
int count = 0;
Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
// TODO Auto-generated method stub
switch (msg.what) {
case UPDATE:
count ++;
xml.setText(count);
break;
default:
break;
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
IntentFilter javaFilter = new IntentFilter();
javaFilter.addAction("android.intent.action.TIME_TICK");
registerReceiver(receiver, javaFilter);
xml = (TextView) findViewById(R.id.xml);
java = (TextView) findViewById(R.id.java);
}
BroadcastReceiver receiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
Date date = new Date();
SimpleDateFormat dateFormat = new SimpleDateFormat("HHmm");
java.setText(dateFormat.format(date));
}
};
protected void onDestroy() {
unregisterReceiver(receiver);
};
class Accept extends BroadcastReceiver {
@Override
public void onReceive(Context arg0, Intent arg1) {
// TODO Auto-generated method stub
Message message = handler.obtainMessage();
message.what = UPDATE;
handler.sendMessage(message);
}
}
}
在manifest文件中注册如下:
<receiver android:name="com.example.android.test.MainActivity.Accept">
<intent-filter >
<action android:name="android.intent.action.TIME_TICK"/>
</intent-filter>
</receiver>
布局文件如下:
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical">
- <TextView
- android:id="@+id/xml"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/hello_world" />
- <TextView
- android:id="@+id/java"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/hello_world" />
- </LinearLayout>
/
Android属性之build.prop生成过程
本文简要分析一下build.prop是如何生成的。Android的build.prop文件是在Android编译时刻收集的各种property(LCD density/语言/编译时间, etc.),编译完成之后,文件生成在out/target/product/<board>/system/目录下。在Android运行时刻可以通过property_get()[c/c++域] / SystemProperties_get*()[Java域]读取这些属性值。
build.prop的生成是由make系统解析build/core/Makefile完成。
1) Makefile中首先定义各种变量,这在下一步执行时会用到。比如:
[plain] view plain copy
- ...
- PRODUCT_DEFAULT_LANGUAGE="$(calldefault-locale-language,$(PRODUCT_LOCALES))" \
- PRODUCT_DEFAULT_REGION="$(calldefault-locale-region,$(PRODUCT_LOCALES))" \
- ...
2) Makefile中调用build/tools/buildinfo.sh执行脚本,并输出到build.prop
Buildinfo.sh很简单,只是echo一些属性,比如:
[plain] view plain copy
- ...
- echo"ro.product.locale.language=$PRODUCT_DEFAULT_LANGUAGE"
- echo"ro.product.locale.region=$PRODUCT_DEFAULT_REGION"
- ...
而,ro.product.locale.language/ ro.product.locale.region就是些属性,等号后面是值。
3) Makefile中直接把$(TARGET_DEVICE_DIR)/system.prop的内容追加到build.prop中。
4) 收集ADDITIONAL_BUILD_PROPERTIES中的属性,追加到build.prop中。
ADDITIONAL_BUILD_PROPERTIES又会收集PRODUCT_PROPERTY_OVERRIDES中定义的属性
[plain] view plain copy
- ADDITIONAL_BUILD_PROPERTIES:= \
- $(ADDITIONAL_BUILD_PROPERTIES)\
- $(PRODUCT_PROPERTY_OVERRIDES)
通过build.prop生成过程的分析,可知哪里可以修改原有的属性或加入自己定义属性,那就是2) buildinfo.sh; 3) system.prop; 4) ADDITIONAL_BUILD_PROPERTIES或PRODUCT_PROPERTY_OVERRIDES。不过个人建议改在system.prop或PRODUCT_PROPERTY_OVERRIDES,这对应于具体特定平台或产品的修改。
/