안드로이드 개발 질문/답변
(글 수 45,052)
WebView / Tab 시리즈로 계속 질문을 올리네요...(크.. 계속 막혀여... ㅜ.ㅜ)
화면 맨 상단에 이미지나 텍스트를 디스플레이 하고(로고 같은 것..) 그 바로 밑에 두개의 tab이 있고 각각의 tab은 intent로 WebView class가 구동되도록 구현하고자 합니다.
그런데 문제는 일반 TextView나 ImageView를 tabview의 setContent할 때는 전혀 문제가 없는데 유독 intent를 연결하고자 하면 exception이 뜨면서 프로그램 수행이 중단됩니다. Exception도 uncaught exception이라 어찌 해야할 지 모르겠네요... 다시 한번 고수님의 가르침을 받고자 합니다.
tab을 생성할 때 xml에 layout 지정 하지 않고 바로 자바 코드에서 생성하는 방법도 있는데 이 방식을 쓰게 되면 각 tab에 intent를 set해도 잘 동작합니다. 하지만 이 경우는 tabview가 전체 화면을 차지하기 때문에 tab위에 image난 text를 디스플레이할 수가 없습니다.
지금 문제는 tabhost 관련 layout을 xml에 지정하고 이를 intent로 다른 view와 연결시켰을 때에만 발생을 하고 있습니다.
verson 1.5에서 작업하고 있습니다.
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.mytest.tabviewtest" android:versionCode="1" android:versionName="1.0"> <uses-permission android:name="android.permission.INTERNET" /> <application android:icon="@drawable/icon" android:label="@string/app_name" android:debuggable="true"> <activity android:name=".Main" android:screenOrientation="portrait" android:label="@string/app_name"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:name=".MyTab" android:screenOrientation="portrait"> </activity> <activity android:name=".WebView1"> </activity> <activity android:name=".WebView2"> </activity> </application> <uses-sdk android:minSdkVersion="3" /> </manifest>
MyTab.java
public class MyTab extends TabActivity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); TabHost tabHost = (TabHost) findViewById(android.R.id.tabhost); tabHost.setup(new LocalActivityManager(this, false)); TabSpec ts1 = tabHost.newTabSpec("tab1"); ts1.setIndicator(getResources().getString(R.string.my_account),getResources().getDrawable(R.drawable.tabaccount)); ts1.setContent(new Intent(this, WebView1.class)); //ts1.setContent(R.id.webview1); tabHost.addTab(ts1); TabSpec ts2 = tabHost.newTabSpec("tab2"); ts2.setIndicator(getResources().getString(R.string.internet), getResources().getDrawable(R.drawable.tabinternet)); ts2.setContent(new Intent(this, WebView2.class)); //ts2.setContent(R.id.webview2); tabHost.addTab(ts2); for (int i=0; i<tabHost.getTabWidget().getChildCount(); i++) { RelativeLayout relLayout = (RelativeLayout)tabHost.getTabWidget().getChildAt(i); TextView tv = (TextView)relLayout.getChildAt(1); tv.setTextSize(17.0f); } tabHost.setCurrentTab(0); } }
MyTab.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent"> <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/icon"/> <TabHost android:id="@android:id/tabhost" android:layout_width="fill_parent" android:layout_height="fill_parent"> <LinearLayout android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent"> <TabWidget android:layout_width="fill_parent" android:layout_height="wrap_content" android:id="@android:id/tabs"/> <FrameLayout android:id="@android:id/tabcontent" android:layout_width="fill_parent" android:layout_height="fill_parent"> <RelativeLayout android:layout_width="fill_parent" android:layout_height="fill_parent"> <WebView android:id="@+id/webview1" android:layout_width="fill_parent" android:layout_height="fill_parent"/> <ProgressBar android:id="@+android:id/progress_large" style="?android:attr/progressBarStyleLarge" android:layout_centerHorizontal="true" android:layout_centerVertical="true" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </RelativeLayout> <RelativeLayout android:layout_width="fill_parent" android:layout_height="fill_parent"> <WebView android:id="@+id/webview2" android:layout_width="fill_parent" android:layout_height="fill_parent"/> <ProgressBar android:id="@+android:id/progress_large" style="?android:attr/progressBarStyleLarge" android:layout_centerHorizontal="true" android:layout_centerVertical="true" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </RelativeLayout> </FrameLayout> </LinearLayout> </TabHost> </LinearLayout>
WebView1.java
public class WebView1 extends Activity { @Override public void onCreate(Bundle icicle) { super.onCreate(icicle); setContentView(R.layout.selfservetab); WebView webview; webview = (WebView) findViewById(R.id.webview1); webview.setWebViewClient(new WebView1Client()); webview.getSettings().setJavaScriptEnabled(true); webview.loadUrl(http://m.naver.com); } private class WebView1Client extends WebViewClient { @Override public boolean shouldOverrideUrlLoading(WebView view, String url) { final ProgressBar loadingIcon = (ProgressBar) findViewById(R.id.progress_large); loadingIcon.setVisibility(View.VISIBLE); view.loadUrl(url); return true; } public void onPageFinished(WebView view, String url) { final ProgressBar loadingIcon = (ProgressBar) findViewById(R.id.progress_large); loadingIcon.setVisibility(View.INVISIBLE); } public boolean onKeyDown(int keyCode, KeyEvent event) { WebView webview; webview = (WebView) findViewById(R.id.webview1); if ((keyCode == KeyEvent.KEYCODE_BACK) && webview.canGoBack()) { webview.goBack(); return true; } return super.onKeyDown(keyCode, event); } }
WebView2.java는 위 코드와 거의 동일합니다.
LogCat
======
01-28 12:16:27.748: INFO/ActivityManager(579): Starting activity: Intent { action=android.intent.action.MAIN categories={android.intent.category.LAUNCHER} flags=0x10200000 comp={com.mytest.tabviewtest/com.mytest.tabviewtest.Main} }
01-28 12:16:27.968: DEBUG/dalvikvm(579): GC freed 16269 objects / 863944 bytes in 172ms
01-28 12:16:28.088: INFO/ActivityManager(579): Start proc com.mytest.tabviewtest for activity com.mytest.tabviewtest/.Main: pid=838 uid=10025 gids={3003}
01-28 12:16:28.239: INFO/jdwp(838): received file descriptor 13 from ADB
01-28 12:16:28.329: WARN/System.err(838): Can't dispatch DDM chunk 46454154: no handler defined
01-28 12:16:28.329: WARN/System.err(838): Can't dispatch DDM chunk 4d505251: no handler defined
01-28 12:16:28.830: WARN/IInputConnectionWrapper(626): showStatusIcon on inactive InputConnection
01-28 12:16:28.910: INFO/ActivityManager(579): Displayed activity com.mytest.tabviewtest/.Main: 1148 ms
01-28 12:16:30.769: INFO/ActivityManager(579): Starting activity: Intent { comp={com.mytest.tabviewtest/com.mytest.tabviewtest.MyTab} }
01-28 12:16:30.900: DEBUG/AndroidRuntime(838): Shutting down VM
01-28 12:16:30.910: WARN/dalvikvm(838): threadid=3: thread exiting with uncaught exception (group=0x4000fe70)
01-28 12:16:30.920: ERROR/AndroidRuntime(838): Uncaught handler: thread main exiting due to uncaught exception
01-28 12:16:30.970: ERROR/AndroidRuntime(838): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.mytest.tabviewtest/com.mytest.tabviewtest.MyTab}: java.lang.NullPointerException
01-28 12:16:30.970: ERROR/AndroidRuntime(838): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2268)
01-28 12:16:30.970: ERROR/AndroidRuntime(838): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2284)
01-28 12:16:30.970: ERROR/AndroidRuntime(838): at android.app.ActivityThread.access$1800(ActivityThread.java:112)
01-28 12:16:30.970: ERROR/AndroidRuntime(838): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1692)
01-28 12:16:30.970: ERROR/AndroidRuntime(838): at android.os.Handler.dispatchMessage(Handler.java:99)
01-28 12:16:30.970: ERROR/AndroidRuntime(838): at android.os.Looper.loop(Looper.java:123)
01-28 12:16:30.970: ERROR/AndroidRuntime(838): at android.app.ActivityThread.main(ActivityThread.java:3948)
01-28 12:16:30.970: ERROR/AndroidRuntime(838): at java.lang.reflect.Method.invokeNative(Native Method)
01-28 12:16:30.970: ERROR/AndroidRuntime(838): at java.lang.reflect.Method.invoke(Method.java:521)
01-28 12:16:30.970: ERROR/AndroidRuntime(838): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:782)
01-28 12:16:30.970: ERROR/AndroidRuntime(838): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:540)
01-28 12:16:30.970: ERROR/AndroidRuntime(838): at dalvik.system.NativeStart.main(Native Method)
01-28 12:16:30.970: ERROR/AndroidRuntime(838): Caused by: java.lang.NullPointerException
01-28 12:16:30.970: ERROR/AndroidRuntime(838): at com.mytest.tabviewtest.MyTab.onCreate(MyTab.java:36)
01-28 12:16:30.970: ERROR/AndroidRuntime(838): at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1123)
01-28 12:16:30.970: ERROR/AndroidRuntime(838): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2231)
01-28 12:16:30.970: ERROR/AndroidRuntime(838): ... 11 more
01-28 12:16:31.009: INFO/Process(579): Sending signal. PID: 838 SIG: 3
01-28 12:16:31.009: INFO/dalvikvm(838): threadid=7: reacting to signal 3
01-28 12:16:31.049: INFO/dalvikvm(838): Wrote stack trace to '/data/anr/traces.txt'
01-28 12:16:35.269: INFO/Process(838): Sending signal. PID: 838 SIG: 9
01-28 12:16:35.349: INFO/ActivityManager(579): Process com.mytest.tabviewtest (pid 838) has died.
01-28 12:16:35.381: INFO/WindowManager(579): WIN DEATH: Window{436cf810 com.mytest.tabviewtest/com.mytest.tabviewtest.Main paused=false}
01-28 12:16:35.579: WARN/InputManagerService(579): Got RemoteException sending setActive(false) notification to pid 838 uid 10025
2010.01.29 09:57:19
저도 tab으로 구성된 화면으로 앱을 만들고 있습니다.
위와 같은 오류인지는 모르겠으나,,
저는 (총 탭3개) 첫번째 탭의 이미지는 화면에 보이는데,, 2번째, 3번째 탭의 이미지가 나타나지 않더라구요
그래서 getResources().getString(R.string.my_account) -> this.getString(R.string.my_account)로 변경 했습니다. 이걸 변경하니까 탭 이미지가 잘 나타나더라구요.
참고로 avd 2.0.1입니다.
위와 같은 오류인지는 모르겠으나,,
저는 (총 탭3개) 첫번째 탭의 이미지는 화면에 보이는데,, 2번째, 3번째 탭의 이미지가 나타나지 않더라구요
그래서 getResources().getString(R.string.my_account) -> this.getString(R.string.my_account)로 변경 했습니다. 이걸 변경하니까 탭 이미지가 잘 나타나더라구요.
참고로 avd 2.0.1입니다.
2010.01.29 23:21:42
아.. 제가 드린 질문은 tab안의 이미지를 디스플레이하는 것이 아니고.. tab view를 벗어나서 아예 위쪽에 이미지나 text를 디스플레이하는 방법에 관련된겁니다.. 일반적으로 tabview는 화면 전체를 차지하고 tab들은 화면의 위쪽에 디스플레이가 되는데 저는 그 tab들을 화면 중간에 그리고 tab의 위에 다른 이미지를 넣고 싶은 겁니다. MyTab.xml을 보시면 아시겠지만 <TabHost> element위로 imageview가 있습니다.(임시로 app icon을 넣어놨습니다.)
2010.01.29 23:27:30
제가 지금까지 알아본 바로는 tab을 구현하는 방법은 두가지가 있는데요. xml파일에 TabHost, Tabwidget, Framelayout을 정의하고 java code 상에서 fineViewById로 해당 tab을 찾아서 구현하는 방법과, SmarkPark님처럼 xml 파일 정의 없이 getTabHost를 이용해서 tab을 add하는 방법이 있습니다만, 두번째 방법은 tab이 default로 화면 상단을 차지하기 때문에 저처럼 tab위쪽에 다른 view을 집어넣고자 할 때는 적절한 방법이 아닌듯 합니다. 지금 문제가 되는 첫번째 xml파일을 이용하는 방법은 setContent에 intent를 인자로 주어서 다른 class를 연결할 때만 문제가 발생합니다. 그냥 일반 imageview나 textview를 연결하면 정상동작하구요...
2010.01.30 01:04:24
Android Developer site에 있는 Tab View 예제 페이지가 오늘 날짜로 업데이트가 되었네요.. 예전에는 TabView라고 나왔는데 TabLayout으로 바뀌고 요런 문구가 추가되었군요... ㅜ.ㅜ 예전에는 없었던 것 같았었는데....
"The
아무래도 TabView쪽에 문제가 있긴 했나봅니다. 계속 document를 정비하는 것을 보니...
"The
TabHost
must be the root node for the layout, which contains both the TabWidget
for displaying the tabs and a FrameLayout
for displaying the tab content."아무래도 TabView쪽에 문제가 있긴 했나봅니다. 계속 document를 정비하는 것을 보니...
로그로 봐선
01-28 12:16:30.970: ERROR/AndroidRuntime(838): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.mytest.tabviewtest/com.mytest.tabviewtest.MyTab}: java.lang.NullPointerException
이 부분이 문제인듯 합니다.
tabhost 사용방법이 제가 해본 것과 약간 다르네요 ^_^
setContentView( R.layout.main );TabHost tabHost = getTabHost();
Resources res = getResources();
tabHost.addTab( tabHost.newTabSpec( "" ).setIndicator( res.getString( R.string.call ),
res.getDrawable( R.drawable.icon ) ).setContent( R.id.tab1 ) );
tabHost.addTab( tabHost.newTabSpec( "" ).setIndicator( res.getString( R.string.sms ),
res.getDrawable( R.drawable.icon ) ).setContent( R.id.tab2 ) );
ㅎㅎ 저도 아직 초보라~ 잘 모르겠네용..
NullPointerException 요걸 잡으셔야 될것 같네요 ㅎㅎ 그럼 수고하세요~!