저장소 파일 불러올 때 읽기 권한 요청 설정

반응형

import android.Manifest;

import android.content.pm.PackageManager;

import android.support.v4.app.ActivityCompat;

import android.support.v4.content.ContextCompat;

 

 

onCreate 내부에 아래 내용 삽입

//읽기 권한 요청

if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE)!= PackageManager.PERMISSION_GRANTED) {

      if (ActivityCompat.shouldShowRequestPermissionRationale(this,Manifest.permission.READ_EXTERNAL_STORAGE)) {

      } else {

            ActivityCompat.requestPermissions(this,

            new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},

            1);

      }

}

 

AndroidManifest.xml 에 아래 내용 추가

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

 

반응형

댓글()

Fragment 에서 상위 Activity 재시작 하기

프로그래밍/Android (Java)|2019. 8. 28. 17:19
반응형

                         Intent intent = getActivity().getIntent();
                    intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK
                            | Intent.FLAG_ACTIVITY_NO_ANIMATION);
                    getActivity().overridePendingTransition(0, 0);
                    getActivity().finish();
                    getActivity().overridePendingTransition(0, 0);
                    startActivity(intent);

 

 

[출처] https://gist.github.com/chrisjenx/3176258

반응형

댓글()

디렉토리내 파일명 가져올때 정렬하기

프로그래밍/Android (Java)|2019. 8. 28. 14:29
반응형

파일명을 가져올 때 따로 정렬하는 API는 없지만 Arrays 클래스의 sort 메소드를 사용하면 된다.

File[] filesList = mDirectory.listFiles();

Arrays.sort(filesList); // 가져온 파일을 파일명으로 정렬  

 

 

[출처] https://seojune.tistory.com/m/105

반응형

댓글()

파일 브라우저 만들기

프로그래밍/Android (Java)|2019. 8. 28. 13:54
반응형

디렉토리 읽기권한 필수

https://sysdocu.tistory.com/1429

 

 

파일 입출력 메소드는 파일 안에 저장된 데이터를 관리하는데 비해 파일 관리 메소드는 파일 그 자체가 관리 대상이다.

 

File 클래스의 다음 메소드는 파일의 목록을 구한다.

 

    String[] list([FilenameFilter filter])

    File[] listFiles([FilenameFilter filter])

 

파일의 경로 목록을 구할 수도 있고 File 객체의 목록을 구할 수도 있다.

 

filter를 지정하면 특정 조건에 맞는 파일의 목록만 조사하며 생략하면 모든 파일이 조사된다. 디렉터리도 같이 조사되지만 현재 디렉터리인 .과 부모 디렉터리인 ..은 제외된다.

만약 파일이 하나도 없으면 null이 리턴된다.

 

다음 메소드는 파일의 이름을 변경하거나 삭제한다.

 

    boolean renameTo(File newPath)

    boolean delete()

    void deleteOnExit()

 

둘 다 패키지 디렉터리 아래의 파일만 관리할 수 있으며 경로는 역시 사용할 수 없다. deleteOnExit는 가상 머신이 종료될 때 삭제하도록 예약하는 것이다.

 

다음 메소드는 파일에 대한 정보를 조사한다.

 

    boolean exists()

    boolean isFile()

    boolean isDirectory()    

    long length()

    boolean isHidden()

    long lastModified()

    boolean canRead()

    boolean canWrite()

 

디렉터리를 생성할 때는 다음 메소드를 사용한다.

    boolean mkdir()

    boolean mkdirs()

 

mkdir은 부모 폴더까지 생성하지 않는데 비해 mkdirs는 부모 폴더까지 한꺼번에 생성한다는 점이 다르다.

 

다음 예제는 SD카드의 파일과 디렉터리 목록을 보여준다.

 

 

SD카드를 사용하기 때문에 반드시 매니페스트 파일에 퍼미션을 추가해야한다.

 

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>

<manifest xmlns:android="http://schemas.android.com/apk/res/android"

package="com.example.ch25_fileexplorer"

android:versionCode="1"

android:versionName="1.0" >

 

<uses-sdk

android:minSdkVersion="19"

android:targetSdkVersion="19" />

 

<application

android:allowBackup="true"

android:icon="@drawable/ic_launcher"

android:label="@string/app_name"

android:theme="@style/AppTheme" >

<activity

android:name=".FileExplorer"

android:label="@string/app_name" >

<intent-filter>

<action android:name="android.intent.action.MAIN" />

 

<category android:name="android.intent.category.LAUNCHER" />

</intent-filter>

</activity>

</application>

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

</manifest>

 

 

fileexplorer.xml 

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

xmlns:tools="http://schemas.android.com/tools"

android:orientation="vertical"

android:layout_width="match_parent"

android:layout_height="match_parent"

>

 

<LinearLayout

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:orientation="vertical"

>

 

<TextView

android:id="@+id/current"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:text="current"

/>

<LinearLayout

android:layout_width="match_parent"

android:layout_height="wrap_content">

<Button

android:id="@+id/btnroot"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:onClick="mOnClick"

android:text="Root"/>

<Button

android:id="@+id/btnup"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:onClick="mOnClick"

android:text="Up"/> 

 

</LinearLayout> 

</LinearLayout>

    <ListView

     android:id="@+id/filelist"

     android:layout_width="match_parent"

     android:layout_height="match_parent"

     />

 

</LinearLayout>

 

 

 

FileExplorer.java

package com.example.ch25_fileexplorer;

 

import java.io.File;

import java.util.ArrayList;

 

import android.app.Activity;

import android.os.Bundle;

import android.os.Environment;

import android.view.View;

import android.widget.AdapterView;

import android.widget.ArrayAdapter;

import android.widget.ListView;

import android.widget.TextView;

import android.widget.Toast;

 

 

public class FileExplorer extends Activity {

    String mCurrent;

    String mRoot;

    TextView mCurrentTxt;

    ListView mFileList;

    ArrayAdapter<String> mAdapter;

    ArrayList<String> arFiles;

      

    

    @Override

    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.fileexplorer);

      

        mCurrentTxt = (TextView)findViewById(R.id.current);

        mFileList = (ListView)findViewById(R.id.filelist);

        

        arFiles = new ArrayList<String>();

        //SD카드 루트 가져옴

        mRoot = Environment.getExternalStorageDirectory().getAbsolutePath();

        mCurrent = mRoot;

        

        //어댑터를 생성하고 연결해줌

        mAdapter = new ArrayAdapter<String>(this,

                android.R.layout.simple_list_item_1, arFiles);

        mFileList.setAdapter(mAdapter);//리스트뷰에 어댑터 연결

        mFileList.setOnItemClickListener(mItemClickListener);//리스너 연결

        

        refreshFiles();

        

    }

    

    //리스트뷰 클릭 리스너

    AdapterView.OnItemClickListener mItemClickListener =

            new AdapterView.OnItemClickListener() {

 

                @Override

                public void onItemClick(AdapterView<?> parent, View view,

                        int position, long id) {

                    // TODO Auto-generated method stub

                    String Name = arFiles.get(position);//클릭된 위치의 값을 가져옴

                    

                    //디렉토리이면 

                    if(Name.startsWith("[") && Name.endsWith("]")){

                        Name = Name.substring(1, Name.length() - 1);//[]부분을 제거해줌

                    }

                    //들어가기 위해 / 터치한 파일 명을 붙여줌

                    String Path = mCurrent + "/" + Name;

                    File f = new File(Path);//File 클래스 생성

                    if(f.isDirectory()){//디렉토리면?

                        mCurrent = Path;//현재를 Path 바꿔줌

                        refreshFiles();//리프레쉬

                    }else{//디렉토리가 아니면 토스트 메세지를 뿌림

                    Toast.makeText(FileExplorer.this, arFiles.get(position), 0).show();

                }

            }

    };

    

    //버튼 2 클릭시

    public void mOnClick(View v){

        switch(v.getId()){

        case R.id.btnroot://루트로 가기

            if(mCurrent.compareTo(mRoot) != 0){//루트가 아니면 루트로 가기

                mCurrent = mRoot;

                refreshFiles();//리프레쉬

            }

            break;

        case R.id.btnup:

            if(mCurrent.compareTo(mRoot) != 0){//루트가 아니면

                int end = mCurrent.lastIndexOf("/");/// 나오는 마지막 인덱스를 찾고

                String uppath = mCurrent.substring(0, end);//그부분을 짤라버림  위로가게됨

                mCurrent = uppath;

                refreshFiles();//리프레쉬

            }

            break;

        }

    }

      

    

    void refreshFiles(){

        mCurrentTxt.setText(mCurrent);//현재 PATH 가져옴

        arFiles.clear();//배열리스트를 지움

        File current = new File(mCurrent);//현재 경로로 File클래스를 만듬

        String[] files = current.list();//현재 경로의 파일과 폴더 이름을 문자열 배열로 리턴

        

        //파일이 있다면?

        if(files != null){

            //여기서 출력을 해줌

            for(int i = 0; i < files.length;i++){

                String Path = mCurrent + "/" + files[i];

                String Name = "";

                

                File f = new File(Path);

                if(f.isDirectory()){

                    Name = "[" + files[i] + "]";//디렉토리면 [] 붙여주고

                }else{

                    Name = files[i];//파일이면 그냥 출력

                }

                

                arFiles.add(Name);//배열리스트에 추가해줌

            }

        }

        //다끝나면 리스트뷰를 갱신시킴

        mAdapter.notifyDataSetChanged();

    }

}

 

 

 

 

출력 화면

 



출처: https://gakari.tistory.com/entry/안드로이드-파일-탐색기-만들기 [가카리의 공부방]

 

 

 

 

 

반응형

댓글()

[탭버튼] 프래그먼트 (Fragment) 를 이용한 탭 버튼 구현 예제 (슬라이딩 아님)

프로그래밍/Android (Java)|2019. 8. 23. 09:45
반응형

안녕하세요. PEACE- 에요.

안드로이드 스터디의 [다섯 번째] 글이네요.

 

 

오늘은 탭 버튼을 구현에 대해 포스팅하겠습니다.

 

# 수정

[2019.05.06] fragment_fragment2.xml -> " 빠진 부분 채움

 

 

1. Tab Button


요즘 Tab을 이용한 앱 구성이 많이 활발해졌습니다. 페이스북이나 인스타그램, 카카오톡만 해도 탭 버튼을 이용한 화면 구성 법을 사용하고 있습니다. 이 앱들의 소스코드에서는 어떤 방식으로 Tab을 구현하였는지는 알지 못하나 저희도 Tab을 쉽게 구현 할 수 있다는 것은 확실합니다!

 

[그림 1] 카카오톡과 인스타그램의 탭 버튼 구성

 

Tab버튼을 구성하는데는 여러가지의 방법이 있습니다. 이 포스팅에서는 아래 그림과 같이 Activity의 버튼(보여줄 화면의 수 만큼)과 나머지 영역에 framLayout이라는 위젯을 배치하여 전체적인 레이아웃을 구성하고, 버튼 선택 시 framLayout에 원하는fragment를 띄우는 방식으로 구현할 것 입니다.

 

 

[그림 2] FrameLayout과 button을 이용한 탭 버튼 구성

 

 

 

 

 

2. 소스코드와 구현화면

 

[그림 3] 구현 화면

 

 

 

 

[그림 4] 소스 리스트

 

핵심**activity_main.xml : 탭 버튼과 프레임레이아웃 구성

핵심**MainActivity.class : 탭 버튼 클릭을 통해 프레임레이아웃에 프래그먼트를 띄움

fragment_fragment1.xml : 프래그먼트1 레이아웃
fragment_fragment2.xml : 프래그먼트2 레이아웃

Fragment1.class : 프래그먼트1
Fragment2.class : 프래그먼트2

 

 

 

#소스코드

 

activity_main.xml 

<?xml version="1.0"
encoding="utf-8"?>
<RelativeLayout 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="peace.tabbutton.MainActivity">


<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="@+id/linearLayout" />

<LinearLayout
android:layout_width="match_parent"
android:layout_height="50dp"
android:orientation="horizontal"
android:layout_alignParentBottom="true"
android:id="@+id/linearLayout">

<Button
android:layout_weight="1"
android:id="@+id/bt_tab1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Tab 1"/>

<Button
android:layout_weight="1"
android:id="@+id/bt_tab2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Tab 2"/>

</LinearLayout>

</RelativeLayout>

 

MainActivity.class

import android.support.v4.app.FragmentTransaction;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;

public class MainActivity extends AppCompatActivity implements View.OnClickListener{

private final int FRAGMENT1 = 1;
private final int FRAGMENT2 = 2;

private Button bt_tab1, bt_tab2;

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

// 위젯에 대한 참조
bt_tab1 = (Button)findViewById(R.id.bt_tab1);
bt_tab2 = (Button)findViewById(R.id.bt_tab2);

// 탭 버튼에 대한 리스너 연결
bt_tab1.setOnClickListener(this);
bt_tab2.setOnClickListener(this);

// 임의로 액티비티 호출 시점에 어느 프레그먼트를 프레임레이아웃에 띄울 것인지를 정함
callFragment(FRAGMENT1);


}

@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.bt_tab1 :
// '버튼1' 클릭 시 '프래그먼트1' 호출
callFragment(FRAGMENT1);
break;

case R.id.bt_tab2 :
// '버튼2' 클릭 시 '프래그먼트2' 호출
callFragment(FRAGMENT2);
break;
}
}

private void callFragment(int frament_no){

// 프래그먼트 사용을 위해
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();

switch (frament_no){
case 1:
// '프래그먼트1' 호출
Fragment1 fragment1 = new Fragment1();
transaction.replace(R.id.fragment_container, fragment1);
transaction.commit();
break;

case 2:
// '프래그먼트2' 호출
Fragment2 fragment2 = new Fragment2();
transaction.replace(R.id.fragment_container, fragment2);
transaction.commit();
break;
}

}


}

 

fragment_fragment1.xml

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="peace.tabbutton.Fragment1">

<!-- TODO: Update blank fragment layout -->
<TextView
android:gravity="center"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="프래그먼트 1" />

</FrameLayout>

 

Fragment1.class

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

/**
* A simple {@link Fragment} subclass.
*/
public class Fragment1 extends Fragment {


public Fragment1() {
// Required empty public constructor
}


@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_fragment1, container, false);
}

}

 

fragment_fragment2.xml

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="peace.tabbutton.Fragment1">

<!-- TODO: Update blank fragment layout -->
<TextView
android:gravity="center"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="프래그먼트 2" />

 

</FrameLayout>

 

Fragment2.class

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;


/**
* A simple {@link Fragment} subclass.
*/
public class Fragment2 extends Fragment {


public Fragment2() {
// Required empty public constructor
}


@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_fragment2, container, false);
}

}

 

 

# 참고 사항

본 포스팅 내용은 '탭 뷰' 구현에 있어서 항상 올바른 방향을 제시하는 것은 아님을 미리 말씀드립니다.

개발 목적에 따라 다르며 오픈소스를 참고하여 '탭 뷰'를 구현하는 것도 시도해 보시길 추천합니다.

수 많은 방법 중 하나의 '예'일 뿐 입니다.

 

 

[출처] https://mailmail.tistory.com/7

반응형

댓글()

안드로이드 기본아이콘 사용하기

프로그래밍/Android (Java)|2019. 8. 22. 15:30
반응형

레이아웃에서 아래와 같이 사용

 

<ImageView
                android:id="@+id/imageView"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginLeft="10dp"
                app:srcCompat="@android:drawable/ic_menu_search" />

 

 

반응형

댓글()

초간단 리스트뷰 (listview - 로컬 이미지, 텍스트)

프로그래밍/Android (Java)|2019. 8. 21. 08:36
반응형

* 설명부분 생략 후 코딩 부분만 스크랩

* 이미지는 4번 항목을 통해서 다운로드 할것

* 터치 이벤트를 사용하고 싶을때는 아래 url 참조 (추가된 포스팅) > 레이아웃 변경했다면 LinearLayout 깊이를 나타내는 부분 주의

http://wptrafficanalyzer.in/blog/android-itemclicklistener-for-a-listview-with-images-and-text/

 

 

4. Download and extract the zip file containing flag’s images to the directory /res/drawable-ldpi

 

 

5. Open and update the file /res/layout/main.xml with the given below code

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

    android:layout_width="fill_parent"

    android:layout_height="fill_parent"

    android:orientation="vertical" >

 

    <TextView

        android:id="@+id/textview"

        android:layout_width="fill_parent"

        android:layout_height="wrap_content"

    />

 

    <ListView

        android:id="@+id/listview"

        android:layout_width="fill_parent"

        android:layout_height="wrap_content"

    />

</LinearLayout>

 

 

6. Create a new file namely /res/layout/listview_layout.xml  and update the content with the given below code

<?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="match_parent"

    android:orientation="horizontal"

>

    <ImageView

        android:id="@+id/flag"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:contentDescription="@string/hello"

        android:paddingTop="10dp"

        android:paddingRight="10dp"

        android:paddingBottom="10dp"

    />

 

    <LinearLayout

        android:layout_width="match_parent"

        android:layout_height="match_parent"

        android:orientation="vertical"

    >

        <TextView

            android:id="@+id/txt"

            android:layout_width="wrap_content"

            android:layout_height="wrap_content"

            android:textSize="15dp"

        />

 

        <TextView

            android:id="@+id/cur"

            android:layout_width="wrap_content"

            android:layout_height="wrap_content"

            android:textSize="10dp"

        />

    </LinearLayout>

</LinearLayout>

 

 

7. Open and update the file /src/in/wptrafficanalyzer/listviewwithimagesandtext/MainActivity.java with the given below code

package in.wptrafficanalyzer.listviewwithimagesandtext;

 

import java.util.ArrayList;

import java.util.HashMap;

import java.util.List;

 

import android.app.Activity;

import android.os.Bundle;

import android.widget.ListView;

import android.widget.SimpleAdapter;

 

public class MainActivity extends Activity {

 

    // Array of strings storing country names

    String[] countries = new String[] {

        "India",

        "Pakistan",

        "Sri Lanka",

        "China",

        "Bangladesh",

        "Nepal",

        "Afghanistan",

        "North Korea",

        "South Korea",

        "Japan"

    };

 

    // Array of integers points to images stored in /res/drawable-ldpi/

    int[] flags = new int[]{

        R.drawable.india,

        R.drawable.pakistan,

        R.drawable.srilanka,

        R.drawable.china,

        R.drawable.bangladesh,

        R.drawable.nepal,

        R.drawable.afghanistan,

        R.drawable.nkorea,

        R.drawable.skorea,

        R.drawable.japan

    };

 

    // Array of strings to store currencies

    String[] currency = new String[]{

        "Indian Rupee",

        "Pakistani Rupee",

        "Sri Lankan Rupee",

        "Renminbi",

        "Bangladeshi Taka",

        "Nepalese Rupee",

        "Afghani",

        "North Korean Won",

        "South Korean Won",

        "Japanese Yen"

    };

 

    /** Called when the activity is first created. */

    @Override

    public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.main);

 

        // Each row in the list stores country name, currency and flag

        List<HashMap<String,String>> aList = new ArrayList<HashMap<String,String>>();

 

        for(int i=0;i<10;i++){

            HashMap<String, String> hm = new HashMap<String,String>();

            hm.put("txt", "Country : " + countries[i]);

            hm.put("cur","Currency : " + currency[i]);

            hm.put("flag", Integer.toString(flags[i]) );

            aList.add(hm);

        }

 

        // Keys used in Hashmap

        String[] from = { "flag","txt","cur" };

 

        // Ids of views in listview_layout

        int[] to = { R.id.flag,R.id.txt,R.id.cur};

 

        // Instantiating an adapter to store each items

        // R.layout.listview_layout defines the layout of each item

        SimpleAdapter adapter = new SimpleAdapter(getBaseContext(), aList, R.layout.listview_layout, from, to);

 

        // Getting a reference to listview of main.xml layout file

        ListView listView = ( ListView ) findViewById(R.id.listview);

 

        // Setting the adapter to the listView

        listView.setAdapter(adapter);

    }

}

 

 

8. Run the application

 

 

9. Download the source code

ListView with Images and Text 187.83 KB

Download Source Code

 

 

[출처] http://wptrafficanalyzer.in/blog/listview-with-images-and-text-using-simple-adapter-in-android/

반응형

댓글()

Custom Dialog 만들기

프로그래밍/Android (Java)|2019. 8. 19. 11:48
반응형

http://android.pcsalt.com/create-alertdialog-with-custom-layout-using-xml-layout/

반응형

댓글()

나침반 만들기

반응형

[출처] https://www.wlsdevelop.com/index.php/en/blog?option=com_content&view=article&id=38

[이미지] https://www.wlsdevelop.com/materiale/android/compass.png

 

* 주의

public class Compass extends AppCompatActivity implements SensorEventListener {

 

위와 같은 부분이 있으므로 SensorEventListener 를 implements 에 추가하도록 하고,

만약 다른 것이 있을 경우 이것 (, SensorEventListener) 과 같이 콤마를 사용해서 추가하면 됩니다.

 

 

반응형

댓글()

어플 모두 로딩시까지 로딩화면 보여주기 (Intro Screen)

반응형

아래 포스팅에서 주의할 점은

 

1. SplashActivity.java 파일에서 레이아웃은 사용하지 않는다는 것.

 

2. 화면에 출력시킬 drawable 파일에서는 이미지를 보통 1개만 사용 (꽉찬 이미지) 하므로

    장치별로 보여줄 이미지를 크기에 맞게 만들어 두어야 합니다.

    사용할때는 @mipmap 를 이용합니다.

    - @drawable/bg_splash (x)

    - @mipmap/bg_splash (o)

 

* 디렉토리별 화면 크기 (pixel) (\app\src\main\res\)

mipmap-hdpi   : 480*800         // 171 px

mipmap-xhdpi  : 720*1280      // 256 px

mipmap-xxhdpi : 1080*1920   // 384 px

mipmap-xxxhdpi : 1440*2560    // 512 px (로고가 512px 의 경우 위 주석값으로 맞추면 됨)

위 기준으로 만든 이미지를 각 디렉토리에 넣어둡니다.

 

=========================

 

예전에 안드로이드 로딩 화면 구현하기에 대해 포스팅한 적이 있다. 같은 내용에 대해 다시 글을 작성하는 이유는 보다 나은 방법을 알게 되었기 때문이다.

기존의 구현

위의 포스팅을 확인해보면 알겠지만, 기존에 사용했던 방법은 핵심은 로딩 화면에서 Handler.postDelayed를 이용하여 일정 시간의 지연을 주는 것이다. 이러한 구현 방법에 대해 사용자의 입장과 개발자의 입장에서 다시 한번 고민할 필요가 있다.

 

1. 일정 시간의 기준?

로딩 화면 지연을 위한 ‘일정 시간’의 기준은 없다. 사용자는 로딩 화면이 띄어질 때 무엇을 하고 있는지 알 수 없으며 알고 싶지 않을 수도 있다. 즉, 앱을 실행할 때마다 ‘일정 시간’을 로딩 화면을 보면서 시간 낭비한다고 생각할 수도 있겠다.

2. 안드로이드 앱의 Cold Start?

Cold start란 기기 부팅 후 앱이 처음 실행되거나 시스템에서 종료한 후에 앱을 시작하는 것을 말한다. 안드로이드는 특히 cold start 시동에 약간의 시간이 걸린다. 만약 기존의 방법으로 구현하는 경우, 아래의 이미지와 같이 빈 화면이 먼저 나타나고 나서야 로딩 화면이 보이게 된다.

개선된 구현

개선된 구현의 핵심은 splash activity(로딩 화면)에 대한 layout 파일을 사용하지 않고 background theme를 이용하는 것이다.

샘플 코드: https://github.com/dudmy/blog-sample

  • splash_background.xml

우선 res/drawable 에 XML drawable 파일을 생성한다. 본 파일이 사용자에게 보이는 화면이다.

<?xml version="1.0" encoding="utf-8"?>

<layer-list xmlns:android="http://schemas.android.com/apk/res/android">

    <item

        android:drawable="@android:color/holo_blue_bright" />

    <item>

    <bitmap

        android:src="@mipmap/ic_launcher_round"

        android:gravity="center" />

    </item>

</layer-list>

 

  • values/styles.xml

다음으로는 splash activity의 background를 위한 theme를 만들어준다.

<!-- Splash theme. --> 

<style name="SplashTheme" parent="Theme.AppCompat.NoActionBar"> 

    <item name="android:windowBackground">@drawable/splash_background</item> 

</style>

 

 

  • SplashActivity.class

더는 기존에 사용되었던 Handler.postDelayed를 이용한 지연이 필요 없다. 그저 로딩 화면에서 해야할 작업들과 끝난 후의 처리만 해주면 된다.

public class SplashActivity extends AppCompatActivity { 

    @Override protected void onCreate(@Nullable Bundle savedInstanceState) { 

        super.onCreate(savedInstanceState); 

        Intent intent = new Intent(this, MainActivity.class); 

        startActivity(intent); 

        finish(); 

    } 

}

 

 

  • AndroidManifest.xml

마지막으로 새로 만든 SplashTheme 스타일을 splash activity의 theme로 등록한다. Splash activity에 대한 layout 파일이 없으므로, 이에 대한 뷰는 theme에서 가져오게 된다.

<activity 

    android:name=".SplashActivity" 

    android:theme="@style/SplashTheme"> 

    <intent-filter> 

        <action android:name="android.intent.action.MAIN" /> 

        <category android:name="android.intent.category.LAUNCHER" /> 

    </intent-filter> 

</activity> 

 

 

 

[출처] http://dudmy.net/android/2017/04/09/improved-loading-screen/

 

반응형

'프로그래밍 > Android (Java)' 카테고리의 다른 글

Custom Dialog 만들기  (0) 2019.08.19
나침반 만들기  (0) 2019.08.07
확장자와 어플 연결하기  (0) 2019.08.05
여러가지 작업 설정 후 호출하기  (0) 2019.07.12
서비스 (service) 가동 여부 확인하기  (0) 2019.07.12

댓글()

확장자와 어플 연결하기

반응형

AndroidManifest.xml 파일에 설정한 어플 구동시 최초로 열리는 파일에 아래와 같이

기존 <intent-filter> 를 두고 아래에 <intent-filter> 를 또 추가해줍니다. (예: gpx 파일 연결)

 

<intent-filter>

<action android:name="android.intent.action.VIEW" />

<category android:name="android.intent.category.DEFAULT" />

<category android:name="android.intent.category.BROWSABLE" />

<data android:scheme="file" android:host="*" android:pathPattern=".*.gpx" android:mimeType="*/*" />

</intent-filter>

 

그리고 메인이 되는 Activity.java 에서 onCreate 함수의 getIntent() 로 Intent 정보를 가져와 이용하면 됩니다.

 

public class SplashActivity extends AppCompatActivity {
    @Override protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // 어플 구동방식 구분하기
        Intent intent = getIntent();
        if (intent.getAction().equals(Intent.ACTION_VIEW)) {
            // gpx 파일이 실행되서 어플이 구동 됐을 경우

 

          } else {
            // 어플이 직접 실행 됐을 경우

 

          }

 

    }
}

 

 

 

반응형

댓글()