@GET("/member/userprofile/{userPK}")
Observable<Response<UserInformation>> getOtherUserInfo(@Path("userPK") String userPK);
@Multipart
@PATCH("/member/userprofile/update/")
Observable<Response<UserEditProfile>> userEditProfile(@Part MultipartBody.Part filePart,
@Part("username") RequestBody username);
@POST("/member/login/")
Observable<Response<User>> signIn(@Body SignIn signIn);
@Multipart
@PATCH("/member/userprofile/update/")
Observable<Response<UserEditProfile>> userEditProfile(@Header("Authorization") String token,
@Part MultipartBody.Part filePart, @Part("username") RequestBody username);
Map<String, RequestBody> requestBodyMap = new HashMap<>();
requestBodyMap.put("email", toRequestBody(signUp.getEmail()));
requestBodyMap.put("password", toRequestBody(signUp.getPassword()));
requestBodyMap.put("username", toRequestBody(signUp.getUsername()));
if(signUp.getImg_profile() != null){
File file = new File(signUp.getImg_profile());
// create RequestBody instance from file
RequestBody requestFile = RequestBody.create(MediaType.parse("image/*"), file);
requestBodyMap.put("img_profile\"; filename=\""+file.getName(), requestFile);
}else{
RequestBody requestFile = RequestBody.create(MediaType.parse(""),"");
requestBodyMap.put("img_profile\"; filename=\"", requestFile);
}
return signAPI.signUp(requestBodyMap);
DataService dataService = getDataFromDB().create(DataService.class);
Observable<Response<SearchResponse>> observable = dataService.observable(word);
observable.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(data->{
}
java.lang.IllegalStateException: Expected BEGIN_OBJECT but was BEGIN_ARRAY at line 1 column 2 path $
Observable<Response<SearchResponse>> observable -> Observable<ArrayList<Response<SearchResponse>>> observable
public class DBHelperUtil extends SQLiteOpenHelper {
@Override
public void onCreate(SQLiteDatabase db) {
String createQuery = "CREATE TABLE 'history' ('id' INTEGER PRIMARY KEY AUTOINCREMENT, " +
"'word' TEXT)";
db.execSQL(createQuery);
}
}
- SQLite DB 생성 후 DB에 있는 내용을 ArrayList에 담는다. 담을 때는 list.add(0, data)로 하여 recyclerView에서 가장 나중에 add된 data가 먼저 보여지도록 한다.
Cursor cursor = connection.rawQuery(query, null);
while(cursor.moveToNext()){
String word = cursor.getString(1);
list.add(0, word);
}
- 검색을 하였을 때는 delete Query와 insert Query가 동시에 실행이 되도록 한다. 그 이유는 이미 기록에 내가 검색한 값이 있다면 그 값을 없애고 맨 처음 History로 올리기 위해서이다. 혹시라도 기록에 없다하더라도 delete Query에 맞는 검색어가 없으므로 실행되어도 상관없다.
private void insert() {
String word = editSearch.getText().toString();
SearchHistoryDAO dao = new SearchHistoryDAO(getContext());
String deleteQuery = "delete from history where word = '" + word + "'";
String insertquery = "insert into history(word)" + " values('" + word + "')";
dao.executeQuery(deleteQuery);
dao.executeQuery(insertquery);
executeList();
}
private void executeList() {
searchRecyclerAdapter.historyNotifier(dao.read());
//dao.read()함수는 DB에 있는 모든 데이터를 list로 반환하는 함수이다.
}
public interface PostContract {
interface iView {
void setPresenter(iPresenter presenter);
void recyclerDown(int position);
}
interface iPresenter {
void loadFollowing(ArrayList<User> list);
void setOnPostDelete();
}
}
public interface PostAdapterContract {
interface iView {
void setOnReplyButtonClickListener(OnReplyButtonClickListener replyButtonClickListener);
void notifyAllAdapter();
void notifyLike(int position); // RecyclerView에서 특정 위치의 데이터가 바뀌었을 때 호출된다.
}
interface iModel {
void setCheckIfFollowing(boolean check);
void setReply(int[] liked, int likeCount, User author, Reply reply);
void setReplyInput(int[] liked, int likeCount, User author);
void addReply(PostContent postContent);
int getListSize();
}
}
public class PostPresenter implements PostContract.iPresenter, OnPostContentClickListener, OnPostLikeClickListener, OnPostFollowClickListener, OnReplyButtonClickListener {
@Override
public void setOnReplyClick(String content) {
PostAPI postAPI = ServiceGenerator.createInterceptor(PostAPI.class);
Observable<Response<Reply>> reply_input = postAPI.reply_input(postPk, content);
reply_input.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(data->{
if(data.isSuccessful()){
Log.d("setOnReplyClick()", "잘 들어옵니다");
PostContent postContent = new PostContent();
Content content1 = new Content();
content1.setReply(data.body());
postContent.setContent(content1);
postContent.setContentType(Const.CONTENT_TYPE_REPLY);
adapterModel.addReply(postContent);
view.recyclerDown(adapterModel.getListSize());
}else{
Log.d("setOnReplyClick()", data.errorBody().string());
}
}, throwable -> {
Log.d("setOnReplyClick()", throwable.getMessage());
});
}
@Override
public void setOnPostDelete(){
PostAPI postAPI = ServiceGenerator.createInterceptor(PostAPI.class);
Observable<Response<Void>> delete = postAPI.delete(postPk);
delete.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(data->{
Log.d("PostPresenter", "setOnPostDelete() work");
}, throwable -> {
Log.d("PostPresenter", throwable.toString());
});
}
public class PostView implements PostContract.iView {
@Override
public void recyclerDown(int position){
recyclerView.scrollToPosition(position);
}
public void getDataFromDB() {
EditProfileAPI profileEditAPI = ServiceGenerator.createInterceptor(EditProfileAPI.class);
Observable<Response<UserInformation>> getUserInfo = profileEditAPI.getUserInfo();
getUserInfo.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(data -> {
if (data.isSuccessful()) {
if (data.code() == 200) {
// 다른 코드 생략
followerUserList = data.body().getFollowers();
followingUserList = data.body().getFollowing_users();
textFollowing.setText(followingUserList.size() + " Following");
textFollower.setText(followerUserList.size() + " Follower");
// 다른 코드 생략
}
}
adapterModel.modifyLike(position, data.body().getLiked(), data.body().getLikeCount()); // DB를 새로운 데이터로 갱신한다.
adapterView.notifyLike(position);//특정 위치의 데이터가 업데이트 되었을 때 호출하여 view를 업데이트 한다.
@BindView(R.id.btnSignUp)
Button btnSignUp;
ButterKnife.bind(this, view);
private void setProfileBackground(){
Glide.with(context)
.load(android.R.drawable.ic_input_add)
.fitCenter()
.centerCrop()
.into(imgProfile);
}
public static boolean isValidEmail(String email) {
String regex = "^[_A-Za-z0-9-]+(.[_A-Za-z0-9-]+)*@(?:\\w+\\.)+\\w+$";
Pattern p = Pattern.compile(regex);
Matcher m = p.matcher(email);
return !m.matches();
}
public static boolean isValidPassword(String password) {
// 영문자와 숫자만 허용
String regex = "^[0-9A-Za-z]{8,14}$";
Pattern p = Pattern.compile(regex);
Matcher m = p.matcher(password);
return !m.matches();
}
public static boolean isValidName(String name){
// 영문자와 숫자만 허용
String regex = "^[0-9A-Za-z가-힣]{2,10}$";
Pattern p = Pattern.compile(regex);
Matcher m = p.matcher(name);
return !m.matches();
}
참고 : AppBarLayout currently expects to be the direct child nested within a CoordinatorLayout according to the official [Google docs]
- CollapsingToolbarLayout에 contentScrim="@color/colorPrimary" 설정을 해서 스크롤을 위로 올렸을 때 지정한 View Group이 사라지게 해준다.
<android.support.design.widget.CollapsingToolbarLayout
android:id="@+id/collapsingToolbarLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
app:contentScrim="@color/colorWhite"
app:layout_scrollFlags="scroll|exitUntilCollapsed"
app:scrimAnimationDuration="500"
app:scrimVisibleHeightTrigger="120dp"
app:titleEnabled="false">
<android.support.design.widget.FloatingActionButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|right"
android:layout_margin="16dp"
android:src="@mipmap/ic_launcher"
app:layout_anchor="@id/myinfoRecyclerView"
app:layout_anchorGravity="bottom|right|end"/>
TextWatcher textWatcher = new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
Log.d("확인", "onTextChanged: " + s.toString() + start + before + count);
if(count>0){
recyclerSearchHistory.setAdapter(searchRecyclerResultAdapter);
}else if(start==0){
recyclerSearchHistory.setAdapter(searchRecyclerAdapter);
}
}
@Override
public void afterTextChanged(Editable s) {
}
};
editSearch.addTextChangedListener(textWatcher);
RxTextView.textChanges(editSearch)
.subscribe(ch ->{
if(ch.length()>0){
recyclerSearchHistory.setAdapter(searchRecyclerResultAdapter);
}else{
recyclerSearchHistory.setAdapter(searchRecyclerAdapter);
}
});
- onRestart()에 바뀌는 코드를 넣어줬다.
@Override
protected void onRestart() {
super.onRestart();
mainPresenter.refreshData(mainView);
}