반응형
Firebase DB를 사용하여 RecyclerView에 출력하고, 갱신 버튼을 눌러, DB를 reloading하여 출력해 보자.

 

1. dependency 추가

implementation 'androidx.recyclerview:recyclerview:1.3.0'
implementation 'com.github.bumptech.glide:glide:4.10.0'
annotationProcessor 'com.github.bumptech.glide:compiler:4.10.0'

2. activity_main.xml에 recyclerview 추가. reload 버튼 추가

<Button
    android:id="@+id/btn_Reload"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:text="reload"
    />

<androidx.recyclerview.widget.RecyclerView
    android:id="@+id/recyclerview"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    />

3. 아이템 디자인 list_item.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">
    <LinearLayout
        android:orientation="horizontal"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
        <ImageView
            android:id="@+id/iv_profile"
            android:layout_width="100dp"
            android:layout_height="100dp"
            android:src="@mipmap/ic_launcher"
            />
        <LinearLayout
            android:layout_marginLeft="15dp"
            android:gravity="center_vertical"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:orientation="vertical"
            >
            <TextView
                android:id="@+id/tv_id"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="hello"/>
            <TextView
                android:id="@+id/tv_pw"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="hello"/>
            <TextView
                android:id="@+id/tv_userName"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="hello"/>
        </LinearLayout>
    </LinearLayout>
</LinearLayout>

4. 아이템 class. User class (getter and setter 는  alt+insert키로 쉽게 자동생성 하세요.. )


public class User {
    private String profile ;
    private String id ;
    private int pw ;
    private String userName ;

5. CustomAdapter class

public class CustomAdapter extends RecyclerView.Adapter<CustomAdapter.CustomViewHolder> {
    private ArrayList<User> arrayList ;
    private Context context ;

    public CustomAdapter(ArrayList<User> arrayList, Context context) {
        this.arrayList = arrayList;
        this.context = context;
    }

    @NonNull
    @Override
    public CustomAdapter.CustomViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item, parent, false) ;
        CustomViewHolder holder = new CustomViewHolder(view) ;
        return holder; // 홀더 리턴
    }

    @Override
    public void onBindViewHolder(@NonNull CustomAdapter.CustomViewHolder holder, int position) {
        Glide.with(holder.itemView)
                .load(arrayList.get(position).getProfile())
                .into(holder.iv_profile) ;
        holder.tv_id.setText(arrayList.get(position).getId());
        holder.tv_pw.setText(String.valueOf(arrayList.get(position).getPw()));
        holder.tv_userName.setText(arrayList.get(position).getUserName());
    }

    @Override
    public int getItemCount() {
        return (arrayList!=null ? arrayList.size(): 0);
    }

    public class CustomViewHolder extends RecyclerView.ViewHolder {
        ImageView iv_profile ;
        TextView tv_id ;
        TextView tv_userName ;
        TextView tv_pw ;

        public CustomViewHolder(@NonNull View itemView) {
            super(itemView);
            iv_profile = itemView.findViewById(R.id.iv_profile) ;
            tv_id = itemView.findViewById(R.id.tv_id) ;
            tv_userName = itemView.findViewById(R.id.tv_userName) ;
            tv_pw = itemView.findViewById(R.id.tv_pw) ;

        }
    }
}

6. Firebase 설정.

Tools - firebase 선택.  (예전엔 수작업으로 한 거를 편리하게 다 해준다..)

우측에 Realtime Database 메뉴를 선택한다.  Get started with Realtime Database 로 가서, 차례로 진행한다.

connect your app to firebase ; 브라우저로 구글 로그인하여 firebase 콘솔로 가서 프로젝트 생성까지 진행됨.

(실시간 DB를 잘 만든다. 필드도  User class에 맞게 다 맞춘다. +를 눌러 User를 만들고 다시 +를 눌러 User_01을 만들고 다시 +를 눌러 profile, id, pw, userName 필드들을 만든다.   처음엔 사용법을 몰라 어렵다. 하위 노드를 위해 미리 +를 연속해서 눌러줘야 된다. 미리 만들고, 엔터치면 하위에 추가가 안되서 삽질.. )

Add the Realtime Database to your app ; dependency 등을 알아서 설정해 준다.

그러나,... 나의 경우는 빌드시 에러가...  찾아보니, 버전 문제가 또 있다... (어쩌라고.. 정말  막막하게 만드는  버전 호환성...)

build.gradle (project) 에서 4.3.10 으로 들어가 있는데 찾아보니 버전을 14로 올리면 해결된다고 해서 해보니 성공하였음.

classpath 'com.google.gms:google-services:4.3.14'

 

7.MainActivity에서 RecyclerView와 Adapter 연결 및 Firebase 연동...

public class MainActivity extends AppCompatActivity {
    private RecyclerView recyclerView ;
    private RecyclerView.Adapter adapter ;
    private RecyclerView.LayoutManager layoutManager ;
    private ArrayList<User> arrayList ;
    private FirebaseDatabase database ;
    private DatabaseReference databaseReference ;
    private ValueEventListener valueEventListener ;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        recyclerView = findViewById(R.id.recyclerview) ;
        recyclerView.setHasFixedSize(true);
        layoutManager = new LinearLayoutManager(this) ;
        recyclerView.setLayoutManager(layoutManager);
        arrayList = new ArrayList<User>() ;

        adapter = new CustomAdapter(arrayList, this) ;
        recyclerView.setAdapter(adapter);

        database = FirebaseDatabase.getInstance();
        databaseReference = database.getReference("User") ; // User table

        valueEventListener = new ValueEventListener() {
            @Override
            public void onDataChange(@NonNull DataSnapshot snapshot) {
                Log.e("AAA", "reload data") ;
                // 데이터를 수신.
                arrayList.clear();
                for (DataSnapshot ds : snapshot.getChildren()) {
                    User user = ds.getValue(User.class) ;
                    Log.e("AAA", user.getId()) ;
                    arrayList.add(user) ;
                }
                adapter.notifyDataSetChanged();
            }

            @Override
            public void onCancelled(@NonNull DatabaseError error) {
                Log.e("AAA", error.toString()) ;
            }
        } ;

        databaseReference.addListenerForSingleValueEvent(valueEventListener);

        findViewById(R.id.btn_Reload).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                databaseReference.addListenerForSingleValueEvent(valueEventListener);
            }
        });

    }
}

- Reload를 어떻게 하나 궁금했는데 찾아보니 위와 같이 하니 되었다. databaseReference에 리스너를 또 등록하면 됨. 그러면 노드들을 다시 가져오고 갱신되었다. 

 

'Develop > Android' 카테고리의 다른 글

ViewPager2, TabLayout  (0) 2023.03.19
[Android] JSON 데이터 송수신  (1) 2023.03.18
반응형

안드로이드 스튜디오에서 okhttp3를 사용하여 JSON 데이터를 비동기 방식으로 전송하고 수신하는 코드는 다음과 같습니다. 

(참고 app: build.gradle의 dependencies에 추가)

implementation 'com.squareup.okhttp3:okhttp:4.9.3'

(manifest에 권한 추가)

<uses-permission android:name="android.permission.INTERNET"/>
import okhttp3.*;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.IOException;

public class MainActivity extends AppCompatActivity {

    private OkHttpClient client = new OkHttpClient();
    private MediaType JSON = MediaType.parse("application/json; charset=utf-8");

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // JSON 객체 생성
        JSONObject json = new JSONObject();
        try {
            json.put("name", "John Doe");
            json.put("age", 30);
        } catch (JSONException e) {
            e.printStackTrace();
        }

        // RequestBody 생성
        RequestBody body = RequestBody.create(json.toString(), JSON);

        // Request 생성
        Request request = new Request.Builder()
                .url("https://example.com/api")
                .post(body)
                .build();

        // 비동기 방식으로 요청 전송
        client.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                e.printStackTrace();
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                if (!response.isSuccessful()) {
                    throw new IOException("Unexpected code " + response);
                }

                // 수신된 JSON 데이터 디버그 로그로 출력
                try {
                    String responseData = response.body().string();
                    JSONObject receivedJson = new JSONObject(responseData);
                    Log.d("Received JSON", receivedJson.toString());
                } catch (JSONException e) {
                    e.printStackTrace();
                }
            }
        });
    }
}

 

* 에러 관련

not permitted by network security policy

  • 버전이 올라가면서 기본적으로 http는 거부한다.. 이런 에러를 만날 것이다.
android okhttp not permitted by network security policy
해결방안은... 
manifest, application 태그
android:usesCleartextTraffic="true"

  • 하지만 스토어에 등록은 안될 것이다!!. https에 SSL 인증까지 해야 등록가능..
  • 즉, 테스트 용도에서는 가능.

NetworkOnMainThreadException , StrictMode$AndroidBlockGuardPolicy

  • 메인 쓰레드에서 네트웍을 블로킹방식 ( execute() )으로 하게 되면 만나는 에러...
  • 쓰레드를 만들어 돌리든지, 비동기 방식으로 변경..
new Thread() {
    public void run() {
        try {
            listFile();
        } catch (MalformedURLException e) {
            e.printStackTrace();
        }
    }
}.start();

 

'Develop > Android' 카테고리의 다른 글

ViewPager2, TabLayout  (0) 2023.03.19
RecyclerView, Firebase DB, reload  (0) 2023.03.19
반응형

원격 mysql 서버에 있는 DB의 스키마 작성 쿼리만 얻고 싶을 때?

 

mysqldump --no-data -h [서버IP] -P [포트] -u [사용자] -p [DB명]

  • 옵션 대문자 P와 소문자 p를 헛갈리지 않도록 주의!
  • 보통 mysql 디폴트 포트는 3306 이지만 관리자가 변경할 수 도 있다. 
  • --no-data 옵션으로 데이터는 받지 않고, 스키마만 받을 수 있다. (create table 만 나옴)
  • -p 옵션은 password를 프롬프트로 입력받겠다는 의미이다. -p를 생략하면 패스워드 없이 인증하려고 시도하여 인증실패 날 수 있다. 프롬프트로 패스워드를 받지 않고 커맨드에 패스워드를 직접 넣으려면 -p[패스워드]  이렇게 공백없이 붙여쓴다.   -p 옵션뒤에 공백을 넣고 패스워드를 넣으면  프롬프트로 패스워드 넣으라고 나오고, 뒤에 나온 스트링을 DB명으로 인식하여 찾게 된다.

 

mysql 클라이언트 옵션도 동일하다..

  • mysql  -h [서버IP] -P [포트] -u [사용자] -p
  • mysql  -h [서버IP] -P [포트] -u [사용자] -p[패스워드]
  • mysql  -h [서버IP] -P [포트] -u [사용자] -p [DB명]
  • mysql  -h [서버IP] -P [포트] -u [사용자] -p[패스워드] [DB명]

( -h 옵션 생략시 로컬 호스트 , -P 생략시 3306, -p 생략시 암호없음)

 

+ Recent posts