어플 모두 로딩시까지 로딩화면 보여주기 (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 {
            // 어플이 직접 실행 됐을 경우

 

          }

 

    }
}

 

 

 

반응형

댓글()

여러가지 작업 설정 후 호출하기

프로그래밍/Android (Java)|2019. 7. 12. 14:54
반응형

onCreate 바깥에 아래와 같이 작성 후 delete(); 이렇게 불러 올 수 있다.

 


void delete() {
    db.execSQL("delete from mytable;");
}

 

 

 

반응형

댓글()

서비스 (service) 가동 여부 확인하기

프로그래밍/Android (Java)|2019. 7. 12. 08:48
반응형

 

소스 하단부에서 기능 추가하고 onCreate 안에서 호출한다.

 

 

onCreate 안에서 호출하는 부분

 

boolean serviceRunningStatus = isServiceRunning(MyService.class); // 서비스명 입력
String service_status = String.valueOf(serviceRunningStatus); // boolean 값을 string 값으로 변환

TextView notice_record = (TextView) findViewById(R.id.notice_record);

notice_record.setText(service_status); // 이런식으로 출력

 

 

onCreate 바깥에서 기능 추가

 

private boolean isServiceRunning(Class<?> serviceClass) {
        ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
        for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
            if (serviceClass.getName().equals(service.service.getClassName())) {
                return true;
            }
        }
        return false;
    }

 

 

 

반응형

댓글()

Notification 진동 제거하기

프로그래밍/Android (Java)|2019. 7. 10. 18:00
반응형

오레오 (Android 8) 버전 부터는 NotificationChannel 에 할당해야 합니다.

진동을 가능하게하고 빈 패턴을 설정하면 됩니다.

NotificationChannel channel = new NotificationChannel("id", "name", NotificationManager.IMPORTANCE_LOW);  

channel.setVibrationPattern(new long[]{ 0 });

channel.enableVibration(true);

 

오레오 이전 버전의 경우 Notification 에 설정을 주어야 합니다. (아직 안해봄. 버전 낮은 기기에서 해봐야 함)

notificationBuilder.setDefaults(Notification.DEFAULT_LIGHTS | Notification.DEFAULT_SOUND)
                                       .setVibrate(new long[]{0L}); // 이후에도 다른 속성이 있으면 세미콜론 지울것

 

 

반응형

댓글()

백그라운드 동작 (service + notification)

반응형

MyService.java

import android.app.Notification;

import android.app.NotificationChannel;

import android.app.NotificationManager;

import android.app.PendingIntent;

import android.app.Service;

import android.content.Intent;

import android.os.Build;

import android.os.IBinder;

import android.support.annotation.Nullable;

import android.support.v4.app.NotificationCompat;

 

public class MyService extends Service {

    public static final String CHANNEL_ID = "ForegroundServiceChannel";

 

    @Override

    public void onCreate() {

        super.onCreate();

 

          // 이 부분에 추가하는 내용은 백그라운드에서 실행이 된다.

 

    }

 

    @Override

    public int onStartCommand(Intent intent, int flags, int startId) {

        String input = intent.getStringExtra("inputExtra");

        createNotificationChannel();

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

        PendingIntent pendingIntent = PendingIntent.getActivity(this,

                0, notificationIntent, 0);

 

        Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID)

                .setContentTitle("Foreground Service")

                .setContentText(input)

                .setSmallIcon(R.drawable.ic_launcher)

                .setContentIntent(pendingIntent)

                .build();

 

        startForeground(1, notification);

 

        //do heavy work on a background thread

 

 

        //stopSelf();

 

        return START_NOT_STICKY;

    }

 

    @Override

    public void onDestroy() {

        super.onDestroy();

    }

 

    @Nullable

    @Override

    public IBinder onBind(Intent intent) {

        return null;

    }

 

    private void createNotificationChannel() {

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {

            NotificationChannel serviceChannel = new NotificationChannel(

                    CHANNEL_ID,

                    "Foreground Service Channel",

                    NotificationManager.IMPORTANCE_DEFAULT

            );

 

            NotificationManager manager = getSystemService(NotificationManager.class);

            manager.createNotificationChannel(serviceChannel);

        }

    }

}

 

 

MainActivity.java 에서 버튼 누를때 또는 백버튼으로 종료시에 활용하도록 한다.

startService(new Intent(MainActivity.this, MyService.class)); // 서비스 시작

stopService(new Intent(MainActivity.this, MyService.class)); // 서비스 중지

 

AndroidManifest.xml 의 application 안에 아래 내용 추가

<service

    android:name=".MyService"

    android:enabled="true"

    android:exported="true" />

 

내용 추가 =================

 

1) '안드로이드 위젯으로 앱 들어갈 때 액티비티가 쌓이는 현상' 해결 방법

 

(1) Notification 에서 앱으로 들어올때 아래 코드 사용 (MyService.java)

intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_TASK_ON_HOME);

 

(2) 돌아올 Activity (보통 MainActivity.java) 에 아래 소스 추가

if (!isTaskRoot()) {

    finish();

    return;

}

stopService(new Intent(MainActivity.this, MyService.class)); // 알림바 아이콘 없애기 (필요에 따라 사용)

 

2. setContentText 에 여러줄을 사용하고자 할 경우 아래와 같은 형식으로 대체하면 됩니다.

 

.setStyle(new NotificationCompat.BigTextStyle().bigText("시간 : " + getDate + "\n상태 : " + status))

 

 

[출처] https://myksb1223.github.io/develop_diary/2018/08/12/Activity-is-stacked-when-home-screen-widgets-is-clicked.html

 

반응형

댓글()

SQLite3 사용예제

반응형

안드로이드: SQLite3 사용예제1

ExternalStorage 외부저장장치 파일 생성 / 읽기 예제
InternalStorage 장치내부 파일 생성 / 읽기 예제

 

지난 두 포스팅에서 ExternalStorage 와 InternalStorage 를 사용하여 자료 저장하는 방법에 대한 예제를 나누었습니다. 이번 포스팅에서는 SQLite 를 활용한 자료 저장을 해보도록 하겠습니다.

안드로이드에는 모바일용으로 제작된 경량화된 DB인 SQLite3 가 있습니다.
C 언어로 엔진이 제작되어 가볍,고  안드로이드에선 SQLiteOpenHelper 클래스를 제공하여 이를 쉽게 다룰수 있게 합니다.

본 예제에선 SQLiteOpenHelper 를 상속한 별도의 클래스를 MySQLiteOpenHelper 를 만들고
MainActivity에서 이를 활용하여 테이블을 생성하고 insert / update / delete 를 해보겠습니다.
특별히 화면에는 보여주는건 없고, Log.d 를 사용하여 결과만 확인해보겠습니다.

 

[MySQLiteOpenHelper.java]

import android.content.Context;

import android.database.sqlite.SQLiteDatabase;

import android.database.sqlite.SQLiteDatabase.CursorFactory;

import android.database.sqlite.SQLiteOpenHelper;

public class MySQLiteOpenHelper extends SQLiteOpenHelper {

// 안드로이드에서 SQLite 데이터 베이스를 쉽게 사용할 수 있도록 도와주는 클래스
public MySQLiteOpenHelper(Context context, String name,

CursorFactory factory, int version) {

super(context, name, factory, version);

}

@Override
public void onCreate(SQLiteDatabase db) {

// 최초에 데이터베이스가 없을경우, 데이터베이스 생성을 위해 호출됨
// 테이블 생성하는 코드를 작성한다
String sql = "create table mytable(id integer primary key autoincrement, name text);";

db.execSQL(sql);

}

@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

// 데이터베이스의 버전이 바뀌었을 때 호출되는 콜백 메서드
// 버전 바뀌었을 때 기존데이터베이스를 어떻게 변경할 것인지 작성한다
// 각 버전의 변경 내용들을 버전마다 작성해야함
String sql = "drop table mytable;"; // 테이블 드랍
db.execSQL(sql);

onCreate(db); // 다시 테이블 생성
}

}

 

 

[MainActivity.java]

public class MainActivity extends AppCompatActivity {

private MySQLiteOpenHelper helper;

String dbName = "st_file.db";

int dbVersion = 1; // 데이터베이스 버전
private SQLiteDatabase db;

String tag = "SQLite"; // Log 에 사용할 tag

@Override
protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

// sqLite3 : 모바일 용으로 제작된 경량화 DB
// C언어로 엔진이 제작되어 가볍다
// 안드로이드에서 sqLite3 를 쉽게 사용할 수 있도록 SQLiteOpenHelper클래스제공
helper = new MySQLiteOpenHelper(

this, // 현재 화면의 제어권자
dbName,// db 이름
null, // 커서팩토리-null : 표준커서가 사용됨
dbVersion); // 버전

try {

// // 데이터베이스 객체를 얻어오는 다른 간단한 방법
// db = openOrCreateDatabase(dbName, // 데이터베이스파일 이름
// Context.MODE_PRIVATE, // 파일 모드
// null); // 커서 팩토리
//
// String sql = "create table mytable(id integer primary key autoincrement, name text);";
// db.execSQL(sql);

db = helper.getWritableDatabase(); // 읽고 쓸수 있는 DB
//db = helper.getReadableDatabase(); // 읽기 전용 DB select문
} catch (SQLiteException e) {

e.printStackTrace();

Log.e(tag, "데이터베이스를 얻어올 수 없음");

finish(); // 액티비티 종료
}

insert (); // insert 문 - 삽입추가

select(); // select 문 - 조회

update(); // update 문 - 수정변경

delete(); // delete 문 - 삭제 행제거

select();

} // end of onCreate

void delete() {

db.execSQL("delete from mytable where id=2;");

Log.d(tag, "delete 완료");

}

void update() {

db.execSQL("update mytable set name='Park' where id=5;");

Log.d(tag, "update 완료");

}

void select() {

Cursor c = db.rawQuery("select * from mytable;", null);

while(c.moveToNext()) {

int id = c.getInt(0);

String name = c.getString(1);

Log.d(tag,"id:"+id+",name:"+name);

}

}

void insert () {

db.execSQL("insert into mytable (name) values('Seo');");

db.execSQL("insert into mytable (name) values('Choi');");

db.execSQL("insert into mytable (name) values('Park');");

db.execSQL("insert into mytable (name) values('Heo');");

db.execSQL("insert into mytable (name) values('Kim');");

Log.d(tag, "insert 성공~!");

}

} // end of class

 

[실행화면 Logcat]

테이블을 생성하고 최초에 5개의 레코드를 insert 한뒤 update 와 delete 도 성공하여 다시 4개의 레코드를 Logcat 을 통해 보여줍니다.

 


출처: https://bitsoul.tistory.com/118 [Happy Programmer~]

 

반응형

댓글()

[알림] addPreferencesFromResource 줄 처져 있을 때

반응형

기존이 아래와 같은 방식이라면

public class MyPreferenceActivity extends PreferenceActivity

{

    @Override

    protected void onCreate(final Bundle savedInstanceState)

    {

        super.onCreate(savedInstanceState);

        addPreferencesFromResource(R.xml.my_preference_screen);

    }

}

 

이렇게 바꾸어 사용이 가능하다.

 

public class MyPreferenceActivity extends PreferenceActivity

{

    @Override

    protected void onCreate(final Bundle savedInstanceState)

    {

        super.onCreate(savedInstanceState);

        getFragmentManager().beginTransaction().replace(android.R.id.content, new MyPreferenceFragment()).commit();

    }

    public static class MyPreferenceFragment extends PreferenceFragment

    {

        @Override

        public void onCreate(final Bundle savedInstanceState)

        {

            super.onCreate(savedInstanceState);

            addPreferencesFromResource(R.xml.my_preference_screen);

        }

    }

}

 

* 파란 표시는 바뀌는 부분. 놓치지 않도록 주의

 

 

[출처] https://stackoverflow.com/questions/6822319/what-to-use-instead-of-addpreferencesfromresource-in-a-preferenceactivity/6822461#6822461

반응형

댓글()

TextView 줄간격, 자간, 장평 변경하기

반응형

ㆍ 줄간격 : lineSpacingExtra, lineSpacingMultiplier

 

ㆍ 자간 : letterSpacing(API 21)

 

ㆍ 장평 : textScaleX

 

 

줄 간격

 

android:lineSpacingExtra ="0dp"(기본)

 

android:lineSpacingExtra ="5dp"

 

 

android:lineSpacingMultiplier="1"(기본)

 

android:lineSpacingMultiplier="1.5"

 

 

자간

 

android:letterSpacing="0"(기본)

 

android:letterSpacing="0.2"

 

 

장평

 

android:textScaleX="1"(기본)

 

 

android:textScaleX="1.5"(기본)



출처: https://itpangpang.xyz/325 [ITPangPang]

 

 

 

반응형

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

SQLite3 사용예제  (0) 2019.07.08
[알림] addPreferencesFromResource 줄 처져 있을 때  (0) 2019.07.04
구글맵 줌버튼 위치 조정  (0) 2019.06.27
어플 아이콘 변경  (0) 2019.06.25
구글맵 API document  (0) 2019.06.25

댓글()

구글맵 줌버튼 위치 조정

프로그래밍/Android (Java)|2019. 6. 27. 13:18
반응형

    // 구글맵
    @Override
    public void onMapReady(final GoogleMap map) {

        LatLng SEOUL = new LatLng(37.56, 126.97);

        MarkerOptions markerOptions = new MarkerOptions();
        markerOptions.position(SEOUL);
        markerOptions.title("서울");
        markerOptions.snippet("한국의 수도");
        map.addMarker(markerOptions);
        map.moveCamera(CameraUpdateFactory.newLatLng(SEOUL));
        map.animateCamera(CameraUpdateFactory.zoomTo(17));  // 2 (축소) to 21 (확대)

        UiSettings mapUiSettings = map.getUiSettings();
        mapUiSettings.setZoomControlsEnabled(true);  // 줌버튼

        // 줌버튼 컨트롤러 위치 조정
        MapFragment mapFragment = (MapFragment) getFragmentManager().findFragmentById(R.id.map);
        View zoomControls = mapFragment.getView().findViewById(0x1);
        if (zoomControls != null && zoomControls.getLayoutParams() instanceof RelativeLayout.LayoutParams) {
            // ZoomControl is inside of RelativeLayout
            RelativeLayout.LayoutParams params_zoom = (RelativeLayout.LayoutParams) zoomControls.getLayoutParams();
            // Align it to - parent top|left
            params_zoom.addRule(RelativeLayout.ALIGN_PARENT_TOP);
            params_zoom.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
            // Update margins, set to 10dp
            final int margin = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 10,
                    getResources().getDisplayMetrics());
            params_zoom.setMargins(margin, margin, margin, margin);
        }

    }

 

 

반응형

댓글()

어플 아이콘 변경

프로그래밍/Android (Java)|2019. 6. 25. 10:38
반응형

res\drawable 에 이미지를 넣고 AndroidManifest.xml 파일에서 설정한다.

 

<application

    ....

    android:icon="@drawable/ic_launcher_new"
    ....

 

 

반응형

댓글()