2.新浪微盘授权登录完成
1.微盘开发平台 :http://vdisk.weibo.com/developers/
(1)创建新应用
(2)与新浪微博授权一样
(3)获得appkey和appscr...
2.完成登录----第三方登录
(1)布局:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".LoginActivity" >
<Button
android:id="@+id/btnLogin"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:text="点击授权" />
</RelativeLayout>
(2)查看官方demo,开发文档
(3)关联lib或jar包
(4)配置文件
权限:
<uses-permission android:name="android.permission.INTERNET" >
</uses-permission>
<uses-permission android:name="android.permission.READ_PHONE_STATE" >
</uses-permission>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" >
</uses-permission>
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" >
</uses-permission>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" >
</uses-permission>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
(5)登录代码
public class LoginActivity extends Activity implements VDiskDialogListener {
/*--- 以下的 CONSUMER_KEY CONSUMER_SECRET REDIRECT_URL 是老师申请的.没有basic权限,不能直接反问目录.为了继续往下写,所以使用demo里面的这个几个东西---------------*/
/*public static final String CONSUMER_KEY = "3237555059";
public static final String CONSUMER_SECRET = "2b6c964b071e2ecc28c1835628cc6901";
public static final String REDIRECT_URL = "http://billy.itheima.com";*/
/*--------------- 以下的 CONSUMER_KEY CONSUMER_SECRET REDIRECT_URL 是apidemo里面的 ---------------*/
public static final String CONSUMER_KEY = "2330724462";
public static final String CONSUMER_SECRET = "04f81fc56cc936bfc8f0fa1cef285158";
public static final String REDIRECT_URL = "http://vauth.appsina.com/callback1.php";
private Button mBtnLogin;
private VDiskAuthSession session;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
init();
initView();
initData();
initListener();
}
private void init() {
/**
* 初始化 Init
*/
AppKeyPair appKeyPair = new AppKeyPair(CONSUMER_KEY, CONSUMER_SECRET);
/**
* @AccessType.APP_FOLDER - sandbox 模式
* @AccessType.VDISK - basic 模式
*/
session = VDiskAuthSession.getInstance(this, appKeyPair, AccessType.VDISK);
// 如果session没有过期.我们就不需要再次授权.直接跳到主界面就可以了
if (session.isLinked()) {// 未过期
startActivity(new Intent(this, MainActivity.class));
finish();
}
}
private void initView() {
mBtnLogin = (Button) findViewById(R.id.btnLogin);
}
private void initData() {
// TODO
}
private void initListener() {
mBtnLogin.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// 使用微盘Token认证,需设置重定向网址
// Need to set REDIRECT_URL if you want to use VDisk token.
session.setRedirectUrl(REDIRECT_URL);
// 1.发起授权请求-->让用户输入账号/密码
session.authorize(LoginActivity.this, LoginActivity.this);
}
});
}
/*=============== 2.处理授权的结果-->得到accessToken ===============*/
@Override
public void onComplete(Bundle values) {// 授权完成
if (values != null) {
AccessToken mToken = (AccessToken) values.getSerializable(VDiskAuthSession.OAUTH2_TOKEN);
session.finishAuthorize(mToken);// 把token绑定到session
Toast.makeText(getApplicationContext(), mToken.getToken(), 0).show();
}
startActivity(new Intent(this, MainActivity.class));
finish();
}
@Override
public void onError(VDiskDialogError error) {// 授权错误
// TODO
}
@Override
public void onVDiskException(VDiskException exception) {// 授权异常
// TODO
}
@Override
public void onCancel() {// 授权取消
// TODO
}
}
3.通过微盘登录讲解oauth授权的3个步骤
1.点击了发起授权请求的按钮,也是oauth2.0授权步骤中的第一步,其实就是去打开了一个授权的网页
https://auth.sina.com.cn/oauth2/authorize?client_id=3237555059&redirect_uri=http%3A%2F%2Fbilly.itheima.com&display=mobile
2.用户授权完成之后
回调到回调页,同时传递code
http://billy.itheima.com/?code=ce97366666b1b902575ce207401477ff&state=
3.拿着授权的code请求accessToken
请求地址:https://auth.sina.com.cn/oauth2/access_token
请求方式:post
请求参数的形式:key-value
请求具体参数
client_id=3237555059&client_secret=2b6c964b071e2ecc28c1835628cc6901&grant_type=authorization_code&code=ce97366666b1b902575ce207401477ff&redirect_uri=http%3A%2F%2Fbilly.itheima.com
{
"access_token": "26883566623yk3e3x6rXZ3gOj5J35b6d",
"expires_in": 1437982314,
"time_left": 22868,
"uid": "1884774904",
"refresh_token": "f244f166623yk3e3x6rXZ3gOj5Jf1bb7"
}
4.使用accessToken访问个人信息
https://api.weipan.cn/2/account/info?access_token=26883566623yk3e3x6rXZ3gOj5J35b6d
4.token的3层加密
1.jar包自动加密
2.des-->密码唯一化,复杂化(但是还是不安全)
`this.PASSWORD = "com.sina.vdisk.security.password.d7af3082d815945ff47ae58647bd9436"
+ IMEI + appKeyPair.key + appKeyPair.secret;`
3.秘钥放到so库里面.通过jni调用-->密码放到so库里面.这个时候.加到了获取秘钥的难度.(同样,反编译apk,可以拿到so库,然后可以调用本地方法获取到密码)
4.混淆(也是可以拿到,混淆的时候.我们的字符串是不会进行混淆的.只是混淆我们方法名,以及变量名)
5.梆梆加固,爱加密的使用
1.防止apk反编译
2.梆梆加固:http://www.bangcle.com/
(1).上传,签名工具
3.爱加密的使用
6.文件信息列表初步完成
1.参考官网sdk demo
2.数据来源
7.文件信息列表美化完成
1.ListView优化
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null) {
convertView = MainActivity.this.getLayoutInflater().inflate(R.layout.file_item, null);
holder = new ViewHolder();
holder.tvName = (TextView) convertView.findViewById(R.id.tv_name);
holder.tvTime = (TextView) convertView.findViewById(R.id.tv_time);
holder.tvSize = (TextView) convertView.findViewById(R.id.tv_size);
holder.ivIcon = (ImageView) convertView.findViewById(R.id.iv_icon);
holder.ivOption = (ImageView) convertView.findViewById(R.id.iv_option);
holder.cbCheck = (CheckBox) convertView.findViewById(R.id.cb_checkbox);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
// 得到数据
// 设置数据
Entry entry = mEntries.get(position);
holder.tvName.setText(entry.fileName());
holder.tvSize.setText(entry.size);
Date parseDate = RESTUtility.parseDate(entry.modified);
holder.tvTime.setText(Utils.getFormateTime(parseDate));
if (entry.isDir) {// 如果是文件夹
holder.ivIcon.setImageResource(R.drawable.directory_icon);
// 隐藏大小显示
holder.tvSize.setVisibility(8);
} else {
holder.tvSize.setVisibility(0);
// 根据文件类型做不同的展示
Object[] mimeType = Utils.getMIMEType(entry.fileName());
// type = "image/*";
// res[1] = R.drawable.picture_icon;
// mimeType[0]-->mimetype
// mimeType[1]-->就是mimeType对应应该显示的图片
holder.ivIcon.setImageResource((Integer) mimeType[1]);
}
return convertView;
}
class ViewHolder {
TextView tvName;
TextView tvTime;
TextView tvSize;
ImageView ivIcon;
ImageView ivOption;
CheckBox cbCheck;
}
}
8.pulltofresh集成到文件信息列表中
1.pulltorefresh_lib_vdisk---------------lib包,包含listview,gridview等得下拉刷新
(1)关联lib包
(2)使用里面的自定义控件(如:listview)
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".LoginActivity" >
<com.handmark.pulltorefresh.library.PullToRefreshListView
android:background="#fff"
android:id="@+id/listView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</RelativeLayout>
(3)
private PullToRefreshListView mPullToRefreshListView;
mPullToRefreshListView = (PullToRefreshListView) findViewById(R.id.listView);//本身继承linerlayout,不是listview
mListView = mPullToRefreshListView.getRefreshableView();//所以把lieanlayout中的孩子listview拿出来,才可以用适配器
mListView.setAdapter(mAdapter);
// 加载数据的时候应该显示下载刷新中的视图
mPullToRefreshListView.setRefreshing();// 1. 显示正在加载的一个效果
// 2. 加载完成,关闭加载效果
mPullToRefreshListView.onRefreshComplete();
//下拉刷新
mPullToRefreshListView.setOnRefreshListener(new OnRefreshListener() {
@Override
public void onRefresh() {
// 重新请求网络加载数据
initData();
}
});
// 刷新ui
mAdapter.notifyDataSetChanged();
9.xlistview的使用,SwipeRefreshLayout简介
1.xlistview只专注listview,属于lib包,需要关联
2.xlistview小demo
(1)关联lib包
(2)布局:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity" >
<me.maxwin.view.XListView
android:id="@+id/xlv"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</RelativeLayout>
(3)MianActivity.java
public class MainActivity extends Activity {
private XListView mXlv;
private List<String> mDatas = new ArrayList<String>();
private Handler mHandler = new Handler() {
public void handleMessage(android.os.Message msg) {
if (isLoadMore) {// 如果是加载更多我就追加数据
for (int i = 0; i < 50; i++) {
String str = "我是第" + i + "条数据";
mDatas.add(str);
}
isLoadMore = false;
// 关闭加载更多的效果
mXlv.stopLoadMore();
} else {
mDatas.clear();// 如果是下拉刷新.我就clean数据
for (int i = 0; i < 50; i++) {
String str = "我是第" + i + "条数据";
mDatas.add(str);
}
// 关闭下拉刷新的效果
mXlv.stopRefresh();
}
// 刷新listview
mAdapter.notifyDataSetChanged();
};
};
private boolean isLoadMore;
private MainAdapter mAdapter;
private long mPreUpdateTime;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mXlv = (XListView) findViewById(R.id.xlv);
for (int i = 0; i < 50; i++) {
String str = "我是第" + i + "条数据";
mDatas.add(str);
}
mAdapter = new MainAdapter();
mXlv.setAdapter(mAdapter);
mXlv.setPullRefreshEnable(true);// 是否支持下拉刷新.默认是true
mXlv.setPullLoadEnable(true);// 是否支持上拉加载更多.默认是false
mXlv.setXListViewListener(new IXListViewListener() {
@Override
public void onRefresh() {// 下拉刷新
mHandler.sendMessageDelayed(Message.obtain(), 2000);
if (mPreUpdateTime != 0) {
mXlv.setRefreshTime(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date(mPreUpdateTime)));
}
mPreUpdateTime = System.currentTimeMillis();
System.out.println("--onRefresh---");
}
@Override
public void onLoadMore() {// 上拉加载更多
isLoadMore = true;
mHandler.sendMessageDelayed(Message.obtain(), 2000);
System.out.println("--onLoadMore---");
}
});
}
class MainAdapter extends BaseAdapter {
@Override
public int getCount() {
if (mDatas != null) {
return mDatas.size();
}
return 0;
}
@Override
public Object getItem(int position) {
if (mDatas != null) {
return mDatas.get(position);
}
return null;
}
@Override
public long getItemId(int position) {
// TODO
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
TextView tv = new TextView(MainActivity.this);
tv.setText(mDatas.get(position));
return tv;
}
}
}
3.第三种下拉刷新:系统v4包自带--------------SwipeRefreshLayout
4.第四种下拉刷新:系统自带5.0版本的v4包-------------也叫SwipeRefreshLayout
10.网络引擎的初步封装
11.网络引擎封装完成
1.position = position - mListView.getHeaderViewsCount();// 处理添加头之后的position问题
2.不通网络请求封装到CloudEngine.class中,以方法的形式暴露;
3.所有网络请求结果的处理.通过接口方法回调回来;
4.代码:
(1)CloudEngine.java
public class CloudEngine {
public static CloudEngine instance;
VDiskAPI<VDiskAuthSession> mApi;
public static final int REQ_FILE_LIST = 100;
public static final int REQ_FILE_DELETE = 101;
Context ctx;
private CloudEngine(Context context) {
// 在构造方法里面初始化一些访问api需要的类
ctx = context;
init(context);
}
private void init(Context context) {
AppKeyPair appKeyPair = new AppKeyPair(LoginActivity.CONSUMER_KEY, LoginActivity.CONSUMER_SECRET);
/**
VDISK("basic"), APP_FOLDER("sandbox");
//正式环境-->数据是真实
//测试环境-->数据也是真实-->支付(1分钱)
*/
VDiskAuthSession session = VDiskAuthSession.getInstance(context, appKeyPair, AccessType.VDISK);
mApi = new VDiskAPI<VDiskAuthSession>(session);
}
//单例方法
public static CloudEngine getInstance(Context context) {
if (instance == null) {
synchronized (CloudEngine.class) {
if (instance == null) {
instance = new CloudEngine(context);
}
}
}
return instance;
}
/**得到文件夹列表*/
public void getFileList(IDataCallBack dataCallBack, int reqCode) {
new FileListTask(dataCallBack, reqCode).execute();
}
/**删除文件*/
public void deleteFile(IDataCallBack dataCallBack, String path, int reqCode) {
new FileDeleteTask(dataCallBack, path, reqCode).execute();
}
class FileDeleteTask extends BaseTask {
String mPath;
public FileDeleteTask(IDataCallBack dataCallBack, String path, int reqCode) {
super(dataCallBack, reqCode);
mPath = path;
}
@Override
protected Void doInBackground(Void... params) {
// 真正的发起请求删除文件
try {
Entry deletedEntry = mApi.delete(mPath);// 删除完成会返回当前删除的对象
mEvent.data = deletedEntry;// 数据的赋值
} catch (VDiskException e) {
// TODO Auto-generated catch block
e.printStackTrace();
updateEvent(ctx, e, mEvent);
}
return null;
}
}
class FileListTask extends BaseTask {
/**
* 通过构造方法初始化IDataCallBack
* @param dataCallBack
* @param reqCode
*/
public FileListTask(IDataCallBack dataCallBack, int reqCode) {
super(dataCallBack, reqCode);
mEvent.reqCode = reqCode;// 请求码赋值
}
@Override
protected Void doInBackground(Void... params) {// 子线程
try {
Entry metadata = mApi.metadata("/", null, true, false);
List<Entry> contents = metadata.contents;
mEvent.data = contents;// 对应的数据赋值
// 传递数据
// 请求码-->区分不同的请求-->请求的统一管理
// 错误码-->区分不同错误信息-->错误的统一管理
} catch (VDiskException e) {
e.printStackTrace();
updateEvent(ctx, e, mEvent);
}
return null;
}
}
/*--------------- 抽取asynctask的基类 ---------------*/
abstract class BaseTask extends AsyncTask<Void, Void, Void> {
IDataCallBack mDataCallBack;
Event mEvent;
/**
* 通过构造方法初始化IDataCallBack
* @param dataCallBack
* @param reqCode
*/
public BaseTask(IDataCallBack dataCallBack, int reqCode) {
super();
mDataCallBack = dataCallBack;
mEvent = new Event();
mEvent.reqCode = reqCode;// 请求码赋值
}
@Override
protected void onPostExecute(Void result) {
// 需要用接口对象 传递数据
mDataCallBack.handleServerData(mEvent.reqCode, mEvent.errCode, mEvent.data);
super.onPostExecute(result);
}
}
}
(2)IDataCallBack.java
public interface IDataCallBack {
// 传递数据
// 请求码-->区分不同的请求-->请求的统一管理
// 错误码-->区分不同错误信息-->错误的统一管理
void handleServerData(int reqCode, int errCode, Object data);
}
(3)Event.java
public class Event {
public int reqCode;//请求码
public int errCode;//错误码
public Object data;//具体数据
}
(4)CloudEngine.getInstance(this).getFileList(this, CloudEngine.REQ_FILE_LIST);
12.asytask使用总结(基本使用,版本差异,简单封装)
1.asytask网址:http://blog.csdn.net/liuhe688/article/details/6532519
2.基本使用
protected void onPreExecute()
protected abstract Result doInBackground(Params... params)
protected void onPostExecute(Result result)
protected void onProgressUpdate(Progress... values)
3.AsyncTask源码分析
private static final int CORE_POOL_SIZE = 5; //核心线程数
private static final int MAXIMUM_POOL_SIZE = 128; //最大线程数
private static final int KEEP_ALIVE = 1; //超时时间,当线程数超过核心线程数时,超过这个时间的空线程就会被销毁,直到线程数等于核心线程
4.AsyncTask缺陷
* 1.同时只有5个线程去访问网络-->这个是重点
* 2.线程数目超过128,会抛异常-->这个情况其实还好;
5.AsyncTask版本差异
* CORE_POOL_SIZE MAXIMUM_POOL_SIZE KEEP_ALIVE在不同的版本上.值是不一样;
* 1.5前是串行执行的.每次执行1个任务
* 1.6-2.3之前的版本.是并行执行的.每次执行5个任务
* 3.0后提供串行和并行,默认情况是串行
executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, null);//串行
executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, null);//并行
6.AsyncTask简单封装
> 实际开发我们会去继承Asynctask
###AsyncTask函数化的封装,AsyncTask函数式的调用
13.asynctask函数式调用
1.相当于handle消息机制
2.asynctask函数式调用Demo
(1)AsyncTaskUtils.java
public class AsyncTaskUtils {
public static <T> void doAsync(final IDataCallBack<T> callBack) {
new AsyncTask<Void, Void, T>() {
protected void onPreExecute() {
callBack.onTaskBefore();
};
@Override
protected T doInBackground(Void... params) {
// TODO
return callBack.onTasking(params);
}
protected void onPostExecute(T result) {
callBack.onTaskAfter(result);
};
}.execute();
}
}
(2)IDataCallBack.java----回调的方法
public interface IDataCallBack<T> {
/**任务执行之前*/
void onTaskBefore();
/**任务执行中...*/
T onTasking(Void... params);
/**任务执行之后*/
void onTaskAfter(T result);
}
(3)BaseActivity.java
public class BaseActivity extends Activity {
public <T> void doAsync(IDataCallBack<T> callBack) {
AsyncTaskUtils.doAsync(callBack);
}
}
(4)MainActivity.java----使用
findViewById(R.id.btn2).setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
MainActivity.this.doAsync(new IDataCallBack<String>() {
@Override
public void onTaskBefore() {
}
@Override
public String onTasking(Void... params) {
String result = "";
try {
DefaultHttpClient httpClient = new DefaultHttpClient();
HttpGet get = new HttpGet("http://www.baidu.com");
HttpResponse response = httpClient.execute(get);
if (response.getStatusLine().getStatusCode() == 200) {
result = EntityUtils.toString(response.getEntity());
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return result;
}
@Override
public void onTaskAfter(String result) {
System.out.println(result);
}
});
}
});
}
14.接口回调再次理解-----------------------------------另开博客写总结小
1.handler机制+thread
2.怎么理解接口回调-->接口回调就是一个通知机制
3.作用:1.单纯的通知 2.通知+传值
4. 步骤:
(1).定义接口,以及接口方法
(2).定义接口对象
(3).在某一个地方.接口对象调用接口方法
(5).暴露接口对象(构造方法,setter方法)
5.小Demo
(1)Me.java
public class Me {
private Timer mTimer;
/**想睡觉*/
public void wantSleep() {
System.out.println("昨晚敲代码敲到4点钟,突然想睡觉...");
}
/**开始睡觉*/
public void startSleep() {
mTimer = new Timer();
mTimer.schedule(new TimerTask() {
@Override
public void run() {
System.out.println("开始呼呼大睡.........");
}
}, 0, 1000);
}
/**停止睡觉*/
public void stopSleep() {
if (mTimer != null) {
mTimer.cancel();
mTimer = null;
System.out.println("停止了睡觉");
}
}
}
(2)ClassMate.java
public class ClassMate {
// 2.定义接口对象
OnTeacherComeListener mOnTeacherComeListener;
/**
* 方式1:通过构造方法赋值
*/
public ClassMate(OnTeacherComeListener onTeacherComeListener) {
super();
mOnTeacherComeListener = onTeacherComeListener;
}
public ClassMate() {
super();
}
/**模拟老师来了*/
public void doTeacherCome(String teacherName) {
// 3.在某一个地方.接口对象调用接口方法-->老师来了的时候
mOnTeacherComeListener.onTeachCome(teacherName);
}
// 4.暴露接口对象(构造方法,setter方法)
/**
* 方式2:通过setter赋值
*/
public void setOnTeacherComeListener(OnTeacherComeListener onTeacherComeListener) {
mOnTeacherComeListener = onTeacherComeListener;
}
}
(3)OnTeacherComeListener.java
// 1.定义接口,以及接口方法
public interface OnTeacherComeListener {
void onTeachCome(String teacherName);
void onTeachCome();
}
(4)Test
public class Test {
public static void main(String[] args) {
final Me me = new Me();
// 我想睡觉
me.wantSleep();
// 找到一个同桌
ClassMate classMate = new ClassMate();
System.out.println("我去和同桌协商......");
// 和他商量好-->如果老师来了.你拍醒我.让我停止睡觉
classMate.setOnTeacherComeListener(new OnTeacherComeListener() {
@Override
public void onTeachCome(String teacherName) {// 通知+传值的效果
if ("伍老师".equals(teacherName)) {// 回调过程中.有传值的效果
System.out.println("伍老师不是班主任,我继续睡觉");
} else if ("李老师".equals(teacherName)) {
me.stopSleep();//
}
}
@Override
public void onTeachCome() {// 通知
}
});
// 模拟商量了2s钟
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 开始睡觉
me.startSleep();
// 模拟伍老师来了.
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
classMate.doTeacherCome("伍老师");
// 模拟伍老师来了.
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
classMate.doTeacherCome("李老师");
}
}
15.自定义异常,统一异常处理