티스토리 뷰
안드로이드의 RecyclerView를 사용하여 간단한 리스트를 구현해 보는 학습을 하면서 진행 내역을 간단하게 기록해 보고자 합니다.
(사용한 안드로이드 추가 패키지) *아래는 build.gradle파일의 dependancies에 추가된 내용입니다.
//추가로 사용한 패키지 START compile 'com.android.support:support-v4:25.3.1' compile 'com.android.support:recyclerview-v7:25.3.1' //RecyclerView compile 'com.android.support:cardview-v7:25.3.1' //CardView compile 'com.github.bumptech.glide:glide:4.0.0-RC1' //url을 통한 이미지 출력 기능 제공 패키지 compile 'com.squareup.retrofit2:retrofit:2.2.0' //http(s) 통신 기능 제공 패키지 compile 'com.squareup.retrofit2:converter-gson:2.2.0' //json 파일 파싱 기능 제공 패키지 compile 'com.squareup.okhttp3:logging-interceptor:3.8.0' //http 통신 내용 log로 확인할 수 있는 interceptor 제공 패키지 compile 'com.facebook.stetho:stetho:1.5.0' //okhttp가 통신하는 것을 chrome 개발자 도구에서 확인할 수 있도록 해 주는 패키지 compile 'com.facebook.stetho:stetho-okhttp3:1.5.0' //okhttp가 통신하는 것을 chrome 개발자 도구에서 확인할 수 있도록 해 주는 패키지 //추가로 사용한 패키지 END
(사용한 온라인 리소스)
[작업내역]
1. 네트웍에서 접근할 수 있는 json 파일 준비
*현실에서는 리소스를 서버에서 수신하여 처리해야 하므로 네트웍에 json파일을 올려 놓고 놓습니다.
*기본 script가 변경될 수 있으므로 첨부파일(json_generator_default_script.txt)로 파일첨부하였습니다.
*제가 upload한 URL은 다음과 같습니다. http://www.json-generator.com/api/json/get/cqfvIltLma?indent=2
--> json-generator에서는 해당 파일을 언제까지 유지하는지는 모르겠는데, 이와 유사하게는 gist를 활용해도 될 듯 합니다.
a. json generator(http://json-generator.com)로 이동하여 기본 제공 스크립트에서 몇가지 수정
b. 생성된 json파일을 upload한 후 upload된 URL확인
[그림] json-generator를 통해 샘플 json파일 생성
[그림] json-generator에서 생성한 샘플 json파일을 json-generator에서 제공하는 서버로 upload
2. 안드로이드 프로젝트 생성
empty activity로 설정하여 프로젝트 생성
[그림] 안드로이드 기본 프로젝트 생성
3. Layout 생성
아래의 그림과 같이 간단하게 목록을 표시하려 합니다.
[그림] recyclerview 디자인
a. activity_main.xml에 RecyclerView 추가
<?xml version="1.0" encoding="utf-8"?> <android.support.constraint.ConstraintLayout 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" tools:context="com.createall.recyclerviewtest.MainActivity"> <android.support.v7.widget.RecyclerView android:id="@+id/recycler_view" android:layout_width="match_parent" android:layout_height="wrap_content" /> </android.support.constraint.ConstraintLayout>
b. ViewHolder에서 사용할 각 아이템별 layout생성
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:card_view="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="wrap_content"> <RelativeLayout android:layout_width="match_parent" android:layout_height="wrap_content"> <ImageView android:id="@+id/image_view" android:layout_width="match_parent" android:layout_height="wrap_content" android:adjustViewBounds="true" android:src="@drawable/default_image" /> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal"> <android.support.v7.widget.CardView xmlns:card_view="http://schemas.android.com/apk/res-auto" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginLeft="3dp" android:layout_marginTop="3dp" android:layout_weight="7" card_view:cardBackgroundColor="#7F000000" card_view:cardCornerRadius="4dp"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_margin="2dp" android:textColor="@android:color/white" android:text="Name : " /> <TextView android:id="@+id/user_name" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_margin="2dp" android:textColor="@android:color/white" android:text="Alex Lee" /> </LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_margin="2dp" android:textColor="@android:color/white" android:text="Email : " /> <TextView android:id="@+id/user_email" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_margin="2dp" android:textColor="@android:color/white" android:text="dialup71@gmail.com" /> </LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_margin="2dp" android:textColor="@android:color/white" android:text="Phone : " /> <TextView android:id="@+id/user_phone" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_margin="2dp" android:textColor="@android:color/white" android:text="+82 10 3xxx xxxx" /> </LinearLayout> </LinearLayout> </android.support.v7.widget.CardView> <LinearLayout android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="3" /> </LinearLayout> </RelativeLayout> </LinearLayout>
4. 모델 클래스 생성
json으로 전달된 정보를 담을 모델 클래스를 생성합니다. 빠르게 테스트를 하기 위해서 위에서 생성한 json으로 https://jsonutils.com/에서 모델 클래스를 자동으로 생성합니다.
[그림] jsonutils 사이트에서 생성된 json파일이 upload된 URL을 지정하여 모델 클래스 생성
*자동생성된 클래스는 getter setter를 생성하는 옵션을 지정하지 않았으므로, 모두 public으로 생성되는데, 이를 안드로이드 스튜디오에서 private으로 변경하고 getter setter 생성
*하나의 파일로 처리하기 위해서 Friend 클래스는 inner class로 처리
public class UserModel { private String guid; private int index; private String favoriteFruit; private double latitude; private String company; private String email; private String picture; private List<String> tags; private String registered; private String eyeColor; private String phone; private String address; private List<Friend> friends; private boolean isActive; private String about; private String balance; private String name; private String gender; private int age; private String greeting; private double longitude; private String _id; public String getGuid() { return guid; } public void setGuid(String guid) { this.guid = guid; } public int getIndex() { return index; } public void setIndex(int index) { this.index = index; } public String getFavoriteFruit() { return favoriteFruit; } public void setFavoriteFruit(String favoriteFruit) { this.favoriteFruit = favoriteFruit; } public double getLatitude() { return latitude; } public void setLatitude(double latitude) { this.latitude = latitude; } public String getCompany() { return company; } public void setCompany(String company) { this.company = company; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } public String getPicture() { return picture; } public void setPicture(String picture) { this.picture = picture; } public List<String> getTags() { return tags; } public void setTags(List<String> tags) { this.tags = tags; } public String getRegistered() { return registered; } public void setRegistered(String registered) { this.registered = registered; } public String getEyeColor() { return eyeColor; } public void setEyeColor(String eyeColor) { this.eyeColor = eyeColor; } public String getPhone() { return phone; } public void setPhone(String phone) { this.phone = phone; } public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } public List<Friend> getFriends() { return friends; } public void setFriends(List<Friend> friends) { this.friends = friends; } public boolean isActive() { return isActive; } public void setActive(boolean active) { isActive = active; } public String getAbout() { return about; } public void setAbout(String about) { this.about = about; } public String getBalance() { return balance; } public void setBalance(String balance) { this.balance = balance; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getGender() { return gender; } public void setGender(String gender) { this.gender = gender; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getGreeting() { return greeting; } public void setGreeting(String greeting) { this.greeting = greeting; } public double getLongitude() { return longitude; } public void setLongitude(double longitude) { this.longitude = longitude; } public String get_id() { return _id; } public void set_id(String _id) { this._id = _id; } public class Friend { private int id; 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; } } }
5. REST 통신을 위한 인터페이스와 클래스 생성
*REST 통신을 위해서 retrofit2 패키지와 okhttp3 패키지를 사용
a. 서비스별로 생성해야 하는 메소드를 IApiService라는 인터페이스에 정의
public interface IApiService { @GET("api/json/get/cfJljnapcO?indent=2") Call<ArrayList<UserModel>> getUserList(); }
b. retrofit 객체 관리용 클래스 생성
public class RestClient { private static IApiService IApiService; private static OkHttpClient client; public RestClient(String baseUrl) { //json 파싱 시, formatting을 하기 위한 Gson객체 설정 Gson gson = new GsonBuilder().create(); //통신 data 로깅을 위한 인터셉터 설정 HttpLoggingInterceptor httpLoggingInterceptor = new HttpLoggingInterceptor(); httpLoggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY); //http client로 사용할 okhttp 빌드 client = new OkHttpClient().newBuilder() .connectTimeout(5, TimeUnit.SECONDS) .writeTimeout(5, TimeUnit.SECONDS) .readTimeout(10, TimeUnit.SECONDS) .addInterceptor(httpLoggingInterceptor) .addInterceptor(new Interceptor() { @Override public Response intercept(Chain chain) throws IOException { Request newRequest = chain.request().newBuilder() .addHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36") .build(); return chain.proceed(newRequest); } }) .addNetworkInterceptor(new StethoInterceptor()) .build(); Retrofit retrofit = new Retrofit.Builder() .baseUrl(baseUrl) .addConverterFactory(GsonConverterFactory.create(gson)) .client(client) .build(); IApiService = retrofit.create(IApiService.class); } public IApiService getApiService() { return IApiService; } }
6. ViewHolder 생성
public class UserViewHolder extends RecyclerView.ViewHolder { public ImageView mImageView; public TextView mUserName; public TextView mUserEmail; public TextView mUserPhone; public UserViewHolder(View itemView) { super(itemView); mImageView = (ImageView)itemView.findViewById(R.id.image_view); mUserName = (TextView) itemView.findViewById(R.id.user_name); mUserEmail = (TextView) itemView.findViewById(R.id.user_email); mUserPhone = (TextView) itemView.findViewById(R.id.user_phone); } }
7. Adapter 생성
public class UserAdapter extends Adapter{ private ArrayList mList; public UserAdapter(ArrayList list) { mList = list; } @Override public UserViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.user_item, parent, false); return new UserViewHolder(v); } @Override public void onBindViewHolder(UserViewHolder holder, int position) { Glide.with(holder.itemView.getContext()) .load(mList.get(position).getPicture() + "#" + position + System.currentTimeMillis()) //Glide가 동일한 URL일 때, 캐싱한 것을 보여주기 때문에 각각 URL을 틀리게 하기 위해 position과 현재 시각을 추가함 .into(holder.mImageView); holder.mUserName.setText(mList.get(position).getName()); holder.mUserEmail.setText(mList.get(position).getEmail()); holder.mUserPhone.setText(mList.get(position).getPhone()); } @Override public int getItemCount() { return mList.size(); } }
8. Activity 코드 작성
public class MainActivity extends AppCompatActivity { private String mClassName = getClass().getName().trim(); private RecyclerView mRecyclerView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Stetho.initializeWithDefaults(this); setContentView(R.layout.activity_main); mRecyclerView = (RecyclerView)findViewById(R.id.recycler_view); mRecyclerView.setLayoutManager(new LinearLayoutManager(this)); IApiService iApiService = new RestClient("http://www.json-generator.com/").getApiService(); Call<ArrayList<UserModel>> call = iApiService.getUserList(); try { call.enqueue(new Callback<ArrayList<UserModel>>() { @Override public void onResponse(Call<ArrayList<UserModel>> call, Response<ArrayList<UserModel>> response) { if (response.isSuccessful()) { try { UserAdapter ua = new UserAdapter(response.body()); mRecyclerView.setAdapter(ua); } catch(Exception e) { Log.d(mClassName, e.toString()); } } } @Override public void onFailure(Call<ArrayList<UserModel>> call, Throwable t) { Log.d(mClassName, t.getMessage()); } }); } catch(Exception e) { Log.d(mClassName, e.getMessage()); } } }
9. AndroidManifest 수정
*인터넷 연결이 필요하므로 해당 퍼미션 요청 구문 추가
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.createall.recyclerviewtest"> <uses-permission android:name="android.permission.INTERNET" /> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" 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> </application> </manifest>
전체 소스는 첨부하며, 이후에는 당겨서 게시물을 추가하는 기능을 작성하고 공유해 보겠습니다.
감사합니다.
'안드로이드' 카테고리의 다른 글
[버그] Mac 안드로이드 스튜디오 Logcat filter bar 사라짐 (1) | 2019.05.28 |
---|