환경 설정 페이지Activity를 하나의 Activity에서 모두 처리하기 위해서 CommonSettingsActivity를 구현한다.
이 Activity가 하는 일은 setContentView의 리소스 아이디를 Intent 파라미터로 전달 받아서 적절히 layout을 초기화 해 주면 끝이다. 설정 항목에 종속적인 구현은 layout에 따라 적절한 CommonSettingsHandler 와 ActivityCycleListener를 구현해 주면 동작은 여기서 다 해결이 된다.
ActivityCycleListener.java : activity의 생명주기의 method를 자동으로 호출해 준다.
package com.mdiwebma.base.helper;
import android.content.Intent;
import android.os.Bundle;
/**
* @author djkim
*/
public abstract class ActivityCycleListener {
public void onPostCreate(Bundle savedInstanceState) {
}
public void onResume() {
}
public void onPause() {
}
public void onDestroy() {
}
public void onActivityResult(int requestCode, int resultCode, Intent data) {
}
// return true : intercept back pressed event
public boolean onBackPressed() {
return false;
}
}
CommonSettingsHandler.java : setting 아이템이 초기화되거나, 클릭할 때 처리를 담당한다.
기본적인 브라우저로 열기, in app 브라우저로 열기, merket app 페이지 열기 등으 구현되어 있고,
클릭시 선택 메뉴를 호출해 주는 getSelectionMenu, onMenuSelected가 제공된다.
package com.mdiwebma.base.view;
import android.app.Activity;
import android.content.DialogInterface;
import android.content.Intent;
import android.net.Uri;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.Pair;
import com.mdiwebma.base.activity.WebViewActivity;
import com.mdiwebma.base.dialog.CheckedListMessageDialog;
import com.mdiwebma.base.settings.Settings;
import com.mdiwebma.base.settings.SettingsDao;
/**
* @author djkim
*/
public class CommonSettingsHandler {
public static interface Provider {
CommonSettingsHandler getCommonSettingsHandler();
}
@NonNull
protected final Activity activity;
protected CommonSettingsHandler(Activity activity) {
this.activity = activity;
}
protected void onSettingsViewInflated(@Nullable final String key, @Nullable final Settings setting, @NonNull final CommonSettingsView settingView) {
if (setting != null) {
if (setting.settingType == Settings.BooleanType) {
settingView.setChecked(SettingsDao.getBoolean(setting));
} else {
settingView.setValueText(SettingsDao.forceString(setting));
}
}
}
protected void onSettingsViewClicked(@Nullable final String key, @Nullable final Settings setting, @NonNull final CommonSettingsView settingView, final String action) {
if (setting != null) {
if (setting.settingType == Settings.BooleanType) {
boolean checked = !settingView.isChecked();
settingView.setChecked(checked);
SettingsDao.putBoolean(setting, checked);
}
}
if (key != null || setting != null) {
final Pair<Integer, Pair<Integer[], String[]>> selectionMenu = getSelectionMenu(key, setting);
if (selectionMenu != null) {
CheckedListMessageDialog.Builder builder = new CheckedListMessageDialog.Builder(activity).setItems(selectionMenu.second.second);
if (selectionMenu.first >= 0) {
builder.setSelectedItemIndex(selectionMenu.first);
}
builder.setItemClickListener(new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
onMenuSelected(key, setting, settingView, selectionMenu, which);
dialog.dismiss();
}
});
builder.show();
}
}
if (action != null) {
onDefaultAction(action, settingView);
}
}
protected void onDefaultAction(@NonNull final String action, @NonNull final CommonSettingsView settingView) {
if ("com.mdiwebma.base.activity.WebViewActivity".equals(action)) {
// innert browser
activity.startActivity(WebViewActivity.createIntent(activity, settingView.getActionParamTitle(), settingView.getActionParamUrl()));
} else {
// call web browser
// call market uri
Uri uri = Uri.parse(action);
String scheme = uri != null ? uri.getScheme() : null;
if ("http".equals(scheme) || "https".equals(scheme) || "market".equals(scheme)) {
// action="http://.."
// action="https://"
// action="market://details?id=packageId"
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
try {
activity.startActivity(intent);
} catch (Exception ignore) {
}
}
}
}
/// <selectedItemIndex , <valueList, menuStringList>>
protected Pair<Integer, Pair<Integer[], String[]>> getSelectionMenu(@Nullable final String key, @Nullable final Settings setting) {
return null;
}
protected void onMenuSelected(@Nullable final String key, @Nullable final Settings setting,
@NonNull final CommonSettingsView settingView, Pair<Integer, Pair<Integer[], String[]>> selectionMenu,
int selectedItemIndex) {
if (setting != null && setting.settingType == Settings.IntegerType) {
SettingsDao.putInteger(setting, selectionMenu.second.first[selectedItemIndex]);
settingView.setValueText(selectionMenu.second.second[selectedItemIndex]);
} else {
settingView.setValueText(selectionMenu.second.second[selectedItemIndex]);
}
}
}
CommonSettingsActivity.java :
base 라이브러리의 가장 기본적인 구현이다. 직접 사용하는 경우는 거의 없다. ActivityCycleListener를 적절히 관리하고, 호출해 주는 기능은 BaseActionBarActivity에서 한다. 간단하 코드라서 생략한다.
package com.mdiwebma.base.activity;
import android.content.Intent;
import android.os.Bundle;
import android.support.annotation.LayoutRes;
import android.support.annotation.Nullable;
import com.mdiwebma.base.BaseActionBarActivity;
import com.mdiwebma.base.helper.ActivityCycleListener;
import com.mdiwebma.base.utils.StringUtils;
import com.mdiwebma.base.view.CommonSettingsHandler;
/**
* @author djkim
*/
public abstract class CommonSettingsActivity extends BaseActionBarActivity implements CommonSettingsHandler.Provider {
public static final String EXTRA_LAYOUT = "layout";
public static final String EXTRA_TITLE = "title";
@LayoutRes
protected int layoutId;
@Override
protected void onCreate(Bundle bundle) {
super.onCreate(bundle);
Intent intent = getIntent();
if (intent != null) {
int layoutId = intent.getIntExtra(EXTRA_LAYOUT, 0);
if (layoutId != 0) {
this.layoutId = layoutId;
}
String title = intent.getStringExtra(EXTRA_TITLE);
if (StringUtils.isNotEmpty(title)) {
getSupportActionBar().setTitle(title);
}
}
setContentView(this.layoutId);
ActivityCycleListener listener = getActivityCycleListener();
if (listener != null) {
addActivityCycleListener(listener);
}
}
@Nullable
protected ActivityCycleListener getActivityCycleListener() {
return null;
}
}
이제 실제로 CommonSettingsActivity를 이용해서 환경 설정 페이지의 구현이다.
HabitSettingsActivity.java
프로젝트 종속적인 action 처리는 여기서 한다. getCommonSettingsHandler()에서 layoutId마다 적절히 처리할 handler를 구현하고, getActivityCycleListener()를 Override하여 적절히 구현하면 별도의 Activity인처럼 페이지 별로 각자 구현이 가능해 진다.
package com.mdiwebma.learninghabit.activity;
import android.content.Context;
import android.content.Intent;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.Pair;
import com.mdiwebma.base.activity.CommonSettingsActivity;
import com.mdiwebma.base.logging.Dlog;
import com.mdiwebma.base.settings.Settings;
import com.mdiwebma.base.settings.SettingsDao;
import com.mdiwebma.base.view.CommonSettingsHandler;
import com.mdiwebma.base.view.CommonSettingsView;
/**
* @author djkim
*/
public class HabitSettingsActivity extends CommonSettingsActivity {
public static Intent createIntent(Context context, int layoutResourceId, String title) {
Intent intent = new Intent(context, HabitSettingsActivity.class);
intent.putExtra(EXTRA_LAYOUT, layoutResourceId);
intent.putExtra(EXTRA_TITLE, title);
return intent;
}
@Override
public CommonSettingsHandler getCommonSettingsHandler() {
//if(layoutId == ...) {
// return ;
// }
return habitSettingsHandler;
}
CommonSettingsHandler habitSettingsHandler = new CommonSettingsHandler(this) {
@Override
public void onSettingsViewInflated(@Nullable String key, @Nullable Settings setting, @NonNull CommonSettingsView settingView) {
if (setting != null) {
switch (setting) {
}
}
// default processing
super.onSettingsViewInflated(key, setting, settingView);
}
@Override
public void onSettingsViewClicked(@Nullable String key, @Nullable Settings setting, @NonNull CommonSettingsView settingView, @Nullable String action) {
if (setting != null) {
switch (setting) {
// case test_int:
// int i = SettingsDao.getInteger(setting);
// i++;
// SettingsDao.putInteger(setting, i);
// settingView.setValueText(String.valueOf(i));
// return;
}
//EventBus.getDefault().post(new SettingChangedEvent(setting));
}
if (action != null) {
// call other Settings activity, R.layout
if ("com.mdiwebma.learninghabit.activity.HabitSettingsActivity".equals(action)) {
Intent intent = HabitSettingsActivity.createIntent(activity, settingView.getActionParamLayout(), settingView.getActionParamTitle());
activity.startActivity(intent);
return;
} else if (action.startsWith("com.mdiwebma.learninghabit.")) {
// call other Activity
try {
Class klass = Class.forName(action);
Intent intent = new Intent(activity, klass);
activity.startActivity(intent);
} catch (Exception ex) {
Dlog.notReached(ex);
}
return;
}
}
// call Web Browser
// call inner WebView url
// call market app
// call selection menu dialog
// togle boolean type setting value
super.onSettingsViewClicked(key, setting, settingView, action);
}
Pair<Integer[], String[]> testMenuInfo;
@Override
public Pair<Integer, Pair<Integer[], String[]>> getSelectionMenu(@Nullable final String key, @Nullable final Settings setting) {
if (setting == Settings.test_int) {
if (testMenuInfo == null) {
testMenuInfo = new Pair<>(new Integer[]{1, 2, 3}, new String[]{"test1", "test2", "test3"});
}
int settingValue = SettingsDao.getInteger(setting);
int selectedIndex = -1;
for (Integer value : testMenuInfo.first) {
selectedIndex++;
if (value == settingValue) {
break;
}
}
return new Pair<>(selectedIndex, testMenuInfo);
}
return null;
}
@Override
protected void onMenuSelected(@Nullable final String key, @Nullable final Settings setting,
@NonNull final CommonSettingsView settingView, Pair<Integer, Pair<Integer[], String[]>> selectionMenu,
int selectedItemIndex) {
if (setting == Settings.test_int) {
if (selectionMenu.first != selectedItemIndex) {
SettingsDao.putInteger(setting, selectionMenu.second.first[selectedItemIndex]);
settingView.setValueText(selectionMenu.second.second[selectedItemIndex]);
}
}
}
};
}
WebViewActivity.java : in app Web Browser의 구현 Android dev site의 구현을 대부분 이용했다.
나중에 새로고침 버튼과, 닫기 버튼이 필요하겠다 구현 예정
package com.mdiwebma.base.activity;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.view.KeyEvent;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import com.mdiwebma.base.BaseActionBarActivity;
import com.mdiwebma.base.Const;
import com.mdiwebma.base.utils.StringUtils;
import com.mdiwebma.learninghabit.R;
/**
* @author djkim
*/
public class WebViewActivity extends BaseActionBarActivity {
WebView webView;
public static Intent createIntent(Context context, String title, String url) {
Intent intent = new Intent(context, WebViewActivity.class);
intent.putExtra(Const.TITLE, title);
intent.putExtra(Const.URL, url);
return intent;
}
@Override
protected void onCreate(Bundle bundle) {
super.onCreate(bundle);
setContentView(R.layout.webview_activity);
webView = (WebView)findViewById(R.id.webview);
webView.setWebViewClient(new WebViewClient() {
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
return false;
// if (Uri.parse(url).getHost().equals("www.example.com")) {
// // This is my web site, so do not override; let my WebView load the page
// return false;
// }
// // Otherwise, the link is not for a page on my site, so launch another Activity that handles URLs
// Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
// startActivity(intent);
// return true;
}
});
webView.getSettings().setJavaScriptEnabled(true);
Intent intent = getIntent();
if (intent != null) {
String title = intent.getStringExtra(Const.TITLE);
if (StringUtils.isNotEmpty(title)) {
getSupportActionBar().setTitle(title);
// TODO refresh button
// TODO close button
}
String url = intent.getStringExtra(Const.URL);
if (StringUtils.isNotEmpty(url)) {
webView.loadUrl(url);
}
}
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
// Check if the key event was the Back button and if there's history
if ((keyCode == KeyEvent.KEYCODE_BACK) && webView.canGoBack()) {
webView.goBack();
return true;
}
// If it wasn't the Back key or there's no web page history, bubble up to the default
// system behavior (probably exit the activity)
return super.onKeyDown(keyCode, event);
}
}