준비물

1. 우선 import해야 할 것들이 있습니다.

레이아웃에 필요한 위젯들을 가져옵니다.

import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
cs


이렇게 하면 GridLayoutManager 혹은 LinearLayoutManager를 통해 Activity를 조작할 수 있게 됩니다. 구글에서 제공하는 것이니 믿고 써도 됩니다.


2. 그 전에 만들어 놓은 Adapter들을 가져옵니다.

import com.example.keepair.myapplication.adapter.FlowerAdapter;
import com.example.keepair.myapplication.adapter.FlowerAdapter_grid;
cs


이것들은 나중에 설명할 것입니다. 지금은 여러 데이터들이 GridLayoutManager와 연동될 수 있도록 도와주는 역할을 한다고 알면 될 것 같습니다.


3. 레이아웃으로부터 값들을 가져옵니다.

화면에서 보여지는 것들의 값들을 가져올 필요가 있습니다.
RestManager는 따로 만든 것으로 나중에 다시 포스팅할 것입니다.

    private SwipeRefreshLayout swipeContainer_red;
    private RecyclerView mRecyclerView;
    private RestManager mRestManager;
    private FlowerAdapter_grid mFlowerAdapter;
    private TextView mCoordinatesTextGrid;
cs


2. 함수 작성

4. GridLayout을 위한 onCreateView를 구현합니다.

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_red, container, false);
        swipeContainer_red = (SwipeRefreshLayout) view.findViewById(R.id.swipeContainer_red);
        setRetainInstance(true);
 
        mCoordinatesTextGrid = (TextView) view.findViewById(R.id.tv_coordinates_grid);
        getGridPosts();
        swipeContainer_red.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
            @Override
            public void onRefresh() {
                getGridPosts();
            }
        });
        configViews(view);
 
        return view;
    }
cs


OnCreateView를 통해 처음에 GridLayout을 불러올 시에 구성될 화면을 구현할 수 있습니다. SwifeRefreshLayout을 사용했습니다.

5. Posts를 가져올 함수를 지정합니다.

    private void getGridPosts() {
}

cs

이제 이 안에 글들을 가져와서 처리만 하면 됩니다.

6. 위에서 구현한 함수를 더 자세히 지정합니다.

위 getGridPosts() 안에 들어갈 내용입니다.

        ReferSharedPreference preferenceCoordinates = new ReferSharedPreference(getContext());
        String lat = preferenceCoordinates.getValue("Lat", "13");
        String lon = preferenceCoordinates.getValue("Lon", "15");
        mCoordinatesTextGrid.setText(lat + "  , " + lon);
        mRestManager = new RestManager();
        Call<List<Flower>> listCall = mRestManager.getmFlowerApiService(getActivity()).getAllFlowers(lat, lon);
        listCall.enqueue(new Callback<List<Flower>>() {
            @Override
            public void onResponse(Call<List<Flower>> call, Response<List<Flower>> response) {
                if (response.isSuccessful()) {
                    mFlowerAdapter.clear();
                    List<Flower> flowerList = response.body();
                    for(int i =0; i<flowerList.size(); i++) {
                        Flower flower = flowerList.get(i);
                        mFlowerAdapter.addFlower(flower);
                    }
                    swipeContainer_red.setRefreshing(false);
                }
            }
            @Override
            public void onFailure(Call<List<Flower>> call, Throwable t) {
            }
        });
cs


여기서 lat과 lon은 좌표값을 가져오는 것입니다. 이번에도 좌표값이 주어지지 않았다면 기본적으로 (13, 15) 좌표를 찾게 됩니다. 그런 다음 만들어놓은 ApiService를 이용해 비동기통신을 하여 그것을 Adapter를 이용해 추가하게 됩니다. Flower를 Post라고 생각하면 편합니다. 그 후 마지막으로 setRefreshing을 false로 설정해 자동적으로 새로고침을 반복하지 않도록 막아줍니다. 나머지 코드는 앞서 설명한 Retrofit의 Call함수입니다. 포스트에 FlowerList를 사용했습니다.


7. 환경설정을 조금만 더 해줍니다.

이렇게하면 RecyclerView의 여러가지 설정을 할 수 있습니다.

RecyclerView가 고정된 사이즈로 3개 항목을 한 줄에 나타내게끔 만들었습니다. 유행하는 스타일입니다.


    private void configViews(View view) {
        mRecyclerView = (RecyclerView) view.findViewById(R.id.rv_flower_red);
        mRecyclerView.setHasFixedSize(true);
        mRecyclerView.setRecycledViewPool(new RecyclerView.RecycledViewPool());
        mRecyclerView.setLayoutManager(new GridLayoutManager(getActivity().getApplicationContext(), 3));
        mFlowerAdapter = new FlowerAdapter_grid(this);
        mRecyclerView.setAdapter(mFlowerAdapter);
    }
cs

8. 포스트를 클릭했을 때의 이벤트를 설정합니다.

    @Override
    public void onClick(int position) {
        Flower selectedFlower = mFlowerAdapter.getSelectedFlower(position);
        Intent intent = new Intent(getContext(), DetailActivity.class);
        intent.putExtra(Constants.REFERENCE.FLOWER, selectedFlower);
        startActivity(intent);
    }
cs



이렇게하면 GridLayout Fragment를 완성합니다. 마지막에 intent로 포스트 클릭시에 DetailActivity 가 실행되도록 했습니다. DetailActivy는 다음에 알아보겠습니다.

1. 준비물

이번엔 register 기능을 구현할 것입니다.

먼저 몇가지를 import하겠습니다. 그 중 okhttp3의 mediatype을 이용할 것입니다. 나머지는 유저 등록을 위한 모델들입니다.


import com.example.keepair.myapplication.apiservice.RegistrationApiService;
import com.example.keepair.myapplication.helper.Constants;
import com.example.keepair.myapplication.loginhelper.ReferSharedPreference;
import com.example.keepair.myapplication.model.MyKey;
 
import okhttp3.MediaType;
cs


이렇게 하면 requestBody를 따로 만들 수 있게 됩니다. okhttp의 requestBody를 만들기 위해 MediaType이 필요합니다. request의 POST 요청을 위해 사용하는 것입니다.


필요한 정보를 가져옵니다. 저장되어있는 정보도 괜찮고 새로 불러올 정보도 괜찮습니다.


    MyKey keygoven;
 
    RegistrationApiService mRegistrationApiService;
    EditText mUsernameRegistrationEditText;
    EditText mPasswordRegistration1EditText;
    EditText mPasswordRegistration2EditText;
    ImageView mRegisterButton;
    RelativeLayout mLayoutRegstration;
 
    ReferSharedPreference mSavedUserInfo;
cs


저는 SharedPreference 의 변형인 ReferSharedPreference를 쓸 것입니다.


2. 함수 구현

그 다음 onCreate를 작성합니다.


    @Override
    protected void onCreate(Bundle savedInstanceState) {
    }
cs


여기 안에 필요한 코드들을 넣겠습니다.


        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.activity_registration);
        Display display = ((WindowManager) getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
        int width = (int) (display.getWidth() * 0.999); //Display 사이즈
        int height = (int) (display.getHeight() * 0.9);  //Display 사이즈
        getWindow().getAttributes().width = width;
        getWindow().getAttributes().height = height;
cs


이렇게 하면 기본 Activity의 사이즈를 정하게 됩니다. display 되는 사이즈라고 생각하면 됩니다. 안드로이드 화면의 크기를 조절하는 것입니다. getWidth()와 getHeight()를 사용했습니다. 지난 포스트에서는 0.7과 0.9를 사용했지만 이번엔 최대 크기를 잡기 위해 비율을 1에 가깝게 했습니다.


그 다음 레이아웃과 저장된 SharedPreference로부터 값을 불러와서 사용될 값으로 넣어주겠습니다.


        mSavedUserInfo = new ReferSharedPreference(getApplicationContext());
        mUsernameRegistrationEditText = (EditText) findViewById(R.id.et_username_registration);
        mPasswordRegistration1EditText = (EditText) findViewById(R.id.et_password_registration_1);
        mPasswordRegistration2EditText = (EditText) findViewById(R.id.et_password_registration_2);
        mRegisterButton = (ImageView) findViewById(R.id.btn_registration);
        mLayoutRegstration = (RelativeLayout) findViewById(R.id.layoutRegistration);
cs


유저 등록에 필요한 정보들은 모두 가져오게 되었습니다. 그 다음엔 이걸 POST요청으로 전송할 수 있게 onClickListener()를 작성합니다.


                final String givenRegistrationUserName = mUsernameRegistrationEditText.getText().toString();
                final String givenRegistrationPassword1 = mPasswordRegistration1EditText.getText().toString();
                String givenRegistrationPassword2 = mPasswordRegistration2EditText.getText().toString();
                String givenEmail = "";
cs


쓸 값들을 변수에 넣어서 준비합니다. okhttp client에서 사용될 것입니다.

그 다음엔 조건에 맞는다면 전송하는 부분을 작성합니다. 항상 등록을 허가할 순 없으니 조건을 구성합니다. if문을 사용했습니다.


                if(givenRegistrationUserName.length() >= 3){
                    if(givenRegistrationPassword1.equals(givenRegistrationPassword2)){
                    }
                }
cs


username의 길이와 password의 일치여부를 확인한 후 둘 다 True면 실행되는 코드입니다.


                            OkHttpClient client = new OkHttpClient();
                            OkHttpClient.Builder builder = new OkHttpClient.Builder();
                            client = builder.build();
 
                            Retrofit retrofit = new Retrofit.Builder()
                                    .client(client)
                                    .addConverterFactory(GsonConverterFactory.create())
                                    .baseUrl(Constants.BASE_URL)
                                    .build();
 
                            mRegistrationApiService = retrofit.create(RegistrationApiService.class);
 
cs


Api Client를 만듭니다. 그리고 request 보내기 전 데이터를 수집합니다. Retrofit가 편리하게 사용됩니다.


                            RequestBody username =
                                    RequestBody.create(
                                            MediaType.parse("multipart/form-data"), givenRegistrationUserName);
                            RequestBody email =
                                    RequestBody.create(
                                            MediaType.parse("multipart/form-data"), givenEmail);
                            RequestBody password1 =
                                    RequestBody.create(
                                            MediaType.parse("multipart/form-data"), givenRegistrationPassword1);
                            RequestBody password2 =
                                    RequestBody.create(
                                            MediaType.parse("multipart/form-data"), givenRegistrationPassword2);
cs


사용자가 입력한 정보를 RequestBody에 넣어 서버로 전송할 것입니다. 이렇게 하면 requestBody 구성이 완료됩니다.

이제 직접 서버와 통신하는 부분을 작성하겠습니다. 지난 시간의 Call 요청을 좀 더 자세하게 구현합니다.


 
                            Call<ResponseBody> call = mRegistrationApiService.registersecond(username, email, password1, password2);
                            call.enqueue(new Callback<ResponseBody>() {
                                @Override
                                public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
                                    if (response.isSuccessful()){
                                        Toast.makeText(getApplicationContext(), "Success", Toast.LENGTH_LONG).show();
                                        mSavedUserInfo.put("SavedUserName", givenRegistrationUserName);
                                        mSavedUserInfo.put("SavedPassword", givenRegistrationPassword1);
                                        Intent intent = new Intent(RegistrationActivity.this, LoginActivity.class);
                                        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
                                        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                                        startActivity(intent);
                                    }
                                    else {
                                        Toast.makeText(getApplicationContext(), "Something wrong, Would you check password conditions?", Toast.LENGTH_LONG).show();
                                    }
                                }
 
                                @Override
                                public void onFailure(Call<ResponseBody> call, Throwable t) {
 
                                }
                            });
cs


이렇게하여 Retrofit의 Call도 구현했습니다. 유저 등록이 끝나면 다시 LoginActivity로 이동하도록 intent를 만들었습니다. intent에서 현재의 activity를 효과적으로 제거할 수 있게 FLAG들을 사용했습니다.


이 다음엔 failure를 구현하면 됩니다. 위에선 response에서의 response.isSuccessful() 과 else가 있고 따로 onFailure()가 존재하지만 원하는 대로 작성하시면 됩니다.

여러 앱에서 필수적인 기능인 로그인 기능을 구현하겠습니다. 버터나이프라는 좋은 모듈을 사용할 것입니다. 버터나이프는 안드로이드에서 view에 쉽게 접근할 수 있게 해 줍니다. 

butterknife : http://jakewharton.github.io/butterknife/


1. 레이아웃 불러오기

먼저 레이아웃에서 로그인 아이디값, 비밀번호값 등을 가져오기 전에 그 값들을 저장할 데이터 모델과 그 모델을 처리할 apiService를 불러오겠습니다.


import com.example.keepair.myapplication.apiservice.LoginApiService;
import com.example.keepair.myapplication.helper.Constants;
import com.example.keepair.myapplication.loginhelper.ReferSharedPreference;
import com.example.keepair.myapplication.model.LoginData;
import com.example.keepair.myapplication.model.MyKey;
cs

여기서 ReferSharedPreference는 나중에 살펴볼 것입니다. 지금은 자동 로그인을 위한 SharedPreference 라고 알고 넘어가면 될 것 같습니다. SharedPreference는 안드로이드에서 유용하게 사용되는 저장 도구입니다. 앞서 말한대로 버터나이프 모듈을 쓸 것이니 그것도 가져와줍니다.


import butterknife.Bind;
import butterknife.ButterKnife;
import butterknife.OnClick;
cs

그 다음 값을 담을 변수들을 정합니다.


    MyKey keygiven;
    LoginApiService loginApiService;
    @Bind(R.id.usernameTextField)
    EditText mUsernameTextField;
    @Bind(R.id.passwordTextField)
    EditText mPasswordTextField;
    @Bind(R.id.loginButton)
    ImageView mLoginButton;
    @Bind(R.id.btn_start_RegistrationActivity)
    ImageView mStartRegistrationButton;
    @Bind(R.id.layout_Login)
    RelativeLayout mLayoutLogin;
    ReferSharedPreference mSavedUserInfo;
cs

@Bind가 butterknife의 역할입니다. @Bind를 통해 길던 코드가 매우 짧아졌습니다. butterknife를 쓰는 사람들은 이 간결함을 선호합니다.


2. 함수 지정

onCreate를 설정하겠습니다. onCreate는 생성될 때의 옵션을 의미합니다. 화면이 만들어질 때부터 기능할 수 있는 부분을 정하게 됩니다.


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_login);
        ButterKnife.bind(this);
 
        mSavedUserInfo = new ReferSharedPreference(getApplicationContext());
 
        mUsernameTextField.setText(mSavedUserInfo.getValue("SavedUserName"""));
        mPasswordTextField.setText(mSavedUserInfo.getValue("SavedPassword"""));
    }
cs

mSavedUserInfo가 없다면 새로운 값을 가져오게 되는 것입니다. 새로운 값을 가져올 때는 레이아웃에서 값을 가져와보고, 레이아웃에서 값이 존재하지 않는다면 "" 값을 가져옵니다. 빈 텍스트를 가져오게 됩니다. 저장된 값들은 SharedPreference에서 존재합니다.

 

등록 버튼을 눌렀을 때 새로운 RegisterActivity가 생성되도록 intent를 만들겠습니다.

로그인 화면이 있고 로그인 화면에서 등록 버튼을 눌러 사용자 등록을 위한 화면을 생성하는 구조입니다.


    @OnClick(R.id.btn_start_RegistrationActivity)
    public void onClickToStartRegistration(View view){
        Intent intent = new Intent(LoginActivity.this, RegistrationActivity.class);
        startActivity(intent);
    }
cs

로그인 버튼을 구현합니다. @onClick을 butterknife를 이용해 만듭니다. @onClick도 butterknife에서 제공되는 유용한 도구입니다.


    @OnClick(R.id.loginButton)
    public void onClick(View view) {
    }
cs

이제 여기 안에 내용을 채우면 됩니다.

우선 사용자가 작성한 값들을 레이아웃으로부터 가져옵니다.


        final String givenUserName = mUsernameTextField.getText().toString();
        String givenEmail = "";
        final String givenPassword = mPasswordTextField.getText().toString();
        LoginData loginData = new LoginData(givenUserName, givenPassword, givenEmail);
cs


Okhttp3를 이용해서 로깅을 조절합니다. header랑 body를 지정합니다. 이걸 통해 http가 어떻게 통신되는지 확인할 수 있습니다.


        HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
        logging.setLevel(HttpLoggingInterceptor.Level.BODY);
        logging.setLevel(HttpLoggingInterceptor.Level.HEADERS);
 
cs

로그인에 이용할 Retrofit을 불러올 것입니다.  Retrofit는 나중에 살펴볼 비동기 통신 도구입니다. 사전작업을 하겠습니다.

client라는 변수에 okHttpClient() 값을 넣어줍니다.


        OkHttpClient client = new OkHttpClient();
        OkHttpClient.Builder builder = new OkHttpClient.Builder();
        builder.interceptors().add(logging);
 
        client = builder.build();
 
        Retrofit retrofit = new Retrofit.Builder()
                .client(client)
                .addConverterFactory(GsonConverterFactory.create())
                .baseUrl(Constants.BASE_URL)
                .build();
cs


이제 직접적으로 서버와 통신할 Call부분을 만듭니다.

Call부분은 이렇게 성공한 경우와 실패한 경우를 나눠서 대응할 수 있습니다. 서버와의 통신에 성공하면 response.isSuccessful()이 호출되고 그렇지 않다면 onFailure()가 호출될 것입니다.

 
        loginApiService = retrofit.create(LoginApiService.class);
        Call<MyKey> getget = loginApiService.getget(loginData);
        getget.enqueue(new Callback<MyKey>() {
            @Override
            public void onResponse(Call<MyKey> call, Response<MyKey> response) {
                if (response.isSuccessful()) {
                }
                else {
                    Toast.makeText(getApplicationContext(),"Failed", Toast.LENGTH_LONG).show();
                }
            }
            @Override
            public void onFailure(Call<MyKey> call, Throwable t) {
            }
        });
cs

실패한다면 별 반응이 없어도 되지만 성공한다면 로그인 이후의 반응을 작성해야합니다.


                    keygiven = response.body();
 
                    Toast.makeText(getApplicationContext(),"We waited you, " + givenUserName, Toast.LENGTH_LONG).show();
 
                    mSavedUserInfo.put("SavedUserName", givenUserName);
                    mSavedUserInfo.put("SavedPassword", givenPassword);
 
                    ReferSharedPreference givenToken = new ReferSharedPreference(getApplicationContext());
                    givenToken.put("Token""Token "+ keygiven.getKey());
                    Intent intent = new Intent(LoginActivity.this, MainActivity.class);
                    intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
                    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                    startActivity(intent);
cs


이렇게 하면 통신에 성공했을 때 로그인을 하여 startActivity를 실행하게 됩니다.

실패하게 되면 간단히 Toast만 띄워줍니다.


                    Toast.makeText(getApplicationContext(),"Failed", Toast.LENGTH_LONG).show();
cs


LoginActivity를 간단하게 만들어 보았습니다.

+ Recent posts