티스토리 뷰
SharedPreferences를 활용한 글을 보고싶으시면 2번째 글로 가주세요!
이번 글은 그것을 쓰기 위한 과정입니다.
SharedPreferences란?
- 간단한 값을 저장하려고 할 때 사용을 하는 것
- 자동로그인 여부 or 초기 설정 값
- 파일 형태로 데이터가 저장이 된다
data/data/패키지명/shared_prefs/SharedPreference이름.xml 위치에 저장이 된다.
- 어플리케이션이 삭제되기 전까지 보존이 된다.
간단한 어플을 만들면서 이해를 해보겠습니다.
현재 스마트폰에 사용되고 있는 어플을 하나 등록을 해서 바로가기를 누르면
해당 어플이 실행이 되게끔 하는 어플입니다. 그러기 위해서 우선 액티비티 창을 만들어야 합니다.
메인 화면과 스마트폰에 설치된 어플들의 목록, 그리고 리스트들의 형식입니다.
//activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"
android:orientation="vertical"
android:padding="8dp"
tools:context=".MainActivity">
<ImageView
android:id="@+id/shortcut_image"
android:layout_width="100dp"
android:layout_height="100dp"
android:background="#ff00ff"
android:onClick="onImageClicked"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="onButtonClicked"
android:text="바로가기 추가"/>
</LinearLayout>
//activity_app_list.xml
<?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=".AppListActivity">
<ListView
android:id="@+id/list_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:listitem="@layout/item_app">
</ListView>
</androidx.constraintlayout.widget.ConstraintLayout>
//item_app.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="8dp"
android:orientation="horizontal">
<ImageView
android:id="@+id/icon_image"
android:layout_width="50dp"
android:layout_height="50dp"
android:src="@mipmap/ic_launcher"
/>
<TextView
android:id="@+id/app_name_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginStart="8dp"
android:text="앱 이름"
android:textSize="24sp"/>
</LinearLayout>
우선적으로 MainActivity에서 button을 클릭했을 때 스마트폰에 다운되어있는 어플들의 모양이 떠야 합니다.
그러기 위해서 AppInfoAdapter라는 이름으로 시작되는 Java 파일을 만듭니다.
BaseAdapter를 extends하고 있는 AppInfoAdapter 클래스를 만들 것 입니다.
여기서 Adapter를 잠깐 살펴보고 가면 데이터 테이블을 목록 형태로 보여주기 위해 사용되는 것입니다.
데이터를 리스트로 다양한 형식을 보여주기 위해서 데이터와 리스트 뷰 사이에 존재하는 객체입니다.
간단히 말하면 데이터와 리스트 뷰 사이의 통신을 위한 다리역할이라고 보면 됩니다.
처음 클래스를 생성하면 아래와 같이 클래스만 덩그러니 있습니다. 여기다 BaseAdapter를 Extends 해보겠습니다.
extends BaseAdapter를 치면 Override를 해줘야 할 여러개의 메소드들을 코드로 작성을 해주지 않아서
빨간 줄이 그어질 것 입니다. 그럴 때는 하나하나 다 쳐도 괜찮지만 그러면 너무 귀찮아지니 BaseAdapter에
Focus를 해서 alt+enter를 눌러주세요. Implements Methods 이러한 글이 뜨는데 이것을 클릭을 해주세요.
그러면 Override를 할 Method 목록이 뜨게 되고 OK를 눌러주면 알아서 코드에 작성이 됩니다.
스마트폰의 Application들의 정보를 가져와야 하니 ApplicationInfo 변수를 선언을 해줍니다.
private List<ApplicationInfo> mInfos;
그리고 클래스의 생성자와 return값들을 ApplicationInfo에 관한 것들로 다 교체를 해주세요.
public AppInfoAdapter(List<ApplicationInfo> data) {
this.mInfos = data;
}
@Override // 화면에 표시해야 하는 데이터의 갯수 반환
public int getCount() {
return mInfos.size();
}
@Override // 인자로 받은 위치의 데이터 반환
public Object getItem(int position) {
return mInfos.get(position);
}
@Override // 인자로 받은 위치의 데이터 id 구분자 반환
public long getItemId(int position) {
return position;
}
//getCount 메소드의 반환된 데이터 갯수만큼 나머지 메소드들이 호출되어 화면을 그린다
생성자를 만들 때 저렇게 쳐도 괜찮지만 코드창에서
우클릭을 하고 Generate를 가서 Constructor를 해주면 자동으로 편하게 만들 수 있습니다.
그리고 item_app.xml에서 imageView와 TextView가 있기 때문에 이것을 편하게 관리하기 위해
class 내부에 class를 하나 더 만들겠습니다. 이 class는 전개된 뷰의 참조값을 저장할 객체입니다
private static class ViewHolder {
ImageView imageView;
TextView textView;
}
그리고 각 아이템들이 어댑터뷰에 어떻게 보일지 뷰를 그려서 반환하는 메소드인 getView도 아래와 같이 수정을
할 것입니다. getView는 화면에 그려져야 할 때 어댑터뷰로부터 호출이 되는 것입니다.
간단한 동작원리는 아래와 같습니다.
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if(convertView == null){
holder = new ViewHolder();
convertView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.item_app, parent, false);
holder.imageView = convertView.findViewById(R.id.icon_image);
holder.textView = convertView.findViewById(R.id.app_name_text);
//view의 태그에 Holder 객체를 저장
convertView.setTag(holder);
} else {
//convertView가 null이 아니면 뷰를 생성할 때 태그에 저장했던 holder 객체가 존재
// 이 holder 객체는 자신을 inflating한 참조값(다시 전개할 필요가 없다)
holder = (ViewHolder)convertView.getTag();
}
ApplicationInfo info = mInfos.get(position);
Drawable icon = info.loadIcon(parent.getContext().getPackageManager());
//패키지 매니저는 컨텍스트를 통해서 얻을 수 있다. parent에 컨텍스트가 있다.
//아이콘이나 그림을 그리는 객체를 drawble 인터페이스로 받을 수 있다.
holder.imageView.setImageDrawable(icon); // 이미지를 설정
String name = String.valueOf(info.loadLabel(parent.getContext().getPackageManager())); // 어플의 이름을 가져오는 것
holder.textView.setText(name);// 이름을 설정 스트링으로 변환하지 않고 parent.getContext().getPackageManager를 가져올 수 있다.
return convertView;
}
현재 이 함수에 적용된 최적화 기법은 View Holder 패턴입니다.
.뷰 전개(inflating)은 매우 비싼 연산이라 getView에서 findViewById등, 뷰를 전개하는 연산을 반복적으로 하는 것은
퍼포먼스를 떨어뜨립니다.
.View Holder 패턴은 converView를 처음 생성할 때, 미리 뷰를 전개하여 View의 태그에 참조객체를 저장하는 방법
. 뷰 전개를 view 생성 시 딱 한번만 하므로 퍼포먼스가 많이 향상된다.
Inflater
xml로 미리 정의된 view(여기선 item_app)를 실제 객체화 시키는 용도입니다.
코드에서 하나씩 작성해서 생성하기 힘든 구조의 view를
xml로 미리 만들어놓고inflater를 활용하여 바로 view를 생성하는 것
이제 Main에서 바로가기 버튼을 눌렀을 때 어플리케이션의 목록을 뜨게 해보도록 합시다.
그러기 위해서 AppListActivity라는 activity_app_list와 연동이 되어있는 Java파일을 열도록 합시다.
(activity_app_list를 만들 때 이름을 편하게 지으셨다면 그걸 사용하셔도 됩니다.)
public class AppListActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_app_list);
ListView listView = findViewById(R.id.list_view);
PackageManager pm = getPackageManager();
final List<ApplicationInfo> infos = pm.getInstalledApplications(PackageManager.GET_META_DATA);
AppInfoAdapter adapter = new AppInfoAdapter(infos);
listView.setAdapter(adapter);
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
ApplicationInfo info = infos.get(position);
Intent intent = new Intent();
intent.putExtra("info",info);
setResult(RESULT_OK, intent);
finish();
}
});
}
}
PackageManager pm = getPackageManager();
//기기의 설치된 모든 목록들을 가져오기 위해 PackageManager를 가져온다.
List<ApplicationInfo> infos = pm.getInstalledApplications(PackageManager.GET_META_DATA);
//이 코드가 기기에 설치된 모든 앱의 목록을 가져오고 그 객체가 ApplicationInfo라는 객체입니다.
//이것을 토대로 ListView에 원하는 데이터를 뿌리면 됩니다.
AppInfoAdapter adapter = new AppInfoAdapter(infos);
listView.setAdapter(adapter);
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
ApplicationInfo info = infos.get(position); // 데이터를 가지고 오는 것
Intent intent = new Intent();
intent.putExtra("info",info); // 데이터 보내기
setResult(RESULT_OK, intent); //이 액티비티의 결과로 intent를 return
finish(); //리스트의 어플리케이션을 선택하면 finish로 액티비티를 닫는 것
}
});
/*
어플리케이션을 클릭했을 때 클릭한 어플리케이션의 정보를 얻어야 한다.
그래서 위와 같이 ClickListener를 등록을 해놓는다.
*/
그리고 MainActivity에 있는 Button에 아래와 같은 코드를 작성하시면 이번 글은 마무리가 됩니다.
public void onButtonClicked(View view){
Intent intent = new Intent(this, AppListActivity.class);
startActivityForResult(intent, REQUEST_CODE);
}
위의 과정을 하나씩 다 따라서 하면 아래 사진처럼 어플리케이션의 목록이 뜨게 됩니다.
글이 너무 길어질 것 같으니 SharedPreferences를 활용한 데이터 저장은 다음 글에서 진행을 하겠습니다.
그 외
Adapter에 대한 이해가 더 필요하다.
context란 무엇인지에 대한 이해
모르는게 많으니 정작 다뤄야할 내용에 대해서 다루지 못했다..
'Android Studio > 실습위주' 카테고리의 다른 글
안드로이드 스튜디오 - 데이터 저장하기(SharedPreferences)(2) (0) | 2019.11.20 |
---|---|
안드로이드 첫번째 어플 만들어보기 (0) | 2019.11.16 |
- Total
- Today
- Yesterday
- inline
- Link
- 동영상을
- 안드로이드 스튜디오
- GRID
- 언리얼엔진4
- 생활코딩#동영상을#글로#html
- javascript
- 알고리즘
- 기초
- TAG
- C언어
- 선택자
- 생활코딩#MySQL
- HTML
- 관계형데이터베이스
- css
- 생활코딩
- 네트워크 프로그래밍
- 언리얼엔진
- 객체
- 글로
- 정렬
- 조건문
- 차이점
- visual studio code
- 문자열
- 변수
- php
- PHP&MySQL
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |