douban笔记

网络相关的客户端程序:(这其实是最多的一种)

1.新浪微博
2.人人网客户端
3.网易新闻
4.故事会

流程:
1.我们需要了解服务器返回数据的接口(一个非常宽泛的概念)信息.
例如:一个网络地址  , 定义了版本号 定义新版本的地址 


2.解析接口返回的数据.


3.把数据显示到界面.


用户登陆的流程.

1.提供界面让用户可以登陆到服务器上,完成用户身份的认证
2.提供一种身份,会话维持的技术, 识别当前登陆用户的身份状态.

WEB中的。
session 会话的id来识别用户.
cookie  本地硬盘上文件



android oauth认证技术.识别当前的请求来自于哪一个用户。


优米客户端的需求文档
iphone下的文档.

如果我一个iphone应用 移植到android.

1.查看iphone是怎么获取数据的 http://xxx.xxx.xxx.xx/pingdaoxinxi.xml
2.解析xml文件
3.显示到界面上.



关于从服务器上下载数据的操作有很多种:
1.解析xml
2.json
3.html 解析html的标签



02-29 01:39:42.147: INFO/ActivityManager(59): Starting activity: Intent { act=android.intent.action.MAIN cmp=com.android.settings/.WirelessSettings }



selector选择器 





merge 合并 合体操作

 
通过include的标签把定义的merge标签的内容引入到layout界面 



开放平台:

网站 暴露出来一个webservice.  
游戏大厅, 提供了一些接口.

web游戏 qq偷菜

广义讲 windows操作系统 也是一个开放平台.

核心的api暴露 windows api

android os 


豆瓣网站 社交开放式平台
新浪微博
人人网 
豆瓣API是豆瓣为第三方开发人员提供的编程接口。
利用豆瓣API,你可以在你的网站或程序中使用豆瓣的数据和功能


什么是服务器的接口 什么是服务器提供的api?

http://api.douban.com/book/subject/1220562 webservice

客户端通过接口访问服务器的数据 json xml html 

实际上的操作
1.url
2.url 获取到一个urlconntection;
3.获取到服务器返回回来的具体数据信息
4.解析我们关心的内容
5.显示界面



使用开放平台的api 第一步
需要申请一个api使用key文件 
为了保护豆瓣用户的数据;防止API被滥用或恶意使用,豆瓣要求每个API的使用者申请一个API Key, 而每个API Key唯一标识一个API使用者. 


黑客, 抓取人人网数据的操作.
服务器根据api 的key 可以把你的客户端的请求给禁用.



你的豆瓣 API key:

0c51c1ba21ad8cfd24f5452e6508a6f7
API key 的详细信息   · · · · · · 

私钥:359e16e5e5c62b6e -请保护好你的私钥
应用名称:黑马小瓣瓣
创建时间: 2012-02-29
应用说明:
这个应用帮助用户快速访问豆瓣的数据,发豆瓣消息,写日记.


commons-codec-1.3.jar  公用的工具类 
commons-httpclient-3.1.jar httpclient http请求
commons-logging-1.1.jar  日志的输出
c3p0 jdbc 
douban-java-0.2.2-r34.jar 获取服务器数据 xml 格式 解析xml格式数据
gdata-client-1.0.jar
gdata-core-1.0.jar google提供的解析xml的工具 

oauth-1.3.jar 用户身份认证的jar包 
oauth认证的操作 




通过qq号登陆京东网
http://fanli.qq.com/fanli_connect/qq_login.php?mall_id=360buy&mall_cb=http%3A%2F%2Fwww.360buy.com&url=http%3A%2F%2Fqq.360buy.com%2Fnew%2Fqq%2Fcallback.aspx&ts=20120229115122&flag=&forcelogin=1&vkey=87db3016f3f98dc6ac5b4168dfe17148

这个页面的服务器是在那一个公司? 

顶级域名 qq.com 
二级域名 fanli.qq.com


http://www.ccb.yinhang.com
.org
.com.cn
.us

http://www.ccb.yinhang.com

www.ccb.hah6.com


xxc.ccb.com
icbc.com


//得到了豆瓣后门的钥匙 

83e32a78f6148aa28ba97f6ae23d9fe6
ab31cb1271593021

83e32a78f6148aa28ba97f6ae23d9fe6
ab31cb1271593021



特点:一旦我们用户第一次授权完毕后.

如果用户不取消授权 ,accesstoken 和 tokensecret不会发生改变 
9644556d2ba3cabdc2cd004782eb6037
c78f514836b98fed



302 重定向.



jericho-html-3.1.jar  html的解析包 
对html进行面向对象的封装.


剖析ResourceType下的所有东西。

layer-list显然是一个图层的列表,作用就是一层一层的按照顺序叠加图片。
参看:http://blog.csdn.net/chenlaic/article/details/6089989
1.可以将多个图片按照顺序层叠起来
2.在drawable下建立一个xml文件
  
  
    
       
    
       
  


每个item里面是一个图片,不过这个图片可以是png,jpg,gif也可以是我们用XML定义的图片。


    
    
        
            
        
    

这个图层里面只有一张图片,其实也可以不这样做,可以直接用一个shape.
我们看到这张图片是一个shape,图片里面表示渐变色,它就是一个长高均为一的正方形,
这个正方形有渐变色,然后作为了一个背景图片,不过在作为背景的时间,引用它的
那个控件是填充父窗体的的,所以它会变成一个充满屏幕的矩形,那么渐变的色彩也会明显很多 。
调用: android:background="@drawable/home_gradient"
 
 





有一个绝招,当你的系统想要进入系统的某个设置界面,但是又不知道
相应的activity,那么你可这样做,点击进入它,然后看打印出来的信息。

自定义对话框:(所有的布局呢都是自己写的,直接用的是Dialog)


dialog = new Dialog(this,R.style.MyDialog);
//使用这种方式,不可以得到这个View对象 ,不能获得里面的值,所以还是要吹起来。
//dialog.setContentView(R.layout.first_entry_dialog);
//这将是最简单的一种方法,至此把XML转换成View对象已有三种方法
View view = View.inflate(this, R.layout.first_entry_dialog, null);
edp1 = (EditText) view.findViewById(R.id.et_first_entry_pwd);
edp2 = (EditText) view.findViewById(R.id.et_first_entry_pwd_confirm);
Button ok = (Button) view.findViewById(R.id.bt_first_dialog_ok);
Button cancel = (Button) view.findViewById(R.id.bt_first_dialog_cancle);
ok.setOnClickListener(this);
cancel.setOnClickListener(this);
dialog.setContentView(view);
dialog.show();


//延时两秒进入new Handler().postDelayed(r, delayMillis)  //通过handler 延时2秒 执行r任务 
new Handler().postDelayed(new LoadMainTabTask(), 2000);


	/**
	 * 得到网络状态 
	 */
	public boolean isNetWorkConnected(){
		ConnectivityManager manager = (ConnectivityManager) getSystemService(CONNECTIVITY_SERVICE);
		NetworkInfo info = manager.getActiveNetworkInfo();
		
		//判断是wifi连接 还是 无线连接
//		WifiManager wifiManager = (WifiManager) getSystemService(WIFI_SERVICE);
//		wifiManager.isWifiEnabled();
//		wifiManager.getWifiState();
		
		return (info!=null&&info.isConnected());//操,这个比三元表达式更牛逼。
//		return (info!=null&&info.isConnected())?true:false;
	}
最常用的tabhost.
其实它默认是在上面的。你想要让它在哪,要自己再定位。

tabhost这种东西默认的很难看,一般都自定义的。
selector是定义的一上东西在不同状态下的背景。

FitXY.

include merg两个标签 。

如果listview你不指定cacheColorHint="#0000000"
你点击的时间会显示出默认的颜色,所以把它改成透明的。
还有一个listSelector,当你选中的某个条目的时间要显示的颜色,
这次终于明白了。这两个listview下参数的含义。
还有一个divider这个表示每个条目之间的填充物。

tabhost:明白哪个是TabWidget哪个是tabcontent

一个重要的问题,有多个页面用到了同一个东西,跟JSP中一样,可以include过来。
让它作为一个单独的东西。
它表示
它是要被合并的。
在用的地方:    





author:就是因为不信任才产生的,你不信任360,
你可以用QQ登陆,然后腾讯的服务器返回一个结果,
然后360用这个作为你登陆的凭证。
它每次请求都要
4a73c256be235a29df5b47043a6a0e7b
9dcf2bfa571799e2

登陆界面在最外层做一个ScrollView,这样做屏幕适配就非常的好。

找个那个解析HMTLjar包的API。

progressbar通常是在线程里面start,在handler里面dismiss;.

此属性意思是此视图是否显示,例如RelativeLayout中android:visibility="gone"
其有三个属性:visible显示;invisible显示黑背景条;gone不显示(不占空间)
在类中,可以设置其显示与否,setVisibility(View.GONE);不显示 
setVisibility(View.VISIBLE);显示
xml中是visible
代码中是visibility 

我发现了做WEB就是看HTTP协议和服务器返回的源码,然后我们对源码进行解析和封装。

既然你发现很多是一样的,所以要抽取出来。

之前我们在线程启动之前开个progressbar,子线程结束后,
发个消息告诉主线程,把那个progressbar关了,然后结束。

异步从网络下载操作,下载完毕自动放到页面中。太厉害了。非常常见的操作。
要做初始化和扫尾工作,但是它并不知道要怎么做,让调用者来做。
所以弄一个实现了该接口的对象给传进来。
其实就是调用者为了用这两个方法,我们必须把它给抽象出来,然后
通过构造函数把这个接口的实现给传递过来,那么调用 者就可以调用
接口里面的方法了。

异步加载过来,其实就是先把整个页面给展现出来,然后图片在自己在
后台下载,后台下载完毕后自动显示出来,绝大部分都是这样做的。
这是一个可以共用的图片异步下载方法。
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;

/**
 *
 * 第一个参数 就是图片下载路径的url
 * 第二个参数是 下载的进度 
 * 第三个参数就是异步任务执行完毕后的返回值
 * @author Administrator
 *
 */
public class LoadImageAsynTask extends AsyncTask {
	LoadImageAsynTaskCallback loadImageAsynTaskCallback;
	
	
	
	public LoadImageAsynTask(LoadImageAsynTaskCallback loadImageAsynTaskCallback) {
		this.loadImageAsynTaskCallback = loadImageAsynTaskCallback;
	}

	public interface LoadImageAsynTaskCallback{
	   public void	beforeLoadImage();
	   public void afterLoadImage(Bitmap bitmap);
	}

	/**
	 * 当异步任务执行之前调用
	 */
	@Override
	protected void onPreExecute() {
		//初始化的操作具体怎么去实现, LoadImageAsynTask 不知道
		// 需要让调用这个 LoadImageAsynTask 的人 去实现 
		loadImageAsynTaskCallback.beforeLoadImage();
		super.onPreExecute();
	}

	/**
	 * 异步任务执行之后调用
	 */
	@Override
	protected void onPostExecute(Bitmap result) {
		loadImageAsynTaskCallback.afterLoadImage(result);
		super.onPostExecute(result);
	}

	/**
	 * 后台子线程运行的异步任务 
	 * String... params 可变长度的参数 
	 */
	@Override
	protected Bitmap doInBackground(String... params) {
		try {
			String path = params[0];
			URL url = new URL(path);
			HttpURLConnection conn =  (HttpURLConnection) url.openConnection();
			InputStream is = conn.getInputStream();
			return  BitmapFactory.decodeStream(is);
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
		
	}

}

这也是一个经典的异步,第一个先把页面加载过来,加载完成之后,再去加载图片。是不是很牛逼。 
 @Override
	public void fillData() {
		new AsyncTask(){
			//onPreExecute 在异步任务执行之前调用的方法 
			// 运行在主线程里面的 
			// 初始化ui的操作
			@Override
			protected void onPreExecute() {
				showLoading();
				super.onPreExecute();
			};
			// onPostExecute 在异步任务(后台任务)执行之后调用的方法 
			// 运行在ui线程中 , 
			@Override
			protected void onPostExecute(Void result) {
				hideLoading();
				super.onPostExecute(result);
				tv_info.setText(content);
				tv_location.setText(location);
				tv_name.setText(name);
				//设置用户的头像 ,这个是自定义实现的,其实那些系统的对话框这些东西也是这样实现的。
				LoadImageAsynTask loadImageAsynTask = new LoadImageAsynTask(new LoadImageAsynTaskCallback() {
					@Override
					public void beforeLoadImage() {
						iv_icon.setImageResource(R.drawable.ic_launcher);
						
					}
					
					@Override
					public void afterLoadImage(Bitmap bitmap) {
						if (bitmap!=null) {
							iv_icon.setImageBitmap(bitmap);
						}else{
							iv_icon.setImageResource(R.drawable.ic_launcher);
						}
						
					}
				});
				loadImageAsynTask.execute(iconurl);
			};
			// doInBackground 后台执行的任务 
			// 方法运行在一个子线程当中 
			@Override
			protected Void doInBackground(Void... params) {
				// 执行耗时的操作 
				try {
					UserEntry ue = doubanService.getAuthorizedUser();
					name = ue.getTitle().getPlainText();
					location = ue.getLocation();
					content = ((TextContent) ue.getContent()).getContent().getPlainText();
					for (Link link : ue.getLinks()) {
						if ("icon".equals(link.getRel())) {
							System.out.println("图片 。"+link.getHref());
							iconurl = link.getHref();
						}
					}
				} catch (Exception e) {
					e.printStackTrace();
				} 
				
				return null;
			}
			
		}.execute();
	}

那些 listview中,不可能每次读取一次就从网络下载一次 ,肯定是要缓存起来。如果在缓存中就用缓存中的,
如果不在,就重新下载。

通过构造方法和成员变量配合的传值是一种传值的非常重要的手段。

1、异步加载图片,非常重要。
2、加载过的图片存在SD卡上,直接用缓存,十分重要。
3、可以不用2,用更好的方法,软引用,不会增加用户的SD卡负担。


为了不每次从互联网上下载图片,而是从缓存中读取,有几种方法。
1、存到SD卡上。
2、在java里面还有一种引用类型,叫做软引用,它是在java虚拟机的层面保证
java虚拟机会尽量长时间的保留引用的对象。
当java虚拟机发现内存不足的时侯,才去回收软件软引用的对象。
我们可以使用软件引用的对象做内存缓存。
软件引用对象其实是一个容器,包装类。
key:是图片的URL
value:是一个软引用类型的bitmap
//软引用 
Map> iconCache;
//初始化内存缓存 
iconCache = new HashMap>();
//第二种方法:把图片存储到内存缓存里面,把bitmap的软件引用存储到map集合里面。
iconCache.put(iconname, new SoftReference(bitmap));

如果listview数据量很大10万条。
1、分页加载,每个页面显示的条目都一样多。
2、分批加载。

当滚动到最下方,并且静止的时间再加载五条,所以
就是加一个滚动的监听事件。

如果有人问,10000条数据怎么办?
1、分批,分页加载。
2、如果每个条目中有大对象,异步加载,然后把大对象存储到软件引用中。
3、如果引用的内存溢出,写一个类继承application.
软引用当内存不足的时间先给清空,如果把所有的软引用清空后,
还显示内存不足的时间,才会爆出内存不足的错误。
待做?
public class MyApp extends Application{

	/**
	 * 当内存不足的时间调用这个方法。
	 */
	@Override
	public void onLowMemory() {
		super.onLowMemory();
		// 发送一些广播 关闭掉一些activity service 
		Intent intent = new Intent();
		intent.setAction("kill_activity_action");
		sendBroadcast(intent);
	}

}
然后在相应的activity里面写广播接收者的类,并为其注册,在相应的方法里面处理。
这个方法是onScrollStateChanged拖住滑动。

/**
 * 在代码中注册的广播接收者话,你要在destory方法里面把广播接收者
 * 反注册掉。否则会报错。
 */
@Override
protected void onDestroy() {
	super.onDestroy();
	unregisterReceiver(receiver);
}

虽然分批加载可以在一定程序上解决大数据量问题,不过
加载过多还是会产生内存溢出问题。
分页获取数据?
分页原理:指定每一个页面显示的最大数目,每个页面最多
显示内容为100条。


book movie music等。

为什么这种分页不是很好呢?因为我们API没有提供这种方法 
第二,当这个listview中某个条目为空的时间可以用
setEmptyView()去填充,例如用某个图片等。

上下文菜单:
先在主UI里面注册
registerForContextMenu(subjectlist);
/**
 * 创建菜单 
 */
@Override
public void onCreateContextMenu(ContextMenu menu, View v,
		ContextMenuInfo menuInfo) {
	super.onCreateContextMenu(menu, v, menuInfo);
	MenuInflater inflater = getMenuInflater();
	inflater.inflate(R.menu.context_menu, menu);
}
/**
 * 监听菜单
 */
@Override
public boolean onContextItemSelected(MenuItem item) {
	AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo();
	int position = (int) info.id;
	Note note = (Note) subjectlist.getItemAtPosition(position);
	NoteEntry entry = note.getNoteEntry();
	switch (item.getItemId()) {
	case R.id.menu_add_note:
		
		return true;
	case R.id.menu_delete_note://删除也是一个耗时的操作。
		deleteNote(entry);
		return true;

	case R.id.menu_edit_note:
		return true;
	}
	return super.onContextItemSelected(item);
}



    
    

    
    

    
    


1. AsyncTask的三个泛型参数说明(三个参数可以是任何类型) 
2.    第一个参数:传入doInBackground()方法的参数类型 
3.    第二个参数:传入onProgressUpdate()方法的参数类型 
4.    第三个参数:传入onPostExecute()方法的参数类型,也是doInBackground()方法返回的类型。
execute的参数类型是这个任务要接受的参数,也就是doInBackground执行的参数,这个类型与第一个类型
是一致的,如果这个任务的执行不需要参数,可以为空。
private void deleteNote(NoteEntry entry) {
	new AsyncTask() {
		@Override
		protected void onPostExecute(Boolean result) {
			pd.dismiss();
			if (result) {
				fillData();
			}else {
				showToast("删除日记失败");
			}
			super.onPostExecute(result);
		}

		@Override
		protected void onPreExecute() {
			pd = new ProgressDialog(MyNoteActivity.this);
			pd.setTitle("正在删除日记");
			pd.show();
			super.onPreExecute();
		}
		@Override
		protected Boolean doInBackground(NoteEntry... params) {
			try {
				doubanService.deleteNote(params[0]);
				return true;
			} catch (Exception e) {
				e.printStackTrace();
				return false;
			} 
		}
	}.execute(entry);
	
}

新增成功之后 ,finish当前的activity,返回到列表页面的时间,自动让这条日记新增出来
,很明显,在那个页面要setResult(200);然后在列表页面重写onActivityResult方法,让它重新
获取数据即可。

编辑日记是一个非常好的操作。
第一,它用到了不同的请求码去对应同一个页面。
第二,更新时间如何把日记给传过去 。有两种方法,一种是
放在Bundle中,另外一种是放在全局的app中。

case R.id.menu_edit_note:
	Intent editIntent = new Intent(MyNoteActivity.this,NewNoteActivity.class);
	editIntent.putExtra("iseditnote", true);//用来区别是更新还是新增。
	//把数据放到全局里面,那边好取。
	MyApp myApp = (MyApp) getApplication();
	myApp.note = note;
	//需要告诉NewNoteActivity操作这是一个编辑日记的操作。
	startActivityForResult(editIntent, EDIT_NOTE);
return true;
取:
boolean flag = getIntent().getBooleanExtra("iseditnote", false);
if (false) {
	// 编辑日记  从全局中取数据
	MyApp myApp = (MyApp) getApplication();
	Note  note = myApp.note;
	EditTextTitle.setText(note.getTitle());
	EditTextContent.setText(note.getContent());
	.........
}else {
	// 新日记
}

我的错误,写完Application后,一定要在配置文件里面注册,否则会爆出类型转换异常。


程序中的异常处理?十分重要,在面试中可以大说,特说的东西。
打开之后突然不见了,就是这些捕获的异常。UncaughtExceptionHandler
这个是十分重要的,如果出现异常,程序会自动退出,并且把错误的所有信息
发送到服务器上,让工程师去解决。

Build这个类里面有你手机的固件信息。

通过解析HTML数据获取我们需要的内容。
一淘网,抓取各种购物网站的同种商品。这是在别人没有开放网络接口的时间
获取别人的数据,它是从HTML里面直接获取的。
用jericho-html-3.1jar包。
这个东西是自己先分析别人的HTML,然后用J2SE项目调试。
看一它相关的资料和文档。
http://jericho.htmlparser.net/docs/javadoc/index.html
/**
	 * Html解析 获取新书数据 
	 * @param context
	 * @return
	 * @throws Exception
	 */
	public static List getNewBooks(Context context ) throws Exception{
		String path =context.getResources().getString(R.string.newbookpath);
		URL url = new URL(path);
		URLConnection conn = url.openConnection();
		Source source = new Source(conn);
		List newbooks = new ArrayList();
		List  lielements  = source.getAllElements("li");
		System.out.println(lielements.size());
		for(Element lielement : lielements){
			List childrenlists = lielement.getChildElements();
			if(childrenlists.size()==2){
			
			  if("detail-frame".equals(childrenlists.get(0).getAttributeValue("class"))){
				  NewBook newbook = new NewBook();
				  //数目对应的div信息 
				  Element div = childrenlists.get(0);
				  List divChildren = div.getChildElements();
				  String name = divChildren.get(0).getTextExtractor().toString();
				  newbook.setName(name);
				  String description = divChildren.get(1).getTextExtractor().toString();
				  newbook.setDescription(description);
				  String summary = divChildren.get(2).getTextExtractor().toString();
				  newbook.setSummary(summary);
				
				  Element achild = childrenlists.get(1);
				  String iconpath = achild.getChildElements().get(0).getAttributeValue("src");
				  newbook.setIconpath(iconpath);
				  newbooks.add(newbook);
			  }
				
			}
			
		}
		return newbooks;
	}

十分重要的问题,出现图片乱跳的现象?
虽然使用listview的缓存,很简单,效率高,不过
由于它缓存了历史的view对象,不过,当你的图片
是异步下载的时间会出现跳图片的现象,因为缓存了
图片,会出现新的条目一直显示老的图片,并且一直在
与新的图片切换。
其实浪费时间的操作都在View.inflate这个方法的操作上。
我们在布局里面把imageview干掉,在代码里面生成
我们自己定义的imageview就不会再被listview缓存。


PreferenceActivity可以直接用它。
配置信息的页面这样用。其实在系统的设置里面其实都是用的这个activity.
参看项目中的代码 。只要记住Setting里面基本用的都是PreferenceActivity。

在线格式化JSON格式 。
每一个大括号是一个JSON对象----JSONObject
每一个中括号叫一个JSON数组----JSONArray.
{}JSON对象里面的内容,必须是键值对的形式,如果不是就是产生JSONException.


    
	
导入代码问题:


你可能感兴趣的:(douban)