需求:使用MVP框架
1、登录注册功能,登录页面和注册页面分别用一个Fragment实现,
点击对应按钮时动态切换Fragment的显示,
使用sqlite操作模拟登录注册的网络请求,
登录注册使用MVP模式完成,正确创建View层接口,
正确创建Model层接口和实现
正确使用Presenter完成view和model层的逻辑实现
2、登录成功后,跳转到主界面,实现页面效果
点击“QQ登录”,实现第三方登录,并获取用户的信息,把头像、姓名、等级、地址显示到界面上。
3、点击列表选项卡,进入列表页面,使用线程安全的单例模式封装OkHttp网络请求,把OkHttp回调封装在主线程中执行,
添加拦截器(必须添加指定拦截器LoggingInterceptor.java,否则数 据无法加载) ,
4、把接口地址请求回来的数据封装成JavaBean,
使用RecyclerView加载数据,
根据offset参数实现下拉刷新上拉加载(可使用第三方,如xRecyclerView或 SwipeRefreshLayout)
5. 添加RecyclerView的单击事件,
点击RecyclerView控件后把对应条目的标题传到详情Activity并显示(详情页效果图未提供,里面就一个TextView,接收到数据后,给TextView设置值即可)
6. 添加RecyclerView的长按事件,长按删除该条目
1. 导包:gson包,ImageLoader包,open_sdk_r5886_lite.jar包用于第三方QQ登录
2. 添加依赖:
(1)butterknife自动生成控件id和点击事件:
compile 'com.jakewharton:butterknife:7.0.0'
(2)okhttp依赖: compile 'com.squareup.okhttp3:okhttp:3.9.0'
(3)recyclerview依赖(我自己的版本需要把SDK改为25版本):
compile 'com.android.support:recyclerview-v7:25.3.1'
compile 'com.yqritc:recyclerview-flexibledivider:1.4.0'
(4)springview依赖
compile 'com.liaoinstan.springview:library:1.3.0'
一 . 首先编写OKhttp的封装类
import java.io.File; import java.util.Map; import java.util.concurrent.TimeUnit; import okhttp3.FormBody; import okhttp3.MediaType; import okhttp3.MultipartBody; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.RequestBody; /** * Okhttp 单例 范型的封装 */ public class OkhttpUtils { private static OkhttpUtils okhttpUtils = null ; private OkhttpUtils(){ } public static OkhttpUtils getInstance(){ if(okhttpUtils == null){ okhttpUtils = new OkhttpUtils(); client = new OkHttpClient.Builder() .readTimeout(20, TimeUnit.SECONDS) .writeTimeout(20,TimeUnit.SECONDS) .connectTimeout(20,TimeUnit.SECONDS) .addInterceptor(new LoggingInterceptor()) .build(); } return okhttpUtils ; } private static OkHttpClient client ; public void asy(Map<String,String> params,String url,AbstractUiCallBack callBack){ Request request = null ; if(params != null){ FormBody.Builder builder = new FormBody.Builder() ; for(Map.Entry<String,String> entry : params.entrySet()){ builder.add(entry.getKey(),entry.getValue()); } FormBody body = builder.build(); request = new Request.Builder() .url(url) .post(body) .build(); } else { request = new Request.Builder() .url(url) .build(); } client.newCall(request).enqueue(callBack); } private static final MediaType MEDIA_TYPE_PNG = MediaType.parse("image/png"); public static void postFile(Map<String,String> map, String url, File file,AbstractUiCallBack callBack) { String[] array = file.getAbsolutePath().split("\\/"); MultipartBody.Builder builder = new MultipartBody.Builder(); builder.setType(MultipartBody.FORM); for (Map.Entry<String, String> entry : map.entrySet()) { builder.addFormDataPart(entry.getKey(), entry.getValue()); } builder.addFormDataPart("imageFileName", array[array.length - 1]); if (file.exists() && file.length() > 0) { builder.addFormDataPart("image", array[array.length - 1], RequestBody.create(MEDIA_TYPE_PNG, file)); } MultipartBody body = builder.build(); Request request = new Request.Builder() .url(url) .post(body) .build(); client.newCall(request).enqueue(callBack); } }
OKhttp封装需实现的接口类
import android.os.Handler; import android.os.Looper; import com.google.gson.Gson; import com.google.gson.JsonSyntaxException; import java.io.IOException; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import okhttp3.Call; import okhttp3.Callback; import okhttp3.Response; /** * * Okhttp 单例 范型的封装 */ public abstract class AbstractUiCallBack<T> implements Callback { /** * 成功回调 * @param t */ public abstract void success(T t); /** * 失败回调 * @param e */ public abstract void failure(Exception e); private Handler handler = null ; private Class clazz ; public AbstractUiCallBack(){ handler = new Handler(Looper.getMainLooper()); // 得到的是一个 AbstractUiCallBack<T> 的Type Type type = getClass().getGenericSuperclass() ; // 得到的是T的实际Type Type [] arr = ((ParameterizedType)type).getActualTypeArguments() ; clazz = (Class) arr[0] ; } @Override public void onFailure(Call call, IOException e) { failure(e); } @Override public void onResponse(Call call, Response response) throws IOException { try { String result = response.body().string(); System.out.println("result = " + result); Gson gson = new Gson(); final T t = (T) gson.fromJson(result,clazz); handler.post(new Runnable() { @Override public void run() { success(t); } }); } catch (IOException e) { e.printStackTrace(); failure(e); } catch (JsonSyntaxException e) { e.printStackTrace(); failure(e); } } }
二. 拦截器类
package com.bwie.secondweek_moni.okhttp; import android.os.Build; import java.io.IOException; import okhttp3.Interceptor; import okhttp3.Request; import okhttp3.Response; /** * Created by 笔片 on 2017/10/16. * 网络拦截器 */ public class LoggingInterceptor implements Interceptor{ private static final String UA = "User-Agent"; @Override public Response intercept(Chain chain) throws IOException { Request request = chain.request() .newBuilder() .addHeader(UA, makeUA()) .build(); return chain.proceed(request); } private String makeUA() { String s = Build.BRAND + "/" + Build.MODEL + "/" + Build.VERSION.RELEASE; return Build.BRAND + "/" + Build.MODEL + "/" + Build.VERSION.RELEASE; } }
package com.bwie.secondweek_moni.model; import android.content.Context; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import com.bwie.secondweek_moni.sqlite.MyHelper; import com.bwie.secondweek_moni.view_jiekou.LoginModelCallBack; import com.bwie.secondweek_moni.view_jiekou.RegModelCallBack; //model层模块,即对数据库操作的类 public class MyModel { //注册数据时的 访问数据库方法 public void reg(Context context, String tel, String pwd, RegModelCallBack regModelCallBack){ //注册时添加数据库数据 MyHelper myHelper = new MyHelper(context); SQLiteDatabase database = myHelper.getWritableDatabase(); database.execSQL("insert into user(tel,pwd) values(?,?)",new String[]{tel,pwd}); database.close(); //注册成功的回调 regModelCallBack.regSuccess(); } //登录时的 访问数据库方法 public void login(Context context, String tel, String pwd, LoginModelCallBack loginModelCallBack){ //登录时查询数据库数据 MyHelper myHelper = new MyHelper(context); SQLiteDatabase database = myHelper.getWritableDatabase(); Cursor cursor = database.rawQuery("select * from user where tel = ? and pwd = ?", new String[]{tel, pwd}); if (cursor.moveToNext()){ //数据查询到时就成功回调方法 loginModelCallBack.loginSuccess(); }else { loginModelCallBack.loginFailed(); } } }
四. view层
1. 登录时model层接口
package com.bwie.secondweek_moni.view_jiekou; //登录时的接口 public interface LoginModelCallBack { public void loginSuccess(); public void loginFailed(); }
2. 登录时view层接口
package com.bwie.secondweek_moni.view_jiekou; //登录时在view层回调判断数据的接口 public interface LoginViewCallBack { //登陆判断非空 public void loginTelEmpty(); public void loginPwdEmpty(); public void loginSuccess(); public void loginFailed(); }
3. 注册时model层接口
package com.bwie.secondweek_moni.view_jiekou; //注册时的接口 public interface RegModelCallBack { public void regSuccess(); }4. 注册时view层接口
package com.bwie.secondweek_moni.view_jiekou; //注册时在view层回调判断数据的接口 public interface RegViewCallBack { //注册判断非空 public void regTelEmpty(); public void regPwdEmpty(); public void regSuccess(); public void regFailed(); }
五. presenter层
package com.bwie.secondweek_moni.presenter; import android.support.v4.app.FragmentActivity; import android.text.TextUtils; import com.bwie.secondweek_moni.model.MyModel; import com.bwie.secondweek_moni.view_jiekou.LoginModelCallBack; import com.bwie.secondweek_moni.view_jiekou.RegModelCallBack; //Presenter层 调用model中的注册 和 登录的方法 public class MyPresenter { FragmentActivity activity; //获取登录和注册时view层数据,声明为当前变量 LoginViewCallBack loginViewCallBack; RegViewCallBack regViewCallBack; public MyPresenter(FragmentActivity activity, LoginViewCallBack loginViewCallBack, RegViewCallBack regViewCallBack) { this.activity = activity; this.loginViewCallBack = loginViewCallBack; this.regViewCallBack = regViewCallBack; } //获取model层 MyModel model = new MyModel(); //注册时在view层回调判断数据的接口 public interface RegViewCallBack { //注册判断非空 public void regTelEmpty(); public void regPwdEmpty(); public void regSuccess(); public void regFailed(); } //登录时在view层回调判断数据的接口 public interface LoginViewCallBack { //登陆判断非空 public void loginTelEmpty(); public void loginPwdEmpty(); public void loginSuccess(); public void loginFailed(); } //在Presenter层逻辑判断注册时非空 public void reg_PanDuan(String tel,String pwd){ if (TextUtils.isEmpty(tel)){ //回调判断注册手机号时的接口方法 regViewCallBack.regTelEmpty(); return; }else if (TextUtils.isEmpty(pwd)){ //回调判断注册密码时的接口方法 regViewCallBack.regPwdEmpty(); return; } //如果注册成功就调用注册接口的成功方法 model.reg(activity, tel, pwd, new RegModelCallBack() { @Override public void regSuccess() { regViewCallBack.regSuccess(); } }); } //在Presenter层逻辑判断登录时非空 public void login_PanDuan(String tel,String pwd){ if (TextUtils.isEmpty(tel)){ //回调判断登录手机号时的接口方法 loginViewCallBack.loginTelEmpty(); return; }else if (TextUtils.isEmpty(pwd)){ //回调判断登录密码时的接口方法 loginViewCallBack.loginPwdEmpty(); return; } //调用登录接口的方法 model.login(activity, tel, pwd, new LoginModelCallBack() { @Override public void loginSuccess() { loginViewCallBack.loginSuccess(); } @Override public void loginFailed() { loginViewCallBack.loginFailed(); } }); } }
六. imageloader工具类及其全局初始化配置
(1)全局初始化配置类:
package com.bwie.secondweek.util; import android.app.Application; //全局初始化Application类 public class BaseApplication extends Application { @Override public void onCreate() { super.onCreate(); //配置imageLoader ImageLoaderUtil.init(this); } }
(2)imageloader工具类:
package com.bwie.secondweek.util; import android.content.Context; import android.graphics.Bitmap; import com.nostra13.universalimageloader.cache.disc.impl.UnlimitedDiscCache; import com.nostra13.universalimageloader.cache.disc.naming.HashCodeFileNameGenerator; import com.nostra13.universalimageloader.cache.memory.impl.LruMemoryCache; import com.nostra13.universalimageloader.core.DisplayImageOptions; import com.nostra13.universalimageloader.core.ImageLoader; import com.nostra13.universalimageloader.core.ImageLoaderConfiguration; import com.nostra13.universalimageloader.core.assist.ImageScaleType; import com.nostra13.universalimageloader.core.assist.QueueProcessingType; import com.nostra13.universalimageloader.core.decode.BaseImageDecoder; import com.nostra13.universalimageloader.core.display.RoundedBitmapDisplayer; import com.nostra13.universalimageloader.core.display.SimpleBitmapDisplayer; import com.nostra13.universalimageloader.core.download.BaseImageDownloader; import com.nostra13.universalimageloader.utils.StorageUtils; import java.io.File; public class ImageLoaderUtil { /** * 初始化imageLoader * @param context */ public static void init(Context context) { //1.获取配置config对象 File cacheDir = StorageUtils.getCacheDirectory(context); //缓存文件夹路径 ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(context) .threadPoolSize(3) // default 线程池内加载的数量 .threadPriority(Thread.NORM_PRIORITY - 2) // default 设置当前线程的优先级 .tasksProcessingOrder(QueueProcessingType.FIFO) // default .denyCacheImageMultipleSizesInMemory() .memoryCache(new LruMemoryCache(2 * 1024 * 1024)) //可以通过自己的内存缓存实现 .memoryCacheSize(2 * 1024 * 1024) // 内存缓存的最大值 .memoryCacheSizePercentage(13) // default .diskCache(new UnlimitedDiscCache(cacheDir)) // default 可以自定义缓存路径 .diskCacheSize(50 * 1024 * 1024) // 50 Mb sd卡(本地)缓存的最大值 .diskCacheFileCount(100) // 可以缓存的文件数量 // default为使用HASHCODE对UIL进行加密命名, 还可以用MD5(new Md5FileNameGenerator())加密 .diskCacheFileNameGenerator(new HashCodeFileNameGenerator()) .imageDownloader(new BaseImageDownloader(context)) // default .imageDecoder(new BaseImageDecoder(true)) // default .defaultDisplayImageOptions(DisplayImageOptions.createSimple()) // default .writeDebugLogs() // 打印debug log .build(); //开始构建 //2.初始化配置...ImageLoader.getInstance()图片加载器的对象,单例模式 ImageLoader.getInstance().init(config); } /** * imageLoader加载图片的默认选项 * @return */ public static DisplayImageOptions getDefaultOption(){ DisplayImageOptions options = new DisplayImageOptions.Builder() .showImageOnLoading(R.mipmap.ic_launcher) // 设置图片下载期间显示的默认图片 .showImageForEmptyUri(R.mipmap.ic_launcher) // 设置图片Uri为空或是错误的时候显示的图片 .showImageOnFail(R.mipmap.ic_launcher) // 设置图片加载或解码过程中发生错误显示的图片 .resetViewBeforeLoading(true) // default 设置图片在加载前是否重置、复位 .delayBeforeLoading(1000) // 下载前的延迟时间 .cacheInMemory(true) // default 设置下载的图片是否缓存在内存中 .cacheOnDisk(true) // default 设置下载的图片是否缓存在SD卡中 .considerExifParams(true) // default .imageScaleType(ImageScaleType.IN_SAMPLE_POWER_OF_2) // default 设置图片以如何的编码方式显示 .bitmapConfig(Bitmap.Config.RGB_565) // default 设置图片的解码类型 .displayer(new SimpleBitmapDisplayer()) // default 还可以设置圆角图片new RoundedBitmapDisplayer(20) .build(); return options; } /** * imageLoader加载圆角图片....指定圆角的大小 * @return */ public static DisplayImageOptions getRoundedOption(int corner){ DisplayImageOptions options = new DisplayImageOptions.Builder() .showImageOnLoading(R.mipmap.ic_launcher) // 设置图片下载期间显示的图片 .showImageForEmptyUri(R.mipmap.ic_launcher) // 设置图片Uri为空或是错误的时候显示的图片 .showImageOnFail(R.mipmap.ic_launcher) // 设置图片加载或解码过程中发生错误显示的图片 .resetViewBeforeLoading(true) // default 设置图片在加载前是否重置、复位 .delayBeforeLoading(1000) // 下载前的延迟时间 .cacheInMemory(true) // default 设置下载的图片是否缓存在内存中 .cacheOnDisk(true) // default 设置下载的图片是否缓存在SD卡中 .considerExifParams(true) // default .imageScaleType(ImageScaleType.IN_SAMPLE_POWER_OF_2) // default 设置图片以如何的编码方式显示 .bitmapConfig(Bitmap.Config.RGB_565) // default 设置图片的解码类型 .displayer(new RoundedBitmapDisplayer(corner)) // default 还可以设置圆角图片new RoundedBitmapDisplayer(20) .build(); return options; } }
七. 数据接口封装的bean类(根据自己需要定义)
1.一个是第三方登录QQ时返回的个人数据bean类;
2.一个是网络请求数据时返回的bean类;
八. 数据库创建类
package com.bwie.secondweek_moni.sqlite; import android.content.Context; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; //数据库 public class MyHelper extends SQLiteOpenHelper{ public MyHelper(Context context) { super(context, "user.db", null, 1); } @Override public void onCreate(SQLiteDatabase db) { //创建数据库 db.execSQL("create table user(tel varchar(20),pwd password(20))"); } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { } }
九. 主功能代码MainActivity类
package com.bwie.secondweek_moni; import android.os.Bundle; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentPagerAdapter; import android.support.v4.view.ViewPager; import android.support.v7.app.AppCompatActivity; import android.widget.RadioButton; import android.widget.RadioGroup; import com.bwie.secondweek_moni.fragment.Login_Fragment; import com.bwie.secondweek_moni.fragment.Reg_Fragment; import java.util.ArrayList; import java.util.List; import butterknife.Bind; import butterknife.ButterKnife; public class MainActivity extends AppCompatActivity { @Bind(R.id.button_person) RadioButton buttonPerson; @Bind(R.id.button_list) RadioButton buttonList; @Bind(R.id.groups) RadioGroup groups; @Bind(R.id.main_viewPager) ViewPager mainViewPager; private List<Fragment> list; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ButterKnife.bind(this); //定义集合添加数据 list = new ArrayList<>(); list.add(new Login_Fragment()); list.add(new Reg_Fragment()); //加入此行代码可使当页数据一直有效显示,不会随着页面滑动而消失 mainViewPager.setOffscreenPageLimit(list.size()); //设置适配器 mainViewPager.setAdapter(new FragmentPagerAdapter(getSupportFragmentManager()) { @Override public Fragment getItem(int position) { return list.get(position); } @Override public int getCount() { return list.size(); } }); //设置viewpager的滑动监听事件 mainViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() { @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { } @Override public void onPageSelected(int position) { groups.check(groups.getChildAt(position).getId()); } @Override public void onPageScrollStateChanged(int state) { } }); //设置button按钮的监听事件 groups.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() { @Override public void onCheckedChanged(RadioGroup group, int checkedId) { switch (checkedId) { case R.id.button_person: mainViewPager.setCurrentItem(0, false); break; case R.id.button_list: mainViewPager.setCurrentItem(1, false); break; default: break; } } }); } }
9.1 对应的登录页面fragment:
package com.bwie.secondweek_moni.fragment; import android.content.Intent; import android.os.Bundle; import android.support.annotation.Nullable; import android.support.v4.app.Fragment; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.Button; import android.widget.EditText; import android.widget.Toast; import com.bwie.secondweek_moni.R; import com.bwie.secondweek_moni.activity.SecondActivity; import com.bwie.secondweek_moni.activity.ThirdActivity; import com.bwie.secondweek_moni.presenter.MyPresenter; import butterknife.Bind; import butterknife.ButterKnife; import butterknife.OnClick; //登录页 public class Login_Fragment extends Fragment { @Bind(R.id.tel_Login) EditText telLogin; @Bind(R.id.pwd_Login) EditText pwdLogin; @Bind(R.id.login) Button login; @Bind(R.id.qqLogin) Button qqLogin; private MyPresenter myPresenter; @Nullable @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { View view = inflater.inflate(R.layout.login_fragment, container, false); ButterKnife.bind(this, view); return view; } @Override public void onActivityCreated(@Nullable Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); myPresenter = new MyPresenter(getActivity(), new MyPresenter.LoginViewCallBack() { @Override public void loginTelEmpty() { Toast.makeText(getActivity(),"登录时 手机号不能为空",Toast.LENGTH_SHORT).show(); } @Override public void loginPwdEmpty() { Toast.makeText(getActivity(),"登录时 密码不能为空",Toast.LENGTH_SHORT).show(); } @Override public void loginSuccess() { Toast.makeText(getActivity(),"登录成功!即将跳转到主页面",Toast.LENGTH_SHORT).show(); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } Intent intent = new Intent(getActivity(), ThirdActivity.class); startActivity(intent); } @Override public void loginFailed() { Toast.makeText(getActivity(),"登录失败!用户信息输入错误...",Toast.LENGTH_SHORT).show(); } }, new MyPresenter.RegViewCallBack() { @Override public void regTelEmpty() { } @Override public void regPwdEmpty() { } @Override public void regSuccess() { } @Override public void regFailed() { } }); } @Override public void onDestroyView() { super.onDestroyView(); ButterKnife.unbind(this); } @OnClick({R.id.login,R.id.qqLogin}) public void onViewClicked(View view) { switch (view.getId()) { case R.id.login: //登录按钮的非空判断 myPresenter.login_PanDuan(telLogin.getText().toString(),pwdLogin.getText().toString()); break; case R.id.qqLogin: //第三方QQ登录 Intent intent = new Intent(getActivity(), SecondActivity.class); startActivity(intent); break; } } }9.2 对应的注册页面fragment:
package com.bwie.secondweek_moni.fragment; import android.os.Bundle; import android.support.annotation.Nullable; import android.support.v4.app.Fragment; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.Button; import android.widget.EditText; import android.widget.Toast; import com.bwie.secondweek_moni.R; import com.bwie.secondweek_moni.presenter.MyPresenter; import butterknife.Bind; import butterknife.ButterKnife; import butterknife.OnClick; //注册页 public class Reg_Fragment extends Fragment { @Bind(R.id.tel_Reg) EditText telReg; @Bind(R.id.pwd_Reg) EditText pwdReg; @Bind(R.id.reg) Button reg; private MyPresenter myPresenter; @Nullable @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { View view = inflater.inflate(R.layout.reg_fragment, container, false); ButterKnife.bind(this, view); return view; } @Override public void onActivityCreated(@Nullable Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); myPresenter = new MyPresenter(getActivity(), new MyPresenter.LoginViewCallBack() { @Override public void loginTelEmpty() { } @Override public void loginPwdEmpty() { } @Override public void loginSuccess() { } @Override public void loginFailed() { } }, new MyPresenter.RegViewCallBack() { @Override public void regTelEmpty() { Toast.makeText(getActivity(),"注册时 手机号不能为空",Toast.LENGTH_SHORT).show(); } @Override public void regPwdEmpty() { Toast.makeText(getActivity(),"注册时 密码不能为空",Toast.LENGTH_SHORT).show(); } @Override public void regSuccess() { Toast.makeText(getActivity(),"注册成功!请前往登录页面!",Toast.LENGTH_SHORT).show(); } @Override public void regFailed() { Toast.makeText(getActivity(),"注册失败!请重新注册!",Toast.LENGTH_SHORT).show(); } }); } @Override public void onDestroyView() { super.onDestroyView(); ButterKnife.unbind(this); } @OnClick(R.id.reg) public void onViewClicked() { //点击注册按钮 调用presenter层去逻辑判断非空 myPresenter.reg_PanDuan(telReg.getText().toString(),pwdReg.getText().toString()); } }
十. 第三方QQ登录页
package com.bwie.secondweek_moni.activity; import android.content.Intent; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.util.Log; import android.view.View; import android.widget.Toast; import com.bwie.secondweek_moni.R; import com.bwie.secondweek_moni.bean.UserBean; import com.google.gson.Gson; import com.tencent.connect.UserInfo; import com.tencent.connect.auth.QQToken; import com.tencent.connect.common.Constants; import com.tencent.tauth.IUiListener; import com.tencent.tauth.Tencent; import com.tencent.tauth.UiError; import org.json.JSONException; import org.json.JSONObject; //QQ第三方登录页 public class SecondActivity extends AppCompatActivity { private static final String APP_ID = "1105602574";//官方获取的APPID private static final String TAG = "MainActivity"; private BaseUiListener mIUiListener; private UserInfo mUserInfo; private Tencent mTencent; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_second); //传入参数APPID和全局Context上下文 mTencent = Tencent.createInstance(APP_ID,SecondActivity.this.getApplicationContext()); } public void qq_Second(View v){ /**通过这句代码,SDK实现了QQ的登录,这个方法有三个参数,第一个参数是context上下文,第二个参数SCOPO 是一个String类型的字符串,表示一些权限 官方文档中的说明:应用需要获得哪些API的权限,由“,”分隔。例如:SCOPE = “get_user_info,add_t”;所有权限用“all” 第三个参数,是一个事件监听器,IUiListener接口的实例,这里用的是该接口的实现类 */ mIUiListener = new BaseUiListener(); //all表示获取所有权限 mTencent.login(SecondActivity.this,"all", mIUiListener); } /** * 自定义监听器实现IUiListener接口后,需要实现的3个方法 * onComplete完成 onError错误 onCancel取消 */ private class BaseUiListener implements IUiListener { @Override public void onComplete(Object response) { Toast.makeText(SecondActivity.this, "授权成功", Toast.LENGTH_SHORT).show(); Log.e(TAG, "response:" + response); JSONObject obj = (JSONObject) response; try { String openID = obj.getString("openid"); String accessToken = obj.getString("access_token"); String expires = obj.getString("expires_in"); mTencent.setOpenId(openID); mTencent.setAccessToken(accessToken,expires); QQToken qqToken = mTencent.getQQToken(); mUserInfo = new UserInfo(getApplicationContext(),qqToken); mUserInfo.getUserInfo(new IUiListener() { @Override public void onComplete(final Object response) { //用户登录成功后会返回用户的数据,在此可以封装成bean类,跳转传值,设置用户的基本信息 Log.i(TAG,"登录成功"+response.toString()); runOnUiThread(new Runnable() { @Override public void run() { //跳转传值,设置用户信息 UserBean userBean = new Gson().fromJson(response.toString(), UserBean.class); Intent intent = new Intent(SecondActivity.this,ThirdActivity.class); intent.putExtra("headPhoto",userBean.getFigureurl_qq_1()); intent.putExtra("name",userBean.getNickname()); intent.putExtra("gender",userBean.getGender()); String province = userBean.getProvince(); String city = userBean.getCity(); String address = province + city; intent.putExtra("address",address); startActivity(intent); } }); } @Override public void onError(UiError uiError) { Log.e(TAG,"登录失败"+uiError.toString()); } @Override public void onCancel() { Log.e(TAG,"登录取消"); } }); } catch (JSONException e) { e.printStackTrace(); } } @Override public void onError(UiError uiError) { Toast.makeText(SecondActivity.this, "授权失败", Toast.LENGTH_SHORT).show(); } @Override public void onCancel() { Toast.makeText(SecondActivity.this, "授权取消", Toast.LENGTH_SHORT).show(); } } /** * 在调用Login的Activity或者Fragment中重写onActivityResult方法 * @param requestCode * @param resultCode * @param data */ @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if(requestCode == Constants.REQUEST_LOGIN){ Tencent.onActivityResultData(requestCode,resultCode,data,mIUiListener); } super.onActivityResult(requestCode, resultCode, data); } }
十一. 主页面显示页:
package com.bwie.secondweek_moni.activity; import android.os.Bundle; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentPagerAdapter; import android.support.v4.view.ViewPager; import android.support.v7.app.AppCompatActivity; import android.widget.RadioButton; import android.widget.RadioGroup; import com.bwie.secondweek_moni.R; import com.bwie.secondweek_moni.fragment.List_Fragment; import com.bwie.secondweek_moni.fragment.QQ_Fragment; import java.util.ArrayList; import java.util.List; import butterknife.Bind; import butterknife.ButterKnife; public class ThirdActivity extends AppCompatActivity { @Bind(R.id.button_person) RadioButton buttonPerson; @Bind(R.id.button_list) RadioButton buttonList; @Bind(R.id.groups) RadioGroup groups; @Bind(R.id.second_viewPager) ViewPager secondViewPager; private List<Fragment> list; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_third); ButterKnife.bind(this); //定义集合添加数据 list = new ArrayList<>(); list.add(new QQ_Fragment()); list.add(new List_Fragment()); //加入此行代码可使当页数据一直有效显示,不会随着页面滑动而消失 secondViewPager.setOffscreenPageLimit(list.size()); //设置适配器 secondViewPager.setAdapter(new FragmentPagerAdapter(getSupportFragmentManager()) { @Override public Fragment getItem(int position) { return list.get(position); } @Override public int getCount() { return list.size(); } }); //设置viewpager的滑动监听事件 secondViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() { @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { } @Override public void onPageSelected(int position) { groups.check(groups.getChildAt(position).getId()); } @Override public void onPageScrollStateChanged(int state) { } }); //设置button按钮的监听事件 groups.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() { @Override public void onCheckedChanged(RadioGroup group, int checkedId) { switch (checkedId) { case R.id.button_person: secondViewPager.setCurrentItem(0, false); break; case R.id.button_list: secondViewPager.setCurrentItem(1, false); break; default: break; } } }); } }
11. 1 对应的 QQ 信息显示页fragment:
package com.bwie.secondweek_moni.fragment; import android.content.Intent; import android.os.Bundle; import android.support.annotation.Nullable; import android.support.v4.app.Fragment; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.Button; import android.widget.ImageView; import android.widget.TextView; import com.bwie.secondweek_moni.MainActivity; import com.bwie.secondweek_moni.R; import com.bwie.secondweek_moni.util.ImageLoaderUtil; import com.nostra13.universalimageloader.core.ImageLoader; import butterknife.Bind; import butterknife.ButterKnife; import butterknife.OnClick; //个人中心页 public class QQ_Fragment extends Fragment { @Bind(R.id.headPhoto) ImageView headPhoto; @Bind(R.id.userName) TextView userName; @Bind(R.id.gener) TextView gener; @Bind(R.id.address) TextView address; @Bind(R.id.outLogin) Button outLogin; @Nullable @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { View view = inflater.inflate(R.layout.qq_fragment, container, false); ButterKnife.bind(this, view); return view; } @Override public void onActivityCreated(@Nullable Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); //获取传递信息 Intent intent = getActivity().getIntent(); String icon = intent.getStringExtra("headPhoto"); String name = intent.getStringExtra("name"); String sex = intent.getStringExtra("gender"); //设置用户信息 String addRess = intent.getStringExtra("address"); ImageLoader.getInstance().displayImage(icon,headPhoto, ImageLoaderUtil.getDefaultOption()); /*Glide.with(this).load(icon).into(headPhoto);*/ userName.setText(" "+name); gener.setText(" "+sex); address.setText(" "+addRess); } @Override public void onDestroyView() { super.onDestroyView(); ButterKnife.unbind(this); } //退出登录到主页 @OnClick(R.id.outLogin) public void onViewClicked() { startActivity(new Intent(getActivity(), MainActivity.class)); } }
11. 2 对应的列表数据显示页fragment:
package com.bwie.secondweek_moni.fragment; import android.os.Bundle; import android.support.annotation.Nullable; import android.support.v4.app.Fragment; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.Toast; import com.bwie.secondweek_moni.R; import com.bwie.secondweek_moni.adapter.DataAdapter; import com.bwie.secondweek_moni.bean.DataBean; import com.bwie.secondweek_moni.okhttp.AbstractUiCallBack; import com.bwie.secondweek_moni.okhttp.OkhttpUtils; import com.liaoinstan.springview.container.DefaultFooter; import com.liaoinstan.springview.container.DefaultHeader; import com.liaoinstan.springview.widget.SpringView; import butterknife.Bind; import butterknife.ButterKnife; //列表页 public class List_Fragment extends Fragment { @Bind(R.id.recyclerView) RecyclerView recyclerView; @Bind(R.id.springView) SpringView springView; int page = 0; //初始化为第0页数据 @Nullable @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { View view = inflater.inflate(R.layout.list_fragment, container, false); ButterKnife.bind(this, view); return view; } @Override public void onActivityCreated(@Nullable Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); //设置线性布局管理器,加载数据 LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity(), LinearLayoutManager.VERTICAL, false); recyclerView.setLayoutManager(layoutManager); getData(); //设置SpringView进行多条目加载的头布局和尾布局 springView.setHeader(new DefaultHeader(getActivity())); springView.setFooter(new DefaultFooter(getActivity())); //设置SpringView的刷新监听事件 springView.setListener(new SpringView.OnFreshListener() { @Override public void onRefresh() { //上拉刷新显示数据更多 page++; getData(); springView.onFinishFreshAndLoad(); } @Override public void onLoadmore() { //下拉加载初始化页数据 page = 0; getData(); springView.onFinishFreshAndLoad(); } }); } public void getData(){ String path = "http://tingapi.ting.baidu.com/v1/restserver/ting?method=baidu.ting.billboard.billList&type=1&size=10&offset="+page; OkhttpUtils.getInstance().asy(null, path, new AbstractUiCallBack<DataBean>() { @Override public void success(DataBean dataBean) { //获取数据 .调用适配器中的添加数据的方法,,刷新添加到前面 DataAdapter adapter = new DataAdapter(getActivity()); adapter.addData(dataBean.getSong_list()); recyclerView.setAdapter(adapter); } @Override public void failure(Exception e) { Toast.makeText(getActivity(),"数据错误"+e,Toast.LENGTH_SHORT).show(); } }); } @Override public void onDestroyView() { super.onDestroyView(); ButterKnife.unbind(this); } }11. 3 显示列表信息的适配器类:
package com.bwie.secondweek_moni.adapter; import android.content.Context; import android.content.Intent; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; import android.widget.TextView; import android.widget.Toast; import com.bwie.secondweek_moni.R; import com.bwie.secondweek_moni.activity.FourthActivity; import com.bwie.secondweek_moni.bean.DataBean; import com.bwie.secondweek_moni.util.ImageLoaderUtil; import com.nostra13.universalimageloader.core.ImageLoader; import java.util.ArrayList; import java.util.List; import butterknife.Bind; import butterknife.ButterKnife; //自定义适配器类 public class DataAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> { private Context context; private List<DataBean.SongListBean> list; public DataAdapter(Context context) { this.context = context; } //声明数据来源,添加数据 public void addData(List<DataBean.SongListBean> songList) { if (this.list == null) { this.list = new ArrayList<>(); } this.list.addAll(songList); notifyDataSetChanged(); } //创建条目布局 @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View view = LayoutInflater.from(context).inflate(R.layout.item, null); return new ItemViewHolder(view); } //绑定数据 @Override public void onBindViewHolder(final RecyclerView.ViewHolder holder, final int position) { //设置条目信息 final ItemViewHolder viewHolder = (ItemViewHolder) holder; viewHolder.text01.setText("歌曲: " + list.get(position).getTitle()); viewHolder.text02.setText("歌手: " + list.get(position).getAuthor()); ImageLoader.getInstance().displayImage(list.get(position).getPic_premium(), viewHolder.image, ImageLoaderUtil.getDefaultOption()); //添加RecyclerView的单击事件,点击RecyclerView控件后把对应条目的标题传到详情Activity并显示(详情页效果图未提供,里面就一个TextView,接收到数据后,给TextView设置值即可) ((ItemViewHolder) holder).text01.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Intent intent = new Intent(context, FourthActivity.class); intent.putExtra("title",list.get(position).getTitle()); context.startActivity(intent); } }); //添加RecyclerView的长按事件,长按删除该条目 ((ItemViewHolder) holder).text02.setOnLongClickListener(new View.OnLongClickListener() { @Override public boolean onLongClick(View v) { list.remove(position); Toast.makeText(context,"长按删除当前条目",Toast.LENGTH_SHORT).show(); notifyDataSetChanged(); return false; } }); } @Override public int getItemCount() { return list.size(); } static class ItemViewHolder extends RecyclerView.ViewHolder { @Bind(R.id.image) ImageView image; @Bind(R.id.text01) TextView text01; @Bind(R.id.text02) TextView text02; ItemViewHolder(View itemView) { super(itemView); ButterKnife.bind(this, itemView); } } }
十二. 跳转显示数据的Activity页
package com.bwie.secondweek_moni.activity; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.widget.TextView; import com.bwie.secondweek_moni.R; import butterknife.Bind; import butterknife.ButterKnife; //TextView详情页 public class FourthActivity extends AppCompatActivity { @Bind(R.id.text) TextView text; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_fourth); ButterKnife.bind(this); String title = getIntent().getStringExtra("title"); text.setText("歌曲:"+title); } }
十三. 页面布局
1. color文件夹中显示字体颜色的color.xml文件:
<?xml version="1.0" encoding="utf-8"?> <selector xmlns:android="http://schemas.android.com/apk/res/android"> <!-- 被选中的按钮,文本显示成红色,其他显示成黑色 --> <item android:state_checked="true" android:color="@color/selected"></item> <item android:state_checked="false" android:color="@color/defaulted"></item> </selector>在对应的values文件夹下的colors.xml布局文件中添加代码:
<!--字体颜色--> <color name="selected">#FF0000</color> <color name="defaulted">#000000</color>
2. MainActivity对应的activity_main.xml
<?xml version="1.0" encoding="utf-8"?> <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" > <android.support.v4.view.ViewPager android:id="@+id/main_viewPager" android:layout_above="@+id/groups" android:layout_width="match_parent" android:layout_height="match_parent"></android.support.v4.view.ViewPager> <RadioGroup android:id="@+id/groups" android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentBottom="true"> <RadioButton android:text="登录" android:padding="10dp" android:button="@null" android:checked="true" android:textSize="18sp" android:gravity="center" android:layout_weight="1" android:layout_width="0dp" android:id="@+id/button_person" android:textColor="@color/color" android:layout_height="wrap_content" /> <RadioButton android:text="注册" android:padding="10dp" android:button="@null" android:textSize="18sp" android:gravity="center" android:layout_weight="1" android:layout_width="0dp" android:id="@+id/button_list" android:textColor="@color/color" android:layout_height="wrap_content" /> </RadioGroup> </RelativeLayout>
3. SecondActivity对应的activity_second.xml
<?xml version="1.0" encoding="utf-8"?> <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" > <Button android:text="点击登录QQ" android:onClick="qq_Second" android:background="#1E90FF" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_centerInParent="true"/> </RelativeLayout>
4. ThirdActivity对应的activity_third.xml
<?xml version="1.0" encoding="utf-8"?> <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" > <android.support.v4.view.ViewPager android:id="@+id/second_viewPager" android:layout_above="@+id/groups" android:layout_width="match_parent" android:layout_height="match_parent"></android.support.v4.view.ViewPager> <RadioGroup android:id="@+id/groups" android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentBottom="true"> <RadioButton android:text="个人中心" android:padding="10dp" android:button="@null" android:checked="true" android:textSize="18sp" android:gravity="center" android:layout_weight="1" android:layout_width="0dp" android:id="@+id/button_person" android:textColor="@color/color" android:layout_height="wrap_content" /> <RadioButton android:text="列表" android:padding="10dp" android:button="@null" android:textSize="18sp" android:gravity="center" android:layout_weight="1" android:layout_width="0dp" android:id="@+id/button_list" android:textColor="@color/color" android:layout_height="wrap_content" /> </RadioGroup> </RelativeLayout>
5. FourthActivity对应的activity_fourth.xml
<?xml version="1.0" encoding="utf-8"?> <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" > <TextView android:id="@+id/text" android:textSize="28sp" android:gravity="center" android:textColor="#3609ea" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_centerVertical="true"/> </RelativeLayout>6. 登录页面对应的login_fragment.xml
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:background="@drawable/b" android:layout_width="match_parent" android:layout_height="match_parent"> <RelativeLayout android:id="@+id/reative" android:background="#1e8ffe" android:layout_width="match_parent" android:layout_height="wrap_content"> <TextView android:padding="20dp" android:textSize="26sp" android:text="登录界面" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" /> </RelativeLayout> <EditText android:id="@+id/tel_Login" android:hint="请输入您的手机号" android:layout_marginTop="58dp" android:layout_below="@+id/reative" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_centerHorizontal="true"/> <EditText android:id="@+id/pwd_Login" android:hint="请输入您的密码" android:layout_marginTop="58dp" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_below="@+id/tel_Login" android:layout_centerHorizontal="true"/> <Button android:text="登录" android:textSize="21sp" android:id="@+id/login" android:background="#1E90FF" android:layout_width="188dp" android:layout_marginTop="108dp" android:layout_height="wrap_content" android:layout_below="@+id/pwd_Login" android:layout_centerHorizontal="true" /> <Button android:textSize="21sp" android:id="@+id/qqLogin" android:text="第三方QQ登录" android:background="#1E90FF" android:layout_width="188dp" android:layout_marginBottom="108dp" android:layout_height="wrap_content" android:layout_centerHorizontal="true" android:layout_alignParentBottom="true" /> </RelativeLayout>
7. 注册页面对应的_fragment.xml
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:background="@drawable/b" android:layout_width="match_parent" android:layout_height="match_parent"> <RelativeLayout android:id="@+id/reative" android:background="#1e8ffe" android:layout_width="match_parent" android:layout_height="wrap_content"> <TextView android:padding="20dp" android:textSize="26sp" android:text="注册界面" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" /> </RelativeLayout> <EditText android:id="@+id/tel_Reg" android:hint="请输入您的手机号" android:layout_marginTop="58dp" android:layout_below="@+id/reative" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_centerHorizontal="true"/> <EditText android:id="@+id/pwd_Reg" android:hint="请输入您的密码" android:layout_marginTop="58dp" android:layout_below="@+id/tel_Reg" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_centerHorizontal="true"/> <Button android:text="注册" android:id="@+id/reg" android:textSize="21sp" android:background="#1E90FF" android:layout_width="188dp" android:layout_marginTop="108dp" android:layout_below="@+id/pwd_Reg" android:layout_height="wrap_content" android:layout_centerHorizontal="true" /> </RelativeLayout>
8. QQ登录信息页面对应的_fragment.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout 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" android:orientation="vertical" > <RelativeLayout android:background="#1e8ffe" android:layout_width="match_parent" android:layout_height="wrap_content"> <TextView android:padding="20dp" android:textSize="26sp" android:text="个人中心" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" /> </RelativeLayout> <ImageView android:layout_gravity="center_horizontal" android:src="@mipmap/ic_launcher" android:layout_marginTop="58dp" android:layout_height="88dp" android:layout_width="88dp" android:id="@+id/headPhoto" /> <RelativeLayout android:layout_width="match_parent" android:layout_marginTop="88dp" android:layout_height="50dp"> <TextView android:layout_alignParentLeft="true" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="120dp" android:textSize="18sp" android:text="用户名:"/> <TextView android:layout_alignParentRight="true" android:layout_width="wrap_content" android:layout_marginRight="138dp" android:layout_height="50dp" android:id="@+id/userName" android:textSize="18sp" android:text="userName" /> </RelativeLayout> <RelativeLayout android:layout_width="match_parent" android:layout_height="50dp"> <TextView android:layout_alignParentLeft="true" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="120dp" android:textSize="18sp" android:text="性别" /> <TextView android:layout_alignParentRight="true" android:layout_width="wrap_content" android:layout_marginRight="138dp" android:layout_height="50dp" android:id="@+id/gener" android:textSize="18sp" android:text="gener" /> </RelativeLayout> <RelativeLayout android:layout_width="match_parent" android:layout_height="50dp"> <TextView android:layout_alignParentLeft="true" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="120dp" android:textSize="18sp" android:text="地址:" /> <TextView android:layout_alignParentRight="true" android:layout_width="wrap_content" android:layout_marginRight="138dp" android:layout_height="50dp" android:id="@+id/address" android:textSize="18sp" android:text="address" /> </RelativeLayout> <Button android:text="退出登录" android:id="@+id/outLogin" android:layout_marginTop="88dp" android:layout_width="match_parent" android:layout_height="wrap_content" android:textColor="@android:color/white" android:background="@android:color/holo_blue_light" /> </LinearLayout>
9. 列表页面对应的_fragment.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:background="@drawable/b" android:layout_width="match_parent" android:layout_height="match_parent"> <RelativeLayout android:background="#1e8ffe" android:layout_width="match_parent" android:layout_height="wrap_content"> <TextView android:padding="20dp" android:text="列表" android:textSize="26sp" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" /> </RelativeLayout> <com.liaoinstan.springview.widget.SpringView android:id="@+id/springView" android:layout_width="match_parent" android:layout_height="match_parent"> <android.support.v7.widget.RecyclerView android:id="@+id/recyclerView" android:layout_width="match_parent" android:layout_height="match_parent"></android.support.v7.widget.RecyclerView> </com.liaoinstan.springview.widget.SpringView> </LinearLayout>
10. 列表数据适配器类对应的item.xml
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" > <ImageView android:id="@+id/image" android:layout_width="88dp" android:layout_height="88dp" android:src="@mipmap/ic_launcher" /> <LinearLayout android:layout_toRightOf="@id/image" android:layout_alignParentRight="true" android:layout_width="match_parent" android:gravity="center_horizontal" android:orientation="vertical" android:layout_height="88dp" > <TextView android:id="@+id/text01" android:layout_marginTop="18dp" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <TextView android:id="@+id/text02" android:layout_marginBottom="10dp" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </LinearLayout> </RelativeLayout>
清单文件 AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.bwie.secondweek_moni"> <!-- QQ登录授权所需权限 --> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <application android:name=".util.BaseApplication" android:allowBackup="true" android:icon="@drawable/home_data" android:label="@string/app_name" android:supportsRtl="true" android:theme="@style/AppTheme"> <activity android:name=".MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:name=".activity.SecondActivity" /> <!-- 注册SDKActivity --> <activity android:name="com.tencent.tauth.AuthActivity" android:launchMode="singleTask" android:noHistory="true"> <intent-filter> <action android:name="android.intent.action.VIEW" /> <category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.BROWSABLE" /> <data android:scheme="tencent1105602574" /> <!-- 开放平台获取的APPID --> </intent-filter> </activity> <activity android:name="com.tencent.connect.common.AssistActivity" android:screenOrientation="portrait" android:theme="@android:style/Theme.Translucent.NoTitleBar" /> <activity android:name=".activity.ThirdActivity" /> <activity android:name=".activity.FourthActivity"></activity> </application> </manifest>