1.抽取到BaseFragment


1.把共性代码提取出来---各方法的注释见第一天代码


(1)每个界面都有4种界面,5种状态


public static final int STATE_UNKOWN = 0;
	public static final int STATE_LOADING = 1;
	public static final int STATE_ERROR = 2;
	public static final int STATE_EMPTY = 3;
	public static final int STATE_SUCCESS = 4;
	public static int state = STATE_UNKOWN;
	
	private View loadingView;// 加载中的界面
	private View errorView;// 错误界面
	private View emptyView;// 空界面
	private View successView;// 加载成功的界面
	private FrameLayout frameLayout;



(2)每个界面都有一个Fraglayout帧布局


public View onCreateView(LayoutInflater inflater, ViewGroup container,
			Bundle savedInstanceState) {
		if(frameLayout==null){
		frameLayout = new FrameLayout(getActivity());
		init(); // 在FrameLayout中 添加4种不同的界面
		}else{
			ViewUtils.removeParent(frameLayout);// 移除frameLayout之前的爹
		}

		// showPage();// 根据不同的状态显示不同的界面
		show();// 根据服务器的数据 切换状态

		return frameLayout;

	}



(3)init方法


// 添加4种不同界面
	private void init() {
		loadingView = createLoadingView(); // 创建了加载中的界面
		if (loadingView != null) {
			frameLayout.addView(loadingView, new FrameLayout.LayoutParams(
					LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
		}
		errorView = createErrorView(); // 加载错误界面
		if (errorView != null) {
			frameLayout.addView(errorView, new FrameLayout.LayoutParams(
					LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
		}
		emptyView = createEmptyView(); // 加载空的界面
		if (emptyView != null) {
			frameLayout.addView(emptyView, new FrameLayout.LayoutParams(
					LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
		}
		
		showPage();// 根据不同的状态显示不同的界面
	}



(4)showPager方法


// 根据不同的状态显示不同的界面
	private void showPage() {
		if (loadingView != null) {
			loadingView.setVisibility(state == STATE_UNKOWN
					|| state == STATE_LOADING ? View.VISIBLE : View.INVISIBLE);
		}
		if (errorView != null) {
			errorView.setVisibility(state == STATE_ERROR ? View.VISIBLE
					: View.INVISIBLE);
		}
		if (emptyView != null) {
			emptyView.setVisibility(state == STATE_EMPTY ? View.VISIBLE
					: View.INVISIBLE);
		}
		if (state == STATE_SUCCESS) {
			successView = createSuccessView();
			if (successView != null) {
				frameLayout.addView(successView, new FrameLayout.LayoutParams(
						LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
				successView.setVisibility(View.VISIBLE);
			}
		}
	}



(5)创建界面的方法相同


// 创建界面
	private View createEmptyView() {
		View view = View.inflate(getActivity(), R.layout.loadpage_empty, null);
		return view;
	}

	private View createErrorView() {
		View view = View.inflate(getActivity(), R.layout.loadpage_error, null);
		Button page_bt = (Button) view.findViewById(R.id.page_bt);
		page_bt.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {
				show();
			}
		});
		return view;
	}

	private View createLoadingView() {
		View view = View
				.inflate(getActivity(), R.layout.loadpage_loading, null);
		return view;
	}



(6)show方法


public enum LoadResult {
		error(2), empty(3), success(4);

		int value;

		LoadResult(int value) {
			this.value = value;
		}

		public int getValue() {
			return value;
		}

	}

	// 根据服务器的数据切换状态
	private void show() {
		if (state == STATE_ERROR || state == STATE_EMPTY) {
			state = STATE_LOADING;
		}
		// 请求服务器 获取服务器上数据 进行判断
		// 请求服务器 返回一个结果
		// 请求服务器 在子线程中执行,但改变界面需要在主线程中执行,所以使用runOnUiThread
		new Thread() {
			public void run() {
				SystemClock.sleep(2000);
				final LoadResult result = load();
				if (getActivity() != null) {
					getActivity().runOnUiThread(new Runnable() {

						@Override
						public void run() {
							if (result != null) {
								state = result.getValue();
								showPage(); // 状态改变了,重新判断当前应该显示哪个界面
							}
						}
					});
				}
			};
		}.start();
		showPage();

	}




(7)成功界面变为抽象,由子类实现


public  abstract View createSuccessView();



(8)请求服务器的方法也变为抽象,由子类实现



public abstract LoadResult load();



 


2.让每一个Pager滑动时都重新加载数据


(1)在MainActivity中为ViewPager设置监听事件


mViewPager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener(){

			@Override
			public void onPageSelected(int position) {
				super.onPageSelected(position);
				BaseFragment createFragment = FragmentFactory.createFragment(position);
				createFragment.show();//  当切换界面的时候 重新请求服务器 
			}
			
		});



show方法只调用一次,只在ViewPager滑动时调用


(2)第一次打开应用时没有调用show方法,为首页单独设置一个show方法


// 当Fragment挂载的activity创建的时候调用
	@Override
	public void onActivityCreated(Bundle savedInstanceState) {
		super.onActivityCreated(savedInstanceState);
		show();
	}



3.不能把状态改为静态


public   int state = STATE_UNKOWN;



4.总结:BaseFragment的代码


public abstract class BaseFragment extends Fragment {
	public static final int STATE_UNKOWN = 0;
	public static final int STATE_LOADING = 1;
	public static final int STATE_ERROR = 2;
	public static final int STATE_EMPTY = 3;
	public static final int STATE_SUCCESS = 4;
	public   int state = STATE_UNKOWN;
	
	private View loadingView;// 加载中的界面
	private View errorView;// 错误界面
	private View emptyView;// 空界面
	private View successView;// 加载成功的界面
	private FrameLayout frameLayout;
	
	public View onCreateView(LayoutInflater inflater, ViewGroup container,
			Bundle savedInstanceState) {
		if(frameLayout==null){
		frameLayout = new FrameLayout(getActivity());
		init(); // 在FrameLayout中 添加4种不同的界面
		}else{
			ViewUtils.removeParent(frameLayout);// 移除frameLayout之前的爹
		}

		// showPage();// 根据不同的状态显示不同的界面
	//	show();// 根据服务器的数据 切换状态

		return frameLayout;

	}
	
	// 添加4种不同界面
		private void init() {
			loadingView = createLoadingView(); // 创建了加载中的界面
			if (loadingView != null) {
				frameLayout.addView(loadingView, new FrameLayout.LayoutParams(
						LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
			}
			errorView = createErrorView(); // 加载错误界面
			if (errorView != null) {
				frameLayout.addView(errorView, new FrameLayout.LayoutParams(
						LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
			}
			emptyView = createEmptyView(); // 加载空的界面
			if (emptyView != null) {
				frameLayout.addView(emptyView, new FrameLayout.LayoutParams(
						LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
			}
			
			showPage();// 根据不同的状态显示不同的界面
		}
		

		// 根据不同的状态显示不同的界面
		private void showPage() {
			if (loadingView != null) {
				loadingView.setVisibility(state == STATE_UNKOWN
						|| state == STATE_LOADING ? View.VISIBLE : View.INVISIBLE);
			}
			if (errorView != null) {
				errorView.setVisibility(state == STATE_ERROR ? View.VISIBLE
						: View.INVISIBLE);
			}
			if (emptyView != null) {
				emptyView.setVisibility(state == STATE_EMPTY ? View.VISIBLE
						: View.INVISIBLE);
			}
			if (state == STATE_SUCCESS) {
				successView = createSuccessView();
				if (successView != null) {
					frameLayout.addView(successView, new FrameLayout.LayoutParams(
							LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
					successView.setVisibility(View.VISIBLE);
				}
			}else{
				if (successView != null) {
				successView.setVisibility(View.INVISIBLE);
			}
			}
		}
		
		public  abstract View createSuccessView();

		public enum LoadResult {
			error(2), empty(3), success(4);

			int value;

			LoadResult(int value) {
				this.value = value;
			}

			public int getValue() {
				return value;
			}

		}

		// 根据服务器的数据切换状态
		public void show() {
			if (state == STATE_ERROR || state == STATE_EMPTY) {
				state = STATE_LOADING;
			}
			// 请求服务器 获取服务器上数据 进行判断
			// 请求服务器 返回一个结果
			// 请求服务器 在子线程中执行,但改变界面需要在主线程中执行,所以使用runOnUiThread
			new Thread() {
				public void run() {
					SystemClock.sleep(2000);
					final LoadResult result = load();
					if (getActivity() != null) {
						getActivity().runOnUiThread(new Runnable() {

							@Override
							public void run() {
								if (result != null) {
									state = result.getValue();
									showPage(); // 状态改变了,重新判断当前应该显示哪个界面
								}
							}
						});
					}
				};
			}.start();
			showPage();

		}

		public abstract LoadResult load(); 

		// 创建界面
		private View createEmptyView() {
			View view = View.inflate(getActivity(), R.layout.loadpage_empty, null);
			return view;
		}

		private View createErrorView() {
			View view = View.inflate(getActivity(), R.layout.loadpage_error, null);
			Button page_bt = (Button) view.findViewById(R.id.page_bt);
			page_bt.setOnClickListener(new OnClickListener() {

				@Override
				public void onClick(View v) {
					show();
				}
			});
			return view;
		}

		private View createLoadingView() {
			View view = View
					.inflate(getActivity(), R.layout.loadpage_loading, null);
			return view;
		}
}






2.代码摘取到loadingPage

1.BaseFragment来回操作的都是FrameLayout,所以把它抽离出来


1.自定义一个控件,继承FrameLayout,防止BaseFragment中代码过于臃肿


/***
 * 创建了自定义帧布局 把baseFragment 一部分代码 抽取到这个类中
 * 
 * @author itcast
 * 
 */
public abstract class LoadingPage extends FrameLayout {

	public static final int STATE_UNKOWN = 0;
	public static final int STATE_LOADING = 1;
	public static final int STATE_ERROR = 2;
	public static final int STATE_EMPTY = 3;
	public static final int STATE_SUCCESS = 4;
	public int state = STATE_UNKOWN;

	private View loadingView;// 加载中的界面
	private View errorView;// 错误界面
	private View emptyView;// 空界面
	private View successView;// 加载成功的界面

	public LoadingPage(Context context) {
		super(context);
		init();
	}

	public LoadingPage(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
		init();
	}

	public LoadingPage(Context context, AttributeSet attrs) {
		super(context, attrs);
		init();
	}

	private void init() {
		loadingView = createLoadingView(); // 创建了加载中的界面
		if (loadingView != null) {
			this.addView(loadingView, new FrameLayout.LayoutParams(
					LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
		}
		errorView = createErrorView(); // 加载错误界面
		if (errorView != null) {
			this.addView(errorView, new FrameLayout.LayoutParams(
					LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
		}
		emptyView = createEmptyView(); // 加载空的界面
		if (emptyView != null) {
			this.addView(emptyView, new FrameLayout.LayoutParams(
					LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
		}
		showPage();// 根据不同的状态显示不同的界面
	}

	// 根据不同的状态显示不同的界面
	private void showPage() {
		if (loadingView != null) {
			loadingView.setVisibility(state == STATE_UNKOWN
					|| state == STATE_LOADING ? View.VISIBLE : View.INVISIBLE);
		}
		if (errorView != null) {
			errorView.setVisibility(state == STATE_ERROR ? View.VISIBLE
					: View.INVISIBLE);
		}
		if (emptyView != null) {
			emptyView.setVisibility(state == STATE_EMPTY ? View.VISIBLE
					: View.INVISIBLE);
		}
		if (state == STATE_SUCCESS) {
			if (successView == null) {
				successView = createSuccessView();
				this.addView(successView, new FrameLayout.LayoutParams(
						LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
			}
			successView.setVisibility(View.VISIBLE);
		} else {
			if (successView != null) {
				successView.setVisibility(View.INVISIBLE);
			}
		}
	}

	/* 创建了空的界面 */
	private View createEmptyView() {
		View view = View.inflate(UiUtils.getContext(), R.layout.loadpage_empty,
				null);
		return view;
	}

	/* 创建了错误界面 */
	private View createErrorView() {
		View view = View.inflate(UiUtils.getContext(), R.layout.loadpage_error,
				null);
		Button page_bt = (Button) view.findViewById(R.id.page_bt);
		page_bt.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {
				show();
			}
		});
		return view;
	}

	/* 创建加载中的界面 */
	private View createLoadingView() {
		View view = View.inflate(UiUtils.getContext(),
				R.layout.loadpage_loading, null);
		return view;
	}

	public enum LoadResult {
		error(2), empty(3), success(4);

		int value;

		LoadResult(int value) {
			this.value = value;
		}

		public int getValue() {
			return value;
		}

	}

	// 根据服务器的数据 切换状态
	public void show() {
		if (state == STATE_ERROR || state == STATE_EMPTY) {
			state = STATE_LOADING;
		}
		// 请求服务器 获取服务器上数据 进行判断
		// 请求服务器 返回一个结果
		ThreadManager.getInstance().createLongPool().execute(new Runnable() {
			
			@Override
			public void run() {
				SystemClock.sleep(2000);
				final LoadResult result = load();
				UiUtils.runOnUiThread(new Runnable() {

					@Override
					public void run() {
						if (result != null) {
							state = result.getValue();
							showPage(); // 状态改变了,重新判断当前应该显示哪个界面
						}
					}
				});
			}
		});
		
		
		showPage();

	}

	/***
	 * 创建成功的界面
	 * 
	 * @return
	 */
	public abstract View createSuccessView();

	/**
	 * 请求服务器
	 * 
	 * @return
	 */
	protected abstract LoadResult load();
}



2.BaseFragment中代码

public abstract class BaseFragment extends Fragment {

	private LoadingPage loadingPage;
	protected BitmapUtils bitmapUtils;
	@Override
	public View onCreateView(LayoutInflater inflater, ViewGroup container,
			Bundle savedInstanceState) {
		bitmapUtils = BitmapHelper.getBitmapUtils();
		
		if (loadingPage == null) {  // 之前的frameLayout 已经记录了一个爹了  爹是之前的ViewPager 
			loadingPage = new LoadingPage(getActivity()){

				@Override
				public View createSuccessView() {
					return BaseFragment.this.createSuccessView();
				}

				@Override
				protected LoadResult load() {
					return BaseFragment.this.load();
				}
			};
		}else{
			ViewUtils.removeParent(loadingPage);// 移除frameLayout之前的爹
		}
	
		return loadingPage;  //  拿到当前viewPager 添加这个framelayout  
	}
	/***
	 *  创建成功的界面
	 * @return
	 */
	public  abstract View createSuccessView();
	/**
	 * 请求服务器
	 * @return
	 */
	protected abstract LoadResult load();

	public void show(){
		if(loadingPage!=null){
			loadingPage.show();
		}
	}
	
	
	/**校验数据 */
	public LoadResult checkData(List datas) {
		if(datas==null){
			return LoadResult.error;//  请求服务器失败
		}else{
			if(datas.size()==0){
				return LoadResult.empty;
			}else{
				return LoadResult.success;
			}
		}
		
	}


}





3.线程池原理和具体实现

1.用线程池管理线程

(1)一般都是直接回收线程,线程池是把它保存下来,提高效率

2.线程池原理 Demo

public class ThreadPool {
			int maxCount = 3;
			AtomicInteger count =new AtomicInteger(0);// 当前开的线程数  count=0
			LinkedList<Runnable> runnables = new LinkedList<Runnable>();
		
			public void execute(Runnable runnable) {
				runnables.add(runnable);
				if(count.incrementAndGet()<=3){
					createThread();
				}
			}
			private void createThread() {
				new Thread() {
					@Override
					public void run() {
						super.run();
						while (true) {
							// 取出来一个异步任务
							if (runnables.size() > 0) {
								Runnable remove = runnables.remove(0);
								if (remove != null) {
									remove.run();
								}
							}else{
								//  等待状态   wake();
							}
						}
					}
				}.start();
			}
		}

 

 3.根据不同业务创建不同线程池,线程池管理者

(1)线程池管理者

/**
 * 管理线程池
 * 
 * @author itcast
 * 
 */
public class ThreadManager {
	private ThreadManager() {

	}

	private static ThreadManager instance = new ThreadManager();
	private ThreadPoolProxy longPool;
	private ThreadPoolProxy shortPool;

	public static ThreadManager getInstance() {
		return instance;
	}
//******************一般创建多个线程池,联网和操作本地文件一般分开,根据不同业务开不同线程池
	// 联网比较耗时
	// cpu的核数*2+1     开多少个线程最合适
	public synchronized ThreadPoolProxy createLongPool() {     //自己定义的方法创建线程池,Long适合长时间的
		if (longPool == null) {
			longPool = new ThreadPoolProxy(5, 5, 5000L);
		}
		return longPool;
	}
	// 操作本地文件
	public synchronized ThreadPoolProxy createShortPool() {   //适合短时间的
		if(shortPool==null){
			shortPool = new ThreadPoolProxy(3, 3, 5000L);
		}
		return shortPool;
	}
//******************************************************
	public class ThreadPoolProxy {
		private ThreadPoolExecutor pool;
		private int corePoolSize;
		private int maximumPoolSize;
		private long time;

		public ThreadPoolProxy(int corePoolSize, int maximumPoolSize, long time) {
			this.corePoolSize = corePoolSize;
			this.maximumPoolSize = maximumPoolSize;
			this.time = time;

		}
		/**
		 * 执行任务
		 * @param runnable
		 */
		public void execute(Runnable runnable) {
			if (pool == null) {
				// 创建线程池
				/*
				 * 1. 线程池里面管理多少个线程2. 如果排队满了, 额外的开的线程数3. 如果线程池没有要执行的任务 存活多久4.
				 * 时间的单位 5 如果 线程池里管理的线程都已经用了,剩下的任务 临时存到LinkedBlockingQueue对象中 排队
				 */
				pool = new ThreadPoolExecutor(corePoolSize, maximumPoolSize,
						time, TimeUnit.MILLISECONDS,
						new LinkedBlockingQueue<Runnable>(10));
			}
			pool.execute(runnable); // 调用线程池 执行异步任务
		}
		/**
		 * 取消任务
		 * @param runnable
		 */
		public void cancel(Runnable runnable) {
			if (pool != null && !pool.isShutdown() && !pool.isTerminated()) {
				pool.remove(runnable); // 取消异步任务
			}
		}
	}
}



 (2)使用


// 请求服务器 获取服务器上数据 进行判断
		// 请求服务器 返回一个结果
		ThreadManager.getInstance().createLongPool().execute(new Runnable() {
			
			@Override
			public void run() {
				SystemClock.sleep(2000);
				final LoadResult result = load();
				UiUtils.runOnUiThread(new Runnable() {

					@Override
					public void run() {
						if (result != null) {
							state = result.getValue();
							showPage(); // 状态改变了,重新判断当前应该显示哪个界面
						}
					}
				});
			}
		});




4.以后使用线程时习惯使用线程池,因为开多个线程池比较消耗内存


4.请求服务器的框架

1.写一个类专门操作联网

2.搭建框架



public class HomeProtocol {
	public void load(int index) {
		String json = loadLocal(index); //获取本地的
		if (json == null) {
			json = loadServer();        //联网获取
			if (json != null) {
				saveLocal(json, index);
			}
		}
		if (json != null) {
			paserJson(json);            //解析json
		}
	}
}

3.再每一个去实现




5.联网

1.权限

2.解决工程部分类乱码方法,编码不一致


1.从XUtils抽取3个类,用于联网,可直接用


(1) HttpClientFactory.java




public class HttpClientFactory {
	/** http请求最大并发连接数 */
	private static final int MAX_CONNECTIONS = 10;
	/** 超时时间 */
	private static final int TIMEOUT = 10 * 1000;
	/** 缓存大小 */
	private static final int SOCKET_BUFFER_SIZE = 8 * 1024; // 8KB
	/** 错误尝试次数,错误异常表请在RetryHandler添加 */
	private static final int MAX_RETRIES = 5;
	private static final String HEADER_ACCEPT_ENCODING = "Accept-Encoding";
	private static final String ENCODING_GZIP = "gzip";

	public static DefaultHttpClient create(boolean isHttps) {
		HttpParams params = createHttpParams();
		DefaultHttpClient httpClient = null;
		if (isHttps) {
			// 支持http与https
			SchemeRegistry schemeRegistry = new SchemeRegistry();
			schemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
			schemeRegistry.register(new Scheme("https", SSLSocketFactory.getSocketFactory(), 443));
			// ThreadSafeClientConnManager线程安全管理类
			ThreadSafeClientConnManager cm = new ThreadSafeClientConnManager(params, schemeRegistry);
			httpClient = new DefaultHttpClient(cm, params);
		} else {
			httpClient = new DefaultHttpClient(params);
		}
		return httpClient;
	}

	private static HttpParams createHttpParams() {
		final HttpParams params = new BasicHttpParams();
		// 设置是否启用旧连接检查,默认是开启的。关闭这个旧连接检查可以提高一点点性能,但是增加了I/O错误的风险(当服务端关闭连接时)。
		// 开启这个选项则在每次使用老的连接之前都会检查连接是否可用,这个耗时大概在15-30ms之间
		HttpConnectionParams.setStaleCheckingEnabled(params, false);
		HttpConnectionParams.setConnectionTimeout(params, TIMEOUT);// 设置链接超时时间
		HttpConnectionParams.setSoTimeout(params, TIMEOUT);// 设置socket超时时间
		HttpConnectionParams.setSocketBufferSize(params, SOCKET_BUFFER_SIZE);// 设置缓存大小
		HttpConnectionParams.setTcpNoDelay(params, true);// 是否不使用延迟发送(true为不延迟)
		HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1); // 设置协议版本
		HttpProtocolParams.setUseExpectContinue(params, true);// 设置异常处理机制
		HttpProtocolParams.setContentCharset(params, HTTP.UTF_8);// 设置编码
		HttpClientParams.setRedirecting(params, false);// 设置是否采用重定向

		ConnManagerParams.setTimeout(params, TIMEOUT);// 设置超时
		ConnManagerParams.setMaxConnectionsPerRoute(params, new ConnPerRouteBean(MAX_CONNECTIONS));// 多线程最大连接数
		ConnManagerParams.setMaxTotalConnections(params, 10); // 多线程总连接数
		return params;
	}

	private static void createHttpClient(DefaultHttpClient httpClient) {
		// 添加request的拦截器,添加必要的头信息
		httpClient.addRequestInterceptor(new HttpRequestInterceptor() {
			public void process(HttpRequest request, HttpContext context) {
				if (!request.containsHeader(HEADER_ACCEPT_ENCODING)) {
					request.addHeader(HEADER_ACCEPT_ENCODING, ENCODING_GZIP);
				}
			}
		});

		// 添加response拦截器,预先对response进行一些处理
		httpClient.addResponseInterceptor(new HttpResponseInterceptor() {
			public void process(HttpResponse response, HttpContext context) {
				final HttpEntity entity = response.getEntity();
				if (entity == null) {
					return;
				}
				final Header encoding = entity.getContentEncoding();
				if (encoding != null) {
					for (HeaderElement element : encoding.getElements()) {
						// 如果是以GZIP压缩的数据,利用内部的填充器包装一层Gzip的流
						if (element.getName().equalsIgnoreCase(ENCODING_GZIP)) {
							response.setEntity(new InflatingEntity(response.getEntity()));
							break;
						}
					}
				}
			}
		});
		// 设置重试次数
		httpClient.setHttpRequestRetryHandler(new HttpRetry(MAX_RETRIES));
	}

	/** 当服务器返回的数据是以Gzip压缩的过后的数据,填充Response返回的实体数据 (Description),则返回GZIP解压流 */
	private static class InflatingEntity extends HttpEntityWrapper {
		public InflatingEntity(HttpEntity wrapped) {
			super(wrapped);
		}

		@Override
		public InputStream getContent() throws IOException {
			return new GZIPInputStream(wrappedEntity.getContent());
		}

		// 因为数据是压缩数据,所以实际长度无法估计,可以返回-1
		@Override
		public long getContentLength() {
			return -1;
		}
	}

	/** 自定义的安全套接字协议的实现,目前采用默认的,未使用到 */
	private static class SSLSocketFactoryEx extends SSLSocketFactory {
		// 此类的实例表示安全套接字协议的实现,它充当用于安全套接字工厂或 SSLEngine 的工厂。用可选的一组密钥和信任管理器及安全随机字节源初始化此类。
		SSLContext sslContext = SSLContext.getInstance("TLS");

		public SSLSocketFactoryEx(KeyStore truststore) throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException {
			super(truststore);
			// TrustManager负责管理做出信任决定时使用的的信任材料,也负责决定是否接受同位体提供的凭据。
			// X509TrustManager此接口的实例管理使用哪一个 X509 证书来验证远端的安全套接字。决定是根据信任的证书授权、证书撤消列表、在线状态检查或其他方式做出的。
			TrustManager tm = new X509TrustManager() {
				public java.security.cert.X509Certificate[] getAcceptedIssuers() {
					return null;// 返回受验证同位体信任的认证中心的数组。
				}

				@Override
				public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) throws java.security.cert.CertificateException {
					// 给出同位体提供的部分或完整的证书链,构建到可信任的根的证书路径,并且返回是否可以确认和信任将其用于基于验证类型的客户端 SSL 验证。
				}

				@Override
				public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) throws java.security.cert.CertificateException {
					// 给出同位体提供的部分或完整的证书链,构建到可信任的根的证书路径,并且返回是否可以确认和信任将其用于基于验证类型的服务器 SSL 验证。
				}
			};
			sslContext.init(null, new TrustManager[]{tm}, null);
		}

		@Override
		public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException, UnknownHostException {
			return sslContext.getSocketFactory().createSocket(socket, host, port, autoClose);
		}

		@Override
		public Socket createSocket() throws IOException {
			return sslContext.getSocketFactory().createSocket();
		}
	}
}



(2)HttpHelper.java

<span style="font-size:14px;">public class HttpHelper {

	public static final String URL = "http://127.0.0.1:8090/";

	/** get请求,获取返回字符串内容 */
	public static HttpResult get(String url) {
		HttpGet httpGet = new HttpGet(url);
		return execute(url, httpGet);
	}

	/** post请求,获取返回字符串内容 */
	public static HttpResult post(String url, byte[] bytes) {
		HttpPost httpPost = new HttpPost(url);
		ByteArrayEntity byteArrayEntity = new ByteArrayEntity(bytes);
		httpPost.setEntity(byteArrayEntity);
		return execute(url, httpPost);
	}

	/** 下载 */
	public static HttpResult download(String url) {
		HttpGet httpGet = new HttpGet(url);
		return execute(url, httpGet);
	}

	/** 执行网络访问 */
	private static HttpResult execute(String url, HttpRequestBase requestBase) {
		boolean isHttps = url.startsWith("https://");//判断是否需要采用https
		AbstractHttpClient httpClient = HttpClientFactory.create(isHttps);
		HttpContext httpContext = new SyncBasicHttpContext(new BasicHttpContext());
		HttpRequestRetryHandler retryHandler = httpClient.getHttpRequestRetryHandler();//获取重试机制
		int retryCount = 0;
		boolean retry = true;
		while (retry) {
			try {
				HttpResponse response = httpClient.execute(requestBase, httpContext);//访问网络
				if (response != null) {
					return new HttpResult(response, httpClient, requestBase);
				}
			} catch (Exception e) {
				IOException ioException = new IOException(e.getMessage());
				retry = retryHandler.retryRequest(ioException, ++retryCount, httpContext);//把错误异常交给重试机制,以判断是否需要采取从事
				LogUtils.e(e);
			}
		}
		return null;
	}

	/** http的返回结果的封装,可以直接从中获取返回的字符串或者流 */
	public static class HttpResult {
		private HttpResponse mResponse;
		private InputStream mIn;
		private String mStr;
		private HttpClient mHttpClient;
		private HttpRequestBase mRequestBase;

		public HttpResult(HttpResponse response, HttpClient httpClient, HttpRequestBase requestBase) {
			mResponse = response;
			mHttpClient = httpClient;
			mRequestBase = requestBase;
		}

		public int getCode() {
			StatusLine status = mResponse.getStatusLine();
			return status.getStatusCode();
		}

		/** 从结果中获取字符串,一旦获取,会自动关流,并且把字符串保存,方便下次获取 */
		public String getString() {
			if (!TextUtils.isEmpty(mStr)) {
				return mStr;
			}
			InputStream inputStream = getInputStream();
			ByteArrayOutputStream out = null;
			if (inputStream != null) {
				try {
					out = new ByteArrayOutputStream();
					byte[] buffer = new byte[1024 * 4];
					int len = -1;
					while ((len = inputStream.read(buffer)) != -1) {
						out.write(buffer, 0, len);
					}
					byte[] data = out.toByteArray();
					mStr = new String(data, "utf-8");
				} catch (Exception e) {
					LogUtils.e(e);
				} finally {
					IOUtils.closeQuietly(out);
					close();
				}
			}
			return mStr;
		}

		/** 获取流,需要使用完毕后调用close方法关闭网络连接 */
		public InputStream getInputStream() {
			if (mIn == null && getCode() < 300) {
				HttpEntity entity = mResponse.getEntity();
				try {
					mIn = entity.getContent();
				} catch (Exception e) {
					LogUtils.e(e);
				}
			}
			return mIn;
		}

		/** 关闭网络连接 */
		public void close() {
			if (mRequestBase != null) {
				mRequestBase.abort();
			}
			IOUtils.closeQuietly(mIn);
			if (mHttpClient != null) {
				mHttpClient.getConnectionManager().closeExpiredConnections();
			}
		}
	}
}
</span>



(3)HttpRetry.java

public class HttpRetry implements HttpRequestRetryHandler {
	// 重试休息的时间
	private static final int RETRY_SLEEP_TIME_MILLIS = 1000;
	// 网络异常,继续
	private static HashSet<Class<?>> exceptionWhitelist = new HashSet<Class<?>>();
	// 用户异常,不继续(如,用户中断线程)
	private static HashSet<Class<?>> exceptionBlacklist = new HashSet<Class<?>>();

	static {
		// 以下异常不需要重试,这样异常都是用于造成或者是一些重试也无效的异常
		exceptionWhitelist.add(NoHttpResponseException.class);// 连上了服务器但是没有Response
		exceptionWhitelist.add(UnknownHostException.class);// host出了问题,一般是由于网络故障
		exceptionWhitelist.add(SocketException.class);// Socket问题,一般是由于网络故障
		// 以下异常可以重试
		exceptionBlacklist.add(InterruptedIOException.class);// 连接中断,一般是由于连接超时引起
		exceptionBlacklist.add(SSLHandshakeException.class);// SSL握手失败
	}

	private final int maxRetries;

	public HttpRetry(int maxRetries) {
		this.maxRetries = maxRetries;
	}

	@Override
	public boolean retryRequest(IOException exception, int executionCount, HttpContext context) {
		boolean retry = true;
		// 请求是否到达
		Boolean b = (Boolean) context.getAttribute(ExecutionContext.HTTP_REQ_SENT);
		boolean sent = (b != null && b.booleanValue());

		if (executionCount > maxRetries) {
			// 尝试次数超过用户定义的测试
			retry = false;
		} else if (exceptionBlacklist.contains(exception.getClass())) {
			// 线程被用户中断,则不继续尝试
			retry = false;
		} else if (exceptionWhitelist.contains(exception.getClass())) {
			// 出现的异常需要被重试
			retry = true;
		} else if (!sent) {
			// 请求没有到达
			retry = true;
		}
		// 如果需要重试
		if (retry) {
			// 获取request
			HttpUriRequest currentReq = (HttpUriRequest) context.getAttribute(ExecutionContext.HTTP_REQUEST);
			// POST请求难道就不需要重试?
			//retry = currentReq != null && !"POST".equals(currentReq.getMethod());
			retry = currentReq != null;
		}
		if (retry) {
			// 休眠1秒钟后再继续尝试
			SystemClock.sleep(RETRY_SLEEP_TIME_MILLIS);
		} else {
			exception.printStackTrace();
		}
		return retry;
	}
}







2.使用


HttpResult httpResult =HttpHelper.get(HttpHelper.URL+"home"+"?index"+index); //http://127.0.0.1:8090/home?index=
String json =httpResult.getString();




3.联网的方式很多,用最适合的

6.把缓存保存到本地

1. 方法:(1)把整个json保存到本地

                 (2)把解析后的数据保存到本地数据库

2.判断json文件是否过期
  (1)MD5比对  加密后的文件与服务器发来的文件加密后对比
  (2)在json文件第一行写一个过期时间,对比



3.管理文件的类---工具类  缓存文件一般写在一个单独的文件夹(GooglePlay)中


   cache和icon是GooglePlay的子文件夹


   cache保存json


   icon保存图片


public class FileUtils {
	public static final String CACHE = "cache";      //保存json
	public static final String ICON = "icon";        //保存图片
	public static final String ROOT = "GooglePlay";  //根路径
	/**
	 * 获取图片的缓存的路径
	 * @return
	 */
	public static File getIconDir(){
		return getDir(ICON);
		
	}
	/**
	 * 获取缓存路径
	 * @return
	 */
	public static File getCacheDir() {
		return getDir(CACHE);
	}
	public static File getDir(String cache) {
		StringBuilder path = new StringBuilder();  //StringBuilder比String效率要高
		if (isSDAvailable()) {                     //如果SD卡可用
			path.append(Environment.getExternalStorageDirectory()
					.getAbsolutePath());           //sd卡根路径
			path.append(File.separator);// '/'
			path.append(ROOT);// /mnt/sdcard/GooglePlay
			path.append(File.separator);
			path.append(cache);// /mnt/sdcard/GooglePlay/cache
			
		}else{                                   //放在程序的cache目录下
			File filesDir = UiUtils.getContext().getCacheDir();    //  cache  getFileDir file
			path.append(filesDir.getAbsolutePath());// /data/data/com.itheima.googleplay/cache
			path.append(File.separator);///data/data/com.itheima.googleplay/cache/
			path.append(cache);///data/data/com.itheima.googleplay/cache/cache
		}
		File file = new File(path.toString());
		if (!file.exists() || !file.isDirectory()) {
			file.mkdirs();// 创建文件夹
		}
		return file;

	}

	private static boolean isSDAvailable() {    //判断SD卡是否可用
		if (Environment.getExternalStorageState().equals(
				Environment.MEDIA_MOUNTED)) {
			return true;
		} else {
			return false;
		}
	}


}




4.使用:把整个Json数据保存到本地文件中


private void saveLocal(String json, int index) {
		
		BufferedWriter bw = null;
		try {
			File dir=FileUtils.getCacheDir();
			//在第一行写一个过期时间 
			File file = new File(dir, "home_"+ index); // /mnt/sdcard/googlePlay/cache/home_0			  FileWriter fw = new FileWriter(file);
			 bw = new BufferedWriter(fw);
			bw.write(System.currentTimeMillis() + 1000 * 100 + "");
			bw.newLine();// 换行
			bw.write(json);// 把整个json文件保存起来
			bw.flush();
			bw.close();
		} catch (Exception e) {
			e.printStackTrace();
		}finally{
			IOUtils.closeQuietly(bw);
		}
	}





7.读取本地缓存

1.读取本地缓存

private String loadLocal(int index) {
		//  如果发现文件已经过期了 就不要再去复用缓存了
		File dir=FileUtils.getCacheDir();// 获取缓存所在的文件夹
		File file = new File(dir, getKey()+"_" + index); 
		try {
			FileReader fr=new FileReader(file);
			BufferedReader br=new BufferedReader(fr);
			long outOfDate = Long.parseLong(br.readLine()); //获取过期时间
			if(System.currentTimeMillis()>outOfDate){       //与本地时间比较
				return null;
			}else{
				String str=null;
				StringWriter sw=new StringWriter();
				while((str=br.readLine())!=null){
				
					sw.write(str);
				}
				return sw.toString();
			}
			
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}

 

8.Json解析


1.不用框架


2.  AppInfo     应用程序信息类


public class AppInfo {
    	 
    private long id;
	private String name;
	private String packageName;
	private String iconUrl;
	private float stars;
	private long size;
	private String downloadUrl;
	private String des;
	public long getId() {
		return id;
	}
	public void setId(long id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getPackageName() {
		return packageName;
	}
	public void setPackageName(String packageName) {
		this.packageName = packageName;
	}
	public String getIconUrl() {
		return iconUrl;
	}
	public void setIconUrl(String iconUrl) {
		this.iconUrl = iconUrl;
	}
	public float getStars() {
		return stars;
	}
	public void setStars(float stars) {
		this.stars = stars;
	}
	public long getSize() {
		return size;
	}
	public void setSize(long size) {
		this.size = size;
	}
	public String getDownloadUrl() {
		return downloadUrl;
	}
	public void setDownloadUrl(String downloadUrl) {
		this.downloadUrl = downloadUrl;
	}
	public String getDes() {
		return des;
	}
	public void setDes(String des) {
		this.des = des;
	}
	public AppInfo() {
		super();
	}
	public AppInfo(long id, String name, String packageName, String iconUrl,
			float stars, long size, String downloadUrl, String des) {
		super();
		this.id = id;
		this.name = name;
		this.packageName = packageName;
		this.iconUrl = iconUrl;
		this.stars = stars;
		this.size = size;
		this.downloadUrl = downloadUrl;
		this.des = des;
	}
	@Override
	public String toString() {
		return "AppInfo [id=" + id + ", name=" + name + ", packageName="
				+ packageName + ", iconUrl=" + iconUrl + ", stars=" + stars
				+ ", size=" + size + ", downloadUrl=" + downloadUrl + ", des="
				+ des + "]";
	}
	
	
}



3.解析Json

//见到大括号 就用JsonObject ,见到中括号就是JsonArray


	private List<AppInfo> paserJson(String json) {
		List<AppInfo> appInfos=new ArrayList<AppInfo>();
		try {
			JSONObject jsonObject=new JSONObject(json);
			JSONArray jsonArray = jsonObject.getJSONArray("list");
			for(int i=0;i<jsonArray.length();i++){
				JSONObject jsonObj = jsonArray.getJSONObject(i);
				long id=jsonObj.getLong("id");
				String name = jsonObj.getString("name");
				String packageName=jsonObj.getString("packageName");
				String iconUrl = jsonObj.getString("iconUrl");
				float stars=Float.parseFloat(jsonObj.getString("stars"));
				long size=jsonObj.getLong("size");
				String downloadUrl = jsonObj.getString("downloadUrl");
				String des = jsonObj.getString("des");
				AppInfo info=new AppInfo(id, name, packageName, iconUrl, stars, size, downloadUrl, des);
				appInfos.add(info);
			}
			return appInfos;
			
		} catch (JSONException e) {
			e.printStackTrace();
			return null;
		}
	}




2.HomeFragment 中判断服务器数据

 

/*
 * 校验数据
 */
   private LoadResult checkData(List<AppInfo> load){
     if(load==null){
        return LoadResult.error;
      }else{
        if(load.size()==0){
           return LoadResult.empty;
         }else{
          return LoadResult.success;
       }
      }
  }
}

 







9.布局的搭建


<!-- 凡是以layout开头的属性 其实都是经过父容器批准才能生效  因为在listView 中 layout_height 无论写什么熟悉 都是包裹内容 -->


Listview之间分隔


<span style="font-size:14px;"><?xml version="1.0" encoding="utf-8"?>
<!-- 凡是以layout开头的属性 其实都是经过父容器批准才能生效  因为在listView 中 layout_height 无论写什么属性 都是包裹内容 -->
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >
    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="113dp"
        android:layout_marginLeft="8dp"
        android:layout_marginRight="8dp"
        android:background="@drawable/list_item_bg" >

        <RelativeLayout
            android:id="@+id/item_top"
            android:layout_width="match_parent"
            android:layout_height="72dp" >

            <ImageView
                android:id="@+id/item_icon"
                android:layout_width="48dp"
                android:layout_height="48dp"
                android:layout_centerVertical="true"
                android:layout_marginLeft="8dp"
                android:layout_marginRight="8dp"
                android:src="@drawable/ic_default" />

            <RelativeLayout
                android:id="@+id/item_action"
                android:layout_width="70dp"
                android:layout_height="match_parent"
                android:layout_alignParentRight="true"
                android:gravity="center" >

                <FrameLayout
                    android:id="@+id/action_progress"
                    android:layout_width="27dp"
                    android:layout_height="27dp"
                    android:layout_centerHorizontal="true"
                    android:background="@drawable/ic_download" />

                <TextView
                    android:id="@+id/action_txt"
                    android:layout_width="fill_parent"
                    android:layout_height="wrap_content"
                    android:layout_below="@id/action_progress"
                    android:layout_marginTop="5dp"
                    android:ellipsize="end"
                    android:gravity="center"
                    android:singleLine="true"
                    android:textColor="#ff7a7a7a"
                    android:textSize="12dp"
                    android:text="下载" />
            </RelativeLayout>

            <RelativeLayout
                android:id="@+id/item_content"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_centerVertical="true"
                android:layout_toLeftOf="@id/item_action"
                android:layout_toRightOf="@id/item_icon" >

                <TextView
                    android:id="@+id/item_title"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:ellipsize="end"
                    android:singleLine="true"
                    android:textColor="#ff333333"
                    android:textSize="16dp" />

                <RatingBar
                    android:id="@+id/item_rating"
                    android:layout_width="wrap_content"
                    android:layout_height="14dp"
                    android:layout_below="@id/item_title"
                    android:layout_marginBottom="2dp"
                    android:layout_marginTop="2dp"
                    android:isIndicator="true"
                    android:progressDrawable="@drawable/process_ratingbar"
                    android:rating="2.5" />

                <TextView
                    android:id="@+id/item_size"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_below="@id/item_rating"
                    android:singleLine="true"
                    android:textColor="#ff7a7a7a"
                    android:textSize="12dp" />
            </RelativeLayout>
        </RelativeLayout>

        <View
            android:id="@+id/item_divider"
            android:layout_width="match_parent"
            android:layout_height="1dp"
            android:layout_below="@id/item_top"
            android:layout_marginLeft="8dp"
            android:layout_marginRight="8dp"
            android:background="@color/item_divider" />

        <TextView
            android:id="@+id/item_bottom"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:layout_below="@id/item_divider"
            android:layout_marginLeft="12dp"
            android:layout_marginRight="12dp"
            android:ellipsize="end"
            android:gravity="center_vertical"
            android:singleLine="true"
            android:textColor="#ff717171"
            android:textSize="14dp" />
    </RelativeLayout>

</FrameLayout></span>





10.加载界面&bitMapUtils的用法

1.ListView优化:ViewHolder

2.查看系统控件的样式    D:\安卓\adt-bundle-windows-x86-20131030\sdk\platforms\android-19\data\res\values


3.RatingBar


和水平进度条非常相似


 图层(和帧布局相似)---------重构系统的,放在drawable中


<?xml version="1.0" encoding="utf-8"?>
	<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
	    <item android:id="@+android:id/background" android:drawable="@drawable/rating_small_empty" />
	    <item android:id="@+android:id/secondaryProgress" android:drawable="@drawable/rating_small_half" />
	    <item android:id="@+android:id/progress" android:drawable="@drawable/rating_small_full" />
	</layer-list>



4.加载服务器的图片(三级缓存)


     使用BitmapUtil,查看BitmapUtil的例子使用方法,仿照使用例子写代码


     BitmapUtils不是单例的 根据需要重载多个获取实例的方法


     指定图片缓存路径


(1)使BitmapUtil变成单例,保证bitmapUtil在内存中只存在一份,方便对图片的管理


public class BitmapHelper {
	private BitmapHelper() {
	}

	private static BitmapUtils bitmapUtils;

	/**
	 * BitmapUtils不是单例的 根据需要重载多个获取实例的方法
	 * 
	 * @param appContext
	 *            application context
	 * @return
	 */
	public static BitmapUtils getBitmapUtils() {
		if (bitmapUtils == null) {
			// 第二个参数 缓存图片的路径 // 加载图片 最多消耗多少比例的内存 0.05-0.8f
			bitmapUtils = new BitmapUtils(UiUtils.getContext(), FileUtils
					.getIconDir().getAbsolutePath(), 0.3f);
		}
		return bitmapUtils;
	}
}



(

2)使用

BitmapUtils bitmapUtils=BitmapHelper.getBitmapUtils();
//显示图片的控件
bitmapUtils.display(holder.item_icon,Url);//第二个参数为图片完整路径



3.ListView的滑动状态--------(三种状态)

(1)飞速滑动时不需要加载图片


BitmapUtil中的方法


ListView listview = new ListView(Uiutils.getContext());
  listview.setAdapter(new HomeAdapter());
  bitmapUtils=BitmapHelper.getBitmapUtils();
  //第二个参数 慢慢滑动的时候是否加载图片 false 加载 true 不加载
  //第三个参数 飞速滑动的时候是否加载图片 true 不加载
  listview.setOnScrollListener(new PauseOnScrollListener(bitmapUtils,false,true));
  bitmapUtils.configDefaultLoadingImage(R.drawable.ic_default);//设置如果图片加载中显示的图片
  bitmapUtils.configDefaultLoadFailedImage(R.drawable.ic_default);//加载失败显示的图片
<span style="font-size:14px;"> </span>


(2)其他方法见BitMapUtils的例子:bitmapUtilFragment



4.ListView适配器代码



public class HomeAdapter extends BaseAdapter {

		@Override
		public int getCount() {
			return datas.size();
		}

		@Override
		public View getView(int position, View convertView, ViewGroup parent) {
			View view;
			ViewHolder holder;
			if(convertView==null){
				view=View.inflate(Uiutils.getContext(), R.layout.item_app, null);
				holder=new ViewHolder();
				holder.item_icon=(ImageView) view.findViewById(R.id.item_icon);
				holder.item_title=(TextView) view.findViewById(R.id.item_title);
				holder.item_size=(TextView) view.findViewById(R.id.item_size);
				holder.item_bottom=(TextView) view.findViewById(R.id.item_bottom);
				holder.item_rating=(RatingBar) view.findViewById(R.id.item_rating);
				view.setTag(holder);
			}else{
				view=convertView;
				holder=(ViewHolder) view.getTag();
			}
			AppInfo appInfo=datas.get(position);
			holder.item_title.setText(appInfo.getName());// 设置应用程序的名字
			String size=Formatter.formatFileSize(Uiutils.getContext(), appInfo.getSize());
			holder.item_size.setText(size);
			holder.item_bottom.setText(appInfo.getDes());
			float stars = appInfo.getStars();
			holder.item_rating.setRating(stars); // 设置ratingBar的值
			String iconUrl = appInfo.getIconUrl();  //http://127.0.0.1:8090/image?name=app/com.youyuan.yyhl/icon.jpg
			 bitmapUtils=BitmapHelper.getBitmapUtils();
			// 显示图片的控件
			bitmapUtils.display(holder.item_icon, HttpHelper.URL+"image?name="+iconUrl);
			return view;
		}

		@Override
		public Object getItem(int arg0) {
			// TODO Auto-generated method stub
			return datas.get(arg0);
		}

		@Override
		public long getItemId(int arg0) {
			// TODO Auto-generated method stub
			return arg0;
		}

	}

	static class ViewHolder {
		ImageView item_icon;
		TextView item_title, item_size, item_bottom;
		RatingBar item_rating;
	}

 





11.专题界面

1.写一个协议类,操作数据(联网,保存到本地,在本地获取)SubjectProtocol

(1)因为HomeProtocol和SubjectProtocol有共性,所以抽取成父类BaseProtocol



public abstract class BaseProtocol<T> {
	public T load(int index) {
		// 加载本地数据
		String json = loadLocal(index);
		if (json == null) {
			// 请求服务器
			json = loadServer(index);
			if (json != null) {
				saveLocal(json, index);
			}
		}
		if (json != null) {
			return paserJson(json);
		} else {
			return null;
		}
	}


	private String loadServer(int index) {
		HttpResult httpResult = HttpHelper.get(HttpHelper.URL +getKey()
				+ "?index=" + index); 
		String json = httpResult.getString();
		return json;
	}
	private void saveLocal(String json, int index) {
		
		BufferedWriter bw = null;
		try {
			File dir=FileUtils.getCacheDir();
			//在第一行写一个过期时间 
			File file = new File(dir, getKey()+"_" + index); // /mnt/sdcard/googlePlay/cache/home_0
			FileWriter fw = new FileWriter(file);
			 bw = new BufferedWriter(fw);
			bw.write(System.currentTimeMillis() + 1000 * 100 + "");
			bw.newLine();// 换行
			bw.write(json);// 把整个json文件保存起来
			bw.flush();
			bw.close();
		} catch (Exception e) {
			e.printStackTrace();
		}finally{
			IOUtils.closeQuietly(bw);
		}
	}

	private String loadLocal(int index) {
		//  如果发现文件已经过期了 就不要再去复用缓存了
		File dir=FileUtils.getCacheDir();// 获取缓存所在的文件夹
		File file = new File(dir, getKey()+"_" + index); 
		try {
			FileReader fr=new FileReader(file);
			BufferedReader br=new BufferedReader(fr);
			long outOfDate = Long.parseLong(br.readLine());
			if(System.currentTimeMillis()>outOfDate){
				return null;
			}else{
				String str=null;
				StringWriter sw=new StringWriter();
				while((str=br.readLine())!=null){
				
					sw.write(str);
				}
				return sw.toString();
			}
			
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}

	/**
	 * 解析json
	 * @param json
	 * @return
	 */
	public abstract T paserJson(String json);
	/**
	 * 说明了关键字
	 * @return
	 */
	public abstract String getKey();
}

 

(2)创建接收对象

public class SubjectInfo {
	private String des;
	private String url;
	public String getDes() {
		return des;
	}
	public void setDes(String des) {
		this.des = des;
	}
	public String getUrl() {
		return url;
	}
	public void setUrl(String url) {
		this.url = url;
	}
	@Override
	public String toString() {
		return "SubjectInfo [des=" + des + ", url=" + url + "]";
	}
	public SubjectInfo() {
		super();
	}
	public SubjectInfo(String des, String url) {
		super();
		this.des = des;
		this.url = url;
	}
	
}

(3)SubjectProtocol

public class SubjectProtocol extends BaseProtocol<List<SubjectInfo>>{

	@Override
	public List<SubjectInfo> paserJson(String json) {
		List<SubjectInfo> subjectInfos=new ArrayList<SubjectInfo>();
		try {
			JSONArray jsonArray=new JSONArray(json);
			for(int i=0;i<jsonArray.length();i++){
				JSONObject jsonObject = jsonArray.getJSONObject(i);
				String des=jsonObject.getString("des");
				String url = jsonObject.getString("url");
				SubjectInfo info=new SubjectInfo(des, url);
				subjectInfos.add(info);
				
			}
			return subjectInfos;
			
		} catch (JSONException e) {
			e.printStackTrace();
			return null;
		}
	}

	@Override
	public String getKey() {
		return "subject";
	}


}

 

2.把校验数据方法放在父类中BaseFragment

/**
	 * 校验数据
	 * @param load
	 * @return
	 */
	protected LoadResult checkData(List load) {
		if (load == null) {
			return LoadResult.error;
		} else {
			if (load.size() == 0) {
				return LoadResult.empty;
			} else {
				return LoadResult.success;
			}
		}
	}

 


3.布局


Android 进度loadingprogress_服务器




4.布局文件


<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" 
    >

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginLeft="9dip"
        android:layout_marginRight="9dip"
        android:background="@drawable/list_item_bg" >

        <ImageView
            android:id="@+id/item_icon"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:scaleType="fitCenter"
            android:src="@drawable/ic_default" 
            android:padding="5dp"/>

        <TextView
            android:id="@+id/item_txt"
            style="@style/TitleStyle"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:layout_below="@id/item_icon"
            android:gravity="center_vertical"
            android:paddingBottom="5dp"
            android:paddingLeft="5dp"
            android:paddingRight="5dp"
            android:singleLine="true" />
    </RelativeLayout>

</FrameLayout>






style



<style name="TitleStyle">
        <item name="android:textColor">@color/txt_title</item>
        <item name="android:textSize">@dimen/list_item_title_size</item>
        <item name="android:ellipsize">end</item>
        <item name="android:singleLine">true</item>
    </style>




 



5.SubjectFragment



public class SubjectFragment extends BaseFragment {

	private List<SubjectInfo> datas;

	@Override
	public View createSuccessView() {
		ListView listView=new ListView(UiUtils.getContext());
		listView.setAdapter(new SubjectAdapter());
		return listView;
	}
	private class SubjectAdapter extends BaseAdapter{

		@Override
		public int getCount() {
			return datas.size();
		}

		@Override
		public Object getItem(int position) {
			return datas.get(position);
		}

		@Override
		public long getItemId(int position) {
			return position;
		}

		@Override
		public View getView(int position, View convertView, ViewGroup parent) {
			View view;
			ViewHolder holder;
			if(convertView!=null){
				view=convertView;
				holder=(ViewHolder) view.getTag();
			}else{
				view=UiUtils.inflate(R.layout.item_subject);
				holder=new ViewHolder();
				holder.item_icon=(ImageView) view.findViewById(R.id.item_icon);
				holder.item_txt=(TextView) view.findViewById(R.id.item_txt);
				view.setTag(holder);
			}
			SubjectInfo info=datas.get(position);
			holder.item_txt.setText(info.getDes());
			bitmapUtils.display(holder.item_icon, HttpHelper.URL+"image?name="+info.getUrl());
			return view;
		}
		
	}
	class ViewHolder{
		ImageView item_icon;
		TextView item_txt;
	}

	@Override
	protected LoadResult load() {
		SubjectProtocol protocol=new SubjectProtocol();
		datas = protocol.load(0);
		return checkData(datas);
	}
}






12.BaseListView



1.透明图片----nothing



1.ListView



//		setSelector  点击显示的颜色
//		setCacheColorHint  拖拽的颜色
//		setDivider  每个条目的间隔	的分割线	
		this.setSelector(R.drawable.nothing);  // 什么都没有
		this.setCacheColorHint(R.drawable.nothing);
		this.setDivider(UiUtils.getDrawalbe(R.drawable.nothing));


 


2.BaseListView