[Android] 기기에 설치된 앱 등록 후 바로가기 만들고 유지하기

Android/Android · 2020. 6. 13. 16:55
반응형

https://survivalcoding.com/p/android_basic

 

될 때까지 안드로이드

될 때까지 안드로이드에 수록된 예제의 라이브 코딩 해설

survivalcoding.com

위 서적을 참고하였습니다.

 

 

 

 이번 포스트는 기기 내에 설치된 앱들의 리스트를 가져오고, 앱 아이콘을 누르면 그 앱이 실행되며, 재실행해도 데이터가 유지되는 앱을 만들어 보겠습니다. 이전 포스트에서 이어지는 내용입니다.

 

먼저 레이아웃을 구성하겠습니다.

 

 

 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"
    tools:context="hello.world.study.MainActivity">

    <ImageView
        android:id="@+id/image_view"
        android:background="#D3CDD3"
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:onClick="onImageView"/>

    <Button
        android:id="@+id/add_btn"
        android:onClick="onButtonClick"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="바로가기 추가"/>

</LinearLayout>

 

 activity_list_item.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"
    tools:context="hello.world.study.ActivityListItem">

    <ListView
        android:id="@+id/list_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:listitem="@layout/layout_item" />

</LinearLayout>

 

 

 layout_item.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:layout_margin="8dp">

    <ImageView
        android:id="@+id/icon_view"
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:src="@mipmap/ic_launcher"/>

    <TextView
        android:id="@+id/item_name"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textSize="24sp"
        android:layout_marginStart="8dp"
        android:text="앱 이름"
        android:layout_gravity="center_vertical"/>

</LinearLayout>

 

 

 여기까지는 별 어려움 없으실 겁니다. 자 이제 기능을 추가하도록 하겠습니다.

 

 

 MainActivity.java

package hello.world.study;

import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;

import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.preference.Preference;
import android.preference.PreferenceManager;
import android.view.View;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;

import org.w3c.dom.Text;

import static android.provider.AlarmClock.EXTRA_MESSAGE;

public class MainActivity extends AppCompatActivity {
    
    public static final int REQUEST_CODE = 1000;
    private ImageView mShortcut;
    private SharedPreferences sharedPreferences;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mShortcut = (ImageView) findViewById(R.id.image_view);
        sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
        //저장된 shortcut 값을 얻음. 만약 저장된 것이 없다면 기본값으로 null 반환
        String pacakageName = sharedPreferences.getString("shortcut", null);
        if(pacakageName != null) {
            try {
                Drawable icon = getPackageManager().getApplicationIcon(pacakageName);
                mShortcut.setImageDrawable(icon);
            } catch (PackageManager.NameNotFoundException e) {
                e.printStackTrace();
            }

        }
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if(requestCode == REQUEST_CODE && resultCode == RESULT_OK && data != null) {
            //pacelable 객체를 받기 위해 getParcelableExtra()사용
            ApplicationInfo info = data.getParcelableExtra("info");
            //loadIcon에 pakageManager()넘겨주면 아이콘 Drawable 형태로 얻음
            Drawable icon = info.loadIcon(getPackageManager());
            //기본 SharedPreferences 환경을 얻음
            SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
            //SharedPreferences를 수정하기 위해 editor 객체 생성
            SharedPreferences.Editor editor = preferences.edit();
            //info 객체로 pakage이름을 얻고, shortcut키와 함께 preferences에 저장
            editor.putString("shortcut", info.packageName);
            editor.apply();
            mShortcut.setImageDrawable(icon);
        }
    }

    public void onImageView(View view) {
        //클릭된 이미지 뷰에서 Drawable 객체 얻음
        ImageView imageView = (ImageView) view;
        Drawable drawable = imageView.getDrawable();
        if(drawable != null) {
            //preferences에 shortcut 키로 저장된 packageName를 가져옴
            SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
            String PackageName = preferences.getString("shortcut", null);
            if(PackageName != null) {
                //이 package를 실행할 수 있는 intent를 얻어서 액티비티 시작
                Intent intent = getPackageManager().getLaunchIntentForPackage(PackageName);
                startActivity(intent);
            }
        }
    }

    public void onButtonClick(View view) {
        Intent intent = new Intent(this, ActivityListItem.class);
        startActivityForResult(intent, REQUEST_CODE);
    }
}

 

 onCreate() : 앱을 재시작 시 데이터 정보가 유지되도록 SharedPreferences에 저장된 shortcut값을 넣어줍니다. 만약 저장할 것이 없다면 기본값으로 null을 저장합니다.

 

onActivityResult() : 이것은 ActivityListItem.java에 있는 리스트 클릭 시 객체를 얻어옵니다. ApplicationInfo로 객체를 얻은 다음, 아이콘 이미지를 설정을 수행하는 메소드입니다. 

 

OnImageView() : 이미지 뷰에 있는 아이콘을 터치하면(이미지 뷰를 터치하면) 그 앱이 실행되는 메소드입니다. PackageManager를 통해 패키지 이름을 얻어오고, 패키지 이름으로 앱을 실행합니다.

 

OnButtonClick() : ActivityListItem.java로 이동하는 메소드입니다. startActivityForResult()를 통해 값을 넘겨주고, 객체를 얻어오게끔 합니다.

 

 

AppAdapter.java

package hello.world.study;

import android.content.pm.ApplicationInfo;
import android.graphics.drawable.Drawable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;

import java.util.List;

public class AppAdapter extends BaseAdapter {

    private List<ApplicationInfo> minfo;

    public AppAdapter(List<ApplicationInfo> data) {
        minfo = data;
    }
    @Override
    public int getCount() {
        return minfo.size();
    }

    @Override
    public Object getItem(int position) {
        return minfo.get(position);
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @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.layout_item, parent, false);
            holder.imageView = (ImageView) convertView.findViewById(R.id.icon_view);
            holder.textView = (TextView) convertView.findViewById(R.id.item_name);
            convertView.setTag(holder);
        }
        else {
            holder = (ViewHolder) convertView.getTag();
        }
        //앱 정보
        ApplicationInfo info = minfo.get(position);
        //앱 아이콘
        Drawable icon = info.loadIcon(parent.getContext().getPackageManager());
        holder.imageView.setImageDrawable(icon);
        //앱 이름
        String name = String.valueOf(info.loadLabel(parent.getContext().getPackageManager()));
        holder.textView.setText(name);

        return convertView;
    }
}

class ViewHolder {
    ImageView imageView;
    TextView textView;
}

 

 Adapter클래스입니다. 이것도 지금까지 다뤘던 Adapter내용이랑 별 다른 것은 없습니다. 다만 PackageManager를 통해 선택한 앱의 패키지 이름을 얻어와서 앱의 이미지와 이름을 추출하는 것 빼곤 어려운 것은 없습니다.

 

 

ActivityListItem.java

package hello.world.study;

import androidx.appcompat.app.AppCompatActivity;

import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ListView;

import java.util.List;

public class ActivityListItem extends AppCompatActivity {

    private ListView listview;
    //설치된 앱의 모든 정보를 얻을 수 있는 객체
    private PackageManager pm;
    private AppAdapter adapter;

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

        listview = (ListView) findViewById(R.id.list_view);
        //패키지 얻어옴
        pm = getPackageManager();
        //List<ApplicationInfo>형태로 앱 정보(ApplicationInfo) 저장
        List<ApplicationInfo> infos = pm.getInstalledApplications(PackageManager.GET_META_DATA);

        adapter = new AppAdapter(infos);
        listview.setAdapter(adapter);
        listview.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                //안드로이드 객체를 Intent를 통해 다른 컴포넌트에 전달하려면 Serializable 또는 Parcelable 사용
                //ApplicationInfo는 Parcelable 인터페이스를 구현하고 있어 Intent를 통해 다른 액티비티로 전달가능
                ApplicationInfo info = (ApplicationInfo) (parent.getAdapter()).getItem(position);
                Intent intent = new Intent();
                intent.putExtra("info", info);
                setResult(RESULT_OK, intent);
                finish();
            }
        });

    }
}

 

 현재 설치된 앱들의 리스트를 보여주는 액티비티입니다. 이것도 마찬가지로 PackageManager로 해당 앱의 정보를 얻어온 다음, ApplicationInfo객체를 MainActivity에 넘겨주는 간단한 액티비티입니다. 근데 객체를 전달하려면 일반적인 putExtra()로는 불가능하고, Parcelable 또는 Serializable을 사용해야 가능합니다. 그러나 여기서 일반적인 방법(intent.getExtra())로 사용이 가능한 이유는 ApplicationInfo객체가 Parcelable의 내용을 이미 담고 있어 사용이 가능합니다. Parcelable과 Serializable에 대해서는 다음에 다시 한번 다루도록 하겠습니다.

 

 

 여기까지 문제없이 넘어오셨다면 다음과 같은 결과물이 나옵니다.

 

앱 실행 화면

설치된 앱 선택 화면

설치된 앱 선택된 화면

아이콘 터치 후 실행된 화면

 

 이 앱은 SharedPreferences에 저장돼있으므로 껐다 켜도 설정한 앱이 사라지지 않도록 구현해보았습니다. 다양한 객체들과 구현이 조금 복잡해진 정도 빼곤 다 배운 내용이고, 이해하기 어렵지 않은 프로그램이었습니다. 한 번 손으로 짜 보는 것도 나쁘지 않다고 생각합니다.(이해하기가 더욱 쉬어집니다.) 감사합니다.

반응형