美文网首页我爱编程
毕设收获总结

毕设收获总结

作者: Utte | 来源:发表于2018-05-27 17:31 被阅读48次

    终于结束了接的毕设,虽然这几天好心心累啊,但是拿到全款还是很开心的,记录一下写完项目后的感受和小总结。

    Retrofit相关

    Retrofit封装
    public class RetrofitFactory {
    
        public static RetrofitFactory INSTANCE = new RetrofitFactory();
        private static final String TAG = "RetrofitFactory";
        private Retrofit mRetrofit;
        private Interceptor mInterceptor;
    
        private RetrofitFactory() {
            mInterceptor = new Interceptor() {
                @Override
                public Response intercept(Chain chain) throws IOException {
                    Request request = chain.request()
                            .newBuilder()
                            .addHeader("Host", "120.79.196.225:8080")//坑爹坑爹坑爹 请求不影响 后台调getServerPort()那一系列方法是从Header掉的,加端口的时候获取的不是请求url的端口,是默认的80端口
                            .addHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:58.0) Gecko/20100101 Firefox/58.0")
                            .addHeader("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8")
                            .addHeader("Accept-Language", "zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2")
                            .addHeader("Accept-Encoding", "gzip, deflate")
                            .addHeader("Connection", "keep-alive")
                            .addHeader("Upgrade-Insecure-Requests", "1")
                            .build();
                    return chain.proceed(request);
                }
            };
    
            mRetrofit = new Retrofit.Builder()
                    .baseUrl(SERVER_ADDRESS)
                    .addConverterFactory(GsonConverterFactory.create())
                    .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
                    .client(initClient())
                    .build();
        }
    
        private OkHttpClient initClient() {
            return new OkHttpClient.Builder()
                    .addInterceptor(mInterceptor)
                    .addInterceptor(new AddCookiesInterceptor())
                    .addInterceptor(new ReceivedCookiesInterceptor())
                    .connectTimeout(10, TimeUnit.SECONDS)
                    .readTimeout(10, TimeUnit.SECONDS)
                    .build();
        }
    
         public <T> T create(Class<T> service) {
             Log.d(TAG, "create: " + "211111");
            return mRetrofit.create(service);
        }
    }
    

    拦截器实现cookie操作

    项目中使用了cookie时可以使用增加两个拦截器来进行相关cookie的操作。
    AddCookiesInterceptor、ReceivedCookiesInterceptor的实现:

    public class AddCookiesInterceptor implements Interceptor {
    
        private static final String TAG = "AddCookiesInterceptor";
        
        public AddCookiesInterceptor() {
            super();
        }
    
        @Override
        public Response intercept(Chain chain) throws IOException {
            final Request.Builder builder = chain.request().newBuilder();
            SharedPreferences sharedPreferences = Constant.context.getSharedPreferences("cookie", Context.MODE_PRIVATE);
            Observable.just(sharedPreferences.getString("cookie", ""))
                    .subscribe(new Action1<String>() {
                        @Override
                        public void call(String cookie) {
                            //添加cookie
                            if (!Objects.equals(cookie, "")) {
                                Log.d(TAG, "call: " + cookie);
                                builder.addHeader("Cookie", cookie);
                            }
                        }
                    });
            return chain.proceed(builder.build());
        }
    }
    
    public class ReceivedCookiesInterceptor implements Interceptor {
        private static final String TAG = "ReceivedCookiesIntercep";
        public ReceivedCookiesInterceptor() {
            super();
        }
    
        @Override
        public Response intercept(Chain chain) throws IOException {
            Response originalResponse = chain.proceed(chain.request());
            if (!originalResponse.headers("Set-Cookie").isEmpty()) {
                final StringBuffer cookieBuffer = new StringBuffer();
                Observable.from(originalResponse.headers("Set-Cookie")).map(new Func1<String, String>() {
                    @Override
                    public String call(String s) {
                        String[] cookieArray = s.split(";");
                        Log.d(TAG, "call: " + cookieArray[0]);
                        return cookieArray[0];
                    }
                }).subscribe(new Action1<String>() {
                    @Override
                    public void call(String cookie) {
                        cookieBuffer.append(cookie).append(";");
                    }
                });
                SharedPreferences sharedPreferences = Constant.context.getSharedPreferences("cookie", Context.MODE_PRIVATE);
                SharedPreferences.Editor editor = sharedPreferences.edit();
                editor.putString("cookie", cookieBuffer.toString());
                editor.commit();
            }
            return originalResponse;
        }
    }
    

    BottomNavigationView去除动画

    定义一个Helper类而不是去自定义,比较方便。通过反射去修改ShiftingMode。

    public class BottomNavigationViewHelper {
        @SuppressLint("RestrictedApi")
        public static void removeShifMode(BottomNavigationView view) {
            BottomNavigationMenuView menuView = (BottomNavigationMenuView) view.getChildAt(0);
            try {
                Field shiftingMode = menuView.getClass().getDeclaredField("mShiftingMode");
                shiftingMode.setAccessible(true);
                shiftingMode.setBoolean(menuView, false);
                shiftingMode.setAccessible(false);
                for (int i = 0; i < menuView.getChildCount(); ++i) {
                    BottomNavigationItemView itemView = (BottomNavigationItemView) menuView.getChildAt(i);
                    itemView.setShiftingMode(false);
                    itemView.setChecked(itemView.getItemData().isChecked());
                }
            } catch (NoSuchFieldException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
    }
    

    文件相关操作

    单文件上传
    1. 获取文件路径
      在这一步,一加3t会打开最近文件列表,如果直接在这里选择文件,获得到的path并不是真实的文件路径,最后会文件选择失败。获取路径必须侧栏打开文件管理器再去选择文件才能拿到path,到目前还没有找到解决方案。
    private void openFileManager() {
            Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
            intent.setType("*/*");//无类型限制
            intent.addCategory(Intent.CATEGORY_OPENABLE);
            startActivityForResult(intent, 1);
        }
    
        @Override
        protected void onActivityResult(int requestCode, int resultCode, Intent data) {
            if (resultCode == Activity.RESULT_OK) {
                Uri uri = data.getData();
                mFilePath = FileUtil.getPathByUri(this, uri);
                if (mFilePath != null) {
                    mFile = new File(mFilePath);
                    if (mFile.exists()) {
                        mTvWenjian.setText("文件选择成功:" + mFile.getName());
                        return;
                    }
                }
                mTvWenjian.setText("文件选择失败");
    
            }
        }
    
    1. 封装成MultipartBody.Part
    if (mFile != null) {
          RequestBody requestFile = RequestBody.create(MediaType.parse("*/*"), mFile);
          MultipartBody.Part body = MultipartBody.Part.createFormData("file", mFile.getName(), requestFile);
          mPresenter.postKaiTFujian(body);
    }
    
    1. 发送请求
    public void postKaiTFujian(MultipartBody.Part body) {
            mService.postKaiTiFujian(1, body)
                    .observeOn(AndroidSchedulers.mainThread())
                    .subscribeOn(Schedulers.io())
                    .subscribe(new BaseSubscriber<ResponseBody>() {
                        @Override
                        public void onNext(ResponseBody responseBody) {
                            super.onNext(responseBody);
                            //...
                        }
                    });
        }
    
    @Override
        public Observable<ResponseBody> postKaiTiFujian(int type, MultipartBody.Part body) {
            return RetrofitFactory.INSTANCE.create(SubjectApi.class)
                    .postFujian(type, body);
        }
    
    @Multipart
    @POST(Constant.FUJIAN)
    Observable<ResponseBody> postFujian(@Part("type") int type, @Part MultipartBody.Part file);
    
    多文件上传

    和单文件唯一不一样的就是参数变为List<MultipartBody.Part> parts

    RequestBody lunwenFile = RequestBody.create(MediaType.parse("*/*"), mLunwenFile);
    MultipartBody.Part lunwen = MultipartBody.Part.createFormData("file", mLunwenFile.getName(), lunwenFile);
    parts.add(lunwen);
    if (mFujianPath != null) {
          RequestBody fujianFile = RequestBody.create(MediaType.parse("*/*"), mFujianFile);
          MultipartBody.Part fujian = MultipartBody.Part.createFormData("file", mLunwenFile.getName(), fujianFile);
          parts.add(fujian);
    }
    mPresenter.postDinggao(parts);
    
    @Multipart
    @POST(Constant.DINGGAO)
    Observable<ResponseBody> postDinggao(@Part("type") int type, @Part List<MultipartBody.Part> parts);
    
    文件下载
    DownloadManager.Request request = new DownloadManager.Request(Uri.parse(Info.mKaitiData.attachment));
    request.setDestinationInExternalPublicDir("/download/", "kaiti");
    DownloadManager downloadManager = (DownloadManager) this.getSystemService(Context.DOWNLOAD_SERVICE);
    downloadManager.enqueue(request);
    

    代码复用

    写了小万代码也说明我不太会复用,写到最后发现重复代码很多,我也有认识到,列举出来,下次开项目之前先想好再开始写。

    Gson实体类封装
    public class KaitiAll {
        public int status;
        public String msg;
        public List<KaitiData> data;
    }
    public class DinggaoAll {
        public int status;
        public String msg;
        public List<DinggaoData> data;
    }
    

    这种某某All的实体类我还有很多,写到最后意识到完全可以只写一个的。

    class GsonAll<T> {
        public int status;
        public String msg;
        public List<T> data;
    }
    
    Subscriber的简化

    用rx的时候会传一个Subscriber,实现三个方法,但是平常大部分时间只需要写一个onNext(),所以可以先写一个实现好的BaseSubscriber类。

    public class BaseSubscriber<T> extends Subscriber<T> {
        @Override
        public void onCompleted() {
    
        }
    
        @Override
        public void onError(Throwable e) {
    
        }
    
        @Override
        public void onNext(T t) {
    
        }
    }
    

    用的时候传BaseSubscriber,重写需要重写的方法就可以了。

    new TeacherServiceImpl().getDinggao()
                    .observeOn(AndroidSchedulers.mainThread())
                    .subscribeOn(Schedulers.io())
                    .subscribe(new BaseSubscriber<DinggaoAll>() {
                        @Override
                        public void onNext(DinggaoAll dinggaoAll) {
                            super.onNext(dinggaoAll);
                            //...
                        }
                    });
    
    关于mvp

    整个项目都使用了mvp,虽然使用了mvp之后很好修改某个功能,但是代码量和类的数量增加了很多。是因为该去复用的Presenter和view回调接口没有去复用,几乎每个Activity都写了一套完整的mvp新代码,没有想着功能相似的去共用Presenter和回调接口。

    关于UI

    因为要求用java写,所以能看到我的Activity或者Fragment里面满屏的findViewById啥的,感想就是,如果能用kotlin那就太方便了,关于注入的框架因为不是特别熟悉就没有使用,以后有时间还是要再学一下的。另外,如果页面有类似表单的东西,不要一个一个TextView EditText,能用ListView RecyclerView就用吧,用了就知道会方便很多.....

    相关文章

      网友评论

        本文标题:毕设收获总结

        本文链接:https://www.haomeiwen.com/subject/gnnbjftx.html