美文网首页
安卓开发中的一点经验总结

安卓开发中的一点经验总结

作者: JasonBourney | 来源:发表于2017-06-23 16:29 被阅读0次

架构(风格)

第一次接触安卓项目,一开始感觉无从下手。虽然已经学习了基本的UI组件的用法,但是出于对项目负责的态度,仍然不想就胡乱开始写。于是就从整个项目的架构开始思考,了解了MVC,MVP,MVVM这三种风格的架构,后两者差别其实不大,我在项目中实际采用的就是第二种风格。下面我结合实际的项目,介绍一下使用这种架构的特点:

这是我的项目的整体分包情况,


接下来我们以获取当前用户的课程为例子,看一看如何用mvp风格实现。首先我们需要的是处理数据,我们创建course实体类,其实是一个简单的pojo用于封装课程信息。

public class Course implements Serializable {

    @SerializedName("id")
    private int id ;

    @SerializedName("name")
    private String name;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

然后我们再创建一个用于展示课程信息的界面组件

public class CourseListFragment extends Fragment implements CourseContract.View{

    @BindView(R.id.course_recycler_view)
    RecyclerView recyclerView;

    CourseContract.Presenter presenter;

    public CourseListFragment() {

    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        presenter = PresenterFactory.getCoursePresenter(this);

    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        View view =inflater.inflate(R.layout.fragment_course_list, container, false);
        ButterKnife.bind(this,view);

        SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(getActivity().getApplicationContext());
        String token = TokenBuilder.getToken(preferences);
        String username = preferences.getString("username","liuqin");
        Log.d("get Username", username);
        presenter.getCoursesByUsername(token,username);
        return  view;
    }

    @Override
    public void showCourses(List<Course> courses) {
        for(Course course : courses){
            System.out.println(course.getName());
        }

        CourseAdapter adapter = new CourseAdapter(courses, getContext());
        recyclerView.setAdapter(adapter);
        recyclerView.setLayoutManager(new LinearLayoutManager(this.getContext()));
        recyclerView.addItemDecoration(new GridItemDividerDecoration
                (getContext(), R.dimen.divider_height, R.color.divider));
    }
}

看到这里你可能已经注意到了,CourseListFragment 实现了一个接口CourseContract.View,没错这个接口实际上正是使用mvp架构的精髓所在,我们先来看看这个接口吧:

public interface CourseContract {

    interface View {
        void showCourses(List<Course> courses);
    }

    interface Presenter{
        void getCoursesByUsername(String token , String username);
    }
}

接口采用了内部类的写法,名为contract,包含了两个子类一个是View,另一个是Presenter从接口中定义的方法名我们也不难看出,这两个接口一个是用于界面展示的,而另一个则是用于后台处理的。我们刚才定义的CourseListFragment实际上就实现了View部分的接口,我们再来看看实现Presenter部分的类吧:

public class CoursePresenterImpl implements CourseContract.Presenter {
    private CourseContract.View view;
    public CoursePresenterImpl (CourseContract.View view){
        this.view = view;
    }
    @Override
    public void getCoursesByUsername(String token, String username) {
        ApiManager.getInstance().getCommonApi().getCoursesByUsername(token,username)
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Subscriber<List<Course>>() {
                    @Override
                    public void onCompleted() {
                    }

                    @Override
                    public void onError(Throwable e) {
                        String err = (e.getMessage()==null)?"Get Courses failed":e.getMessage();
                        Log.e("error:",err);
                        e.printStackTrace();
                    }

                    @Override
                    public void onNext(List<Course> courses) {
                        Log.d("courseSize",courses.size()+"");
                        if(courses.size()==0){
                            Course course = new Course();
                            course.setName("软件工程与计算1");
                            course.setId(1);
                            courses.add(course);
                        }
                        view.showCourses(courses);
                    }
                });
    }
}

接下来,我们仔细看一下这个类的成员变量,它包含了一个对CourseContract.View的引用,并实现了CourseContract.Presenter接口;我们再回头看CourseListFragment它包含了一个对CourseContract.Presenter的引用。说到这里,大家应该就明白了:

mvp架构的根本目的在于将modelview解耦。

它充分利用了面向接口编程和依赖倒置的思想,使得负责界面展示的组件能够专注于展示界面,而无需关注究竟如何获得需要展示的内容,以及了解这些数据的状态;同时负责处理数据的组件只需要关注数据本身,而无需关注这些数据将会由那种界面元素使用以及如何使用。这种做法克服了android开发中的常见的却又令很多开发人员无奈的问题:我们的activity或者fragment将变得越来越臃肿,我们的controller将只能与当前的界面绑定,想要更换UI将变得十分繁杂,界面组件与逻辑组件难分难解。

框架

其实框架这种东西,对于真正想要学习和了解android的人来说并不是十分必要。但是为了加快开发,适当地引用一些好的框架的确可以使得开发工作事半功倍。

Butterknife

在处理界面元素的绑定以及事件监听的处理时,我们会感到在做大量的重复劳动,于是我选择了ButterKnife这个轻量级的框架来帮助我们用注解的方式轻松解决上述问题。举个例子:

public class QuestionAnalysisActivity extends AppCompatActivity implements QuestionAnalysisContract.View{

    @BindView(R.id.analysis_title_text)
    TextView titleText;
    @BindView(R.id.analysis_git_text)
    TextView gitText;
    @BindView(R.id.analysis_scored_text)
    TextView scoredText;
    @BindView(R.id.analysis_score_text)
    TextView scoreText;
    @BindView(R.id.analysis_compile_text)
    TextView compileText;
    @BindView(R.id.analysis_testcase_sum_text)
    TextView testcaseSumText;
    @BindView(R.id.analysis_testcase_passed_text)
    TextView testcasePassedText;

    private QuestionAnalysisContract.Presenter presenter;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_question_analysis);
        ButterKnife.bind(this);
        this.presenter = new QuestionAnalysisPresenterImpl(this);
    }

    @Override
    public void showAnalysis(QuestionResult analysis) {
    }
}

值得注意的地方是这两行代码,帮助ButterKnife进行绑定

   setContentView(R.layout.activity_question_analysis);
   ButterKnife.bind(this);
Retrofit

由于本次项目是实现一个客户端,会有大量的网络请求代码,所以我采用了Retrofit一款针对Android的网络请求框架,底层实现依赖于okHttp。整体来说使用起来还是相当简单的,举个例子:

public interface CommonApi {

    @POST("user/auth")
    Observable<Response<User>> login (@Body LoginUser user);

    @GET("user/{username}/course")
    Observable<List<Course>> getCoursesByUsername
            (@Header("Authorization") String token, @Path("username") String username);

    @GET("course/{courseId}/homework")
    Observable<List<Homework>> getHomeworkByCourseId
            (@Header("Authorization") String token, @Path("courseId") int courseId);

    @GET("course/{courseId}/exercise")
    Observable<List<Exercise>> getExerciseByCourseId
            (@Header("Authorization") String token, @Path("courseId") int courseId);

    @GET("course/{courseId}/exam")
    Observable<List<Exam>> getExamByCourseId
            (@Header("Authorization") String token, @Path("courseId") int courseId);

}

retorfit帮助我们用简单的语法来定义http请求接口,实际使用时我还配合了Rxjava来实现异步的请求:

@Override
    public void getCoursesByUsername(String token, String username) {
        ApiManager.getInstance().getCommonApi().getCoursesByUsername(token,username)
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Subscriber<List<Course>>() {
                    @Override
                    public void onCompleted() {
                    }
                    @Override
                    public void onError(Throwable e) {
                        String err = (e.getMessage()==null)?"Get Courses failed":e.getMessage();
                        Log.e("error:",err);
                        e.printStackTrace();
                    }
                    @Override
                    public void onNext(List<Course> courses) {
                        Log.d("courseSize",courses.size()+"");
                        view.showCourses(courses);
                    }
                });
    }

我们定义两个回调函数onNextonError来分别处理请求成功和失败的情况。

参考链接

相关文章

网友评论

      本文标题:安卓开发中的一点经验总结

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