코로나 API 이용하여 어플 만들기 * 2/24일 수정
1. 개요
-
만들게 된 이유: 코로나 현황을 홈페이지나 어플로 들어가 확인하기 귀찮아 API정보를 받아와 위젯으로 바탕화면에서 바로바로 볼 수 있게 하기 위해 제작
-
공부 해야할 내용
- 공공 api 이용 방법
- 위젯 클래스 이용 방법
2-1 ROOM(DB) 이용하기
- UI 설계하기
- 스마트폰 해상도별로 대응하기
1. 공공 API 이용하기
- 원하는 공공 API 찾기
https://www.data.go.kr/index.do 에서
코로나 감영현황 조회 서비스를 신청하여 키를 받았습ㅂ니다.
https://www.data.go.kr/tcs/dss/selectApiDataDetailView.do?publicDataPk=15043376
서비스 신청 후 1~2시간 후면 인증키가 발급되고 인증키가 발급 된다해도 바로 API를 이용할 수
있는 것은 아니였었습니다.(이것도 모르고 3시간 동안 API 확인 단계에서 헤맸습니다...)
인증키를 받은 후 5~24시간 이후에 미리보기를 눌러 화면 같이 API 자료가 잘 나오는지 확인 후에 API를 받아 사용 할 수 있습니다.
그 후 참고 문서를 다운 받아 각 API에 있는 변수와 파일 형식 등을 확인 가능합니다
-
앱 기본 UI 틀 잡기
어플의 메인 화면은 간단하게 현 상황을 받아 텍스트뷰에 띄우는 식으로 만들었습니다.
-
앱 위젯 화면
앱 위젯 화면은 네이버에 나오는 기본 형식과 비슷하게 하려 했습니다.
- API이용 하기
API는 처음 활용해봐서 많은 시행 착오를 겪었습니다. 내가 받은 API는 XML 파일이였기에 XML 파싱을 하여
list에 저장을 해야했다. 이 부분 또한 몰라 구글링을 통해 여러 가지 코드를 써가며 나에게 맞는 코드를 찾아서 개발하였습니다.
제일 먼저 api를 접속하여 보면
만들게 된 이유: 코로나 현황을 홈페이지나 어플로 들어가 확인하기 귀찮아 API정보를 받아와 위젯으로 바탕화면에서 바로바로 볼 수 있게 하기 위해 제작
공부 해야할 내용
2-1 ROOM(DB) 이용하기
https://www.data.go.kr/index.do 에서
코로나 감영현황 조회 서비스를 신청하여 키를 받았습ㅂ니다.
https://www.data.go.kr/tcs/dss/selectApiDataDetailView.do?publicDataPk=15043376
서비스 신청 후 1~2시간 후면 인증키가 발급되고 인증키가 발급 된다해도 바로 API를 이용할 수
있는 것은 아니였었습니다.(이것도 모르고 3시간 동안 API 확인 단계에서 헤맸습니다...)
인증키를 받은 후 5~24시간 이후에 미리보기를 눌러 화면 같이 API 자료가 잘 나오는지 확인 후에 API를 받아 사용 할 수 있습니다.
그 후 참고 문서를 다운 받아 각 API에 있는 변수와 파일 형식 등을 확인 가능합니다
앱 기본 UI 틀 잡기
어플의 메인 화면은 간단하게 현 상황을 받아 텍스트뷰에 띄우는 식으로 만들었습니다.
앱 위젯 화면
앱 위젯 화면은 네이버에 나오는 기본 형식과 비슷하게 하려 했습니다.
API는 처음 활용해봐서 많은 시행 착오를 겪었습니다. 내가 받은 API는 XML 파일이였기에 XML 파싱을 하여
list에 저장을 해야했다. 이 부분 또한 몰라 구글링을 통해 여러 가지 코드를 써가며 나에게 맞는 코드를 찾아서 개발하였습니다.
제일 먼저 api를 접속하여 보면
item 이라는 태그로 시작되어 그 안에 모든 정보가 반복되어 있는 것을 볼 수 있습니다.
이것을 기준으로 안드로이드 스튜디오에서 파싱하여 사용하면 됩니다.
안드로이드 스튜디오에선 xml 파싱을 위해
우선 2가지가 필요하다.
XmlPullParser 과
AsyncTask 이다.
AsynceTask - https://youngest-programming.tistory.com/11 아주 상세하게 나와있습니다.
XmlPullParser-https://developer.android.com/reference/org/xmlpull/v1/XmlPullParser
두 문서를 참고하여 메인 엑티비티에서 xml를 파싱 하여 DB에 저장하였습니다.
MainActivity.java
package com.lg.covid_19;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.room.Room;
import android.content.Context;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import org.w3c.dom.Text;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserFactory;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.Locale;
public class MainActivity extends AppCompatActivity {
//레이아웃에 있는 뷰 들과 API URL 등을 선언해주었다.
final String TAG = "MainActivity";
private String requestUrl;
ArrayList<Item> list = null;
Item bus = null;
TextView date_view;
TextView decide_cnt;
TextView exam_cnt;
TextView death_cnt;
TextView clear_cnt;
TextView today_decide_cnt;
TextView today_exam_cnt;
TextView today_death_cnt;
TextView toady_clear_cnt;
TextView decide;
InformationDatabase db;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//db 초기화
db = Room.databaseBuilder(this, InformationDatabase.class, "information_database").
allowMainThreadQueries().build();
//각 레이아웃들 선언
date_view = (TextView) findViewById(R.id.data_view);
decide_cnt = (TextView) findViewById(R.id.decide_cnt);
exam_cnt = (TextView) findViewById(R.id.exam_cnt);
clear_cnt = (TextView) findViewById(R.id.clear_cnt);
death_cnt = (TextView) findViewById(R.id.death_cnt);
today_decide_cnt = (TextView) findViewById(R.id.today_decide_cnt);
today_exam_cnt = (TextView) findViewById(R.id.today_exam_cnt);
today_death_cnt = (TextView) findViewById(R.id.today_death_cnt);
toady_clear_cnt = (TextView) findViewById(R.id.today_clear_cnt);
decide = (TextView) findViewById(R.id.decide);
AysyncTask 초기화 및 실행
MyAsyncTask myAsyncTask = new MyAsyncTask();
myAsyncTask.execute();
System.out.println("list 불러오기 " + list);
}
public class MyAsyncTask extends AsyncTask<String, Void, String> {
Date nowDate = new Date(); //api에서 현재 날짜 정보를 가져오기 위해 선언하였다.
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMdd"); //api속 날짜 형식과 맞도록 포맷
String now_date = simpleDateFormat.format(nowDate);
GregorianCalendar yd = new GregorianCalendar();
int yester = yd.get(Calendar.DATE - 1);
@Override
protected String doInBackground(String... strings) {
Log.d("파싱이 시작됩니다", "파싱 시작");
System.out.println(yester);
//현재 날짜 기준 2일전까지 데이터를 저장하기 위함이다
이유는 12시에 날짜가 바뀜에 따라 새롭게 저장되는데 api 업데이트 시간이 오전 9~10시 사이로 그 전까지는 당일 날짜의 자료가 null값이 되어 2일 전까지 저장하게하였다.
yd.add(Calendar.DATE, -2);
String yesterday = simpleDateFormat.format(yd.getTime());
System.out.println("오늘 날짜 : " + now_date);
System.out.println("어제 날짜 : " + yesterday);
requestUrl = "http://openapi.data.go.kr/openapi/service/rest/Covid19/getCovid19InfStateJson?serviceKey=받아온 서비스 키 &pageNo=1&numOfRows=10&startCreateDt=" + yesterday + "&endCreateDt=" + now_date;
try {
boolean b_date = false;
boolean b_decideCnt = false;
boolean b_examCnt = false;
boolean b_deathCnt = false;
boolean b_clearCnt = false;
boolean b_accExamCnt = false;
URL url = new URL(requestUrl);
InputStream is = url.openStream();
XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
XmlPullParser parser = factory.newPullParser();
parser.setInput(new InputStreamReader(is, "UTF-8"));
String tag;
int eventType = parser.getEventType();
while (eventType != XmlPullParser.END_DOCUMENT) {
switch (eventType) {
case XmlPullParser.START_DOCUMENT:
list = new ArrayList<Item>();
System.out.println("문서 시작");
break;
case XmlPullParser.END_DOCUMENT:
break;
case XmlPullParser.END_TAG: //마지막 태크가 item이면 bus안의 내용 리스트에 저장
if (parser.getName().equals("item") && bus != null) {
list.add(bus);
System.out.println("중간 리스트 점검" + list);
}
break;
case XmlPullParser.START_TAG:// item 시작 태그시 안에 내용 버스에넣기 위한 작업
if (parser.getName().equals("item")) {
bus = new Item();
}
//각각의 api속 변수명이다.
if (parser.getName().equals("stateDt")) b_date = true;
if (parser.getName().equals("decideCnt")) b_decideCnt = true;
if (parser.getName().equals("examCnt")) b_examCnt = true;
if (parser.getName().equals("deathCnt")) b_deathCnt = true;
if (parser.getName().equals("clearCnt")) b_clearCnt = true;
if (parser.getName().equals("accExamCnt")) b_accExamCnt = true;
break;
case XmlPullParser.TEXT:
if (b_date) {
bus.setDate(parser.getText());
b_date = false;
} else if (b_decideCnt) {
bus.setDecideCnt(parser.getText());
b_decideCnt = false;
} else if (b_examCnt) {
bus.setExamCnt(parser.getText());
b_examCnt = false;
} else if (b_deathCnt) {
bus.setDeathCnt(parser.getText());
b_deathCnt = false;
} else if (b_clearCnt) {
bus.setClearCnt(parser.getText());
b_clearCnt = false;
} else if (b_accExamCnt) {
bus.setAccExamCnt(parser.getText());
b_accExamCnt = false;
}
break;
}
eventType = parser.next();
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
//위 과정이 다 끝나고 메인 스레드에서 UI에 각 항목들을 setText 시켜준다.
protected void onPostExecute(String s) {
super.onPostExecute(s);
date_view.setText(list.get(0).date);
decide_cnt.setText(list.get(0).decideCnt);
exam_cnt.setText(list.get(0).examCnt);
clear_cnt.setText(list.get(0).clearCnt);
death_cnt.setText(list.get(0).deathCnt);
today_decide_cnt.setText(Integer.toString(Integer.parseInt(list.get(0).decideCnt) - Integer.parseInt(list.get(1).decideCnt)));
today_exam_cnt.setText(Integer.toString(Integer.parseInt(list.get(0).examCnt) - Integer.parseInt(list.get(1).examCnt)));
today_death_cnt.setText(Integer.toString(Integer.parseInt(list.get(0).deathCnt) - Integer.parseInt(list.get(1).deathCnt)));
toady_clear_cnt.setText(Integer.toString(Integer.parseInt(list.get(0).clearCnt) - Integer.parseInt(list.get(1).clearCnt)));
decide.setText(today_decide_cnt.getText() + " 명 발생하였습니다");
//마지막으로 db에 list를 넣는다.
db.informationDAO().insertAll(list);
System.out.println(db.informationDAO().getAll());
}
}
}
- Room 사용하여 내부 DB 다루기
메인에서 xml 파싱하여 데이터 값을 저장해 놓은 list를 가져오기위해서 방법을 찾아보았습니다.
DB를 이용한 방법과 sharedpreferences 를 이용한 방법등이 있었는데
어플 개발자 오픈톡방에서 물어본 결과 sharedpreferences은 DB보다 안정성이 떨어지다고 하여 DB 다룰 공부도 해볼겸 Room 을 선택하였습니다.
룸 사용 법 및 공식 문서
https://developer.android.com/jetpack/androidx/releases/room?hl=ko
Item.java -> DB에 저장한 테이블이다.
package com.lg.covid_19;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.room.Entity;
import androidx.room.Ignore;
import androidx.room.PrimaryKey;
@Entity(tableName = "info")
public class Item {
@PrimaryKey
@NonNull
String date; // 현재 날짜 (현재 날짜를 primarykey로 줫다)
String decideCnt; //확진자 수
String examCnt; //검사중 환자수
String deathCnt; //사망한 환자수
String clearCnt; //격리 해제
String accExamCnt; //누적 검사 수
public Item() {
}
public Item(String date, String decideCnt, String accExamCnt, String clearCnt, String deathCnt) {
}
public String getDate() {
return date;
}
public void setDate(String date) {
this.date = date;
}
public String getDecideCnt() {
return decideCnt;
}
public void setDecideCnt(String decideCnt) {
this.decideCnt = decideCnt;
}
public String getExamCnt() {
return examCnt;
}
public void setExamCnt(String examCnt) {
this.examCnt = examCnt;
}
public String getDeathCnt() {
return deathCnt;
}
public void setDeathCnt(String deathCnt) {
this.deathCnt = deathCnt;
}
public String getClearCnt() {
return clearCnt;
}
public void setClearCnt(String clearCnt) {
this.clearCnt = clearCnt;
}
public String getAccExamCnt() {
return accExamCnt;
}
public void setAccExamCnt(String accExamCnt) {
this.accExamCnt = accExamCnt;
}
@Override
public String toString() {
return "Item{" +
"date='" + date + '\'' +
", decideCnt='" + decideCnt + '\'' +
", examCnt='" + examCnt + '\'' +
", deathCnt='" + deathCnt + '\'' +
", clearCnt='" + clearCnt + '\'' +
'}';
}
}
InformationDAO -> Room에서 Item를 다루기 위한 DAO입니다.
package com.lg.covid_19;
import androidx.room.Dao;
import androidx.room.Delete;
import androidx.room.Insert;
import androidx.room.OnConflictStrategy;
import androidx.room.Query;
import androidx.room.Update;
import java.util.ArrayList;
import java.util.List;
@Dao
public interface InformationDAO {
@Query("SELECT * FROM info")
List<Item> getAll();
@Query("DELETE FROM info")
public void droptable();
@Insert(onConflict = OnConflictStrategy.REPLACE) //중복 데이터가 있을 시 덮어 쓰기를 위한 코드
void insertAll(List<Item> list);
@Delete
void delete(Item item);
@Update
void updateInfo(Item item);
}
InformationDatabase.java ->데이터 베이스 클래스이다.
package com.lg.covid_19;
import android.content.Context;
import android.os.strictmode.InstanceCountViolation;
import androidx.room.Database;
import androidx.room.Room;
import androidx.room.RoomDatabase;
@Database(entities = {Item.class}, version = 1, exportSchema = false)
public abstract class InformationDatabase extends RoomDatabase {
public abstract InformationDAO informationDAO();
private static InformationDatabase INSTANCE;
public static InformationDatabase getDatabase(final Context context) {
if (INSTANCE == null) {
synchronized (InformationDatabase.class) {
if (INSTANCE == null) {
INSTANCE = Room.databaseBuilder(context.getApplicationContext(),
InformationDatabase.class, "information_database").build();
}
}
}
return INSTANCE;
}
}
covid_19_widget.java
위젯을 다룰 때 매우 많은 시행착오를 겪었습니다.. 다른 클래스와도 사용법이 다르고 레이아웃 또한
지원이 안되는 뷰가 많았기에 많은 정보를 찾아보았습니다.
https://developer.android.com/guide/topics/appwidgets - 공식 개발 문서
package com.lg.covid_19;
import android.app.PendingIntent;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
import android.widget.Button;
import android.widget.RemoteViews;
import android.widget.TextView;
import android.widget.Toast;
import androidx.room.Room;
import org.w3c.dom.Text;
import java.util.ArrayList;
import java.util.List;
import static android.widget.Toast.LENGTH_LONG;
/**
* Implementation of App Widget functionality.
*/
public class covid_19_widget extends AppWidgetProvider {
static List<Item> list = new ArrayList<Item>();
Context context;
TextView date_view;
Button btn_re;
private static final String ACTION_BTN = "ButtonClick";
//위젯이 처음실행 될 때 db에서 list 정보를 가져와 위젯 뷰에 뿌릴 수 있게 하기위함
static void updateAppWidget(Context context, AppWidgetManager appWidgetManager, int appWidgetId) {
InformationDatabase db = Room.databaseBuilder(context, InformationDatabase.class, "information_database").
allowMainThreadQueries().build();
list = db.informationDAO().getAll();
System.out.println("위젯 클래스에서 : " + list);
// Construct the RemoteViews object
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.covid_19_widget);
Intent intent = new Intent(context, covid_19_widget.class).setAction(ACTION_BTN);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intent, 0);
views.setOnClickPendingIntent(R.id.btn_re, pendingIntent);
views.setTextViewText(R.id.wg_today_decide_cnt, Integer.toString(Integer.parseInt(list.get(0).decideCnt) - Integer.parseInt(list.get(1).decideCnt)));
views.setTextViewText(R.id.wg_today_exam_cnt, Integer.toString(Integer.parseInt(list.get(0).examCnt) - Integer.parseInt(list.get(1).examCnt)));
views.setTextViewText(R.id.wg_today_death_cnt, Integer.toString(Integer.parseInt(list.get(0).deathCnt) - Integer.parseInt(list.get(1).deathCnt)));
views.setTextViewText(R.id.wg_today_clear_cnt, Integer.toString(Integer.parseInt(list.get(0).clearCnt) - Integer.parseInt(list.get(1).clearCnt)));
views.setTextViewText(R.id.wg_data_view, list.get(0).date);
views.setTextViewText(R.id.wg_decide_cnt, list.get(0).decideCnt);
views.setTextViewText(R.id.wg_exam_cnt, list.get(0).examCnt);
views.setTextViewText(R.id.wg_clear_cnt, list.get(0).clearCnt);
views.setTextViewText(R.id.wg_death_cnt, list.get(0).deathCnt);
views.setTextViewText(R.id.wg_decide, Integer.toString(Integer.parseInt(list.get(0).decideCnt) - Integer.parseInt(list.get(1).decideCnt)));
// Instruct the widget manager to update the widget
appWidgetManager.updateAppWidget(appWidgetId, views);
}
@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
// 위젯 갱신 주기에 따라 위젯을 갱신할 떄 호출,
for (int appWidgetId : appWidgetIds) {
updateAppWidget(context, appWidgetManager, appWidgetId);
}
}
@Override
public void onEnabled(Context context) { // 위젯이 처음 생성될 때 호출
}
@Override
public void onDisabled(Context context) { // 위젯의 마지막 인스턴스가 제거될 때
// Enter relevant functionality for when the last widget is disabled
}
//새로고침 버튼을 눌렀을 시 뷰를 다시 그리기
@Override
public void onReceive(Context context, Intent intent) {
super.onReceive(context, intent);
String action = intent.getAction();
if (action.equals(ACTION_BTN)) {
Log.d("이벤트 클릭 테스트 ", "클릭!");
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.covid_19_widget);
ComponentName componentName = new ComponentName(context, covid_19_widget.class);
InformationDatabase db = Room.databaseBuilder(context, InformationDatabase.class, "information_database").
allowMainThreadQueries().build();
list = db.informationDAO().getAll();
views.setTextViewText(R.id.wg_today_decide_cnt, Integer.toString(Integer.parseInt(list.get(0).decideCnt) - Integer.parseInt(list.get(1).decideCnt)));
views.setTextViewText(R.id.wg_today_exam_cnt, Integer.toString(Integer.parseInt(list.get(0).examCnt) - Integer.parseInt(list.get(1).examCnt)));
views.setTextViewText(R.id.wg_today_death_cnt, Integer.toString(Integer.parseInt(list.get(0).deathCnt) - Integer.parseInt(list.get(1).deathCnt)));
views.setTextViewText(R.id.wg_today_clear_cnt, Integer.toString(Integer.parseInt(list.get(0).clearCnt) - Integer.parseInt(list.get(1).clearCnt)));
views.setTextViewText(R.id.wg_data_view, list.get(0).date);
views.setTextViewText(R.id.wg_decide_cnt, list.get(0).decideCnt);
views.setTextViewText(R.id.wg_exam_cnt, list.get(0).examCnt);
views.setTextViewText(R.id.wg_clear_cnt, list.get(0).clearCnt);
views.setTextViewText(R.id.wg_death_cnt, list.get(0).deathCnt);
views.setTextViewText(R.id.wg_decide, Integer.toString(Integer.parseInt(list.get(0).decideCnt) - Integer.parseInt(list.get(1).decideCnt)));
appWidgetManager.updateAppWidget(componentName, views);
Toast.makeText(context,"새로고침 되었습니다",Toast.LENGTH_SHORT).show();
}
}
}
코드를 전부 이해하고 짠 코드가 아니기에 불필요한 코드도 많은거 같네요
혹시라도 글을 읽고 수정해야 하는 부분이 있으면 댓글로 말씀해주세요.
2.12 일 수정
어플을 3일 정도 돌려본 결과 몇 가지 문제점이 발생했습니다.
1.자동 업데이트의 미흡점
2.코드의 중복성과 지저분함
3.매일 00시에 의문의 데이터 하나가 DB에 들어간다는 점
1번은 자동 업데이트의 미흡함을 보완하고자 새로고침 버튼을 만들어 놓고 , api 정보가 업데이트 되는 보편적 시간인 10시에 푸쉬알림을 통해 사용자가 새로고침을 누를 수 있도록 하였습니다. 이는 추후에 더 보완해 번거로움을 없게 할 예정입니다.
이 과정에도 문제점이 있었습니다.
문제점 푸쉬알림 - 맨 처음 코드를 짜서 돌렸을 때 시간이 지난 경우 앱을 실행 시킬 떄마다 알림이 왔었습니다. 이를 인터넷에 검색해보니 시간이 지난 경우 다음날 같은 시간으로 설정해주는 코드가있어 추가하여 해결했습니다.
AlarmRecevier.class
package com.lg.covid_19;
import android.accounts.AbstractAccountAuthenticator;
import android.app.AlarmManager;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import androidx.core.app.NotificationCompat;
public class AlarmRecevier extends BroadcastReceiver {
NotificationManager manager;
NotificationCompat.Builder builder;
//오레오 이상은 반드시 채널을 설정해줘야 Notification이 작동함
private static String CHANNEL_ID = "channel1";
private static String CHANNEL_NAME = "Channel1";
@Override
public void onReceive(Context context, Intent intent) {
AlarmManager am = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
builder = null;
manager = (NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE);
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){
manager.createNotificationChannel(
new NotificationChannel(CHANNEL_ID, CHANNEL_NAME, NotificationManager.IMPORTANCE_DEFAULT)
);
builder = new NotificationCompat.Builder(context, CHANNEL_ID);
} else {
builder = new NotificationCompat.Builder(context);
}
//알림창 클릭 시 activity 화면 부름
Intent intent2 = new Intent(context, MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(context,101,intent2, PendingIntent.FLAG_UPDATE_CURRENT);
//알림창 제목
builder.setContentTitle("새로고침을 눌러주세요!");
//알림창 아이콘
builder.setSmallIcon(R.drawable.ic_launcher_background);
//알림창 터치시 자동 삭제
builder.setAutoCancel(true);
builder.setContentIntent(pendingIntent);
Notification notification = builder.build();
manager.notify(1,notification);
}
}
MainActivity 추가 부분
private AlarmManager alarmManager;
private GregorianCalendar mCalender;
private NotificationManager notificationManager;
NotificationCompat.Builder builder;
public void setAlarm() {
notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
mCalender = new GregorianCalendar();
setContentView(R.layout.activity_main);
Intent receiverIntent = new Intent(MainActivity.this, AlarmRecevier.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(MainActivity.this, 0, receiverIntent, 0);
Date nowDate = new Date();
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
String now_date = simpleDateFormat.format(nowDate);
System.out.println("시간은 " + now_date);
String from = now_date + " 10:00:00"; //임의로 날짜와 시간을 지정
//날짜 포맷을 바꿔주는 소스코드
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date datetime = null;
try {
datetime = dateFormat.parse(from);
} catch (ParseException e) {
e.printStackTrace();
}
Calendar calendar = Calendar.getInstance();
calendar.setTime(datetime);
// 시간 초과시 다음날 같은 시간으로 설정 해주는 코드
if (calendar.before(Calendar.getInstance())) {
calendar.add(Calendar.DATE, 1);
}
System.out.println("설정된 시간 " + calendar.getTime());
alarmManager.set(AlarmManager.RTC, calendar.getTimeInMillis(), pendingIntent);
}
2번은 중복 코드는 최대한 메소드화하여 코드를 줄였습니다.
3번은 매일 12시가 되면 db안에 맨 마지막 내용이 맨 앞으로 이동하는 정체모를 일이 계속 일어났습니다. 처음엔 어떻게 해결 하는지 감이 안잡혀 이것저것 건드려보고 질문해본 결과
가장 기본적인 정렬을 생각을 못했음을 깨달았습니다.
이 후 compareTo 함수를 사용해서 db에 넣기 전 정렬을 해줌으로서 이상현상을 방지 하도록 했습니다. 다음 12시에 다시 확인해봐야겠습니다.
-> 2월 14일 데이터 정렬되서 들어가는거 확인 했습니당 ㅠㅠㅠ 가장 기본적인 정렬을
잊다니.. 기본기가 중요하네요..
2월 24일 수정
지역별 Api를 받아 오기 위해 Main.activity 안에있는 APi 파싱클래스를 분리하는 시도를 했습니다. 그 와중에 많은 오류와.. 어려움을 겪었습니다. 그것은 클래스에선 액티비티에서 사용하는 콘텍트가 따로 없어 db정보를 불러오지 못한다는 것이였습니다 이를 위해선 메인의 커콘텍트를 불러와야 했습니다 이 방법을 수없이 찾고 어려움을 겪던 와중 단톡방 질문을 통해 생성자를 통해 불러오면 된다는 것을 배우게 되었습니다. 간단한 코드였지만 그 간단함 조차 몰랐습니다. 코드는 다음과 같습니다.
Main.java 추가 부분
CoronaAsnk coronaAsnk = new CoronaAsnk(MainActivity.this); <-이렇게 콘텐트를 넘겨 줄 수 있습니다.
CoromnaAsnk 추가 부분
Context context;
public CoronaAsnk(MainActivity mainActivity) {
this.context =mainActivity;
}
이제 지역별만 따로 구현 할 수있을거같습니다 ㅎㅎ
Author And Source
이 문제에 관하여(코로나 API 이용하여 어플 만들기 * 2/24일 수정), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@park517/코로나-API-이용하기저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)