TabLayout + ViewPager + Fragment + Retrofit + Fresco + NDK + AIDL + WebView
效果图:
导入依赖
compile 'com.android.support:design:26.0.0-alpha1' compile 'com.squareup.retrofit2:retrofit:2.3.0' compile 'com.squareup.retrofit2:converter-gson:2.3.0' compile 'com.facebook.fresco:fresco:1.5.0'
页面:
activity_mian.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context="bw.com.week3_test.MainActivity"> <android.support.design.widget.TabLayout android:layout_width="match_parent" android:layout_height="60dp" android:id="@+id/tab_layout_id" /> <android.support.v4.view.ViewPager android:layout_width="match_parent" android:layout_height="match_parent" android:id="@+id/view_pager_id" /> </LinearLayout>
my_fragment01.xml
<FrameLayout 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="bw.com.week3_test.demo01.MyFragment01"> <android.support.v7.widget.RecyclerView android:layout_width="match_parent" android:layout_height="match_parent" android:id="@+id/rv_id"/> </FrameLayout>
my_fragment02.xml
<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" tools:context="bw.com.week3_test.demo02.MyFragment02"> <EditText android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="请输入用户名" android:id="@+id/name_et_id"/> <EditText android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="请输入密码" android:id="@+id/pwd_et_id"/> <EditText android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="请输入验证码 1234" android:id="@+id/code_et_id"/> <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:text="登录" android:id="@+id/but_id" /> </LinearLayout>
my_fragment03.xml
<FrameLayout 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="bw.com.week3_test.demo03.MyFragment03"> <!-- TODO: Update blank fragment layout --> <TextView android:id="@+id/tv_id" android:layout_width="match_parent" android:layout_height="match_parent" android:text="@string/hello_blank_fragment" /> </FrameLayout>
my_fragment04.xml
<FrameLayout 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="bw.com.week3_test.demo04.MyFragment04"> <!-- TODO: Update blank fragment layout --> <WebView android:layout_width="match_parent" android:layout_height="match_parent" android:id="@+id/web_view_id"/> </FrameLayout>
item_rv.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:fresco="http://schemas.android.com/apk/res-auto" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="wrap_content"> <com.facebook.drawee.view.SimpleDraweeView android:layout_width="300dp" android:layout_height="200dp" android:id="@+id/sdv_id" fresco:roundedCornerRadius="5dp" fresco:roundTopLeft="true" fresco:roundTopRight="true" fresco:roundBottomLeft="true" fresco:roundBottomRight="true" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/tv_id" android:text="标题" android:layout_marginTop="10dp" android:textSize="20sp" /> <View android:layout_width="match_parent" android:layout_height="2dp" android:background="@color/colorAccent" android:layout_margin="10dp"/> </LinearLayout>
MyApp.java
public class MyApp extends Application { @Override public void onCreate() { super.onCreate(); //初始化Fresco Fresco.initialize(this); } }
清单文件:
<uses-permission android:name="android.permission.INTERNET"/> <application android:name=".MyApp"
MainActivity.java
public class MainActivity extends AppCompatActivity { private TabLayout mTabLayout;//导航 private List<String> titles = new ArrayList<>();//所有的标题 private ViewPager mViewPager;//视图页面 private List<Fragment> data = new ArrayList<>();//数据源 private MyAdapter adapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mTabLayout = (TabLayout) findViewById(R.id.tab_layout_id); mViewPager = (ViewPager) findViewById(R.id.view_pager_id); //构建标题 titles.add("获取数据"); titles.add("NDK 登录"); titles.add("AIDL"); titles.add("加载网页"); //构建数据源 data.add(new MyFragment01()); data.add(new MyFragment02()); data.add(new MyFragment03()); data.add(new MyFragment04()); //定义适配器 adapter = new MyAdapter(getSupportFragmentManager()); //设置适配器 mViewPager.setAdapter(adapter); //将tabLayout 和ViewPager 结合在一起 mTabLayout.setupWithViewPager(mViewPager); } //自定义适配器 class MyAdapter extends FragmentPagerAdapter { public MyAdapter(FragmentManager fm) { super(fm); } @Override public Fragment getItem(int position) { return data.get(position); } @Override public int getCount() { return data.size(); } //返回当前对应的标题 @Override public CharSequence getPageTitle(int position) { return titles.get(position); } } }
第一个Fragment
MyFragment01.java
/** * 通过Retrofit 获取网络数据, 展示在RecycleView 中, 图片用Fresco 加载, 图片圆角处理 * 通过Retrofit : * 导入依赖 * 1, 接口 @GET() * Call<实体类> getInfo(); * 2, 实体类 * 3, MyFragment -- 7小步骤 * * Fresco 使用 * 1, 导入依赖 * 2, 必须初始化 -- MyApp * 3, 在布局页面中 , 使用控件 * 4, 在代码中, 加载图片 */ public class MyFragment01 extends Fragment { private RecyclerView mRv;//控件 private List<VMoiver.DataBean> data;//数据源 -- 网络获取 private MyRecycleViewAdapter adapter;//适配器 @Override public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) { View view = inflater.inflate(R.layout.my_fragment01, container, false); mRv = (RecyclerView) view.findViewById(R.id.rv_id); //设置显示模式 LinearLayoutManager manager = new LinearLayoutManager(getContext(),LinearLayoutManager.VERTICAL,false); mRv.setLayoutManager(manager); //Retrofit 执行的步骤 //1, 得到构建者 Retrofit.Builder builder = new Retrofit.Builder(); //2, 设置基础地址 builder.baseUrl("http://app.vmoiver.com/apiv3/post/"); //3, 设置gson 解析 builder.addConverterFactory(GsonConverterFactory.create()); //4, 得到Retrofit对象 Retrofit retrofit = builder.build(); //5, 通过Retrofit得到接口 VMoiverInterface vMoiverInterface = retrofit.create(VMoiverInterface.class); //6, 得到Call 对象 Call<VMoiver> call = vMoiverInterface.getInfo(); //7, 异步请求数据 call.enqueue(new Callback<VMoiver>() { @Override public void onResponse(Call<VMoiver> call, Response<VMoiver> response) { VMoiver vMoiver = response.body(); //得到数据源 data = vMoiver.getData(); adapter = new MyRecycleViewAdapter(getContext(),data); mRv.setAdapter(adapter); } @Override public void onFailure(Call<VMoiver> call, Throwable t) { } }); return view; } }
VMoiver.java --- GsonFromant 生成的实体类
VMoiverInterface.java
public interface VMoiverInterface { //http://app.vmoiver.com/apiv3/post/ ---- getPostInCate?cateid=0&p=1 @GET("getPostInCate?cateid=0&p=1") Call<VMoiver> getInfo(); }
MyRecycleViewAdapter.java
public class MyRecycleViewAdapter extends RecyclerView.Adapter<MyRecycleViewAdapter.ViewHolder> { private Context context; private List<VMoiver.DataBean> data; public MyRecycleViewAdapter(Context context, List<VMoiver.DataBean> data) { this.context = context; this.data = data; } @Override public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View view = LayoutInflater.from(context).inflate(R.layout.item_rv,parent,false); ViewHolder viewHolder = new ViewHolder(view); return viewHolder; } @Override public void onBindViewHolder(ViewHolder holder, int position) { //加载图片 Uri uri = Uri.parse(data.get(position).getImage()); holder.sdv.setImageURI(uri); //设置标题 holder.tv.setText(data.get(position).getTitle()); } @Override public int getItemCount() { return data.size(); } class ViewHolder extends RecyclerView.ViewHolder { SimpleDraweeView sdv; TextView tv; public ViewHolder(View itemView) { super(itemView); this.sdv = (SimpleDraweeView) itemView.findViewById(R.id.sdv_id); this.tv = (TextView) itemView.findViewById(R.id.tv_id); } } }
第二个Fragment -- NDK 实现登陆
1, 配置ndk 的环境, 参考网址: http://blog.****.net/xiuxiu_861223/article/details/78792939
2, 创建 JinTest.java
public class JniTest { //********************导入依赖库*********************** static { System.loadLibrary("app"); } private static Context context; public JniTest(Context context) { this.context = context; } //登录的方法 -- java 调用 C public static native String login(String uName, String uPwd,int code); //登录成功的信息 -- C 调用Java //javah -d jni -classpath ../../build/intermediates/classes/debug bw.com.week3_test.demo02.JniTest public static void showMessage(String message) { Toast.makeText(context, message, Toast.LENGTH_SHORT).show(); } }
3, 点击菜单栏的Make Module 'app'即可
4, 生成头文件(*.h)
首先打开工具栏的Terminal工具,使用cd命令定位到Moduel
app的main目录
执行: 红色的文字是需要根据自己的Jni 改变的
javah -d jni -classpath ../../build/intermediates/classes/debug bw.com.week3_test.demo02.JniTest
5, 创建 :bw_com_week3_test_demo02_JniTest.c
#include "bw_com_week3_test_demo02_JniTest.h" JNIEXPORT jstring JNICALL Java_bw_com_week3_1test_demo02_JniTest_login (JNIEnv *env, jclass jobj, jstring juName, jstring juPwd, jint jcode) { const char* resultMessage;//声明字符变量 jclass jc; //1, 加载java 类中的class 对象 jc = (*env)->FindClass(env, "bw/com/week3_test/demo02/JniTest");//反射机制来获取对象 //jc = (*env)->GetObjectClass(env, jobj);//使用GetObjectClass函数来获取class对象: //2, 获取java 类的方法 //2.1 获取java 类的方法 --- 得到静态的方法 jmethodID showMessageID = (*env)->GetStaticMethodID(env,jc,"showMessage","(Ljava/lang/String;)V"); //查看验证码是否正确 if(jcode==1234) { const char* cstr; jboolean isCopy; cstr = (*env)->GetStringUTFChars(env,juName,&isCopy); int result = strcmp(cstr,"admin"); if(result==0) { resultMessage = "login success"; // 2.2 通过方法的id , 回调java 的代码 (*env)->CallStaticVoidMethod(env,jc,showMessageID,resultMessage); }else { resultMessage = "login Error"; // 2.2 通过方法的id , 回调java 的代码 (*env)->CallStaticVoidMethod(env,jc,showMessageID,resultMessage); } } else { resultMessage = "code Error"; // 2.2 通过方法的id , 回调java 的代码 (*env)->CallStaticVoidMethod(env,jc,showMessageID,resultMessage); } return resultMessage; }
6,准备就绪,开始构建.so文件 -- 点击菜单栏的Make Module 'app'即可
7,使用so库。在JniTest.java中添加代码
static {
System.loadLibrary("app");
}
8, MyFragment02.java
/** * NDK 实现登录 */ public class MyFragment02 extends Fragment implements View.OnClickListener { private EditText name_et_id; private EditText pwd_et_id; private EditText code_et_id; private Button but_id; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.my_fragment02, container, false); initView(view); return view; } private void initView(View view) { name_et_id = (EditText) view.findViewById(R.id.name_et_id); pwd_et_id = (EditText) view.findViewById(R.id.pwd_et_id); code_et_id = (EditText) view.findViewById(R.id.code_et_id); but_id = (Button) view.findViewById(R.id.but_id); but_id.setOnClickListener(this); } @Override public void onClick(View v) { JniTest jniTest = new JniTest(getContext()); int code = Integer.parseInt(code_et_id.getText().toString()); jniTest.login(name_et_id.getText().toString(),pwd_et_id.getText().toString(),code); } }
第三个Fragment -- AIDL 获取服务器中数据库的内容
1, 创建服务器的 App -- > 名称为 Server
1.1 在src/mian 中创建 aidl 文件
DataAidl.aidl
interface DataAidl { String getDbInfo(); }
1.2 编译工程, 生成同名的DataAidl.java文件
1.3 创建数据库的帮助类
DbOpenHelper.java
public class DbOpenHelper extends SQLiteOpenHelper{ public DbOpenHelper(Context context) { super(context, "bw1511A.db", null, 1); } @Override public void onCreate(SQLiteDatabase db) { db.execSQL("create table if not exists user(_id integer primary key autoincrement,name varchar(20),age integer)"); db.execSQL("insert into user(name,age) values('abc',12)"); db.execSQL("insert into user(name,age) values('bcd',22)"); db.execSQL("insert into user(name,age) values('cde',33)"); db.execSQL("insert into user(name,age) values('def',34)"); db.execSQL("insert into user(name,age) values('efg',45)"); db.execSQL("insert into user(name,age) values('fgh',55)"); db.execSQL("insert into user(name,age) values('ghi',65)"); db.execSQL("insert into user(name,age) values('hig',43)"); db.execSQL("insert into user(name,age) values('igk',32)"); } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { } }
1.4 创建服务器 --- MyService.java
public class MyService extends Service { DataAidl.Stub stub = new DataAidl.Stub() { @Override public String getDbInfo() throws RemoteException { DbOpenHelper dbOpenHelper = new DbOpenHelper(MyService.this); SQLiteDatabase db = dbOpenHelper.getReadableDatabase(); Cursor cursor = db.rawQuery("select * from user",null); StringBuilder stringBuilder = new StringBuilder(); while (cursor.moveToNext()) { String name = cursor.getString(cursor.getColumnIndex("name")); int age = cursor.getInt(cursor.getColumnIndex("age")); stringBuilder.append("姓名: "+name).append(" , ").append("年龄: " + age).append("\n"); } return stringBuilder.toString(); } }; @Nullable @Override public IBinder onBind(Intent intent) { return stub; } }
1.5 在清单文件中注册Service
<service android:name=".MyService"> <intent-filter> <action android:name="com.bw.aidl"/> </intent-filter> </service>
2, 在客户端的App 中 -- App工程的第三个Fragment
将服务端的src/main中的aidl 文件夹, 复制到客户端的 src/main 文件夹中,编译工程
MyFragment03.java
/** * * 通过AIDL 获取服务器中, 数据库的所有内容 * * AIDL 实现跨进程间的通信 * * Server : * * 1, 数据库 * 2, Service -- 注册 -- action * 3, AIDL * * Client : * * 1, 绑定服务 * 2, 复制服务器中的AIDL文件 * 3, 通过AIDL 获取数据 */ public class MyFragment03 extends Fragment { private DataAidl dataAidl; private ServiceConnection connection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { dataAidl = DataAidl.Stub.asInterface(service); try { String result = dataAidl.getDbInfo(); mTv.setText(result); } catch (RemoteException e) { e.printStackTrace(); } } @Override public void onServiceDisconnected(ComponentName name) { } }; private TextView mTv; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.my_fragment03, container, false); mTv = (TextView) view.findViewById(R.id.tv_id); return view; } //绑定服务 @Override public void onResume() { super.onResume(); Intent intent = new Intent("com.bw.aidl"); intent.setPackage("bw.com.server"); getContext().bindService(intent,connection, Context.BIND_AUTO_CREATE); } //解绑服务 @Override public void onPause() { super.onPause(); getContext().unbindService(connection); } }
第四个Fragment 中 -- WebView 加载网络数据
MyFragment04.java
/** * A simple {@link Fragment} subclass. */ public class MyFragment04 extends Fragment { private WebView mWebView; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.my_fragment04, container, false); mWebView = (WebView) view.findViewById(R.id.web_view_id); mWebView.loadUrl("http://baidu.com"); WebSettings settings = mWebView.getSettings(); settings.setJavaScriptEnabled(true); settings.setJavaScriptCanOpenWindowsAutomatically(true); mWebView.setWebViewClient(new WebViewClient(){ @Override public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) { mWebView.loadUrl("http://baidu.com"); return super.shouldOverrideUrlLoading(view, request); } }); return view; } }