感悟:
每一次学习,都会有新的收获
我相信我看到的奇迹,没有是平白无故产生的,它们是源于环环相扣的逻辑巧妙组合而成。
在调用setContentView()之前,写上下面代码:
requestWindowFeature(Window.FEATURE_NO_TITLE);
隐式里的category和data就像是更精确的过滤器
当启动新的活动时,当前的活动数据如果不加以保存,那么就会丢失掉数据(系统回收)。
这样的用户体验不好,可以通过onSaveInstanceState()
方法来解决这个问题。
相应的,在onCreate(Bundle)
中进行恢复操作。
修改方式:在Manifest.xml的对应activity中添加android:launchMode="standard|singleTop|singleTask|singleInstance"
总结:现在还不是很会用哦,只是知道有这个东西。
技巧:
- 快速找到对应界面的活动(p77):简单的说在基类BaseActivity中设置打印的日志,其继承的类就会响应的打印日志。清晰的说是在基类的onCreate()方法中,使用代码
Log.d("BaseActivity", getClass().getSimpleName())
- 随时随地退出程序(p78):利用集合类对活动进行管理(自己创建ActivityCollector类,添加和删除活动)。
- 启动活动(p80):为每个活动添加一个封装优美的,静态的,清晰的启动方法(传入参数即可启动活动)。
感悟:
从整体到局部,从构架到细节。
match_parent:表示让当前控件的大小和父控件的大小一样
fill_parent:同match_parent
wrap_content:使当前控件的大小正好包含住控件包含的内容--文字,图片等。
为控件添加属性(所有控件均支持),android:visibility="visible|invisible|gone"
visible或者不写:可见,占空间
invisible:不可见,占空间(透明状态)
gone:不可见,不占空间
动态控制可见性:setVisibility(View.VISIBLE|View.INVISIBLE|View.GONE)
效果同xml
另外,可以通过getVisibility()方法获取当前的控件状态
android:layout_gravity
和android:gravity
属性区别:
android:layout_gravity
属性:用于指定该控件在父控件中的对齐方式(可选值:top|bottom|left|right|center|center_vertical|center_horizontal)android:gravity
属性:用于指定文字在控件中的对齐方式(可选值:top|bottom|left|right|center|center_vertical|center_horizontal)RelaviteLayout中的控件,既可以相对于父布局进行定位:
RelaviteLayout中的控件,也可以相对于其他控件进行布局:
RelaviteLayout中的控件,也可以相对于其他控件的边缘进行对齐显示:
其他:
注意1:引用的控件一定要先定义。
注意2:可以在一个控件中使用上面的一个或多个。例如,相对于父布局的“左上”布局,就需要填写两个属性android:layout_alignParentTop="true";android:layout_alignParentLeft="true"
。
android:stretchColumns="1"
,使指定的那一列拉伸,以自动适应屏幕的宽度。(0表示第一列,1表示第二列)需要的元素:
- 数据源
- 单项模板
- 适配器(一般继承自ArrayAdapter,以后会接触到SimpleAdapter等)
优化
其他补充:
感悟
第一遍:不知道自己不知道。
第二遍:知道自己不知道,或不知道自己知道。
第三遍:知道自己知道。
碎片(Fragment)是一种可以嵌入在活动当中的UI片段,它能让程序更加合理和充分地利用大屏幕空间。
下面的参考资料讲的都很不错:
http://blog.csdn.net/guolin_blog/article/details/8881711
http://blog.csdn.net/lmj623565791/article/details/37970961
http://blog.csdn.net/lmj623565791/article/details/37992017
ForLou要点难点:
1. 动态注册(p190)
新建一个类,继承BroadcastReceiver,重写父类的onReceive方法。
自定义的MainActivity中通过Context的registerReceiver(BroadCastReceiver bc,IntentFilter if)方法来注册。
说明:其中参数bc是刚才新建类的实例,参数if是广播发送过来的action值包装成IntentFilter对象。
注意:用完之后需要销毁,在activity的onDestroy()方法中调用unregisterReceiver()方法。
注意:当访问的内容涉及到系统的关键性信息,那么需要在配置文件中配置相应的权限permission(http://developer.android.com/reference/android/Manifest.permission.html )。
注意:应用程序发送的广播是可以被其他应用程序接收到的。跨进程通信。
2. 静态注册
另外:使用静态注册可以达到开机启动的目的。静态注册在程序未启动的时候也可以接收广播。
注意:监听某些广播也是需要声明权限的。
注意:不要在onReceive()中添加过多的逻辑或者任何的耗时操作,因为在广播接收器中是不允许开启线程的(如果运行时间较长,程序会报错)。
应用场合/扮演的角色:打开程序其他组件,例如创建一条状态栏通知,或启动一个服务等。
标准广播
例如在MainActivity中点击按钮时发送广播:
Intent intent = new Intent("com.lyloou.broadcasttest.MY_BROADCAST");//还可以绑定一些数据到Intent中供接收者使用;
sendBroadcast(intent);
有序广播
sendBroadcast(Intent intent)
,有序广播是sendOrderedBroadcast(Intent intent, String receiverPermission)
。(可以参考Context的API文档看更详细内容)
。abortBroadcast();
方法将广播截断,后续的接收器就无法接收到该条广播。(only works with broadcasts sent through Context.sendOrderedBroadcast.
)registerReceiver()
,本地广播使用: LocalBroadcastManager localBroadCastManager = LocalBroadcastManager.getInstance(Context c);
localBroadCastManager.registerReceiver(BroadcastReceiver br, Intent i);
sendBroadcast(intent)
,本地广播使用:localBroadCastManager.sendBroadcast(intent)
在广播接收器写一个弹框(p210)。
从广播接收器中启动活动需要注意的内容(p211):给Intent加入FLAG_ACTIVITY_NEW_TASK标识。
以下三种存储方式均属于本地持久化
文件存储:存储简单的文本数据和二进制数据。
SharePreference存储:存储键值对。
数据库--SQLITE:存储复杂关系型的数据。
核心方法:Context提供的openFileInput()和openFileOutput()方法;
注意:不适用于存储复杂类型的数据。
技巧:
TextUtils.isEmpty(String str);
:如果str为""或者为null,都会返回true
。
EditText.setSelection(str.length());
:将光标至于str最后。
保存数据:
SharedPreferences.Editor editor = sp.edit();
获取数据:
数据库创建后,将不再重新创建,这意味着onCreate只执行一次。除非卸载掉重新安装,另外下一次更改数据库结构的时候可以通过onUpgrade来控制了。
利用ContentValues组件一组数据,通过insert来添加到数据库中。
ContentValues利用键值的方式添加:,
ContentValues contentValues = new ContentValues();
contentValues.put("name", "think in java");
contentValues.put("version", 3);
db.insert("Book", null, contentValues);
利用ContentValues组件一组数据,通过update来添加到数据库中。
ContentValues利用键值的方式更新:,
ContentValues contentValues = new ContentValues();
contentValues.put("version", 4);
db.update("Book", contentValues, "name=?" , new String[]{"think in java"});
获取到db实例后,即可删除
SQLiteDatabase db = dbHelper.getWritableDatabase();
db.delete("Book", "version < ?", new String[]{"4"});
利用db的query方法来得到一个Cursor实例。对Cursor进行取值操作,即可得到想要的值。
cursor.moveToFirst(); 指针移动到第一行;
cursor.moveToNext(); 指针移动到下一个;
Cursor cursor = db.query("Book", null, null, null, null, null, null);
cursor.moveToFirst();
Log.d("LOU",cursor.getString(cursor.getColumnIndex("name")));
Log.d("LOU",cursor.getInt(cursor.getColumnIndex("version")));
cursor.close();
技巧:利用switch来优化数据库升级(p264)。
感悟:
目前所有的工作都是对上api,利用好api。
内容提供器的用法有两种:
Uri:区别于SQLiteDatabase接受的参数“table”,ContentResolver接受的参数是“URI”,要对某程序的数据进行读取和操作,需要制定其Uri。
注意:在每次创建内容提供者的时候,都要提醒自己,是不是真的需要这样做。因为只有真正需要将数据共享出去的时候我们才应该创建内容提供器,仅仅是用于内部程序访问的数据没必要使用内容提供者。
Lou理解:ContentProvider扮演的是程序和程序之间的桥梁角色。A程序规定好自己的哪些数据内容可以访问,并设置好对应的Uri,B程序借助ContentProvider提供器传入A程序规定好的Uri来读取和操作A程序的数据。
在ContentProvider中操作数据库,好像是ContentProvider提供了一个包装,在其内根据传入的Uri来进行具体的数据库操作,对外只需要提供一个接口即可(接口需要有正确的参数,例如Uri,以及过滤条件)。
使用步骤:
NotifictionManager manager = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
Notification notification = new Notification(R.drawable.ic_launcher, "This is ticker text", System.curentTimeMillis());
notification.setLatesEventInfor(this, "This is content title", "This is content text", null);
,其中第四个参数是用来设置点击通知触发的逻辑,用PendingIntent来设定。manager.notify(1, notification);
,其中1是该通知的唯一标志,可以用于之后的取消。取消通知栏的通知:
NotificationManager manager = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
manager.cancel(1); //其中1表示刚才设置的通知唯一标志。
使通知栏的通知可点击
PendingIntent(p302)
notification.setLatesEvenInfor()
的第四个参数以实现点击通知的逻辑(启动一个Activity,发送一条广播,启动某个服务等等)。通知的其他内容(p305)
Uri soundUri = Uri.fromFile(new File("/system/media/audio/ringtones/Basic_tone.ogg"));
notification.sound = sounUri;
添加振动:
long[] vibrates = {0, 1000, 1000, 1000};
notification.vibrate = vibrates;
//需要添加权限
添加LED通知
notification.ledARGB = Color.GREEN;
notification.ledOnMS = 1000;
notification.ledOffMS = 1000;
notification.flags = Notification.FLAG_SHOW_LIGHTS;
设置默认通知类型:
notification.defaults = Notification.DEFAUT_ALL
扩展:
点亮屏幕
Handler(p348)
handler.handleMessage(msg);
)AsyncTask(p349)
常用的方法(重写)
执行方式:new MyAsyncTask().execute();
间接继承自Context
两种创建服务的路径:
我们完全有可能读一个服务既调用了startService()方法,有调用了bindService()方法。这种情况如何销毁服务?需要同时调用stopService()(或者stopself())和unBindService()方法才行。(p364)
stopself()可以在MyService的任何位置调用,以停止服务。
*stopService()跟startService()一样,需要根据传入的参数来确定stop哪个服务。
Intent stopIntent = new Intent(this, MyService.class);
stopService(stopIntent);
需要在Manifest中注册服务。
通过bindService的方式创建的服务,可以更方便的控制它。
IntentService,一个异步的,可以自动停止的服务。(p367)。在重写的方法onHandleIntent()里的操作,就相当于在Handler.handleMessage()里的操作一样(查看IntentService的源码)。
学习资料:
http://www.cnblogs.com/mengdd/archive/2013/03/24/2979944.html
http://www.cnblogs.com/mengdd/archive/2013/03/24/2979903.html
http://www.cnblogs.com/yejiurui/p/3429451.html
get数据
private void sendRequestWithHttpURLConnection(){
new Thread(
@Override
public void run(){
HttpURLConnection connection = null;
try{
URL url = new URL("http://www.baidu.com");
connection = (HttpURLConnection)url.openConnection();
// Get表示希望从服务器获取数据;Post表示希望提交数据给服务器
connection.setRequestMethod("GET");
// 设置连接超时
connection.setConnectionTimeout(8000);
// 设置读取超时
connection.setReadTimeout(8000);
// 获取输入流
InputStream in = connection.getInputStream();
// 对输入流进行读取操作
BufferReader reader = new BufferReader(new InputStreamReader(in));
StringBuilder response = new StringBuilder();
String line;
while((line=reader.readline()) != null){
response.append(line);
}
// 将结果返回
Message msg = new Message();
msg.what = 1;
msg.obj = response.toString();
handler.sendMessage(msg);
} catch(Exception e) {
e.printStackTrace();
} finally {
if(connection != null){
connection.disconnect();
}
}
}
).start();
}
post数据
// 获取输出流并写出数据。
DataOutputStream out = new DataOutputStream (connection.getOutputStream());
out.writeBytes("username=admin&password=123456");
get数据
private void sendRequestWithHttpClient(){
new Thread(
@Override
public void run(){
HttpClient httpClient = null;
try{
httpClient = new DefaultHttpClient();
HttpGet httpGet = new HttpGet("http://www.baidu.com");
HttpResponse httpResponse = httpClient.execute(httpGet);
if(httpResponse.getStatusLine().getStatusCode() == 200) {
HttpEntity entity = httpResponse.getEntity();
String response = EntityUtils.toString(entity, "utf-8"); // 将entity转换为字符串,并指定字符集编码
// 将结果返回
Message msg = new Message();
msg.what = 1;
msg.obj = response.toString();
handler.sendMessage(msg);
}
} catch(Exception e) {
e.printStackTrace();
} finally {
if(client != null){
client.disconnect();
}
}
}
).start();
}
post数据
HttpPost httpPost = new HttpPost("http://www.baidu.com");
List<NameValuePair> params = new ArrayList<NameValuePair>();
params.add(new BasicNameValuePair("username", "admin"));
params.add(new BasicNameValuePair("password", "123456"));
UrlEncodedFormEntity entity = new UrlEncodedFormEntity(param, "utf-8");
httpPost.setEntity(entity);
HttpResponse httpResponse = httpClient.execute(httpPost);
public interface HttpCallbackListener{
void onFinish(String response);
void onError(Exception e);
}
......
private void sendRequest(final String address, final HttpCallbackListener listener){
new Thread(
@Override
public void run(){
HttpURLConnection connection = null;
try{
URL url = new URL(address);
connection = (HttpURLConnection)url.openConnection();
// Get表示希望从服务器获取数据;Post表示希望提交数据给服务器
connection.setRequestMethod("GET");
// 设置连接超时
connection.setConnectionTimeout(8000);
// 设置读取超时
connection.setReadTimeout(8000);
// 获取输入流
InputStream in = connection.getInputStream();
// 对输入流进行读取操作
BufferReader reader = new BufferReader(new InputStreamReader(in));
StringBuilder response = new StringBuilder();
String line;
while((line=reader.readline()) != null){
response.append(line);
}
// 将结果回调到参数中去处理,而不是return的方式返回数据(return的数据可能因为主线程先执行完而不能接受到,而通过参数就一定会执行了)。
if( listener != null){
listener.onFinish(response.toString());
}
} catch(Exception e) {
if( listener != null){
listener.onError(e);
}
} finally {
if(connection != null){
connection.disconnect();
}
}
}
).start();
}
1
Google Maps
1.0
2
Chrome
1.0
3
Google Play
2.3
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();
}
}
private void parseXMLWithSAX(String xmlData){
try{
SAXParserFactory factory = SAXParserFactory.newInstance();
XMLReader xmlReader = factory.newSAXParser().getXMLReader();
ContentHandler contentHandler = new ContentHandler();
xmlReader.setContentHandler(contentHandler);
xmlReader.parse(new InputSource(new StringReader(xmlData)));
} catch (Exception e) {
e.printStackTrace();
}
}
......
public class ContentHandler extend DefaultHandler{
private String nodeName;
private StringBuilder id;
private StringBuilder name;
private StringBuilder version;
// startDocument会在开始XML解析的时候调用
@Override
public void startDocument() throws SAXException{
id = new StringBuilder();
name = new StringBuilder();
version = new StringBuilder();
}
// startElement会在解析某个节点的时候调用
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException{
nodeName = localName;
}
// characters会在获取节点内容的时候调用,可能会调用多次,需要对澶蠕动char进行控制
@Override
public void characters(char[] ch, int start, int length) throws SAXException{
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);
}
}
// endElement会在完成解析某个节点的时候调用
@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());
// 清空还原数据
id.setLength(0);
name.setLength(0);
version.setLength(0);
}
}
// endDocument会在完成解析XML的时候调用
@Override
public void endDocument() throws SAXException{
Log.d("ContentHandler", "completed!!!"");
}
}
[
{"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"},
]
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 version = jsonObject.getString("version");
String name = jsonObject.getString("name");
Log.d("MainActivity", "id is " + id);
Log.d("MainActivity", "version is " + version);
Log.d("MainActivity", "name is " + name);
}
} catch (Exception e) {
e.printStackTrace();
}
}
class App{
private int id;
private String name;
private String version;
public void setId(int id){
this.id = id;
}
public void setName(String name){
this.name = name;
}
public void setVersion(String version){
this.version = version;
}
public int getId(){
return this.id;
}
public String getName(){
return this.name;
}
public String getVersion(){
return this.version;
}
}
......
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());
}
}