반응형

안드로이드에서 Webview로 웹사이트를 호출하면 err_cleartext_not_permitted 에러가 발생했습니다.

http://로 시작하는 웹페이지에 접근할 때 보안문제로 인해 발생하게 됩니다.

Android 9.0이상(API 수준 28)에서 발생합니다.

 

가장 빠른 해결 방법은 app\manifests\AndroidManifest.xml에 항목을 다음 항목을 추가하면 됩니다.

android:usesCleartextTraffic="true"

 

반응형
반응형

안녕하세요.

오늘은 앱바(App Bar)에 제목을 변경하거나 버튼을 추가하는 법에 대해 알아보도록 하겠습니다.

앱바는 앱의 아래 부분을 말합니다.
앱바는 액션바(Action Bar)라고도 합니다.


최근 버전이 올라가면서 다양한 기능을 맞춤 설정을 할 수 있기 때문에 툴바를 사용합니다. 

일단 다음과 같은 순서로 앱바 기능에 대해 알아보도록 하겠습니다.

1. 앱바 제목 변경

2. 앱바 색상 변경하기

3. 버튼 추가

4. 버튼에 따른 이벤트 추가

5. 앱바에 아이콘추가

6. 앱바 보이기/안보이기

기본설정은 "Empty Activity"상태로 하겠습니다.

 

 

1. 앱바 제목 변경

manifests/AndroidManifest.xml파일에서 label값을 변경해주면 됩니다.

그냥 값을 변경해줘도 적용이 되지만 위에 이미지와 같이 "@string/app_name" 경로로 표기하여 경로에 있는 스트링을 변경해줘도 됩니다.

res/values/strings.xml값을 변경하면 제목을 변경할 수 있습니다.

하지만 이렇게 하면 앱이 실행 전에만 바꿀 수 있습니다.

앱이 실행중일 때 제목을 바꾸려면 코드상에서 수정해야 합니다.

다음 코드를 사용합니다.

getSupportActionBar().setTitle("Change Title");

MainActivity.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package com.testcompany.appbar;
 
import androidx.appcompat.app.AppCompatActivity;
 
import android.os.Bundle;
 
public class MainActivity extends AppCompatActivity {
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
 
        // 실행 중 제목을 변경할 수 있습니다.
        getSupportActionBar().setTitle("Change Title");
    }
}
cs

 

2. 앱바 색상 변경하기

/res/values/themes.xml을 열어보면 다음과 같이 되어있습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<resources xmlns:tools="http://schemas.android.com/tools">
    <!-- Base application theme. -->
    <style name="Theme.Appbar" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
        <!-- Primary brand color. -->
        <item name="colorPrimary">@color/purple_500</item>
        <item name="colorPrimaryVariant">@color/purple_700</item>
        <item name="colorOnPrimary">@color/white</item>
        <!-- Secondary brand color. -->
        <item name="colorSecondary">@color/teal_200</item>
        <item name="colorSecondaryVariant">@color/teal_700</item>
        <item name="colorOnSecondary">@color/black</item>
        <!-- Status bar color. -->
        <item name="android:statusBarColor" tools:targetApi="l">?attr/colorPrimaryVariant</item>
        <!-- Customize your theme here. -->
    </style>
</resources>
cs

다음 부분을 수정하면 됩니다.

<item name="colorPrimary">@color/purple_500</item>

<item name="colorPrimaryVariant">@color/purple_700</item>

"@color/purple_500", "@color/purple_700" 는 "/res/value/colors.xml" 파일을 확인해보면 됩니다.

1
2
3
4
5
6
7
8
9
10
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="purple_200">#FFBB86FC</color>
    <color name="purple_500">#FF6200EE</color>
    <color name="purple_700">#FF3700B3</color>
    <color name="teal_200">#FF03DAC5</color>
    <color name="teal_700">#FF018786</color>
    <color name="black">#FF000000</color>
    <color name="white">#FFFFFFFF</color>
</resources>
cs

 

colorPrimary, colorPrimaryVariant는 각각 다음 위치를 가리킵니다.

3. 버튼 추가

3-1. 메뉴 XML 파일 추가

버튼을 추가하기 위해서는 일단 메뉴(Meunu) XML 파일을 먼저 추가해야 합니다.

다음과 같이 합니다.

res폴더를 선택합니다.

File - New - Android Resource File을 선택합니다.

그리고 다음 나오는 창에서 "Resource type"항목의 리스트 박스에서 Menu를 선택합니다.

다음 파일 이름을 입력한 후 OK 버튼을 누릅니다.

res/menu/main_menu.xml이 추가되었습니다.

3-2 메뉴 XML 파일 코드 수정

main_menu.xml에 코드를 추가하여 버튼을 추가할 수 있습니다.

1
2
3
4
5
6
7
8
9
10
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">
  <item
      android:id="@+id/search_action"
      android:icon="@android:drawable/ic_menu_search"
      android:title="Search"
      app:showAsAction="always"/>
 
</menu>
cs

"<item ..... />" 부분을 추가해서 버튼을 더 추가할 수 있습니다.

item구문에서 showAsAction항목에 따라 어떻게 보이게 할 건지 설정할 수 있습니다.

설정한 값에 따라 다음과 같이 표시됩니다.

always - 항상 표시해야 한다면 사용합니다. 

ifRoom - 표시할 공간이 있는 경우에만 표시되고 아니면 더보기 메뉴에 표기되게 됩니다.

withText - 아이콘과 텍스트(android:tilte로 지정한 텍스트)가 같이 표기됩니다. 파이프로 다른 설정과 포함할 수 있습니다. (설명은 이렇게 적혀있는데, 제가 해봤을 때 넣으면 never와 같이 더보기 메뉴에만 추가됩니다. )

never - 앱바에 배치하지 않고, 더보기 메뉴에 표기합니다.

3-3 앱바에 표기하기

막상 위에까지 하고 실행시켜보면 앱바에 표기가 안됩니다.

아직 코드에서 연결을 안 했기 때문입니다.

mainActivity.java파일에서 다음 코드를 추가합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package com.testcompany.appbar;
 
import androidx.appcompat.app.AppCompatActivity;
 
import android.os.Bundle;
import android.view.Menu;
 
public class MainActivity extends AppCompatActivity {
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
    @Override
    public boolean onCreateOptionsMenu(Menu menu)    {
        getMenuInflater().inflate(R.menu.main_menu, menu);
        return true;
    }
}
cs

 

R.menu.main_menu는 main_menu.xml을 의미합니다.

실행해보면 버튼이 추가되어있는 것을 확인할 수 있습니다.

4. 버튼에 따른 이벤트 추가

이제 버튼에 따른 이벤트를 추가해야합니다.
onOptionsItemSelected함수를 추가하여 구현할 수 있습니다.
다음과 같이 추가하면 됩니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
package com.testcompany.appbar;
 
import androidx.appcompat.app.AppCompatActivity;
 
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Toast;
 
public class MainActivity extends AppCompatActivity {
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
    @Override
    public boolean onCreateOptionsMenu(Menu menu)    {
        getMenuInflater().inflate(R.menu.main_menu, menu);
        return true;
    }
 
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId())
        {
            case R.id.search_action:
                Toast.makeText(getApplicationContext(), "Search Action", Toast.LENGTH_SHORT).show();
                return true;
            default:
                return super.onOptionsItemSelected(item);
        }
    }
}
cs

 

5. 앱바에 아이콘 추가

onCreate에 다음 구문을 추가하면 됩니다.

    getSupportActionBar().setIcon(R.drawable.ic_baseline_4k_24);
    getSupportActionBar().setDisplayUseLogoEnabled(true);
    getSupportActionBar().setDisplayShowHomeEnabled(true);

R.drawable.ic_baseline_4k_24 는 아이콘으로 설정할 리소스입니다.

6. 앱바 보이기/안보이기

코드에서 다음 구문을 사용할 수 있습니다.

getSupportActionBar().show();     // 보이도록 합니다.
getSupportActionBar().hide();      // 안 보이도록 합니다.

반응형
반응형

안녕하세요. 

이전시간에 안드로이드와 Firebase와 연결을 해보았습니다.

이번에는 안드로이드 스튜디오에서 Firebase의 Database를 연동해서 DB 데이터 저장 및 로드를 해보도록 하겠습니다.

일단 Database 추가를 위해서 Firebase colsole으로 들어갑니다.

 

 

 

로그인 - Google 계정

하나의 계정으로 모든 Google 서비스를 Google 계정으로 로그인

accounts.google.com

 

추가한 프로젝트를 클릭합니다.

왼쪽에 Firestore Database와 Realtime Database가 있는데, 저는 Realtime Database로 셋팅해보겠습니다.

"Realtime Database"를 클릭합니다.

Firestore Database와 Realtime Database의 차이가 궁금하시다면, 다음 페이지를 참조하시면 될 것 같습니다.

https://firebase.google.com/docs/database/rtdb-vs-firestore?authuser=0 

 

데이터베이스 선택: Cloud Firestore 또는 실시간 데이터베이스  |  Firebase

Firebase는 실시간 데이터 동기화를 지원하며 클라이언트에서 액세스할 수 있는 2가지 클라우드 기반 데이터베이스 솔루션을 제공합니다. Cloud Firestore는 모바일 앱 개발을 위한 Firebase의 최신 데이

firebase.google.com

 

데이터베이스 만들기를 클릭합니다.

 

대한민국은 없기때문에 Default인 미국으로 설정하고 다음을 클릭합니다.

 

테스트를 하기위해서 테스트 모드에서 시작으로 변경해주고 사용설정을 클릭해줍니다.

잠시 기다리면 데이터베이스를 추가할 수 있는 창이 생성되었습니다.

 

이제 안드로이드 스튜디오에서 관련 코드를 넣습니다.

다음 코드로 데이터베이스를 얻어옵니다.

DatabaseReference m_Database;

m_Database = FirebaseDatabase.getInstance().getReference();

 

저장은 다음과 같은 코드로 넣습니다.

                        m_Database.child("child1").child("child2").child("child3").setValue("child3 저장할데이터")
                        .addOnSuccessListener(new OnSuccessListener<Void>() {
                            @Override
                            public void onSuccess(Void aVoid) {
                                // 저장 성공 시 처리
                            }
                        })
                        .addOnFailureListener(new OnFailureListener() {
                            @Override
                            public void onFailure(@NonNull Exception e) {
                                // 저장 실패 시 처리
                            }
                        });

                       

로드는 다음과 같은 코드로 할 수 있습니다.

ValueEventListener postListener = new ValueEventListener() {
            @Override
            public void onDataChange(DataSnapshot dataSnapshot) {
                // 데이터를 불러올 때 처리
                int nCount = (int)dataSnapshot.getChildrenCount();
                String name;
                for (DataSnapshot postSnapshot: dataSnapshot.getChildren()) {
                  // 저장된 데이터를 하나씩 얻어옵니다.
                    if(postSnapshot.child("child3").getValue(String.class) != null) {

                        name = postSnapshot.child("child3").getValue(String.class);
                    }

                }
            }

            @Override
            public void onCancelled(DatabaseError databaseError) {
                // 데이터 불러오기 실패 시 처리
            }
        };
       // child3으로 정렬합니다.
        Query sortbyAge = m_Database.child("child1").orderByChild("child3");
        sortbyAge.addListenerForSingleValueEvent(postListener);

 

실제적으로 안드로이드 스튜디오에서 적용은 다음과 같이합니다.

MainActivity.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
package com.Testcompany.test;
 
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
 
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.Toast;
 
import com.google.android.gms.tasks.OnFailureListener;
import com.google.android.gms.tasks.OnSuccessListener;
import com.google.firebase.database.DataSnapshot;
import com.google.firebase.database.DatabaseError;
import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.FirebaseDatabase;
import com.google.firebase.database.Query;
import com.google.firebase.database.ValueEventListener;
 
import java.util.ArrayList;
 
public class MainActivity extends AppCompatActivity {
    private DatabaseReference m_Database;
    EditText m_edittext1;
    Button m_button1;
    ListView m_listview;
    int m_nCount = 0;
    ArrayList<String> m_arritems;
    ArrayAdapter m_adapter;
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
 
        m_Database = FirebaseDatabase.getInstance().getReference();
        m_edittext1 = findViewById(R.id.edit1);
        m_button1 = findViewById(R.id.button1);
        m_listview =findViewById(R.id.listview1);
 
        m_arritems = new ArrayList<String>() ;
        m_adapter = new ArrayAdapter(this, android.R.layout.simple_list_item_1, m_arritems);
 
 
        m_listview.setAdapter(m_adapter);
 
        readUser();
 
        m_button1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                String data1 = m_edittext1.getText().toString();
 
                m_Database.child("users").child("Data"+m_nCount).child("username").setValue(data1)
                        .addOnSuccessListener(new OnSuccessListener<Void>() {
                            @Override
                            public void onSuccess(Void aVoid) {
                                Toast.makeText(MainActivity.this"저장 성공.", Toast.LENGTH_SHORT).show();
                                readUser();
                                m_edittext1.setText("");
                            }
                        })
                        .addOnFailureListener(new OnFailureListener() {
                            @Override
                            public void onFailure(@NonNull Exception e) {
                                Toast.makeText(MainActivity.this"저장 실패.", Toast.LENGTH_SHORT).show();
                            }
                        });
 
            }
 
        });
 
 
    }
 
 
    private void readUser(){
        ValueEventListener postListener = new ValueEventListener() {
            @Override
            public void onDataChange(DataSnapshot dataSnapshot) {
                m_arritems.clear();
                m_nCount = (int)dataSnapshot.getChildrenCount();
                String name;
                for (DataSnapshot postSnapshot: dataSnapshot.getChildren()) {
                    if(postSnapshot.child("username").getValue(String.class!= null) {
                        name = postSnapshot.child("username").getValue(String.class);
                        m_arritems.add(name);
                    }
                }
                m_adapter.notifyDataSetChanged();
            }
 
            @Override
            public void onCancelled(DatabaseError databaseError) {
                Log.w("FirebaseDatabase","onCancelled", databaseError.toException());
            }
        };
        Query sortbyAge = m_Database.child("users").orderByChild("users");
        sortbyAge.addListenerForSingleValueEvent(postListener);
 
    }
}
cs

activity_main.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.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=".MainActivity">
 
    <EditText
        android:id="@+id/edit1"
        android:layout_width="189dp"
        android:layout_height="70dp"
        android:layout_marginEnd="36dp"
        android:layout_marginRight="36dp"
        android:layout_marginTop="28dp"
        android:ems="10"
        android:inputType="textPersonName"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.236"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
 
    <Button
        android:id="@+id/button1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="44dp"
        android:text="Button"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.861"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
 
    <ListView
        android:id="@+id/listview1"
        android:layout_width="409dp"
        android:layout_height="300dp"
        android:layout_marginTop="104dp"
        app:layout_constraintTop_toTopOf="parent"
        tools:layout_editor_absoluteX="1dp" />
</androidx.constraintlayout.widget.ConstraintLayout>
cs

 

 

반응형
반응형

오늘은 안드로이드 스튜디오와 Firebase를 연동하는 방법에 대해 알려드리도록 하겠습니다.

과정은 다음과 같습니다.

1. Firebase Colsole에서 Firebase 프로젝트 만들기

firebase 콘솔에 접속한 후 구글아이디로 로그인합니다.

 

로그인 - Google 계정

하나의 계정으로 모든 Google 서비스를 Google 계정으로 로그인

accounts.google.com

이 페이지에서 일단 프로젝트를 추가해줘야합니다. 

프로젝트 추가를 클릭합니다.

프로젝트 이름을 지정한 후 "계속" 버튼을 클릭합니다.

Google 애널리틱스 를 사용할지를 정한 후 계속 버튼을 클릭합니다.

애널리틱스 계정을 선택합니다. 

계정이 따로 없다면, Default Account for Firebase로 설정한 후 "프로젝트 만들기" 버튼을 클릭합니다.

프로젝트 생성 중 화면이 나오면 완료될 때 까지 기다립니다.

기다리면, 새 프로젝트가 준비되었다고 나옵니다.

"계속" 버튼을 클릭합니다.

 

프로젝트 창으로 이동하게 되는데, 여기서는 어떤 플랫폼에서 사용할지 지정할 수 있습니다.

안드로이드 모양 버튼을 클릭합니다.

Android 패키지 이름, 앱 닉네임(선택), 디버그 서명 인증서 SHA-1(선택)을 입력해야합니다.

Android 패키지 이름은 처음에 안드로이드 스튜디오에서 프로젝트 만들때 지정된 패키지 이름을 넣습니다.

MainActivity.java파일에서 바로 확인가능합니다.

앱 닉네임, 디버그 서명 인증서 SHA-1은 넣습니다.

"앱등록" 버튼을 누릅니다.

"google-services.json 다운로드" 버튼을 누릅니다.

설명과 같이 다운로드 받은 google-services.json을 프로젝트의 app에 넣어줍니다.

이제 안드로이드 스튜디오와 Firebase를 연결을 해야합니다.

build.gradle파일을 수정해야합니다.

앱수준의 build.gradle, 프로젝트 수준의 build.gradle을 수정해야합니다.

밑에 이미지에서는 1번이 앱수준의 build.gradle, 2번이 프로젝트 수준의 build.gradle입니다.

1번 앱 수준의 build.gradle은 다음과 같이 추가가 되어야합니다.

2번 프로젝트 수준의 build.gradle은 다음과 같이 추가가 되어야합니다.

 

이 후 동기화를 합니다.

 

이제 Firebase 콘솔에서 설정은 끝났습니다.

 

이제 연결을 확인합니다.

안드로이드 스튜디오 메뉴에서 Tool-Firebase를 클릭합니다.

Firebase 메뉴가 나옵니다.

저는 실시간 디비를 통해 연결을 확인해보도록 하겠습니다.

3번째 Realtime Database를 클릭해봅니다.

Save and retrieve data가 생깁니다. 클릭합니다.

 

다음과 같은 화면이 나옵니다.

1, 2번이 모두 체크가 되어야 합니다.

2번은 아직 체크가 안되었기 때문에 Add to Realtime Database to your app을 클릭합니다.

클릭하면 메세지 박스가 하나 뜹니다. app/build.gradle파일에 database 관련 라이브러리 관련 구문을 추가하겠냐고 물어봅니다.

Accept Changes를 클릭합니다.

잠시 기다리면 "Dependencies set up correctly"로 변경된 것을 볼 수 있습니다.

안드로이드 스튜디오에서 Firebase와 연결되었습니다.

반응형

+ Recent posts