活动
Toast
activity:
Toast.makeText(FirstActivity.this,"You clicked Button 1",
Toast.LENGTH_SHORT).show();
Menu
res/menu/main.xml:
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/add_item"
android:title="Add"/>
<item
android:id="@+id/remove_item"
android:title="Remove"/>
</menu>
activity:
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main,menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()){
case R.id.add_item:
Toast.makeText(this,"Add",Toast.LENGTH_SHORT).show();
break;
case R.id.remove_item:
Toast.makeText(this,"Remove",Toast.LENGTH_SHORT).show();
break;
default:
}
return true;
}
Intent
显式intent
隐式intent
manifest文件中:
<activity
android:name=".SecondActivity"
android:launchMode="singleInstance">
<intent-filter>
<action android:name="com.example.activitytest.ACTION_START" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="com.example.activitytest.MY_CATEGORY" />
</intent-filter>
</activity>
activity中:
Intent intent = new Intent("com.example.activity.ACTION_START");
intent.addCategory("com.example.activitytest.MY_CATEGORY");
startActivity(intent);
更多隐式intent的用法:
activity:
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse("http://www.baidu.com"));
startActivity(intent);
//用于启动系统浏览器
如果在manifest文件中添加下列代码,则可响应上述intent:
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<data android:schema="http" />
</intent-filter>
返回数据给上一个活动
FirstActivity中:
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:
}
}
SecondActivity中:
Intent intent = new Intent();
intent.putExtra("data_return",数据内容);
setResult(RESULT_OK,intent);
//第一个参数用于向上一个活动返回处理结果,一般只使用RESULT_OK和RESULT_CANCELED
finish();
防止活动被回收的方法
在该活动中添加下列代码:
@Override
protected void onSaveInstanceState(Bundle outState){
super.onSaveInstanceState();
String tempData = "数据";
outState.putString("data_key",tempData);
}
在onCreate方法中添加下列内容可获得保存的数据:
if(saveInstanceState != null){
String tempData = saveInstanceState.getString("data_key");
}
引入自定义的布局
新建一个布局title.xml
将title.xml引入其他布局文件,即可被复用
<include layout="@layout/title" />
创建自定义控件
新建一个布局title.xml
自定义的控件,该控件有响应点击的功能
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();
}
});
}
}
将该控件引入其他布局文件:
activity_main.xml:
<?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" >
<com.example.uicustomviews.TitleLayout
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
活动的生命周期
(1)运行状态
(2)暂停状态
(3)停止状态
(4)销毁状态
活动的启动模式
(1)standard
(2)singleTop
(3)singleTask
(4)singleInstance
manifest中的activity标签中:
android:launchMode="singleTop"
UI控件
#
获取单选按钮的值的两种方法
final RadioGroup sex = (RadioGroup) findViewById(R.id.radioGroup1); //获取单选按钮组
//为单选按钮组添加事件监听
sex.setOnCheckedChangeListener(new OnCheckedChangeListener() {
@Override
public void onCheckedChanged(RadioGroup group, int checkedId) {
RadioButton r = (RadioButton) findViewById(checkedId); //获取被选择的单选按钮
Log.i("单选按钮", "您的选择是:" + r.getText());
}
});
Button button = (Button) findViewById(R.id.button1); //获取提交按钮
//为提交按钮添加单击事件监听
button.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
//通过for循环遍历单选按钮组
for (int i = 0; i < sex.getChildCount(); i++) {
RadioButton r = (RadioButton) sex.getChildAt(i);
if (r.isChecked()) {//判断单选按钮是否被选中
Log.i("单选按钮", "性别:" + r.getText());
break; //跳出for循环
}
}
}
});
获取复选框选中值的方法
//创建一个状态改变监听对象
private OnCheckedChangeListener checkBox_listener=new OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if(isChecked){ //判断复选按钮是否被选中
Log.i("复选按钮","选中了["+buttonView.getText().toString()+"]");
}
}
};
final CheckBox like1=(CheckBox)findViewById(R.id.like1); //获取第1个复选按钮
final CheckBox like2=(CheckBox)findViewById(R.id.like2); //获取第2个复选按钮
final CheckBox like3=(CheckBox)findViewById(R.id.like3); //获取第3个复选按钮
like1.setOnCheckedChangeListener(checkBox_listener); //为like1添加状态改变监听
like2.setOnCheckedChangeListener(checkBox_listener); //为like2添加状态改变监听
like3.setOnCheckedChangeListener(checkBox_listener); //为like3添加状态改变监听
Button button = (Button) findViewById(R.id.button1); //获取提交按钮
//为提交按钮添加单击事件监听
button.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
//通过for循环遍历单选按钮组
String like=""; //保存选中的值
if(like1.isChecked()) //当第一个复选按钮被选中
like+=like1.getText().toString()+" ";
if(like2.isChecked()) //当第一个复选按钮被选中
like+=like2.getText().toString()+" ";
if(like3.isChecked()) //当第一个复选按钮被选中
like+=like3.getText().toString()+" ";
Toast.makeText(MainActivity.this, like, Toast.LENGTH_SHORT).show(); //显示被选中的复选按钮
}
});
自动完成文本框(AutoCompleteTextView)
需要ArrayAdapter实现。
进度条(ProgressBar)
private ProgressBar horizonP; //水平进度条
private ProgressBar circleP; //圆形进度条
private int mProgressStatus = 0; //完成进度起始值
private Handler mHandler; //声明一个用于处理消息的Handler类的对象
horizonP = (ProgressBar) findViewById(R.id.progressBar1); //获取水平进度条
circleP=(ProgressBar)findViewById(R.id.progressBar2); //获取圆形进度条
circleP.incrementProgressBy(-10);
circleP.setVisibility(View.VISIBLE);
mHandler=new Handler(){
@Override
public void handleMessage(Message msg) {
if(msg.what==0x111){
horizonP.setProgress(mProgressStatus); //更新进度
circleP.setProgress(100-mProgressStatus);
}else{
Toast.makeText(MainActivity.this, "耗时操作已经完成", Toast.LENGTH_SHORT).show();
horizonP.setVisibility(View.GONE); //设置进度条不显示,并且不占用空间
circleP.setVisibility(View.GONE);//设置进度条不显示,并且不占用空间
}
}
};
new Thread(new Runnable() {
public void run() {
while (true) {
mProgressStatus = doWork(); //获取耗时操作完成的百分比
Message m=new Message();
if(mProgressStatus<100){
m.what=0x111;
mHandler.sendMessage(m); //发送信息
}else{
m.what=0x110;
mHandler.sendMessage(m); //发送消息
break;
}
}
}
//模拟一个耗时操作
private int doWork() {
mProgressStatus+=Math.random()*10; //改变完成进度
try {
Thread.sleep(200); //线程休眠200毫秒
} catch (InterruptedException e) {
e.printStackTrace();
}
return mProgressStatus; //返回新的进度
}
}).start(); //开启一个线程
拖动条(SeekBar)
<SeekBar
android:layout_height="wrap_content"
android:id="@+id/seekBar1"
android:max="100"
android:progress="50"
android:padding="10px"
android:layout_width="match_parent"/>
private SeekBar seekbar; //拖动条
final TextView result=(TextView)findViewById(R.id.textView1);
seekbar = (SeekBar) findViewById(R.id.seekBar1); //获取拖动条
seekbar.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
Toast.makeText(MainActivity.this, "结束滑动", Toast.LENGTH_SHORT).show();
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
Toast.makeText(MainActivity.this, "开始滑动", Toast.LENGTH_SHORT).show();
}
@Override
public void onProgressChanged(SeekBar seekBar, int progress,
boolean fromUser) {
result.setText("当前值:"+progress); //修改文本视图的值
}
});
星级评分条(RatingBar)
getRating()方法:获取等级,表示选中了几颗星。
getStepSize()方法:获取每次最少要改变多少个星级,默认为0.5个。
getProgress()方法:获取进度,以上两个方法返回值的乘积。
对话框(AlertDialog)
ListView
RecyclerView
碎片(Fragment)
动态添加碎片
private void replaceFragment(Fragment fragment){
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction transaction = fragmentManager.beginTransaction(); //开启事务
transaction.replace(R.id.right_layout,fragment); //向容器内添加或替换该碎片
transaction.addToBackStack(null); //用于将一个事务添加到返回栈中,按下Back键可以返回到上一个碎片
transaction.commit(); //提交事务
}
碎片和活动之间进行通信
(1)在活动中得到响应碎片的实例
RightFragment rightFragment = (RightFragment)getFragmentManager()
.findFragmentById(R.id.right_fragment);
(2)在碎片中得到和当前碎片相关联的活动实例
MainActivity activity = (MainActivity)getActivity();
碎片的生命周期
(1)运行状态
(2)暂停状态
(3)停止状态
(4)销毁状态
广播
广播机制
- 标准广播:完全异步执行,在广播发出之后所有的广播接收器几乎都会在同一时刻接收到这条广播消息,没先后顺序。效率高,无法被截断。
- 有序广播:同步执行,优先级高度先收到,然后才继续传递。可截断。
接收系统广播
- 动态注册
public class MainActivity extends AppCompatActivity {
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) {
//重写执行逻辑
}
}
}
- 静态注册
manifest中:
<receiver
android:name=".BootCompleteReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
发送自定义广播
// 一般静态注册
发送标准广播
- MainActivity中:
Intent intent = new Intent("com.example.broadcasttest.MY_BROADCAST");
sendBroadcast(intent);
- 定义一个广播接收器类
发送有序广播
- MainActivity中:
Intent intent = new Intent("com.example.broadcasttest.MY_BROADCAST");
sendOrderedBroadcast(intent,null);
- 定义两个个广播接收器类MyBroadcastReceive和AnotherBroadcastReceiver
其中MyBroadcastReceiver在onReceive方法中截断消息
abortBroadcast();
- 在manifest中定义优先级
<receiver
android:name=".MyBroadcastReceiver"
android:enabled="true"
android:exported="true">
<intent-filter android:priority="100">
<action android:name="com.example.broadcasttest.MY_BROADCAST"/>
</intent-filter>
</receiver>
使用本地广播
// 只能动态注册
增加以下代码
private LocalBroadcastManager localBroadcastManager;
localBroadcastManager = LocalBroadcastManager.getInstance(this); // 获取实例
对发送接收取消注册进行相应修改
localBroadcastManager.sendBroadcast(intent); // 发送本地广播
localBroadcastManager.registerReceiver(localReceiver,intentFilter); // 注册本地广播监听器
localBroadcastManager.unregisterReceiver(localReceiver); //取消动态注册
```
# 数据存储--持久化技术
### 文件存储
存储目录:/data/data/"package name"/files/
```java
public class MainActivity extends AppCompatActivity {
private EditText edit;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
edit = (EditText) findViewById(R.id.edit);
String inputText = load();
if (!TextUtils.isEmpty(inputText)) {
edit.setText(inputText);
edit.setSelection(inputText.length());
Toast.makeText(this, "Restoring succeeded", Toast.LENGTH_SHORT).show();
}
}
@Override
protected void onDestroy() {
super.onDestroy();
String inputText = edit.getText().toString();
save(inputText);
}
public void save(String inputText) {
FileOutputStream out = null;
BufferedWriter writer = null;
try {
out = openFileOutput("data", Context.MODE_PRIVATE);
writer = new BufferedWriter(new OutputStreamWriter(out));
writer.write(inputText);
} 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();
}
}
<div class="se-preview-section-delimiter"></div>
SharedPreferences存储
存储目录:/data/data/”package name”/shared_prefs/
使用键值对的方式
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button saveData = (Button) findViewById(R.id.save_data);
saveData.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
SharedPreferences.Editor editor = getSharedPreferences("data", MODE_PRIVATE).edit();
editor.putString("name", "Tom");
editor.putInt("age", 28);
editor.putBoolean("married", false);
editor.apply();
}
});
Button restoreData = (Button) findViewById(R.id.restore_data);
restoreData.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
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);
}
});
}
}
<div class="se-preview-section-delimiter"></div>
SQLite数据库存储
存储目录:/data/data/”package name”/databases/
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)";
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);
mContext = context;
}
@Override
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) {
db.execSQL("drop table if exists Book");
db.execSQL("drop table if exists Category");
onCreate(db);
}
}
<div class="se-preview-section-delimiter"></div>
public class MainActivity extends AppCompatActivity {
private MyDatabaseHelper dbHelper;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
dbHelper = new MyDatabaseHelper(this, "BookStore.db", null, 2);
Button createDatabase = (Button) findViewById(R.id.create_database);
createDatabase.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dbHelper.getWritableDatabase();
}
});
Button addData = (Button) findViewById(R.id.add_data);
addData.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
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); // 插入第二条数据
}
});
Button updateData = (Button) findViewById(R.id.update_data);
updateData.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
SQLiteDatabase db = dbHelper.getWritableDatabase();
ContentValues values = new ContentValues();
values.put("price", 10.99);
db.update("Book", values, "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 = dbHelper.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 = 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();
}
});
}
}
注:创建或打开一个数据库:当数据库不可写入的时候(如磁盘空间已满),getReadableDatabase()方法返回的对象将以只读方式去打开数据库,而getWritableDatabase()方法则将出现异常。
使用LitePal操作数据库
build.gradle文件:
compile 'org.litepal.android:core:1.3.2'
assets目录下的litepal.xml
<?xml version="1.0" encoding="utf-8"?>
<litepal>
<dbname value="BookStore" ></dbname>
<version value="2" ></version>
<list>
<mapping class="com.example.litepaltest.Book"></mapping>
<mapping class="com.example.litepaltest.Category"></mapping>
</list>
</litepal>
AndroidManifest.xml:
<application
android:name="org.litepal.LitePalApplication">
</application>
import org.litepal.crud.DataSupport;
public class Book extends DataSupport {
private int id;
private String author;
private double price;
private int pages;
private String name;
private String press;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
public int getPages() {
return pages;
}
public void setPages(int pages) {
this.pages = pages;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPress() {
return press;
}
public void setPress(String press) {
this.press = press;
}
}
public class Category {
private int id;
private String categoryName;
private int categoryCode;
public void setId(int id) {
this.id = id;
}
public void setCategoryName(String categoryName) {
this.categoryName = categoryName;
}
public void setCategoryCode(int categoryCode) {
this.categoryCode = categoryCode;
}
}
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button createDatabase = (Button) findViewById(R.id.create_database);
createDatabase.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Connector.getDatabase();
}
});
Button addData = (Button) findViewById(R.id.add_data);
addData.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Book book = new Book();
book.setName("The Da Vinci Code");
book.setAuthor("Dan Brown");
book.setPages(454);
book.setPrice(16.96);
book.setPress("Unknow");
book.save();
}
});
Button updateData = (Button) findViewById(R.id.update_data);
updateData.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Book book = new Book();
book.setPrice(14.95);
book.setPress("Anchor");
book.updateAll("name = ? and author = ?", "The Lost Symbol", "Dan Brown");
}
});
Button deleteButton = (Button) findViewById(R.id.delete_data);
deleteButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
DataSupport.deleteAll(Book.class, "price < ?", "15");
}
});
Button queryButton = (Button) findViewById(R.id.query_data);
queryButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
List<Book> books = DataSupport.findAll(Book.class);
for (Book book: books) {
Log.d("MainActivity", "book name is " + book.getName());
Log.d("MainActivity", "book author is " + book.getAuthor());
Log.d("MainActivity", "book pages is " + book.getPages());
Log.d("MainActivity", "book price is " + book.getPrice());
Log.d("MainActivity", "book press is " + book.getPress());
}
}
});
}
}
内容提供器(Content Provider)
运行时申请权限
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button makeCall = (Button) findViewById(R.id.make_call);
makeCall.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//判断用户是否授权打电话权限
if(ContextCompat.checkSelfPermission(MainActivity.this,Manifest.
permissions.CALL_PHONE) ! = PackageManager.PERMISSION_GRANTED){
//向用户申请授权
ActivityCompat.requestPermissions(MainActivity.this,new
String[]{Manifest.permissions.CALL_PHONE},1);
}else{
call();
}
}
});
}
private void call() {
try {
Intent intent = new Intent(Intent.ACTION_CALL);
intent.setData(Uri.parse("tel:10086"));
startActivity(intent);
} catch (SecurityException e) {
e.printStackTrace();
}
}
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
switch (requestCode) {
case 1:
//判断授权结果
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
call();
} else {
Toast.makeText(this, "You denied the permission", Toast.LENGTH_SHORT).show();
}
break;
default:
}
}
}
访问其他程序中的数据
以读取系统联系人为例
public class MainActivity extends AppCompatActivity {
ArrayAdapter<String> adapter;
List<String> contactsList = new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ListView contactsView = (ListView) findViewById(R.id.contacts_view);
adapter = new ArrayAdapter<String>(this, android.R.layout. simple_list_item_1, contactsList);
contactsView.setAdapter(adapter);
if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{ Manifest.permission.READ_CONTACTS }, 1);
} else {
readContacts();
}
}
private void readContacts() {
Cursor cursor = null;
try {
// 查询联系人数据
cursor = getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, null, null, null);
if (cursor != 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);
}
adapter.notifyDataSetChanged();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (cursor != null) {
cursor.close();
}
}
}
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
switch (requestCode) {
case 1:
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
readContacts();
} else {
Toast.makeText(this, "You denied the permission", Toast.LENGTH_SHORT).show();
}
break;
default:
}
}
}
创建自己的内容提供器
需要SQLite支持,所以额外要加上MyDatabaseHelper.java
public class DatabaseProvider extends ContentProvider {
public static final int BOOK_DIR = 0;
public static final int BOOK_ITEM = 1;
public static final int CATEGORY_DIR = 2;
public static final int CATEGORY_ITEM = 3;
public static final String AUTHORITY = "com.example.databasetest.provider";
private static UriMatcher uriMatcher;
private MyDatabaseHelper dbHelper;
static {
uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
uriMatcher.addURI(AUTHORITY, "book", BOOK_DIR);
uriMatcher.addURI(AUTHORITY, "book/#", BOOK_ITEM);
uriMatcher.addURI(AUTHORITY, "category", CATEGORY_DIR);
uriMatcher.addURI(AUTHORITY, "category/#", CATEGORY_ITEM);
}
@Override
public boolean onCreate() {
dbHelper = new MyDatabaseHelper(getContext(), "BookStore.db", null, 2);
return true;
}
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
// 查询数据
SQLiteDatabase db = dbHelper.getReadableDatabase();
Cursor cursor = null;
switch (uriMatcher.match(uri)) {
case BOOK_DIR:
cursor = db.query("Book", projection, selection, selectionArgs, null, null, sortOrder);
break;
case BOOK_ITEM:
String bookId = uri.getPathSegments().get(1);
cursor = db.query("Book", projection, "id = ?", new String[] { bookId }, null, null, sortOrder);
break;
case CATEGORY_DIR:
cursor = db.query("Category", projection, selection, selectionArgs, null, null, sortOrder);
break;
case CATEGORY_ITEM:
String categoryId = uri.getPathSegments().get(1);
cursor = db.query("Category", projection, "id = ?", new String[] { categoryId }, null, null, sortOrder);
break;
default:
break;
}
return cursor;
}
@Override
public Uri insert(Uri uri, ContentValues values) {
// 添加数据
SQLiteDatabase db = dbHelper.getWritableDatabase();
Uri uriReturn = null;
switch (uriMatcher.match(uri)) {
case BOOK_DIR:
case BOOK_ITEM:
long newBookId = db.insert("Book", null, values);
uriReturn = Uri.parse("content://" + AUTHORITY + "/book/" + newBookId);
break;
case CATEGORY_DIR:
case CATEGORY_ITEM:
long newCategoryId = db.insert("Category", null, values);
uriReturn = Uri.parse("content://" + AUTHORITY + "/category/" + newCategoryId);
break;
default:
break;
}
return uriReturn;
}
@Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
// 更新数据
SQLiteDatabase db = dbHelper.getWritableDatabase();
int updatedRows = 0;
switch (uriMatcher.match(uri)) {
case BOOK_DIR:
updatedRows = db.update("Book", values, selection, selectionArgs);
break;
case BOOK_ITEM:
String bookId = uri.getPathSegments().get(1);
updatedRows = db.update("Book", values, "id = ?", new String[] { bookId });
break;
case CATEGORY_DIR:
updatedRows = db.update("Category", values, selection, selectionArgs);
break;
case CATEGORY_ITEM:
String categoryId = uri.getPathSegments().get(1);
updatedRows = db.update("Category", values, "id = ?", new String[] { categoryId });
break;
default:
break;
}
return updatedRows;
}
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
// 删除数据
SQLiteDatabase db = dbHelper.getWritableDatabase();
int deletedRows = 0;
switch (uriMatcher.match(uri)) {
case BOOK_DIR:
deletedRows = db.delete("Book", selection, selectionArgs);
break;
case BOOK_ITEM:
String bookId = uri.getPathSegments().get(1);
deletedRows = db.delete("Book", "id = ?", new String[] { bookId });
break;
case CATEGORY_DIR:
deletedRows = db.delete("Category", selection, selectionArgs);
break;
case CATEGORY_ITEM:
String categoryId = uri.getPathSegments().get(1);
deletedRows = db.delete("Category", "id = ?", new String[] { categoryId });
break;
default:
break;
}
return deletedRows;
}
@Override
public String getType(Uri uri) {
switch (uriMatcher.match(uri)) {
case BOOK_DIR:
return "vnd.android.cursor.dir/vnd.com.example.databasetest. provider.book";
case BOOK_ITEM:
return "vnd.android.cursor.item/vnd.com.example.databasetest. provider.book";
case CATEGORY_DIR:
return "vnd.android.cursor.dir/vnd.com.example.databasetest. provider.category";
case CATEGORY_ITEM:
return "vnd.android.cursor.item/vnd.com.example.databasetest. provider.category";
}
return null;
}
}
public class MainActivity extends AppCompatActivity {
private MyDatabaseHelper dbHelper;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
dbHelper = new MyDatabaseHelper(this, "BookStore.db", null, 2);
Button createDatabase = (Button) findViewById(R.id.create_database);
createDatabase.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dbHelper.getWritableDatabase();
}
});
Button addData = (Button) findViewById(R.id.add_data);
addData.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
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); // 插入第二条数据
}
});
Button updateData = (Button) findViewById(R.id.update_data);
updateData.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
SQLiteDatabase db = dbHelper.getWritableDatabase();
ContentValues values = new ContentValues();
values.put("price", 10.99);
db.update("Book", values, "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 = dbHelper.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 = 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();
}
});
}
}
百度定位
修改AndroidManifest.xml
<meta-data
android:name="com.baidu.lbsapi.API_KEY"
android:value="密钥"/>
<service android:name="com.baidu.location.f" android:enabled="true"
android:process=":remote">
</service>
确定自己的经纬度
public LocationClient mLocationClient;
mLocationClient = new LocationClient(getApplicationContext());
mLocationClient.registerLocationListener(new LocationListener());
private void requestLocation() {
//initLocation();
mLocationClient.start();
}
public class MyLocationListener implements BDLocationListener{
@Override
public void onReceiveLocation(BDLocation location){
//自行发挥
//location.getLatitude();
//location.getLongitude();
}
}
实时更新位置信息、定位模式、看得懂的位置信息
private void initLocation(){
LocationClientOption option = new LocationClientOption();
//设置每隔5秒更新一次
option.setScanSpan(5000);
//设置定位模式为只使用GPS定位。另外两种Hight_Accuracy和Battery_Saving
option.setLocationMode(LocationClientOption.LocationMode.Device_Sensors);
//设置看得懂的位置信息 在MyLocationListener中可以获得其他位置信息,如省市街道等。
option.setIsNeedAddress(true);
mLocationClient.setLocOption(option);
}
@Override
protected void onDestroy() {
super.onDestroy();
mLocationClient.stop(); //停止定位
// mapView.onDestroy();
// baiduMap.setMyLocationEnabled(false);
}
使用百度地图
显示地图
<com.baidu.mapapi.map.MapView
android:id="@+id/bmapView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clickable="true" />
SDKInitiaLizer.initialize(getApplicationContext());
mapView = (MapView)findViewById(R.id.bmapView);
@Override
protected void onResume() {
super.onResume();
mapView.onResume();
}
@Override
protected void onPause() {
super.onPause();
mapView.onPause();
}
@Override
protected void onDestroy() {
// super.onDestroy();
// mLocationClient.stop(); //停止定位
mapView.onDestroy();
// baiduMap.setMyLocationEnabled(false);
}
移动到我的位置
private boolean isFirstLocate = true;
//地图总控制器
BaiduMap baiduMap = mapView.getMap();
baiduMap.setMyLocationEnabled(true);
private void navigateTo(BDLocation location) {
if (isFirstLocate) {
//定位到经纬度
LatLng ll = new LatLng(location.getLatitude(), location.getLongitude());
MapStatusUpdate update = MapStatusUpdateFactory.newLatLng(ll);
baiduMap.animateMapStatus(update);
//缩放
update = MapStatusUpdateFactory.zoomTo(16f);
baiduMap.animateMapStatus(update);
isFirstLocate = false;
}
//让“我”显示在地图上
MyLocationData.Builder locationBuilder = new MyLocationData.
Builder();
locationBuilder.latitude(location.getLatitude());
locationBuilder.longitude(location.getLongitude());
MyLocationData locationData = locationBuilder.build();
baiduMap.setMyLocationData(locationData);
}
public class MyLocationListener implements BDLocationListener {
@Override
public void onReceiveLocation(BDLocation location) {
if (location.getLocType() == BDLocation.TypeGpsLocation
|| location.getLocType() == BDLocation.TypeNetWorkLocation) {
navigateTo(location);
}
}
}
@Override
protected void onDestroy() {
super.onDestroy();
// mLocationClient.stop();
// mapView.onDestroy();
baiduMap.setMyLocationEnabled(false);
}
```
# 使用通知
振动权限
```xml
<uses-permission android:name="android.permission.VIBRATE" />
```
```java
//点击通知可以跳转到NotificationActivity
Intent intent = new Intent(this, NotificationActivity.class);
PendingIntent pi = PendingIntent.getActivity(this, 0, intent, 0);
NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
Notification notification = new NotificationCompat.Builder(this)
.setContentTitle("This is content title")
.setContentText("This is content text")
.setWhen(System.currentTimeMillis())
.setSmallIcon(R.mipmap.ic_launcher)
.setLargeIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher))
.setContentIntent(pi)
.setAutoCancel(true)
.setSound(Uri.fromFile(new File("/system/media/audio/ringtones/Luna.ogg")))
.setVibrate(new long[]{0, 1000, 1000, 1000})
.setLights(Color.GREEN, 1000, 1000)
.setDefaults(NotificationCompat.DEFAULT_ALL)
.setStyle(new NotificationCompat.BigTextStyle().bigText("Learn how to build notifications, send and sync data, and use voice actions. Get the official Android IDE and developer tools to build apps for Android."))
.setStyle(new NotificationCompat.BigPictureStyle().bigPicture(BitmapFactory.decodeResource(getResources(), R.drawable.big_image)))
.setPriority(NotificationCompat.PRIORITY_MAX)
.build();
manager.notify(1, notification); //1是该通知的id号,后面取消通知会用到
```
```java
public class NotificationActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.notification_layout);
NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
manager.cancel(1);
}
}
```
# 调用摄像头和相册
```xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.cameraalbumtest">
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.example.cameraalbumtest.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
</application>
</manifest>
```
```java
public class MainActivity extends AppCompatActivity {
public static final int TAKE_PHOTO = 1;
public static final int CHOOSE_PHOTO = 2;
private ImageView picture;
private Uri imageUri;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button takePhoto = (Button) findViewById(R.id.take_photo);
Button chooseFromAlbum = (Button) findViewById(R.id.choose_from_album);
picture = (ImageView) findViewById(R.id.picture);
takePhoto.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// 创建File对象,用于存储拍照后的图片
File outputImage = new File(getExternalCacheDir(), "output_image.jpg");
try {
if (outputImage.exists()) {
outputImage.delete();
}
outputImage.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
if (Build.VERSION.SDK_INT < 24) {
imageUri = Uri.fromFile(outputImage);
} else {
imageUri = FileProvider.getUriForFile(MainActivity.this, "com.example.cameraalbumtest.fileprovider", outputImage);
}
// 启动相机程序
Intent intent = new Intent("android.media.action.IMAGE_CAPTURE");
intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
startActivityForResult(intent, TAKE_PHOTO);
}
});
chooseFromAlbum.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(MainActivity.this, new String[]{ Manifest.permission. WRITE_EXTERNAL_STORAGE }, 1);
} else {
openAlbum();
}
}
});
}
private void openAlbum() {
Intent intent = new Intent("android.intent.action.GET_CONTENT");
intent.setType("image/*");
startActivityForResult(intent, CHOOSE_PHOTO); // 打开相册
}
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
switch (requestCode) {
case 1:
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
openAlbum();
} else {
Toast.makeText(this, "You denied the permission", Toast.LENGTH_SHORT).show();
}
break;
default:
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
case TAKE_PHOTO:
if (resultCode == RESULT_OK) {
try {
// 将拍摄的照片显示出来
Bitmap bitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(imageUri));
picture.setImageBitmap(bitmap);
} catch (Exception e) {
e.printStackTrace();
}
}
break;
case CHOOSE_PHOTO:
if (resultCode == RESULT_OK) {
// 判断手机系统版本号
if (Build.VERSION.SDK_INT >= 19) {
// 4.4及以上系统使用这个方法处理图片
handleImageOnKitKat(data);
} else {
// 4.4以下系统使用这个方法处理图片
handleImageBeforeKitKat(data);
}
}
break;
default:
break;
}
}
@TargetApi(19)
private void handleImageOnKitKat(Intent data) {
String imagePath = null;
Uri uri = data.getData();
Log.d("TAG", "handleImageOnKitKat: uri is " + uri);
if (DocumentsContract.isDocumentUri(this, uri)) {
// 如果是document类型的Uri,则通过document id处理
String docId = DocumentsContract.getDocumentId(uri);
if("com.android.providers.media.documents".equals(uri.getAuthority())) {
String id = docId.split(":")[1]; // 解析出数字格式的id
String selection = MediaStore.Images.Media._ID + "=" + id;
imagePath = getImagePath(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, selection);
} else if ("com.android.providers.downloads.documents".equals(uri.getAuthority())) {
Uri contentUri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"), Long.valueOf(docId));
imagePath = getImagePath(contentUri, null);
}
} else if ("content".equalsIgnoreCase(uri.getScheme())) {
// 如果是content类型的Uri,则使用普通方式处理
imagePath = getImagePath(uri, null);
} else if ("file".equalsIgnoreCase(uri.getScheme())) {
// 如果是file类型的Uri,直接获取图片路径即可
imagePath = uri.getPath();
}
displayImage(imagePath); // 根据图片路径显示图片
}
private void handleImageBeforeKitKat(Intent data) {
Uri uri = data.getData();
String imagePath = getImagePath(uri, null);
displayImage(imagePath);
}
private String getImagePath(Uri uri, String selection) {
String path = null;
// 通过Uri和selection来获取真实的图片路径
Cursor cursor = getContentResolver().query(uri, null, selection, null, null);
if (cursor != null) {
if (cursor.moveToFirst()) {
path = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA));
}
cursor.close();
}
return path;
}
private void displayImage(String imagePath) {
if (imagePath != null) {
Bitmap bitmap = BitmapFactory.decodeFile(imagePath);
picture.setImageBitmap(bitmap);
} else {
Toast.makeText(this, "failed to get image", Toast.LENGTH_SHORT).show();
}
}
}
```
# 播放多媒体文件
### 播放音频
```java
public class MainActivity extends AppCompatActivity implements View.OnClickListener{
private MediaPlayer mediaPlayer = new MediaPlayer();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button play = (Button) findViewById(R.id.play);
Button pause = (Button) findViewById(R.id.pause);
Button stop = (Button) findViewById(R.id.stop);
play.setOnClickListener(this);
pause.setOnClickListener(this);
stop.setOnClickListener(this);
if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(MainActivity.this, new String[]{ Manifest.permission. WRITE_EXTERNAL_STORAGE }, 1);
} else {
initMediaPlayer(); // 初始化MediaPlayer
}
}
private void initMediaPlayer() {
try {
File file = new File(Environment.getExternalStorageDirectory(), "music.mp3");
mediaPlayer.setDataSource(file.getPath()); // 指定音频文件的路径
mediaPlayer.prepare(); // 让MediaPlayer进入到准备状态
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
switch (requestCode) {
case 1:
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
initMediaPlayer();
} else {
Toast.makeText(this, "拒绝权限将无法使用程序", Toast.LENGTH_SHORT).show();
finish();
}
break;
default:
}
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.play:
if (!mediaPlayer.isPlaying()) {
mediaPlayer.start(); // 开始播放
}
break;
case R.id.pause:
if (mediaPlayer.isPlaying()) {
mediaPlayer.pause(); // 暂停播放
}
break;
case R.id.stop:
if (mediaPlayer.isPlaying()) {
mediaPlayer.reset(); // 停止播放
initMediaPlayer();
}
break;
default:
break;
}
}
@Override
protected void onDestroy() {
super.onDestroy();
if (mediaPlayer != null) {
mediaPlayer.stop();
mediaPlayer.release();
}
}
}
```
### 播放视频
```java
public class MainActivity extends AppCompatActivity implements View.OnClickListener{
private VideoView videoView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
videoView = (VideoView) findViewById(R.id.video_view);
Button play = (Button) findViewById(R.id.play);
Button pause = (Button) findViewById(R.id.pause);
Button replay = (Button) findViewById(R.id.replay);
play.setOnClickListener(this);
pause.setOnClickListener(this);
replay.setOnClickListener(this);
if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(MainActivity.this, new String[]{ Manifest.permission. WRITE_EXTERNAL_STORAGE }, 1);
} else {
initVideoPath(); // 初始化MediaPlayer
}
}
private void initVideoPath() {
File file = new File(Environment.getExternalStorageDirectory(), "movie.mp4");
videoView.setVideoPath(file.getPath()); // 指定视频文件的路径
}
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
switch (requestCode) {
case 1:
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
initVideoPath();
} else {
Toast.makeText(this, "拒绝权限将无法使用程序", Toast.LENGTH_SHORT).show();
finish();
}
break;
default:
}
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.play:
if (!videoView.isPlaying()) {
videoView.start(); // 开始播放
}
break;
case R.id.pause:
if (videoView.isPlaying()) {
videoView.pause(); // 暂停播放
}
break;
case R.id.replay:
if (videoView.isPlaying()) {
videoView.resume(); // 重新播放
}
break;
}
}
@Override
protected void onDestroy() {
super.onDestroy();
if (videoView != null) {
videoView.suspend();
}
}
}
```
# 使用网络技术
### WebView的用法
AndroidManifest.xml:
```xml
<uses-permission android:name="android.permission.INTERNET" />
```
activity_main.xml:
```xml
<WebView
android:id="@+id/web_view"
android:layout_width="match_parent"
android:layout_height="match_parent" />
```
MainActivity.java:
```java
WebView webView = (WebView) findViewById(R.id.web_view);
webView.getSettings().setJavaScriptEnabled(true); //设置支持JavaScript脚本
webView.setWebViewClient(new WebViewClient()); //当需要从一个网页跳转到另一个网页时,网页仍然在当前WebView中显示,而不是打开系统浏览器
webView.loadUrl("http://www.baidu.com");
```
### 使用HTTP协议访问网络
##### 使用HttpURLConnection
不推荐使用HttpClient(API适量过多、扩展困难,在Android 6.0系统中已经被弃用)。
* 从服务器获取数据(GET)
```java
private void sendRequestWithHttpURLConnection() {
// 开启线程来发起网络请求
new Thread(new Runnable() {
@Override
public void run() {
HttpURLConnection connection = null;
BufferedReader reader = null;
try {
URL url = new URL("http://www.baidu.com");
connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
connection.setConnectTimeout(8000);
connection.setReadTimeout(8000);
InputStream in = connection.getInputStream();
// 下面对获取到的输入流进行读取
reader = new BufferedReader(new InputStreamReader(in));
StringBuilder response = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
response.append(line);
}
showResponse(response.toString());
} catch (Exception e) {
e.printStackTrace();
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (connection != null) {
connection.disconnect();
}
}
}
}).start();
}
private void showResponse(final String response) {
//Android不允许在子线程中进行UI操作,因此需要这个方法将线程切换到主线程,然后再更新UI元素
runOnUiThread(new Runnable() {
@Override
public void run() {
// 在这里进行UI操作,将结果显示到界面上
responseText.setText(response);
}
});
}
```
* 提交数据给服务器(POST)(数据之间用“&”符号隔开)
```java
connection.setRequestMethod("POST");
DataOutputStream out = new DataOutputStream(connection.getOutputStream());
out.writeBytes("username=admin&password=123456");
```
##### 使用OkHttp
build.gradle:
```groovy
compile 'com.squareup.okhttp3:okhttp:3.4.1'
```
* 从服务器获取数据
```java
private void sendRequestWithOkHttp() {
new Thread(new Runnable() {
@Override
public void run() {
try {
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
// 指定访问的服务器地址是电脑本机
.url("http://10.0.2.2/get_data.json")
.build();
Response response = client.newCall(request).execute();
String responseData = response.body().string();
//parseJSONWithGSON(responseData);
// parseJSONWithJSONObject(responseData);
// parseXMLWithSAX(responseData);
// parseXMLWithPull(responseData);
// showResponse(responseData);
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
}
```
* 提交数据给服务器
```java
RequestBody requestBody = new FormBody.Builder()
.add("username","admin")
.add("password","123456")
.build();
Request request = new Request.Builder()
.url("http://www.baidu.com")
.post(requestBody)
.build();
```
接下来的操作和GET请求一样,调用excute()方法来发送请求并获取服务器返回的数据即可。
### 解析 XML 格式数据
##### Pull 解析方式
```java
private void parseXMLWithPull(String xmlData) {
try {
XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
XmlPullParser xmlPullParser = factory.newPullParser();
xmlPullParser.setInput(new StringReader(xmlData));
int eventType = xmlPullParser.getEventType();
String id = "";
String name = "";
String version = "";
while (eventType != XmlPullParser.END_DOCUMENT) {
String nodeName = xmlPullParser.getName();
switch (eventType) {
// 开始解析某个结点
case XmlPullParser.START_TAG: {
if ("id".equals(nodeName)) {
id = xmlPullParser.nextText();
} else if ("name".equals(nodeName)) {
name = xmlPullParser.nextText();
} else if ("version".equals(nodeName)) {
version = xmlPullParser.nextText();
}
break;
}
// 完成解析某个结点
case XmlPullParser.END_TAG: {
if ("app".equals(nodeName)) {
Log.d("MainActivity", "id is " + id);
Log.d("MainActivity", "name is " + name);
Log.d("MainActivity", "version is " + version);
}
break;
}
default:
break;
}
eventType = xmlPullParser.next();
}
} catch (Exception e) {
e.printStackTrace();
}
}
```
##### SAX 解析方式
新建一个类继承自DefaultHandler
```java
import android.util.Log;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
public class ContentHandler extends DefaultHandler {
private String nodeName;
private StringBuilder id;
private StringBuilder name;
private StringBuilder version;
@Override
public void startDocument() throws SAXException {
id = new StringBuilder();
name = new StringBuilder();
version = new StringBuilder();
}
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
// 记录当前结点名
nodeName = localName;
}
@Override
public void characters(char[] ch, int start, int length) throws SAXException {
// 根据当前的结点名判断将内容添加到哪一个StringBuilder对象中
if ("id".equals(nodeName)) {
id.append(ch, start, length);
} else if ("name".equals(nodeName)) {
name.append(ch, start, length);
} else if ("version".equals(nodeName)) {
version.append(ch, start, length);
}
}
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
if ("app".equals(localName)) {
Log.d("ContentHandler", "id is " + id.toString().trim());
Log.d("ContentHandler", "name is " + name.toString().trim());
Log.d("ContentHandler", "version is " + version.toString().trim());
// 最后要将StringBuilder清空掉
id.setLength(0);
name.setLength(0);
version.setLength(0);
}
}
@Override
public void endDocument() throws SAXException {
super.endDocument();
}
}
```
MainActivity.java:
```java
private void parseXMLWithSAX(String xmlData) {
try {
SAXParserFactory factory = SAXParserFactory.newInstance();
XMLReader xmlReader = factory.newSAXParser().getXMLReader();
ContentHandler handler = new ContentHandler();
// 将ContentHandler的实例设置到XMLReader中
xmlReader.setContentHandler(handler);
// 开始执行解析
xmlReader.parse(new InputSource(new StringReader(xmlData)));
} catch (Exception e) {
e.printStackTrace();
}
}
```
### 解析 JSON 格式数据
##### 使用 JSONObject
```java
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);
Log.d("MainActivity", "version is " + version);
}
} catch (Exception e) {
e.printStackTrace();
}
}
```
##### 使用 GSON
可以将一段JSON格式的字符串自动映射成一个对象,使用简单。
build.gradle:
```groovy
compile 'com.google.code.gson:gson:2.7'
```
新增一个 App 类:
```java
public class App {
private String id;
private String name;
private String version;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getVersion() {
return version;
}
public void setVersion(String version) {
this.version = version;
}
}
```
MainActivity.java:
```java
private void parseJSONWithGSON(String jsonData) {
Gson gson = new Gson();
List<App> appList = gson.fromJson(jsonData, new TypeToken<List<App>>() {}.getType());
for (App app : appList) {
Log.d("MainActivity", "id is " + app.getId());
Log.d("MainActivity", "name is " + app.getName());
Log.d("MainActivity", "version is " + app.getVersion());
}
}
```
### 网络编程的最佳实践
##### 使用HttpURLConnection
```java
public class HttpUtil {
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();
}
}
```
定义一个回调接口:
```java
public interface HttpCallbackListener {
void onFinish(String response);
void onError(Exception e);
}
```
调用:
```java
HttpUtil.sendHttpRequest("http://www.baidu.com", new HttpCallbackListener() {
@Override
public void onFinish(String response) {
//根据返回内容执行具体的逻辑
String responseData = response;
}
@Override
pubilc void onError(Exception e) {
//异常处理
}
});
```
##### 使用OkHttp更简单
(有自己的回调接口,enqueue中已经开好子线程)
```java
public class HttpUtil {
public static void sendOkHttpRequest(final String address, final okhttp3.Callback callback) {
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url(address)
.build();
client.newCall(request).enqueue(callback);
}
}
```
调用:
```java
HttpUtil.sendOkHttpRequest("http://www.baidu.com", new okhttp3.Callback() {
@Override
public void onResponse(Call call, Response response) throws IOException {
//根据返回内容执行具体的逻辑
String responseData = response.body().string();
}
@Override
pubilc void onFailure(Call call, IOException e) {
//异常处理
}
});
```
# 服务
### 服务是什么
* 服务(Service)是 Android 中实现程序后台运行的解决方案,非常适合去执行那些不需要和用户交互而且还要求长期运行的任务。
* 服务依赖于创建服务时所在的应用程序进程。进程被杀掉,对应的服务停止运行。
* 服务不会自动开启线程,所有代码都是默认运行在主线程当中的。
* 需要在服务的内部手动创建子线程,执行具体的任务,否则主线程有可能阻塞(遇到耗时操作时)。
### Android 多线程编程
##### 线程的基本用法
* 继承方式
```java
class MyThread extends Thread {
@Override
public void run() {
//处理具体的逻辑
}
}
new MyThread().start();
```
* 接口方式
```java
class MyThread implements Runnable {
@Override
public void run() {
//处理具体的逻辑
}
}
MyThread myThread = new MyThread();
new Thread(myThread).start();
```
简单写法:
```java
new Thread(new Runnable() {
@Override
public void run() {
//处理具体的逻辑
}
}).start();
```
##### 在子线程中更新 UI(不允许)
Android 的 UI 是线程不安全的。更新 UI 元素必须在主线程中进行,否则就会出现异常。
有时候必须在子线程里执行耗时任务,然后根据任务的执行结果来更新相应的 UI 控件。
解决方法---异步消息处理机制
```java
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
public static final int UPDATE_TEXT = 1;
private TextView text;
private Handler handler = new Handler() {
public void handleMessage(Message msg) {
switch (msg.what) {
case UPDATE_TEXT:
// 在这里可以进行UI操作
text.setText("Nice to meet you");
break;
default:
break;
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
text = (TextView) findViewById(R.id.text);
Button changeText = (Button) findViewById(R.id.change_text);
changeText.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.change_text:
new Thread(new Runnable() {
@Override
public void run() {
Message message = new Message();
message.what = UPDATE_TEXT;
handler.sendMessage(message); // 将Message对象发送出去
}
}).start();
break;
default:
break;
}
}
}
<div class="se-preview-section-delimiter"></div>
这里并没有在子线程中直接进行 UI 操作。
解析异步消息处理机制
Message:线程之间传递的消息。
Handler:用于发送和处理消息。(sendMessage(message)–>handleMessage())
MessageQueue:消息队列,用于存放所有通过Handler发送的消息。每个线程只有一个 MessageQueue 对象
Looper:是每个线程中 MessageQueue 的管家,调用 Looper 的 loop() 方法后,就会进入到无限循环中,每当发现 MessageQueue 中存在一条消息,就会将它取出,并传递到 Handler 的 handleMessage() 方法中。每个线程只有一个 Looper 对象。
使用 AsyncTask (异步消息处理)
- AsyncTask 是一个抽象类,需要一个子类(如DownloadTask)去继承它。
- 三个泛型参数
- Params
- Progress
- Result
- 需要重写的4个方法
- onPreExecute()
- 界面的初始化操作
- doInBackground(Params…)
- 处理所有的耗时任务,不可进行 UI 操作
- onProgressUpdate(Progress…)
- 进行 UI 操作
- onPostExecute(Result)
- 执行收尾工作,可进行 UI 操作
- 启动任务
new DownloadTask().execute();
<div class="se-preview-section-delimiter"></div>
示例如下:
class DownloadTask extends AsyncTask<Void, Integer, Boolean> {
@Override
protected void onPreExecute() {
progressDialog.show(); //显示进度对话框
}
@Override
protected Boolean doInBackground(Void... params) {
try {
while(true) {
int downloadPercent = doDownload(); //这是一个虚构的方法
publishProgress(downloadPercent);
if(downloadPercent >= 100) {
break;
}
}
} catch(Exception e) {
return true;
}
}
@Override
protected void onProgressUpdate(Integer... values) {
progressDialog.sendMessage("Download" + values[0] + "%");
}
@Override
protected void onPostExecute(Boolean result) {
progressDialog.dismiss();
// 在这里提示下载结果
if(result) {
Toast.makeText(context, "Download succeeded", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(context, "Download failed", Toast.LENGTH_SHORT).show();
}
}
}
服务的基本用法
定义一个服务
借助AS创建。
启动和停止服务—借助 Intent 实现
onCreate() 方法是在服务第一次创建的时候调用的,而 onStartCommand() 方法则在每次启动服务的时候都会调用。 onDestroy() 在服务销毁时调用。
“`
这里并没有在子线程中直接进行 UI 操作。
解析异步消息处理机制
Message:线程之间传递的消息。
Handler:用于发送和处理消息。(sendMessage(message)–>handleMessage())
MessageQueue:消息队列,用于存放所有通过Handler发送的消息。每个线程只有一个 MessageQueue 对象
Looper:是每个线程中 MessageQueue 的管家,调用 Looper 的 loop() 方法后,就会进入到无限循环中,每当发现 MessageQueue 中存在一条消息,就会将它取出,并传递到 Handler 的 handleMessage() 方法中。每个线程只有一个 Looper 对象。
使用 AsyncTask (异步消息处理)
- AsyncTask 是一个抽象类,需要一个子类(如DownloadTask)去继承它。
- 三个泛型参数
- Params
- Progress
- Result
- 需要重写的4个方法
- onPreExecute()
- 界面的初始化操作
- doInBackground(Params…)
- 处理所有的耗时任务,不可进行 UI 操作
- onProgressUpdate(Progress…)
- 进行 UI 操作
- onPostExecute(Result)
- 执行收尾工作,可进行 UI 操作
- 启动任务
“`java
new DownloadTask().execute();