安卓学习记录(2)
来源:互联网 发布:办公软件怎么求和 编辑:程序博客网 时间:2024/06/10 15:18
<activity …...> <intent-filter> <action android:name= "com.example.activitytest.ACTION_START"></action> <category android:name="android.intent.category.DEFAULT"/> <category android:name="sec_activity"/> <category android:name="sec_activity_02”/> </intent-filter></activity>
Intent _intent = new Intent("com.example.activitytest.ACTION_START");_intent.addCategory("sec_activity”);
_intent.addCategory("sec_activity_02”); startActivity(_intent);
//如果找不到category同时具有sec_activity_02和sec_activity,并且action是com.example.activitytest.ACTION_START,则程序崩溃。
PS:除了category外,还可以添加 data 标签,用来响应 intent
eg.:
<activity …...>
<intent-filter> <category android:name="android.intent.category.DEFAULT"/> <data android:scheme="https”/> //显示网页的时候,对应的 activity 可以选择响应</intent-filter>
</activity>
显示网页:
Intent _intent = new Intent(Intent.ACTION_VIEW);_intent.setData(Uri.parse("https://www.baidu.com"));startActivity(_intent);
拨打电话
Intent intent = new Intent(Intent.ACTION_DIAL);intent.setData(Uri.parse("tel:10086"));startActivity(intent);
使用 intent 获取下一级活动的数据(A->B,B->A),eg:
A:Intent _intent = new Intent(A.this,B.class);
//设置requestCode为1
startActivityForResult(_intent, 1);
在 B 中对应的按钮响应方法或返回按钮响应函数中public void onBackPressed(),实现代码:
Intent _intent = new Intent();
_intent.putExtra("number", “100”);
//设置resultCode = RESULT_OK
setResult(RESULT_OK,_intent);
finish();
返回 A 时会调用 onActivityResult 函数,
@Overrite
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
//requestCode要与之前设置的请求码一致,也可以用resultCode来进行区分
if (requestCode == 1) {
String test = data.getStringExtra(“number”);
Toast.makeText(Activity01.this, test, Toast.LENGTH_LONG).show();
}
}
在 mainfest 文件中,设置 activity 的android:launchMode属性,可控制 activity 的启动方式,
默认是 standard(可重复创建然后启动)
singleTop(当前 activity 位于栈顶,直接使用当前活动,不会创建新的,但如果不是位于栈顶,则还是会创建新的。)
singleTask:上下文只会存在一个该类型的活动,不会重复,并且会把位于该 activity 之上的活动统统出栈
singleInstance:该activity 会位于一个独立栈中,不与其他活动公用一个栈,e.g.:有 A.B.C三个 activity,B是singleInstance模式,即 AC 一个栈,B 是另外一个栈
从A-》B , 然后在B-》C, 此时从C 按返回键会回到 A,在 A 中按返回键会到 B 中,在 B 中按返回键才會退出程序。
打印当前 Activity 名字:Log.i(”Activity”, getClass().getSimpleName());控件基本属性:hint(默认文本)在当前布局文件(xml 文件)引用其他布局文件://title是布局文件title.xml<include layout="@layout/title" />
隐藏导航栏:requestWindowFeature(Window.FEATURE_NO_TITLE);如果继承AppCompatActivity则无效,可使用:if (getSupportActionBar() != null){ getSupportActionBar().hide();}碎片使用XML 文件://left_fragment.xml<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:layout_gravity="center_horizontal" android:text="button" android:id="@+id/id_button" android:layout_width="wrap_content" android:layout_height="wrap_content" /></LinearLayout>
新建LeftFragment类:
public class LeftFragment extends Fragment { @Override public View onCreateView(LayoutInflater layoutInflater, ViewGroup parent, Bundle savedInstanceState) { View v = layoutInflater.inflate(R.layout.left_fragment, parent, false); return v; }}
//main_layout.xml:
…..。。正式使用
<fragment android:name="com.example.shopins.fragmenttest.LeftFragment" android:id="@+id/id_left_fragment" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintTop_toTopOf="parent" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintRight_toLeftOf="@+id/id_right_layout" android:layout_width="0dp" app:layout_constraintHorizontal_weight="1" android:layout_height="0dp"></fragment>
…..
碎片替换:替代以前的 tabhost ,自定义工具栏
//main_layout.xml文件
<FrameLayout app:layout_constraintHorizontal_weight="1" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toRightOf="@+id/id_left_fragment" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" android:id="@+id/id_right_layout" android:layout_width="0dp" android:layout_height="0dp”>
<fragment android:name="com.example.shopins.fragmenttest.RightFragment" android:id="@+id/id_right_fragment" android:layout_width="match_parent" android:layout_height="match_parent”/>
</FrameLayout>
//MainActivity文件。。。。AnotherRightFragment newFragment = new AnotherRightFragment();FragmentManager manager = getFragmentManager();FragmentTransaction transaction = manager.beginTransaction();
//按返回键的时候,返回上一个碎片,一般传入 null
transaction.addToBackStack(null);
//replace 或者 add 方法
transaction.replace(R.id.id_right_layout, newFragment);transaction.commit();
。。。。//在活动中获取对应碎片实例,调用碎片实例方法:…..FragmentManager manager = getFragmentManager();MyFragment _MyF = (MyFragment)manager.findFragmentById(R.id.fragmentid);_MyF.func();…..//在碎片中获取对应活动,调用活动实例方法:。。。。。。。MainActivity activity = (MainActivity) getActivity();
。。。。。。。另外当碎片中需要使用 Context 对象时,也可以使用 getActivity()方法,因为获取到的活动本身就是一个 Context对象了。
碎片的生命周期:从先到后依次为
- onAttach() 当碎片和活动建立关联的时候调用。
- onCreateView() 为碎片创建视图(加载布局)时调用。
- onActivityCreated() 确保与碎片相关联的活动一定已经创建完毕的时候调用。
- onDestroyView() 当与碎片关联的视图被移除的时候调用。
- onDetach() 当碎片和活动解除关联的时候调用
在碎片中也可以用onSaveInstanceState()来保持数据。
在 res 目录下用限定符创建对应文件夹,设备可自动加载对应资源:
大小
small
供给小屏幕设备的资源
normal
供给中等屏幕设备的资源
large
供给大屏幕设备的资源
xlarge
供给超大屏幕设备的资源
分辨率
ldpi
供给低分辨率设备的资源(120dpi 以下)
mdpi
供给中等分辨率设备的资源(120dpi 到 160dpi)
hdpi
供给高分辨率设备的资源(160dpi 到 240dpi)
xhdpi
供给超高分辨率设备的资源(240dpi 到 320dpi)
方向
land
供给横屏设备的资源
port
供给竖屏设备的资源
e.g.:当 layout 文件中有 main_layout.xml文件,在 res目录下新建 layout-large 文件夹,然后在里面新建 main_layout.xml文件,那些屏幕被认为是 large 的设备就会自动加载 layout-large 文件夹下的布局,而小屏幕的设备则还是会加载layout 文件夹下的布局。在 res 目录下,可以看到自动生成的 mdpi 、hdpi 等文件夹如果希望自定义限定宽度,而不是系统认定的”large”,可使用最小宽度限定符,eg:加载activity_main布局的时候,先在 res 目录下新建 layout-sw600dp,当程序运行在屏幕宽度大于 600dp 的设备上时,会加载 layout-sw600dp/activity_main 布局,当程序运行在屏幕宽度小于 600dp 的设备上时,则仍然加载默认的layout/activity_main 布局广播分为有序广播和标准广播(无序)动态注册实现广播接收器:继承BroadcastReceiver并重写 onReceive(Context context, Intent intent)e.g.://在 manifest 文件内声明权限:<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
….protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); intentFilter = new IntentFilter();
//网络状态改变的时候接收通知 intentFilter.addAction("android.net.conn.CONNECTIVITY_CHANGE"); NetworkChangeReceiver _receiver = new NetworkChangeReceiver();
registerReceiver(_receiver, intentFilter);}class NetworkChangeReceiver extends BroadcastReceiver { public void onReceive(Context context, Intent intent) { Toast.makeText(MainActivity.this, "internet changed!!!!", Toast.LENGTH_LONG).show(); }}
….ps:动态注册后注意要撤销注册静态注册实现广播:这种方式可以使程序在未启动的情况下就能接收到广播e.g.://新建 XXXX 类(BootCompleteReceiver)public class BootCompleteReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { Toast.makeText(context, "Boot Complete", Toast.LENGTH_LONG).show(); }}
//在 mainfest 文件中添加权限(开机启动)以及进行注册,android.intent.action.BOOT_COMPLETED(系统内置):
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED”/>
<receiver android:name=".BootCompleteReceiver"> <intent-filter> <action android:name="android.intent.action.BOOT_COMPLETED"/>
</intent-filter></receiver>
//实现:
….
Intent intent = new Intent("android.intent.action.BOOT_COMPLETED");
sendBroadcast(intent);
…..
自定义广播:
//新建 XXXX 类(BootCompleteReceiver)public class BootCompleteReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { Toast.makeText(context, "Boot Complete", Toast.LENGTH_LONG).show(); }}
//manifest 文件注册:
<receiver android:name=".BootCompleteReceiver"> <intent-filter > <action android:name="my_broadcast"/> </intent-filter></receiver>
//实现:
BootCompleteReceiver receive = new BootCompleteReceiver();
Intent intent = new Intent(“ my_broadcast”)
//只要注册my_broadcast的,都能接收到
sendBroadcast(receive,intent);
特别:在广播接收器中是不能开启线程的有序广播:实现方式与自定义相同,区别用sendOrderedBroadcast(第二个参数是一个与权限相关的字符串,可以传入 null )代替sendBroadcast。ps:因为有序关系,前面的广播接收器可以将广播截断,以阻止其继续传播 ,实现方式是在 onReceive()方法中调用了 abortBroadcast()方法,就表示将这条广播截断,后面的广播接收器将无法再接收到这条广播ps:如何设置广播顺序?只需要在 manifest 中设置权限优先级,优先级比较高的先收到广播,eg:<receiver android:name=".MyBroadcastReceiver">
<intent-filter android:priority="100" >
<action android:name="MY_BROADCAST"/></intent-filter>
</receiver>
上面的属于系统全局广播,即发出的广播可以被其他任何的任何应用程序接收到
本地广播:只能在该程序内部进行传递。主要通过LocalBroadcastManager进行管理,并提供发送和接收广播的方法
e.g.:
private MyLocalService _service;private LocalBroadcastManager localBroadcastManager;private IntentFilter intentFilter;@Overrideprotected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); _service = new MyLocalService(); localBroadcastManager = LocalBroadcastManager.getInstance(this); Button btn = (Button)findViewById(R.id.id_btn); btn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Intent intent = new Intent("My_Local"); localBroadcastManager.sendBroadcast(intent); } }); intentFilter = new IntentFilter(); intentFilter.addAction("My_Local"); localBroadcastManager.registerReceiver(_service, intentFilter);}class MyLocalService extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { Toast.makeText(MainActivity.this, "this is local message", Toast.LENGTH_LONG).show(); }}
ps:不需要去 manifest 注册
文件存取:数据持久化:文件存储、数据库存储、sharePreference访问 http://developer.android.com/reference/android/Manifest.permission.html 可以查看 Android系统所有可声明的权限
//保存//读取public void save() { String data = "Data to save"; 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();
} finally {try {
if (writer != null) {
writer.close();
} } catch (IOException e) {
e.printStackTrace(); }
}
}
public String load() { 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: 使用键值对的方式来存储数据的。也就是说当保存一条数据的时候,需要给这条数据 供一个对应的键
获取 sharepreferences 对象的三种方法:
1.Context类中的 getSharePreferences()方法,传入两个参数,第一个是文件名,第2个是操作模式(MODE_PRIVATE 和 MODE_MULTI_PROCESS,MODE_PRIVATE表示只有当前程序才能对该文件进行读写)
2.Activity类中的 getPreferences()方法,传入操作模式,默认文件名是当前活动类名3.PreferenceManager 类中的 getDefaultSharePreferences()方法使用数据库:SQLiteOpenHelper得到了 SharedPreferences 对象之后,就可以开始向 SharedPreferences 文件中存储数据了,主要可以分为三步实现。
- 调用 SharedPreferences 对象的 edit()方法来获取一个 SharedPreferences.Editor 对象。
- 向 SharedPreferences.Editor 对象中添加数据,比如添加一个布尔型数据就使用putBoolean 方法,添加一个字符串则使用 putString()方法,以此类推。
- 调用 commit()方法将添加的数据 交,从而完成数据存储操作
e.g.:
//保存
SharedPreferences.Editor editor = getSharedPreferences("data", MODE_PRIVATE).edit();editor.putString("keep",text);editor.commit();
//读取
TextView v = (TextView)findViewById(R.id.id_textview);SharedPreferences sharedPreferences = getSharedPreferences("data", MODE_PRIVATE);String data = sharedPreferences.getString("keep","null");v.setText(data.toString());
e.g.:新建数据库工具类(继承SQLiteOpenHelper)public class MyDatabaseHelper extends SQLiteOpenHelper { //版本1// public static final String CREATE_BOOK = "create table Book (" +// "id integer primary key autoincrement, "// + "author text, "// + "price real, "// + "pages integer, "// + "name text)"; //版本3 public static final String CREATE_BOOK = "create table Book (" + "id integer primary key autoincrement, " + "author text, " + "price real, " + "pages integer, " + "name text, " + "category_id integer)"; public static final String CREATE_CATEGORY = "create table Category (" + "id integer primary key autoincrement, " + "category_name text, " + "category_code integer)"; private Context mContext; public MyDatabaseHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) { super(context, name, factory, version, null); mContext = context; } @Override //如果用户是从版本2开始安装程序,那么会创建两个表 public void onCreate(SQLiteDatabase db) { db.execSQL(CREATE_BOOK); db.execSQL(CREATE_CATEGORY); Toast.makeText(mContext, "Create succeeded", Toast.LENGTH_SHORT).show(); } @Override //对数据库进行升级时候调用,当 初始化传入的版本号高于之前的,就会升级 public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { switch (oldVersion) { //如果用户已经安装版本1,现在更新到版本2,只需要再创建第2个表 case 1: db.execSQL(CREATE_CATEGORY); break; //用户从版本2更新到版本3 case 2: db.execSQL("alter table Book add column category_id integer"); break; default: } }}
//activity 文件private MyDatabaseHelper myDatabaseHelper;@Overrideprotected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); myDatabaseHelper = new MyDatabaseHelper(this, "BookStore.db", null, 2); setContentView(R.layout.activity_main); //创建表 final Button createDatabase = (Button) findViewById(R.id.create_database); createDatabase.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { myDatabaseHelper.getWritableDatabase(); } }); //添加 Button addData = (Button) findViewById(R.id.add_data); addData.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { SQLiteDatabase db = myDatabaseHelper.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); } }); //更新数据 Button updateData = (Button) findViewById(R.id.update_data); updateData.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { SQLiteDatabase db = myDatabaseHelper.getWritableDatabase(); ContentValues contentValues = new ContentValues(); contentValues.put("price", 10.99); db.update("Book",contentValues,"name = ?", new String[] { "The Da Vinci Code" }); } }); //删除 Button deleteButton = (Button) findViewById(R.id.delete_data); deleteButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { SQLiteDatabase db = myDatabaseHelper.getWritableDatabase(); db.delete("Book", "pages > ?", new String[] { "500" }); } }); //查询 Button queryButton = (Button) findViewById(R.id.query_data); queryButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { SQLiteDatabase db = myDatabaseHelper.getWritableDatabase(); Cursor cursor = db.query("Book", null, null, null, null, null, null); if (cursor.moveToFirst()) { do { 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.w("MainActivity", "book name is " + name); Log.w("MainActivity", "book author is " + author); Log.w("MainActivity", "book pages is " + pages); } while (cursor.moveToNext()); cursor.close(); } } });}
//XML 文件
<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/create_database" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Create database" /> <Button android:id="@+id/add_data" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Add data" /> <Button android:id="@+id/update_data" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Update data" /> <Button android:id="@+id/delete_data" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Delete data" /> <Button android:id="@+id/query_data" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Query data" /></LinearLayout>
SQL 需要注意大小写,比如 Book 和 book 不一样。SQLite 支持事务,事务可保证操作全部完成或者操作一步都没有进行。如何进行事务操作?从SQLiteOpenHelper对象的beginTransaction 方法开始,以SQLiteOpenHelper对象的setTransactionSuccessful 结束。e.g.:SQLiteDatabase db = dbHelper.getWritableDatabase();db.beginTransaction(); // 开启事务try {
db.delete("Book", null, null);
// if (true) {
// 在这里手动抛出一个异常,让事务失败
// throw new NullPointerException();
// }
ContentValues values = new ContentValues();values.put("name", "Game of Thrones");values.put("author", "George Martin");values.put("pages", 720);
} catch (Exception e) {
values.put("price", 20.85);
db.insert("Book", null, values);db.setTransactionSuccessful(); // 事务已经执行成功e.printStackTrace();
} finally {
db.endTransaction(); // 结束事务
}
内容提供器(Content Provider)主要用于在不同的应用程序之间实现数据共享的功能,它 供了一套完整的机制,允许一个程序访问另一个程序中的数据,同时还能保证被访数据的安全性,个人理解,其实就是给外部程序提供访问程序内部数据的接口,令外部程序可以增删改查程序内部的数据
多线程:内容提供器的用法一般有两种,一种是使用现有的内容 供器来读取和操作相应程序中的数据,另一种是创建自己的内容 供器给我们程序的数据 供外部访问接口。
类似电话簿、媒体库等都使用了内容提供器
主要使用ContentResolve类,它的增删改查方法接收 Uri 对象,而Uri 对象字符串有两部分构成,权限和路径,一般权限是包名,路径是表名,前面还需要加上协议。获取短信:内容 URI 最标准的格式写法如下:
content://com.example.app.provider/table1 content://com.example.app.provider/table2
使用内容提供器,需要在 manifest 文件声明权限,eg:自定义内容提供器notification 通知(效果类似push通知):通过 notificationmanager 进行管理,一般通过 getSystemService 获取。e.g.:<provider android:name="com.example.demo.DatabaseProvider" android:authorities="com.example.demo.provider" />
使用了<provider>标签来对 DatabaseProvider 这个内容 供器进行注 册,在 android:name 属性中指定了该类的全名,又在 android:authorities 属性中指定了该内容提供器的权限
NotificationManager manager = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);基本使用:NotificationManager manager = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);//设置点击通知后跳转的 activityIntent _itent = new Intent(this, OtherActivity);PendingIntent pendingIntent = PedingIntent.getActivity(this, 0, _intent,PendingIntent.FLAG_IMMUTABLE);//初始化 Notification对象,Build 传入 context 对象, setSound这是声音Notification _notification = new Notification.Build(this).setContentTitle(“title”).setContentText(“text”).setContentIntent(pendingIntent).setSmallIcon(R.mipmap.xx).setSound(Uri.fromFile(new File("/system/media/audio/ringtones/Basic_tone.ogg"))).build();//自定义行为
//设置手机振动,下标0是手机静止时长,下标1是手机振动时长,下标2又是手机静止时长,以此类推,单位是毫秒,该功能需要权限:<uses-permission android:name="android.permission.VIBRATE"/>long[] vibrates = {0, 1000, 1000, 1000};notification.vibrate = vibrates;
//闪光灯颜色notification.ledARGB = Color.GREEN;//闪光灯暗去,单位:毫秒notification.ledOnMS = 1000;//闪光灯亮起notification.ledOffMS = 1000;//指定通知行为notification.flags = Notification.FLAG_SHOW_LIGHTS;
//或者不自定义,设置全部默认行为。
//notification.defaults = Notification.DEFAULT_ALL;
//传入 id 和 notification 对象manager.notify(1, _notification)ps:如果希望点击之后消除通知,需要在对应的活动调用notificationManager.cancel(id).eg:在上例中OtherActivity:@Overrideprotected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.notification_layout); NotificationManager manager = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE); manager.cancel(1);}
private TextView sender;private TextView content;private IntentFilter intentFilter;private MessageReceiver messageReceiver;@Overrideprotected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); sender = (TextView) findViewById(R.id.id_sender); content = (TextView) findViewById(R.id.id_content); intentFilter = new IntentFilter();
//设置优先级,保证第一个接收到intentFilter.setPriority(100);
intentFilter.addAction("android.provider.Telephony.SMS_RECEIVED");
messageReceiver = new MessageReceiver();
registerReceiver(messageReceiver, intentFilter);
}
@Override//activity文件protected void onDestroy() { super.onDestroy(); unregisterReceiver(messageReceiver);}class MessageReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { Bundle bundle = intent.getExtras(); Object[] obj = (Object[]) bundle.get("pdus"); SmsMessage[] smsMessage = new SmsMessage[obj.length]; for (int i = 0 ; i < smsMessage.length ; i++) { smsMessage[i] = SmsMessage.createFromPdu((byte[])obj[i]); } String address = smsMessage[0].getOriginatingAddress(); String fullMessage = ""; for (SmsMessage message : smsMessage) { fullMessage += message.getMessageBody(); } sender.setText(address.toString()); content.setText(fullMessage.toString());
//拦截通知,不可以继续下发abortBroadcast();
}
}//manifest 文件设置权限
<uses-permission android:name="android.permission.RECEIVE_SMS"/>
1.继承线程类Thread,重写 run2.实现接口Runnable,重写run,使用方式如下:MyRunnable test = new MyRunnable();
Thread thread = new Thread(test);
thread.start();
3.在实例化Thread类的时候,定义了一个实现Runnable接口的匿名内部类,eg:new Thread(new Runnable() {@Override public void run() { …….. }}).start();
更新 UI 的时候只能在主线程里更新。异步消息处理分四部分:Handle,Message,Looper,MessageQueue
4.使用 AsyncTask
- AsyncTask: 为 UI 线程与工作线程之间进行快速的切换提供一种简单便捷的机制。适用于当下立即需要启动,但是异步执行的生命周期短暂的使用场景。
AsyncTask的使用:继承的时候指定三个范型,Params:在执行 AsyncTask 需要传入的参数,可用于后台任务中使用 。 Progress: 后台执行任务时,如果需要在界面显示当前进度,可以设置为进度单位。 Result:当任务结束时,如果需要返回,可以使用这里的范型作为返回类型public class MyAsyncTask extends AsyncTask<Void,Integer,Boolean> { @WorkerThread protected Boolean doInBackground(Void... params) { 这里执行所有耗时操作,但是因为不是主线程,所以不能进行界面操作 返回值和继承范型 Result 的类型是一致的。 如果需要更新 UI 元素,比如说反馈当前任务的执行进度,可以调 用 publishProgress(Progress...)方法来完成。 return true; } @MainThread 这个方法在后台执行前调用,一般用于进行界面一些初始化操作,比如显示一个进度条 protected void onPreExecute() { } @MainThread protected void onPostExecute(Result result) { 当后台任务执行完毕并通过 return 语句进行返回时,这个方法就很快会被调用。 返 回的数据会作为参数传递到此方法中,可以利用返回的数据来进行一些 UI 操作,比如 说 醒任务执行的结果,以及关闭掉进度条对话框等。 } @MainThread protected void onProgressUpdate(Integer... values) { 当在后台任务中调用了 publishProgress(Progress...)方法后,这个方法就会很快被调 用,方法中携带的参数就是在后台任务中传递过来的。在这个方法中可以对 UI 进行操 作,利用参数中的数值就可以对界面元素进行相应地更新 } @MainThread protected void onCancelled(Result result) { onCancelled(); }}
使用: new MyAsyncTask().execute();
自定义服务,并有下载功能: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; }
//通过 Binder 对象获取 Serivce 对象,从而可以调用 MyService 中的方法。
public MyService getService(){
return MyService.this; } } @Override public IBinder onBind(Intent intent) { Log.w("onBind", getClass().getSimpleName()); return mBinder; } @Override,如果初始化,则首先执行。 public void onCreate() { Log.w("onCreate", getClass().getSimpleName()); } @Override,startService 后调用,如果该服务还没创建,则该方法在 onCreate后调用。 public int onStartCommand(Intent _intent, int flags, int _startID) { Log.w("onStartCommand", getClass().getSimpleName()); return super.onStartCommand(_intent, flags, _startID); } @Override public void onDestroy() { Log.w("onDestroy", getClass().getSimpleName()); super.onDestroy(); }}
使用:
1.先声明一个 ServiceConnection 对象:
private MyService.DownloadBinder downloadBinder;
private final ServiceConnection serviceConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { downloadBinder = (MyService.DownloadBinder)service; downloadBinder.startDownload(); downloadBinder.getProgress(); } @Override public void onServiceDisconnected(ComponentName name) { }};
2.执行执行绑定:
需要声明权限:Intent bind = new Intent(this, MyService.class);bindService(bind, serviceConnection,BIND_AUTO_CREATE);
3.接触绑定:
Intent unbind = new Intent(this, MyService.class);unbindService(serviceConnection);
<service android:name=".MyService"/>
ps:需要在后台也能正常的功能可以使用 service,比如后台播放音乐BindService和Started Service都是Service,有什么地方不一样呢:
1. Started Service中使用StartService()方法来进行方法的调用,调用者和服务之间没有联系,即使调用者退出了,服务依然在进行【onCreate()- >onStartCommand()->startService()->onDestroy()】,注意其中没有onStart(),主要是被onStartCommand()方法给取代了,onStart方法不推荐使用了。
2. BindService中使用bindService()方法来绑定服务,调用者和绑定者绑在一起,调用者一旦退出服务也就终止了【onCreate()->onBind()->onUnbind()->onDestroy()】。
一种异步、自动停止的服务:IntentService。它跟 service 的区别是:service不是独立的进程,也不是独立的线程,它是依赖于应用程序的主线程,不建议在service中编写耗时的逻辑和操作IntentService在执行onCreate操作的时候,内部开了一个线程,去执行耗时操作IntentService: 适合于执行由 UI 触发的后台 Service 任务(或者耗时操作),并可以把后台任务执行的情况通过一定的机制反馈给 UI。e.g.:...public class MyIntentService extends IntentService { public MyIntentService() { super("MyIntentService"); } @Override public IBinder onBind(Intent intent) { return null; }// @WorkerThread protected void onHandleIntent( Intent intent) { Log.w("onHandleIntent","Thread id is " + Thread.currentThread().getId()); }}
..
//在 manifest 文件注册权限:
<service android:name=".MyIntentService"/>
使用:
Intent intentService = new Intent(this, MyIntentService.class);
startService(intentService);
延时操作(定时任务):
开启新线程
new Thread(new Runnable(){
public void run(){
Thread.sleep(XXXX); // 程序休眠 X XXX
handler.sendMessage(); //告诉主线程执行任务
}
}).start
利用定时器
TimerTask task = new TimerTask(){
public void run(){
//execute the task
}
};
Timer timer = new Timer();
timer.schedule(task, delay);
//
new Handler().postDelayed(new Runnable(){
public void run() {
//execute the task
}
}, delay);
利用AlarmManager,用于长时间、复杂的任务。
HttpsURLConnection的使用。
e.g.:
private static final int SHOW_RESPONSE = 0;private Button sendRequest;private TextView responseText;private Handler handler = new Handler(){ public void handleMessage(Message msg) { switch (msg.what) { case SHOW_RESPONSE: StringBuilder str = (StringBuilder)msg.obj; responseText.setText(str.toString()); break; default: break; } }};@Overrideprotected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); sendRequest = (Button)findViewById(R.id.id_send_request); responseText = (TextView)findViewById(R.id.id_response); sendRequest.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { sendRequestWithHttpURLConnection(); } });}public void sendRequestWithHttpURLConnection() { new Thread(new Runnable() { @Override public void run() { HttpsURLConnection connection = null; try { URL url = new URL("https://www.baidu.com"); connection = (HttpsURLConnection)url.openConnection(); connection.setConnectTimeout(8000); connection.setReadTimeout(8000); connection.setRequestMethod("GET”);
//执行getInputStream 后connection不能进行任何的配置代码,比如setRequestMethod等代码 InputStream inputStream = connection.getInputStream(); BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream)); StringBuilder stringBuilder = new StringBuilder(); String line = ""; while ((line = bufferedReader.readLine()) != null) { stringBuilder.append(line); } Message message = new Message(); message.what = SHOW_RESPONSE; message.obj = stringBuilder; handler.sendMessage(message); } catch(Exception e) { e.printStackTrace(); } finally { if (connection != null) { connection.disconnect(); } } } }).start();}
解析 JSON使用JSONObjecte.g.://JSON数据反向地理编码建议使用Geocoding Api,如果使用 GeoCoder 也提供正向和反向的地理编码功能,但是有 bug:有一定概率地理位置解析失败,所以使用 Geocoding API 比较稳定网络编程最佳实践:[{"id":"5","version":"5.5","name":"Angry Birds"}, {"id":"6","version":"7.0","name":"Clash of Clans"}, {"id":"7","version":"3.5","name":"Hey Day”}]
//jsonData的值打印出来跟上面一致。
private void parseJSONWithJSONObject(String jsonData) {
try {
JSONArray jsonArray = new JSONArray(jsonData); for (int i = 0; i < jsonArray.length(); i++) {
JSONObject jsonObject = jsonArray.getJSONObject(i);
String id = jsonObject.getString("id"); String name = jsonObject.getString("name"); String version = jsonObject.getString("version"); Log.d("MainActivity", "id is " + id); Log.d("MainActivity", "name is " + name);
} } catch (Exception e) {
e.printStackTrace(); }
}
添加jar 方式:1.赋值 jar 包到 libs 文件夹下,
2.在 android studio 找到加入的 jar 包,右键选择add as library,然后添加
详细:http://www.cnblogs.com/neozhu/p/3458759.html
使用Json 解析轮子GSON:https://github.com/google/gson
下载地址:http://search.maven.org/#artifactdetails%7Ccom.google.code.gson%7Cgson%7C2.8.1%7C
e.g.:
网络功能轮子:
OkHttp:http://square.github.io/okhttp/
或者https://github.com/square/okhttp
用法:http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2015/0106/2275.html//自定义网络工具类public class HttpService { public interface HttpCallbackListener { void onFinish(String response); void onError(Exception e); } public static void sendHttpRequest(final String address, final HttpCallbackListener listener) { new Thread(new Runnable() { @Override public void run() { HttpURLConnection connection = null; try { URL url = new URL(address); connection = (HttpURLConnection) url.openConnection(); connection.setRequestMethod("GET"); connection.setConnectTimeout(8000); connection.setReadTimeout(8000); connection.setDoInput(true); connection.setDoOutput(true); InputStream in = connection.getInputStream(); BufferedReader reader = new BufferedReader(new InputStreamReader(in)); StringBuilder response = new StringBuilder(); String line; while ((line = reader.readLine()) != null) { response.append(line); } if (listener != null) { // 回调onFinish()方法 listener.onFinish(response.toString()); } } catch (Exception e) { if (listener != null) { // 回调onError()方法
listener.onError(e); } } finally { if (connection != null) { connection.disconnect(); } } } }).start(); }
}使用:HttpService.sendHttpRequest(“https://www.baidu.com", new HttpService.HttpCallbackListener() {@Override public void onFinish(String response) { } @Override public void onError(Exception e) { }});
ps:使用网络的时候,需要添加权限<uses-permission android:name="android.permission.INTERNET"/>https://developers.google.com/maps/documentation/geocoding/。
Geocoding API 中规定了很多接口,其中反向地理编码的接口如下:http://maps.googleapis.com/maps/api/geocode/json?latlng=40.714224,-73.961452&sensor=true_or_false
设置获取全局 Content的方法1.自定义 MyApplication 继承 Application2.让程序初始化自定义的MyApplication(而不是 Application),需要在 manifest 文件中进行修改注册说明3.在MyApplication 中重写 onCreate 方法,调用Application的getApplicationContext方法赋值给自定义的static 变量。e.g.://需要在 manifest 文件内,添加注册声明
- <application
- android:name=".MyApplication" //这个相当重要
- android:icon="@drawable/icon"
- android:label="@string/app_name">
public class MyApplication extends Application { private static Context context;
@Override public void onCreate() {
context = getApplicationContext(); }
public static Context getContext() { return context;
}}
ps:可以在自定义的 application 类中,定义一些全局变量。使用 intent 来传递自定义对象:Serializeble方式和 parcelable 方式Serializeble方式:1。自定义对象实现Serializeble2.获取对象时候intent 调用getSerializableExtra方法获取。e.g.:public class Person implements Serializable{
private String name;
private int age;
public String getName() { return name;
}
public void setName(String name) { this.name = name;
}
public int getAge() { return age;
}
public void setAge(int age) { this.age = age;
}}
//使用Person person = new Person();person.setName("Tom"); person.setAge(20); Intent intent = new Intent(FirstActivity.this, SecondActivity.class); intent.putExtra("person_data", person);
startActivity(intent);
//获取对象
文本样式(富文本):Person person = (Person) getIntent().getSerializableExtra("person_data");
parcelable方式:将对象进行分解,分解后的每一个部分都是intent 所支持的数据类型。parcelable比Serializeble的效率要高一点,但更加复杂e.g.:实现Parcelable步骤
1)implements Parcelable
2)重写writeToParcel方法,将你的对象序列化为一个Parcel对象,即:将类的数据写入外部提供的Parcel中,打包需要传递的数据到Parcel容器保存,以便从 Parcel容器获取数据
3)重写describeContents方法,内容接口描述,默认返回0就可以
4)实例化静态内部对象CREATOR实现接口Parcelable.Creator
public class Person implements Parcelable{
private String name;
private int age;
2.当一个线程访问object的一个synchronized(this)同步代码块时,另一个线程仍然可以访问该object中的非synchronized(this)同步代码块。@Override public int describeContents() {
return 0;}
@Override public void writeToParcel(Parcel dest, int flags) {
dest.writeString(name); // 写出name
dest.writeInt(age); // 写出age}
public static final Parcelable.Creator<Person> CREATOR = new Parcelable. Creator<Person>() {
@Override public Person createFromParcel(Parcel source) {
Person person = new Person();
person.name = source.readString(); // 读取nameperson.age = source.readInt(); // 读取agereturn person;}
@Override public Person[] newArray(int size) {
return new Person[size]; }
};
}
ps:选择序列化方法的原则synchronized 是Java语言关键字,当它用来修饰一个方法或者一个代码块的时候,能够保证在同一时刻最多只有一个线程执行该段代码。synchronized 关键字,它包括两种用法:synchronized 方法和 synchronized 块.1)在使用内存的时候,Parcelable比Serializable性能高,所以推荐使用Parcelable。
2)Serializable在序列化的时候会产生大量的临时变量,从而引起频繁的GC。
3)Parcelable不能使用在要将数据存储在磁盘上的情况,因为Parcelable不能很好的保证数据的持续性在外界有变化的情况下。尽管Serializable效率低点,但此时还是建议使用Serializable
效果:1.当两个并发线程访问同一个对象object中的这个synchronized(this){。。。code}同步代码块时, * 一个时间内只能有一个线程得到执行。另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块。3.当一个线程访问object的一个synchronized(this)同步代码块时,其他线程对object中所有其它synchronized(this)同步代码块的访问将被阻塞屏幕横竖屏转换:保证不会销毁后重新创建 ----》设置 activity 的 configchanges标签属性,屏蔽生命周期、软键盘、自适应等因素的影响SpannableString
调度器:调度器调度线程池执行任务,生产者生产任务,消费者消费任务,那么这时就需要一个任务队列,生产者向队列里插入任务,消费者从队列里提取任务执行,调度器里是通过BlockingQueue实现的队列AbsoluteSizeSpan
AlignmentSpan.Standard
BackgroundColorSpan
BulletSpan
DrawableMarginSpan
ForegroundColorSpan
IconMarginSpan
ImageSpan
LeadingMarginSpan
BlockingQueue是个接口,有如下实现类:
1. ArrayBlockQueue:一个由数组支持的有界阻塞队列。此队列按 FIFO(先进先出)原则对元素进行排序。创建其对象必须明确大小,像数组一样。
2. LinkedBlockQueue:一个可改变大小的阻塞队列。此队列按 FIFO(先进先出)原则对元素进行排序。创建其对象如果没有明确大小,默认值是Integer.MAX_VALUE。链接队列的吞吐量通常要高于基于数组的队列,但是在大多数并发应用程序中,其可预知的性能要低。
3. PriorityBlockingQueue:类似于LinkedBlockingQueue,但其所含对象的排序不是FIFO,而是依据对象的自然排序顺序或者是构造函数所带的Comparator决定的顺序。
4. SynchronousQueue:同步队列。同步队列没有任何容量,每个插入必须等待另一个线程移除,反之亦然。eg:使用ArrayBlockQueue来实现生产者消/费者模式
- /** 定义一个盘子类,可以放鸡蛋和取鸡蛋 */
- public class BigPlate {
- /** 装鸡蛋的盘子,大小为5 */
- private BlockingQueue<Object> eggs = new ArrayBlockingQueue<Object>(5);
- /** 放鸡蛋 */
- public void putEgg(Object egg) {
- try {
- eggs.put(egg);// 向盘子末尾放一个鸡蛋,如果盘子满了,当前线程阻塞
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- // 下面输出有时不准确,因为与put操作不是一个原子操作
- System.out.println("放入鸡蛋");
- }
- /** 取鸡蛋 */
- public Object getEgg() {
- Object egg = null;
- try {
- egg = eggs.take();// 从盘子开始取一个鸡蛋,如果盘子空了,当前线程阻塞
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- // 下面输出有时不准确,因为与take操作不是一个原子操作
- System.out.println("拿到鸡蛋");
- return egg;
- }
- /** 放鸡蛋线程 */
- static class AddThread extends Thread {
- private BigPlate plate;
- private Object egg = new Object();
- public AddThread(BigPlate plate) {
- this.plate = plate;
- }
- public void run() {
- plate.putEgg(egg);
- }
- }
- /** 取鸡蛋线程 */
- static class GetThread extends Thread {
- private BigPlate plate;
- public GetThread(BigPlate plate) {
- this.plate = plate;
- }
- public void run() {
- plate.getEgg();
- }
- }
- public static void main(String[] args) {
- BigPlate plate = new BigPlate();
- // 先启动10个放鸡蛋线程
- for(int i = 0; i < 10; i++) {
- new Thread(new AddThread(plate)).start();
- }
- // 再启动10个取鸡蛋线程
- for(int i = 0; i < 10; i++) {
- new Thread(new GetThread(plate)).start();
- }
- }
- }
- 输出:
- 放入鸡蛋
- 放入鸡蛋
- 放入鸡蛋
- 放入鸡蛋
- 放入鸡蛋
- 拿到鸡蛋
- 放入鸡蛋
- 拿到鸡蛋
- 拿到鸡蛋
- 拿到鸡蛋
- 安卓学习记录(2)
- 安卓学习记录
- 安卓学习记录
- 安卓学习记录
- 按照 老罗博客学习安卓 记录 (2)
- 记录安卓学习过程(1)
- 安卓学习记录(一)
- 安卓学习记录(1)
- 安卓学习记录一
- 安卓学习记录02
- 安卓学习记录03
- 安卓开发学习记录
- 安卓学习记录----repo
- 安卓学习记录-Android-day19-UI学习2
- 按照 老罗博客学习安卓 记录 (3)
- 安卓学习记录——(2.界面布局)
- 安卓学习记录——(3.1UI)
- 安卓学习记录-java-day1
- 算术运算与赋值运算
- Dev c++工具将C代码生成dll文件以及如何调用dll文件
- 视频拼接3d合成
- 树莓派点亮一个流水灯
- C++虚基类详解
- 安卓学习记录(2)
- Serializers
- JAVA代码编写30点总结
- python学习五(引用、多参数,缺省参)
- 弹性盒模型 Flex 布局
- 使用ffmpeg AVfilter 中的amix实现混音
- c#学习之--继承
- B. An express train to reveries
- 用类名当做参数类型,定义属性变量。