03.服务器准备
1、将webSerser.apk 安装到手机
2、将WebInfos放入sdcard根目录
04.MyApplication初始化工作
1、清单文件注册
android:name=".AppStoreApplication"
2、应用
public class AppStoreApplication extends Application {}
3、创建服务
<service android:name="myService" android:process=":remote"></service>
4、AppStoreApplication 的onCreate执行2次
列出所有进程:adb shell top
程序入口做什么?
package cn.nubia.nubiaappstore;
import android.app.Application;
import android.content.Context;
import android.os.Handler;
import android.os.Looper;
import android.os.Process;
import cn.nubia.nubiaappstore.utils.LogUtils;
/**
* author : gordon
* e-mail : gordon_sun07@163.com
* date : 2019/4/27 19:24
* version: 1.0
* desc : 清单文件注册
* android:name=".AppStoreApplication"
*
* <service android:name="myService" android:process=":remote"></service>
* onCreate执行多次
*/
public class AppStoreApplication extends Application {
public static Context mContext;
public static int mainThreadId;
public static Handler mainHandler;
public static AppStoreApplication mInstance;
@Override
public void onCreate() {
super.onCreate();
LogUtils.e("gordon", "application onCreate:" + this);
mInstance = this;
//context
mContext = getApplicationContext();
//线程间通信
mainHandler = new Handler();
//判读当前是在主线程还是子线程
mainThreadId = Process.myTid();
new Thread(new Runnable() {
@Override
public void run() {
//主线程的Looper
Handler mainHandler1 = new Handler(Looper.getMainLooper());
//子线程的Looper
Handler subHandler = new Handler();
}
}).start();
}
}
05.UiUtils工具类
package cn.nubia.nubiaappstore.utils;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.os.Process;
import android.view.View;
import android.widget.Toast;
import cn.nubia.nubiaappstore.AppStoreApplication;
/**
* author : gordon
* e-mail : gordon_sun07@163.com
* date : 2019/4/27 20:05
* version: 1.0
* desc : 处理和UI操作相关的工具类
*/
public class UiUtils {
//获取全局context
public static Context getApplicationContext() {
return AppStoreApplication.mInstance.context;
}
//获取主线程的handler
public static Handler getMainThreadHandler() {
return AppStoreApplication.mInstance.mainHandler;
}
//获取主线程的线程id
public static int getMainThreadId() {
return AppStoreApplication.mInstance.mainThreadId;
}
//获取字符串
public static String getString(int resId) {
return getApplicationContext().getResources().getString(resId);
}
//获取字符串数组
public static String[] getStringArray(int resId) {
return getApplicationContext().getResources().getStringArray(resId);
}
//获取drawable
public static Drawable getDrawable(int resId) {
return getApplicationContext().getResources().getDrawable(resId);
}
//获取color
public static int getColor(int resId) {
return getApplicationContext().getResources().getColor(resId);
}
//
public static int getDimen(int resId) {
return getApplicationContext().getResources().getDimensionPixelSize(resId);
}
//dip2px
public static int dip2px(int dip) {
//屏幕密度
float density = getApplicationContext().getResources().getDisplayMetrics().density;
return (int) (dip * density + 0.5f);
}
//px2dip
public static int px2dip(int dip) {
//屏幕密度
float density = getApplicationContext().getResources().getDisplayMetrics().density;
return (int) (dip / density + 0.5f);
}
//加载布局文件
public static View inflateView(int resId) {
return View.inflate(getApplicationContext(), resId, null);
}
//展示toast
public static void showToast(String msg) {
Toast.makeText(getApplicationContext(), msg, Toast.LENGTH_SHORT).show();
}
//是否在主线程
public static boolean isRunOnUiThread() {
//1、获取当前线程id
int curThreadId = Process.myTid();
//2、获取主线程id
int mainThreadId = getMainThreadId();
//3、比较
return curThreadId == mainThreadId;
}
/**
* 保证r在主线程
*
* @param r 任务
*/
public static void runOnUiThread(Runnable r) {
if (isRunOnUiThread()) {//主线程
r.run();
} else {//子线程
getMainThreadHandler().post(r);//将任务r丢到主线程的消息队列
}
}
}
06.布局文件&ViewPager设置数据
在这里插入代码片
08.显示ViewPager内容以及页签控件
创建fragment缓存
package cn.nubia.nubiaappstore.fragment;
import java.util.HashMap;
/**
* author : gordon
* e-mail : gordon_sun07@163.com
* date : 2019/4/27 21:26
* version: 1.0
* desc : viewpager对fragment对象进行缓存
*/
public class FragmentFactory {
private static HashMap<Integer, BaseFragment> sSavedFragment = new HashMap<>();
public static BaseFragment getFragment(int position) {
BaseFragment fragment = sSavedFragment.get(position);
if (fragment == null) {
switch (position) {
case 0:
fragment = new HomeFragment();
break;
case 1:
fragment = new AppFragment();
break;
case 2:
fragment = new GameFragment();
break;
case 3:
fragment = new SubjectFragment();
break;
case 4:
fragment = new RecommendFragment();
break;
case 5:
fragment = new CategoryFragment();
break;
case 6:
fragment = new HotFragment();
break;
}
sSavedFragment.put(position, fragment);
}
return fragment;
}
}
在adapter使用:
@Override
public Fragment getItem(int position) {
BaseFragment fragment = FragmentFactory.getFragment(position);
return fragment;
}
页签控件:绑定viewpager
mViewPager = findViewById(R.id.view_pager);
mPagerTab = findViewById(R.id.pager_tab);
mFm = getSupportFragmentManager();
mViewPager.setAdapter(new MainPagerAdapter(mFm));
//必须重新getPageTitle
mPagerTab.setViewPager(mViewPager);
/**
* 必须重新,父类返回null
* @param position
* @return
*/
@Nullable
@Override
public CharSequence getPageTitle(int position) {
return mTabNames[position];
}
09.LoadingPage的创建_添加相同View
package cn.nubia.nubiaappstore.widget;
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.widget.FrameLayout;
import cn.nubia.nubiaappstore.R;
import cn.nubia.nubiaappstore.utils.UiUtils;
/**
* author : gordon
* e-mail : gordon_sun07@163.com
* date : 2019/4/27 21:55
* version: 1.0
* desc : 载入framelayout,共同的布局等
* LoadingPage作为每个Fragment所需要展示的view对象存在
* 1、加载中的状态 STATE_LOADING mLoadingView
* 2、加载失败 STATE_ERROR mErrorView
* 3、加载成功,但数据集合数量为0 STATE_EMPTY mEmptyView
* 4、加载成功 STATE_SUCCESS mSuccessView
*/
public class LoadingPage extends FrameLayout {
private View mLoadingView;
private View mErrorView;
private View mEmptyView;
private View mSuccessView;
public LoadingPage(Context context) {
this(context, null);
}
public LoadingPage(Context context, AttributeSet attrs) {
this(context, attrs, -1);
}
public LoadingPage(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
if (mLoadingView == null) {
mLoadingView = createLoadingView();
addView(mLoadingView);//add 到帧布局中
}
if (mErrorView == null) {
mErrorView = createErrorView();
addView(mErrorView);//add 到帧布局中
}
if (mEmptyView == null) {
mEmptyView = createEmptyView();
addView(mEmptyView);//add 到帧布局中
}
if (mSuccessView == null) {
mSuccessView = createSuccessView();
addView(mSuccessView);//add 到帧布局中
}
}
private View createSuccessView() {
View view = UiUtils.inflateView(R.layout.layout_success);
return view;
}
private View createEmptyView() {
View view = UiUtils.inflateView(R.layout.layout_empty);
return view;
}
private View createLoadingView() {
View view = UiUtils.inflateView(R.layout.layout_loading);
return view;
}
private View createErrorView() {
View view = UiUtils.inflateView(R.layout.layout_error);
return view;
}
}
10.给LoadingPage增加状态
//状态值
public static final int STATE_LOADING = 0;
public static final int STATE_ERROR = 1;
public static final int STATE_EMPTY = 2;
public static final int STATE_SUCCESS = 3;
//当前状态
private int mCurrState = STATE_LOADING;
/**
* 根据当前状态动态控制显示
*/
private void showRightPage() {
/* if (mCurrState == STATE_LOADING) {
mLoadingView.setVisibility(View.VISIBLE);
mErrorView.setVisibility(View.GONE);
mEmptyView.setVisibility(View.GONE);
} else if (mCurrState == STATE_ERROR) {
mLoadingView.setVisibility(View.GONE);
mErrorView.setVisibility(View.VISIBLE);
mEmptyView.setVisibility(View.GONE);
} else if (mCurrState == STATE_EMPTY) {
mLoadingView.setVisibility(View.GONE);
mErrorView.setVisibility(View.GONE);
mEmptyView.setVisibility(View.VISIBLE);
}*/
mLoadingView.setVisibility((mCurrState == STATE_LOADING) ? View.VISIBLE : View.GONE);
mErrorView.setVisibility((mCurrState == STATE_ERROR) ? View.VISIBLE : View.GONE);
mEmptyView.setVisibility((mCurrState == STATE_EMPTY) ? View.VISIBLE : View.GONE);
}
11.自定义ProgressBar效果
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<!--一层又一层效果叠加-->
<item>
<rotate
android:drawable="@drawable/spinner_big_inner"
android:fromDegrees="0"
android:pivotX="50%"
android:pivotY="50%"
android:toDegrees="720"
android:visible="true"></rotate>
</item>
<item>
<rotate
android:drawable="@drawable/spinner_big_outer"
android:fromDegrees="360"
android:pivotX="50%"
android:pivotY="50%"
android:toDegrees="0"
android:visible="true"></rotate>
</item>
</layer-list>
<ProgressBar
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:indeterminateDrawable="@drawable/customer_progress" />
14.加载网络数据的实现
在这里插入代码片
16.枚举的讲解
/**
* 创建对象简化
* 构造方法私有化,达到对象数量控制
*/
public enum ResultState {
LOADING(STATE_LOADING), ERROR(STATE_ERROR), EMPTY(STATE_EMPTY), SUCCESS(STATE_SUCCESS);
public int state;
private ResultState(int state) {
this.state = state;
}
}
//加载网络数据
//mCurrState = onLoad();
ResultState res = onLoad();
if (res != null) {
mCurrState = res.state;
}
02.MyBaseAdapter抽取第一步
1、抽取基类:
package cn.nubia.nubiaappstore.adapter;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import java.util.ArrayList;
/**
* author : gordon
* e-mail : gordon_sun07@163.com
* date : 2019/5/1 14:38
* version: 1.0
* desc : BaseAdapter抽取
*/
public class MyBaseAdapter extends BaseAdapter {
private ArrayList<String> dataList;
public MyBaseAdapter(ArrayList<String> dataList) {
this.dataList = dataList;
}
@Override
public int getCount() {
return 0;
}
@Override
public Object getItem(int position) {
return null;
}
@Override
public long getItemId(int position) {
return 0;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
return null;
}
}
2、继承
private class MyAdapter extends MyBaseAdapter {
public MyAdapter(ArrayList<String> dataList) {
super(dataList);
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder = null;
if (convertView == null) {
convertView = UiUtils.inflateView(R.layout.list_item_home);
holder = new ViewHolder();
holder.tvContent = (TextView) convertView.findViewById(R.id.tv_content);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
holder.tvContent.setText(mDataList.get(position));
return convertView;
}
}
static class ViewHolder {
TextView tvContent;
}
03.MyBaseAdapter抽取第二步_泛型的引入
package cn.nubia.nubiaappstore.adapter;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import java.util.ArrayList;
/**
* author : gordon
* e-mail : gordon_sun07@163.com
* date : 2019/5/1 14:38
* version: 1.0
* desc : BaseAdapter抽取
* 增加泛型
* 封装的思想:
* 抽取基类:
* 在基类中做的一般都是通用的事情
* 不通用的事情
* 1、父类不知道如何完成的事情,通过抽象方法来交给子类实现
* 2、父类不知道的数据类型,通过泛型来解决,泛型是自定义的一种不存在的类型,这种类型究竟是啥,在定义子类的时候确定
* 尖括号的位置
* 如果在自己的类名后面,代表定义了一个泛型
* 如果跟在父类的名称后面,代表确定父类所定义的泛型类型
*
*/
public class MyBaseAdapter<T> extends BaseAdapter {
private ArrayList<T> dataList;
public MyBaseAdapter(ArrayList<T> dataList) {
this.dataList = dataList;
}
@Override
public int getCount() {
return dataList.size();
}
@Override
public T getItem(int position) {
return dataList.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
return null;
}
}
04.MyBaseAdapter抽取第三步_getView的抽取_BaseHolder的创建
高层次抽取
06.PullToRefreshListView的使用
github:推荐
https://github.com/chrisbanes/Android-PullToRefresh
https://github.com/chrisbanes/PhotoView
自定义属性、自定义控件
08.下拉刷新和上拉加载更多的实现
PullToRefreshListView mListView = new PullToRefreshListView (UiUtils.getApplicationContext());
mListView.setMode(PullToRefreshBase.Mode.BOTH);//既有上拉加载,又有下拉刷新
mListView.setAdapter(new MyAdapter(mDataList));
例子:
@Override
public View fragmentCreateSuccessView() {
for (int i = 0; i < 20; i++) {
mDataList.add("Home:" + i);
}
mListView = new PullToRefreshListView(UiUtils.getApplicationContext());
mListView.setMode(PullToRefreshBase.Mode.BOTH);//既有上拉加载,又有下拉刷新
mAdapter = new MyAdapter(mDataList);
mListView.setAdapter(mAdapter);
mListView.setOnRefreshListener(new RefreshListener());//回调
return mListView;
}
private class RefreshListener implements PullToRefreshBase.OnRefreshListener<ListView> {
@Override
public void onRefresh(PullToRefreshBase<ListView> refreshView) {
LogUtils.e("gordon", "update");
if (mListView.getCurrentMode() == PullToRefreshBase.Mode.PULL_FROM_END) {
//加载下一页数据
loadMore();
} else {
//刷新数据
requestData();
}
}
}
//加载下一页数据
private void loadMore() {
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
for (int i = 0; i < 20; i++) {
mDataList.add("Home:" + i);
}
UiUtils.runOnUiThread(new Runnable() {
@Override
public void run() {
mAdapter.notifyDataSetChanged();
mListView.onRefreshComplete();
}
});
}
}).start();
}
//刷新数据
private void requestData() {
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
mDataList.clear();
for (int i = 0; i < 20; i++) {
mDataList.add("new home:" + i);
}
UiUtils.runOnUiThread(new Runnable() {
@Override
public void run() {
mAdapter.notifyDataSetChanged();
mListView.onRefreshComplete();
}
});
}
}).start();
}
09.HttpHelper的引入
引入以下文件
10.BaseProtocol的建立
package cn.nubia.nubiaappstore.http.protocol;
import cn.nubia.nubiaappstore.http.HttpHelper;
/**
* author : gordon
* e-mail : gordon_sun07@163.com
* date : 2019/5/1 17:12
* version: 1.0
* desc : 自定义http协议
*/
public abstract class BaseProtocol<T> {
public T getData() {
return getDataFromServer();
}
private T getDataFromServer() {
//url组成 主域名+模块名
String url = HttpHelper.URL + getKey() + getParams();
HttpHelper.HttpResult httpResult = HttpHelper.get(url);
if (httpResult!=null) {
String json = httpResult.getString();
return parseJson(json);
}
return null;
}
//解析数据
protected abstract T parseJson(String json);
//请求参数
public abstract String getParams();
//模块名
public abstract String getKey();
}
子类:
package cn.nubia.nubiaappstore.http.protocol;
/**
* author : gordon
* e-mail : gordon_sun07@163.com
* date : 2019/5/1 17:27
* version: 1.0
* desc :
*/
public class HomeProtocol extends BaseProtocol{
@Override
protected Object parseJson(String json) {
return null;
}
@Override
public String getParams() {
return "?index=0";
}
@Override
public String getKey() {
return "home";
}
}
11.okhttp3 请求
基本使用:
https://www.jianshu.com/p/da4a806e599b
P版本异常:
CLEARTEXT communication to 127.0.0.1 not permitted by network security policy
解决:
https://blog.youkuaiyun.com/qq_18620851/article/details/80617549
12.上拉加载下拉刷新更新数据内容
在这里插入代码片