Android Forum 基础实践

Abstract

ISIMA 的Android 实验作业,写一个类似论坛的app,能实现读取信息,上传信息,使得用户能互相通信。

json && activity

实验需求

ISIMA Android实验课程,需要读取Json文件,实现类似图1.1的功能。
关键词: json, Intent, Activity

实验效果图
“图1.1 效果图”

实验步骤

  • 2.1 读取并解析 Json 文件
  • 2.2 按钮响应与添加新的 activity
  • 2.3 Activity间的通信
读取并解析 Json 文件
Json 文件

JSON (JavaScript Object Notation) is a lightweight data-interchange format. It is easy for humans to read and write. It is easy for machines to parse and generate. It is based on a subset of the JavaScript Programming Language, Standard ECMA-262 3rd Edition - December 1999. JSON is a text format that is completely language independent but uses conventions that are familiar to programmers of the C-family of languages, including C, C++, C#, Java, JavaScript, Perl, Python, and many others. These properties make JSON an ideal data-interchange language.

1
2
3
4
5
[
{"title":"Titre 1","author":"Auteur 1","message":"Message 1","id":2,"timestamp":1422400424},
{"title":"Titre 2","author":"Auteur 2","message":"Message 2","id":3,"timestamp":1422400428}
...
]

将json文件,保存到res/raw文件夹中。(需新建raw文件夹)

添加java类: Post.java

添加成员变量title, author, message, timetamp及相应的set && get函数。
注意,为了 “2.3 activity间的通信”使用Serializable方法, Post类的声明需包含Serializable。

1
2
3
4
5
6
7
public class Post implements Serializable{
private String title;
private String author;
private String message;
private String timestamp;
...
}
读取与解析
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
// 调用方法:
// ArrayList<Postposts = readPostsFromJsonFile(R.raw.data);
public ArrayList<PostreadPostsFromJsonFile(int resourceId) {

Log.d(TAG, "Reading posts from JSON file...");
ArrayList<Postposts = new ArrayList();

// read and deserialize the file
BufferedReader br = new BufferedReader(new InputStreamReader(getResources().openRawResource(resourceId)));

//get json array from buffered reader
JsonElement jsonElement = new JsonParser().parse(br);
JsonArray jsonArray = jsonElement.getAsJsonArray();

// create posts from JSON elements and add it to the list
Gson gson = new Gson();

Type listType = new TypeToken<ArrayList<Post>>() {}.getType();
try {
posts = gson.fromJson(jsonArray, listType);
//Log.d(TAG, "parse json, size: " + m_posts.size());
}catch (Exception e)
{
Log.d(TAG, "some errors occur when parse json: " + e.getMessage());

}

Log.d(TAG, "Read JSON file successfully.");

// return a list with the deserialized posts
return posts;
}
按钮响应与添加新的 activity
添加按钮及响应函数

目标: 为主界面添加 Random 按钮

对于任意的activity, 控件的添加都在其对应的 xml 文件中完成。

双击activity_main.xml, 为主界面拉拽一按钮。 为按钮添加响应函数 Search_Random

1
2
3
4
5
6
7
8
9
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Random"
android:id="@+id/button_R"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:onClick="Search_Random" / //为按钮添加响应函数 Search_Random

在 MainActivity.java中添加 Search_Random

1
2
3
4
public void Search_Random(View v)
{
//...
}
添加新的activity

目标: 添加显示 post 具体信息的界面, 即activity。

在Android Studio 左侧的app处右键, new -activity -blank activity。 这里添加DisplayMessageActivity。

添加 DisplayMessageActivity 完成后, res/layout文件夹下会多出activity_display_message.xml。

为按钮显示新的activity.

1
2
3
4
5
6
7
public void action_buttonSearch(View v) {

// create an new intent
Intent i = new Intent(getApplicationContext(), DisplayMessageActivity.class);
// start the new activity
startActivity(i);
}
activity间的通信

目标: 将自定义类Post的实例p作为参数传递给DisplayMessageActivity.

在MainActivity中,将类Post的实例p作为参数传递给DisplayMessageActivity

MainActivity.java:

1
2
3
4
5
6
7
8
9
10
11
public void Search_Random(View v)
{
Random rand = new Random();
int rand_num = rand.nextInt(posts.size() - 1);
Post p = posts.get(rand_num);
Intent intent = new Intent(getApplicationContext(), DisplayMessageActivity.class);
Bundle bundle = new Bundle();
bundle.putSerializable(SHOW_POST_MESSAGE, p);
intent.putExtras(bundle);
startActivity(intent);
}

DisplayMessageActivity.java 的 onCreate 函数里添加:

1
2
3
4
...
Intent intent = getIntent();
Post cur_p = (Post)intent.getSerializableExtra(MainActivity.SHOW_POST_MESSAGE);
...

注意, 两个activity的消息要匹配。如这里 intent.getSerializableExtra 函数的第一个参数要与 bundle.putSerializable函数的第一个参数一致, 都为SHOW_POST_MESSAGE所代表的 “show_post_message” 字符串。

ListView

实验需求:

ISIMA Android实验课程,将Post信息按列排序,并能查阅,添加信息。实现类似图1.1的功能。

实验效果图
“图1.1 效果图”

实验步骤

  • 2.1 Post信息的显示: ListView 与 Adapter的使用
  • 2.2 Post信息的添加与Activity间的数据的同步
Post信息的显示: ListView 与 Adapter的使用

目标: 主界面以列表的形式显示所有信息, 当用户点击ListView中的某一子项时,程序跳转, 显示详细信息。

在控件中拖拽 ListView 至 MainActivity, 并在MainActivity.java中添加成员变量:

1
private ListView list_view;

在MainActivity.java中添加成员函数Set_Posts_To_List_View,负责将Post数组显示到主界面。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public void Set_Posts_To_List_View(ArrayList<Postposts)
{
/*add the authors to each ListView item using Adapter*/
Log.d(TAG, "Set_Posts_To_List_View starts...");
ArrayList<Stringauthors = new ArrayList<String>();
for (int i = 0; i < posts.size(); i++)
{
authors.add(posts.get(i).getAuthor());
}

list_view = (ListView)findViewById(R.id.listView_Main);
list_view.setAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, authors));

/*listen to user's command and respond*/
list_view.setOnItemClickListener(new ItemClickEvent());
Log.d(TAG, "Set_Posts_To_List_View ends...");
}

注意 1: 通过调用ListView的setAdapter方法,可以将Post信息显示到主界面上。

1
2
list_view = (ListView)findViewById(R.id.listView_Main);
list_view.setAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, authors));

注意 2: 通过ListView的setOnItemClickListener方法, 开始监听用户点击列表项的实践。

1
list_view.setOnItemClickListener(new ItemClickEvent());

对于监听的实现函数: ItemClickEvent, 其实现如下,其中arg2参数代表用户点击的位置。
用户点击ListView某一位置时, 使用intent方法(具体参见上篇博文), 将Post的详细信息传递给DisplayMessageActivity.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
private final class ItemClickEvent implements AdapterView.OnItemClickListener
{
/*arg2 is where user clicks*/
public void onItemClick(AdapterView<?arg0, View arg1, int arg2, long arg3)
{
String str = (String)list_view.getItemAtPosition(arg2);
Log.d(TAG, arg2 + " was clicked: " + str);

/*create a DisplayMessageActivity to show the detail message*/
Post p = posts.get(arg2);
Intent intent = new Intent(getApplicationContext(), DisplayMessageActivity.class);
Bundle bundle = new Bundle();
bundle.putSerializable(MainActivity.SHOW_POST_MESSAGE, p);
intent.putExtras(bundle);
startActivity(intent);
}
}
Post信息的添加与Activity间的数据的同步

目标: 用户能自己添加新的Post信息, 并且该信息能被记录。

首先, 为了不同 Activity 都能修改posts的信息, posts可以声明为

1
public static ArrayList<Postposts = null;

当用户点击MainActivity界面的 Add a Message 按钮时。弹出新的界面: AddMessageActivity。 其响应函数如下。

1
2
3
4
5
6
public void Add_Message(View v)
{
Log.d(TAG, "you click Add Message Button");
Intent intent = new Intent(getApplicationContext(), AddMessageActivity.class);
startActivity(intent);
}

用户在AddMessageActivity界面添加新信息以后,新信息被写入到posts里。

1
MainActivity.posts.add(p);

此时, 若退出 AddMessageActivity,返回主界面 MainActivity时, 会发现主界面的post列表里并没有显示新添加的信息。 因此, 这里为 MainActivity 设置了一个定时器及一个 boolean 型变量 Update, 当有信息变更时, Update将被设置为true.

1
public static boolean Update = false;

MainActivity的定时器不断检测Update的值, 若 Update 为 true, 则刷新adapter, 再将 Update 设置位false.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
private Handler handler = new Handler();
private Runnable runnable = new Runnable() {
public void run() {
this.update();
handler.postDelayed(this, 500);// update every 0.5 seconds
}
void update() {
/*when posts are refreshed, Update will be set true*/
if(Update == true) {
Log.d(TAG, "update the data, posts size: " + posts.size());
Set_Posts_To_List_View(posts);
Update = false;
}

}
};

最终程序部分效果图。

最终程序部分效果图

fragment

实验需求

ISIMA Android 实验课程,调整前面的代码,使得程序能同时在手机和平板上正常运行。
效果图

Android introduced fragments in Android 3.0 (API level 11), primarily to support more dynamic and flexible UI designs on large screens, such as tablets. Because a tablet s screen is much larger than that of a handset, there s more room to combine and interchange UI components. Fragments allow such designs without the need for you to manage complex changes to the view hierarchy. By dividing the layout of an activity into fragments, you become able to modify the activity s appearance at runtime and preserve those changes in a back stack that s managed by the activity.

A Fragment represents a behavior or a portion of user interface in an Activity. You can combine multiple fragments in a single activity to build a multi-pane UI and reuse a fragment in multiple activities. You can think of a fragment as a modular section of an activity, which has its own lifecycle, receives its own input events, and which you can add or remove while the activity is running (sort of like a “sub activity” that you can reuse in different activities).
A fragment must always be embedded in an activity and the fragment s lifecycle is directly affected by the host activity s lifecycle.

总结: fragment, 为平板而生。

实验步骤

  • 原程序移植
  • 添加“适应平板”功能
    原程序移植
  • 添加fragment
  • 主界面移植
  • 消息显示界面移植
  • 添加消息界面移植

目标: 将源程序移植成fragment模式,并能正常使用。
关键词: Fragment, getFragmentManager, bundle, container, layout
方法: 添加ListFragment, DetailFragment, AddFragment, 同时为原来的activity_main.xml, activity_display_message.xml, activity_add_message.xml 添加container, 同时将各个控件剪切到对应的fragment,并排列整齐,

添加fragment

右键 -new -Fragment -Fragment(Blank), 依次添加 ListFragment, DetailFragment, AddFragment.

主界面移植

思路:主界面的移植对应 activity_main.xml 与 fragment_list.xml的修改, 此activity_main.xml 对应手机,此activity_main.xml中, listContainer的作用在于存放ListFragment, 这样main_acitivity 只需启动基本的读取json网络数据, 其余具体操作便全部放在ListFragment中。实际上,也可以不要container,直接往activity_xxx.xml里面添加fragment,建议使用前一种方法。

activity_main.xml:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<RelativeLayout 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" android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity"
android:id="@+id/Forum_final">

<LinearLayout
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="fill_parent">

<FrameLayout
android:id="@+id/listContainer"
android:layout_width="0dp"
android:layout_height="fill_parent"
android:layout_weight="4"
android:layout_margin="@dimen/abc_action_bar_default_padding_material">
</FrameLayout>

</LinearLayout>

</RelativeLayout>

fragment_list.xml:
fragment_list

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<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="com.example.lin.lin_homework_v01.ListFragment"
android:id="@+id/Fragment_List">

<!-- TODO: Update blank fragment layout -->


<ListView
android:layout_width="wrap_content"
android:layout_height="462dp"
android:id="@+id/listView_All"
android:background="@drawable/back"
android:layout_alignParentStart="true"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
android:layout_below="@+id/textView"
android:layout_above="@+id/button_Add_Frag" />

<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Add a Message"
android:id="@+id/button_Add_fl"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:layout_gravity="center_horizontal|bottom"/>


</FrameLayout>

在MainActivity.java 中, 由于MainActivity调用了ListFragment, 因此要implement ListFragment的监听函数。其他的fragment也是同理。同时, 加入onFragmentInteraction函数。 代码如下所示。

1
2
3
4
5
6
7
8
9
10
11
public class MainActivity extends ActionBarActivity
implements ListFragment.OnFragmentInteractionListener, //
DetailFragment.OnFragmentInteractionListener,
AddFragment.OnFragmentInteractionListener
{
... //省略很多函数
...
public void onFragmentInteraction(Uri uri) {

}
}

MainActivity与ListFragment之间的通信,MainActivity 通过调用ListFragment的update()函数传递消息给ListFragment。

1
2
3
4
5
ListFragment listFrag = new ListFragment();
FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction();
fragmentTransaction.replace(R.id.listContainer,listFrag);
fragmentTransaction.commit();
listFrag.update(); //update是自己添加的函数,主要负责刷新ListFragment的界面。

MainActivity与ListFragment之间的通信,ListFragment如果想传递消息给MainActivity, 只需在ListFragment中的OnFragmentInteractionListener中声明传递消息函数,在MainActivity实现即可。 这里传递消息的函数是OnItemClick(int pos)。

1
2
3
4
5
6
7
8
9
10
11
public class ListFragment extends Fragment {

....//省略很多函数

public interface OnFragmentInteractionListener {
// TODO: Update argument type and name
public void onFragmentInteraction(Uri uri);
public void OnItemClick(int pos);
}

}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class MainActivity extends ActionBarActivity
implements ListFragment.OnFragmentInteractionListener, //
DetailFragment.OnFragmentInteractionListener,
AddFragment.OnFragmentInteractionListener
{
... //省略很多函数
...

/* receive position from list fragment*/
public void OnItemClick(int pos){
... //省略具体实现
}

}
消息显示界面移植

思路: 此原理类似activity_main.xml, activity_display_message.xml 只负责启动detail_fragment, 因此只存放一个detail_Container, 详细操作放在detail_fragment中。

activity_display_message.xml:

1
2
3
4
5
6
7
8
9
<RelativeLayout 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" android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:paddingBottom="@dimen/activity_vertical_margin"
tools:context="com.example.lin.lin_homework_v01.DisplayMessageActivity"
android:id="@+id/detail_Container">
</RelativeLayout>

fragment_detail.xml:
fragment_detail

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
<LinearLayout 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="com.example.lin.lin_homework_v01.DetailFragment"
android:id="@+id/Fragment_Detail"
android:orientation="vertical"
android:background="@drawable/back"
android:weightSum="1">

<!-- TODO: Update blank fragment layout -->


<TextView
android:layout_width="236dp"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceMedium"
android:text="Title"
android:id="@+id/textView_2"
android:layout_marginTop="29dp"
android:layout_below="@+id/textView_Author_Frag"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true" />

<TextView
android:layout_width="match_parent"
android:layout_height="43dp"
android:textAppearance="?android:attr/textAppearanceMedium"
android:text="here shows the title"
android:background="@drawable/back"
android:id="@+id/textView_Title_Frag"
android:layout_alignParentStart="true"
android:layout_alignParentLeft="true"
android:layout_below="@+id/textView_2"
android:layout_alignRight="@+id/textView_Author_Frag"
android:layout_alignEnd="@+id/textView_Author_Frag"
android:editable="true"
android:enabled="true"
android:focusable="true" />

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceMedium"
android:text="Author"
android:id="@+id/textView_1"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true" />

<TextView
android:layout_width="match_parent"
android:layout_height="43dp"
android:textAppearance="?android:attr/textAppearanceMedium"
android:text="here shows the author"
android:background="@drawable/back"
android:id="@+id/textView_Author_Frag"
android:layout_below="@+id/textView_1"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
android:editable="true"
android:enabled="true"
android:autoText="false" />

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceMedium"
android:text="Date"
android:id="@+id/textView_3"
android:layout_below="@+id/textView_Title_Frag"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_marginTop="29dp" />

<TextView
android:layout_width="match_parent"
android:layout_height="33dp"
android:textAppearance="?android:attr/textAppearanceMedium"
android:text="here shows the date"
android:background="@drawable/back"
android:id="@+id/textView_Date_Frag"
android:layout_alignParentStart="true"
android:layout_alignParentLeft="true"
android:layout_below="@+id/textView_3"
android:layout_alignRight="@+id/textView_Title_Frag"
android:layout_alignEnd="@+id/textView_Title_Frag"
android:editable="true"
android:enabled="true" />

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceMedium"
android:text="Message"
android:id="@+id/textView_4"
android:layout_marginTop="30dp"
android:layout_below="@+id/textView_Date_Frag"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true" />

<TextView
android:layout_width="match_parent"
android:layout_height="175dp"
android:textAppearance="?android:attr/textAppearanceMedium"
android:text="here shows the message"
android:background="@drawable/back"
android:id="@+id/textView_Message_Frag"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_below="@+id/textView_4"
android:layout_alignRight="@+id/textView_Date_Frag"
android:layout_alignEnd="@+id/textView_Date_Frag"
android:layout_above="@+id/button_Add_Frag"
android:editable="true"
android:enabled="true" />


<LinearLayout 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="com.example.lin.lin_homework_v01.DetailFragment"
android:weightSum="1">

<Button
android:layout_width="30dp"
android:layout_height="50dp"
android:text="Prev"
android:id="@+id/button_ShowPrev"
android:onClick="Show_Prev_Message"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_weight="0.33" />

<Button
android:layout_width="30dp"
android:layout_height="50dp"
android:text="Add"
android:id="@+id/button_Add_fd"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:layout_weight="0.35" />

<Button
android:layout_width="30dp"
android:layout_height="50dp"
android:text="Next"
android:id="@+id/button_ShowNext"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
android:layout_weight="0.35" />
</LinearLayout>

</LinearLayout>

注意.xml文件中LinearLayout的使用, 其对布局有重要影响。

同MainActivity, DisplayMessageActivity 也需要implements DetailFragment.OnFragmentInteractionListener

1
2
3
4
5
6
public class DisplayMessageActivity extends ActionBarActivity implements DetailFragment.OnFragmentInteractionListener{
....// 省略很多函数
public void onFragmentInteraction(Uri uri) {

}
}

DisplayMessageActivity 在接收到发自MainActivity的位置信息cur_p以后,启动DetailFragment并传递cur_p。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public class DisplayMessageActivity extends ActionBarActivity implements DetailFragment.OnFragmentInteractionListener{

@Override
protected void onCreate(Bundle savedInstanceState) {

Log.d(TAG, "Display Message Activity starts...");

super.onCreate(savedInstanceState);
setContentView(R.layout.activity_display_message);

/*receive message coming from other activity, main activity or Display Post List Activity*/
Intent intent = getIntent();
cur_p = (int)intent.getSerializableExtra(MainActivity.SHOW_POST_MESSAGE);

/* start detail fragment, replace detail_Container with detailFragment */
DetailFragment detailFrag = new DetailFragment();
FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction();
fragmentTransaction.replace(R.id.detail_Container, detailFrag);

/* transmit the position to detail fragment*/
Bundle bundle = new Bundle();
bundle.putInt("position_communication", cur_p);
detailFrag.setArguments(bundle);

fragmentTransaction.commit();

}
}

在 DetailFragment里, 需要接收位置信息, 并填充到各个控件中。同时, 还需要设置Prev,Add,Next 这三个按钮的监听函数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
public class DetailFragment extends Fragment {
...// 略
private int cur_p;
private View view;
TextView title_TextView;
TextView author_TextView;
TextView time_TextView;
TextView message_TextView;
Button prev_Button;
Button next_Button;
Button add_Button;
...//略

public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment

// Get position from the list activity
Log.d(TAG, "onCreateView starts...");

view = inflater.inflate(R.layout.fragment_detail, container, false);
title_TextView = (TextView)view.findViewById(R.id.textView_Title_Frag);
author_TextView = (TextView)view.findViewById(R.id.textView_Author_Frag);
time_TextView = (TextView)view.findViewById(R.id.textView_Date_Frag);
message_TextView = (TextView)view.findViewById(R.id.textView_Message_Frag);
prev_Button = (Button)view.findViewById(R.id.button_ShowPrev);
next_Button = (Button)view.findViewById(R.id.button_ShowNext);
add_Button = (Button)view.findViewById(R.id.button_Add_fd);
setOnClickListenerForAll();

/* receive position data */
cur_p = (int) getArguments().getInt("position_communication");
Log.d(TAG, "receive: " + cur_p);
if(cur_p < MainActivity.posts.size()) {
update(cur_p);
}else
{
Log.d(TAG, "post array is empty now");
}

return view; //注意, 这里不能return inflater.inflate(R.layout.fragment_detail, container, false); 不然数据无法正常显示! 可能是因为每次inflater.inflate(R.layout.fragment_detail, container, false) 的结果都不一样。 这个bug我找了半天!
}

...//略

public void setOnClickListenerForAll() // 设置三个按钮的监听函数
{
prev_Button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.d(TAG, "show previous message");
Show_Prev_Message();

}
});

next_Button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.d(TAG, "show next message");
Show_Next_Message();
}
});

add_Button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.d(TAG, "add message");
Add_Message();
}
});

}



}
添加消息界面移植

思路: 同上。

activity_add_message.xml

1
2
3
4
5
6
7
8
9
10
<RelativeLayout 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" android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:paddingBottom="@dimen/activity_vertical_margin"
tools:context="com.example.lin.lin_homework_v01.AddMessageActivity"
android:id="@+id/new_post_Container">

</RelativeLayout>

fragment_add.xml:
fragment_add

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
<LinearLayout 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"
android:orientation="vertical"
tools:context="com.example.lin.lin_homework_v01.AddFragment"
android:weightSum="1">

<!-- TODO: Update blank fragment layout -->

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceMedium"
android:text="Author"
android:id="@+id/textView2"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true" />

<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/editText_Author"
android:layout_below="@+id/textView2"/>

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceMedium"
android:text="Title"
android:id="@+id/textView3"
android:layout_below="@+id/editText_Author"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_marginTop="30dp" />

<EditText
android:layout_width="369dp"
android:layout_height="wrap_content"
android:id="@+id/editText_Title"
android:layout_below="@+id/textView3"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_alignRight="@+id/editText_Author"
android:layout_alignEnd="@+id/editText_Author" />

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceMedium"
android:text="Message"
android:id="@+id/textView4"
android:layout_below="@+id/editText_Title"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_marginTop="29dp" />

<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textMultiLine"
android:ems="10"
android:id="@+id/editText_Message"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_below="@+id/textView4"
android:layout_alignRight="@+id/editText_Title"
android:layout_alignEnd="@+id/editText_Title"
android:layout_weight="0.70" />

<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Add"
android:id="@+id/button_AddMessage"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:layout_gravity="center_horizontal" />


</LinearLayout>

适应平板功能

Android 对当前设备是手机还是平板, 有自动检测机制。 只需在res目录下新建名为layout-large的文件夹,并将原来layout里的所有的xml拷贝过去, 再稍微修改activity_main.xml即可。

下面是layout-large里的对应平板的activity_main.xml, 只在原来的基础上添加了detailContainer, 以便放置DetailFragment 和AddFragment。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<RelativeLayout 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" android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity"
android:id="@+id/Forum_final">



<LinearLayout
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="fill_parent">

<FrameLayout
android:id="@+id/listContainer"
android:layout_width="0dp"
android:layout_height="fill_parent"
android:layout_weight="4"
android:layout_margin="@dimen/abc_action_bar_default_padding_material"></FrameLayout>


<FrameLayout
android:id="@+id/detailContainer"
android:layout_width="0dp"
android:layout_height="fill_parent"
android:layout_weight="6"
android:layout_margin="@dimen/abc_action_bar_default_padding_material"></FrameLayout>


</LinearLayout>

</RelativeLayout>

仅仅只是添加detailContainer还不够,还需要修改MainActivity.java的代码。

若Android检测当前设备为平板, 则会自动加载laylout-large里的activity_main.xml的文件。因此,只需要检测是否存在detailContainer即可判定当前的设备是平板还是手机。因此, 添加 IsTablet。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
public class MainActivity extends ActionBarActivity
implements ListFragment.OnFragmentInteractionListener,
DetailFragment.OnFragmentInteractionListener,
AddFragment.OnFragmentInteractionListener{
...// 省略
static boolean isTablet = false;
...//省略

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

FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction();
fragmentTransaction.replace(R.id.listContainer,listFrag);


if(findViewById(R.id.detailContainer) == null)
{
Log.d(TAG, "this is phone");
isTablet = false;

}else
{
Log.d(TAG, "this is tablet");
isTablet = true;
/*start add fragment*/
AddFragment addFragment = new AddFragment();
fragmentTransaction.replace(R.id.detail_Container,addFragment);

}
fragmentTransaction.commit();
Update = true;
handler.postDelayed(runnable, 100);

}


}

对于手机,当用户点击主界面的某一条消息时,程序只需要启动DisplayMessageActivity, 而对于平板, 由于空间剩余甚大,因此启动DetailFragment。使用fragmentTransaction.replace(R.id.detailContainer, detailFragment) 来将detailFragment放置到detailContainer处。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
public class MainActivity extends ActionBarActivity
implements ListFragment.OnFragmentInteractionListener,
DetailFragment.OnFragmentInteractionListener,
AddFragment.OnFragmentInteractionListener{

...// 省略
/* receive position from list fragment*/
public void OnItemClick(int pos)
{

Log.d(TAG, "MainActivity receive: " + pos + " from ListFragment");

if(!isTablet) // phone
{
Intent intent = new Intent(this, DisplayMessageActivity.class);
intent.putExtra(MainActivity.SHOW_POST_MESSAGE, pos);
startActivity(intent);

}else {

Log.d(TAG, "position: " + pos + ", start creating detail fragment...");

DetailFragment detailFragment = new DetailFragment();
FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction();

Bundle bundle = new Bundle();
bundle.putInt("position_communication", pos);
detailFragment.setArguments(bundle);

fragmentTransaction.replace(R.id.detailContainer, detailFragment);
fragmentTransaction.commit();

}

}

...// 省略

}

(注: 不知是因为android studio的bug还是其他原因,以平板作为仿真设备,android还是加载layout里的xml文件。 但同学使用同样的方法,显示正常。除此以外, 尝试修改layout里的activity_main.xml, 以手机作为平板,所有的功能运行正常。此bug以后排除, mark at 2015-03-07 20:56)

本实验代码位于: 我的Github