1.必须设置setLayoutManager
2.在onCreateViewHolder方法中填充布局的时候,inflate的最后一参数必须为false
1 |
View itemview = mInflater.inflate(R.layout.box_list_item, parent, false); |
3.Adapter类的getItemCount方法返回的数量必须是大于0的数量
1.必须设置setLayoutManager
2.在onCreateViewHolder方法中填充布局的时候,inflate的最后一参数必须为false
1 |
View itemview = mInflater.inflate(R.layout.box_list_item, parent, false); |
3.Adapter类的getItemCount方法返回的数量必须是大于0的数量
使用gson进行数据解析后,必须在混淆脚本中添加如下代码,如果不加的话json解析就会失败。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
##---------------Begin: proguard configuration for Gson ---------- # Gson uses generic type information stored in a class file when working with fields. Proguard # removes such information by default, so configure it to keep all of it. -keepattributes Signature # For using GSON @Expose annotation -keepattributes *Annotation* # Gson specific classes -keep class sun.misc.Unsafe { *; } #-keep class com.google.gson.stream.** { *; } -keepclassmembers class * { public <init> (org.json.JSONObject); } # Application classes that will be serialized/deserialized over Gson -keep class com.bcoder.test.datatypes.** { *; } ##---------------End: proguard configuration for Gson ---------- |
其中-keep class com.bcoder.test.datatypes.** { *; }这一行class和.**之间改成你的Bean类所在的包名
我们知道,当app的屏幕进行旋转或者其他的配置变化的时候,Fragment会执行它的周期变化,重新创建Fragment并加载(除非设置了setRetainInstance(true)),那么在重建的时候Fragment中的变量就会被重新初始化,运行中的状态将无法保留。
setArgument中的Bundle可以用来存放各种需要保持的数据,即使Fragment由于配置改变而重建,这些保存的数据也不会被清除。
下面我们将通过一个实例来测试一下,在实例的Fragment中共有3个TextView和一个Button,为了使测试的内容更清晰,下面把三个TextView对应的字符串列表如下:
textview1->banana, textview2->apple, textview3->pear
对应的三个字符串:
测试程序的布局代码和java代码如下:
Fragment部局文件的代码
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 |
<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.bcoder.myapplication.TestFragment" android:orientation="vertical"> <!-- TODO: Update blank fragment layout --> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="textview1" android:id="@+id/textview1"/> <TextView android:text="TextView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/textview2"/> <TextView android:text="TextView" android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/textview3"/> <Button android:text="Button" android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/button1"/> </LinearLayout> |
Fragment的Java代码
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 |
package com.bcoder.myapplication; import android.content.Context; import android.net.Uri; import android.os.Bundle; import android.support.v4.app.Fragment; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.Button; import android.widget.TextView; public class TestFragment extends Fragment { private static final String ARG_PARAM1 = "param1"; private static final String ARG_PARAM3 = "param3"; private String mParam1; private String mParam2; private String mParam3; TextView mTextView1; TextView mTextView2; TextView mTextView3; Button button1; View fragmentView; public TestFragment() { // Required empty public constructor } public static TestFragment newInstance(String param1, String param3) { TestFragment fragment = new TestFragment(); Bundle args = new Bundle(); args.putString(ARG_PARAM1, param1); args.putString(ARG_PARAM3, param3); fragment.setArguments(args); return fragment; } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (getArguments() != null) { mParam1 = getArguments().getString(ARG_PARAM1); mParam3 = getArguments().getString(ARG_PARAM3); } } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { fragmentView = inflater.inflate(R.layout.fragment_test, container, false); initViews(); mTextView1.setText(mParam1); mTextView2.setText(mParam2); mTextView3.setText(mParam3); return fragmentView; } private void initViews() { mTextView1 = (TextView) fragmentView.findViewById(R.id.textview1); mTextView2 = (TextView) fragmentView.findViewById(R.id.textview2); mTextView3 = (TextView) fragmentView.findViewById(R.id.textview3); button1 = (Button) fragmentView.findViewById(R.id.button1); button1.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { mParam1 = "banana2"; mTextView1.setText(mParam1); mParam2 = "apple"; mTextView2.setText(mParam2); mParam3 = "pear click"; getArguments().putString(ARG_PARAM3, mParam3); mTextView3.setText(mParam3); } }); } @Override public void onAttach(Context context) { super.onAttach(context); } @Override public void onDetach() { super.onDetach(); } } |
主Activity的代码
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 |
package com.bcoder.myapplication; import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentTransaction; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.widget.LinearLayout; public class MainActivity extends AppCompatActivity { LinearLayout layoutContainer; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initViews(); TestFragment fragment = TestFragment.newInstance("banana", "pear"); FragmentManager manager = getSupportFragmentManager(); FragmentTransaction transaction = manager.beginTransaction(); transaction.add(R.id.layoutFragmentContainer, fragment); transaction.commit(); } private void initViews() { layoutContainer = (LinearLayout) findViewById(R.id.layoutFragmentContainer); } } |
主Activity的布局文件代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/activity_main" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context="com.bcoder.myapplication.MainActivity" android:orientation="vertical"> <LinearLayout android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent" android:id="@+id/layoutFragmentContainer"> </LinearLayout> </LinearLayout> |
程序启动时显示默认如下内容:
textview1和textview3的值取自getArgument并显示在了屏幕上,当点击按钮时会重新给三个String变量赋值,并显示到textview中,如下图:
这时三个字符串变量都有了新的值,那么当我们把屏幕进行一下旋转操作后,看结果如何呢?
由图可知,字符串1回到了最初的状态(创建Fragment时传入的值),而字符串2被清除了。
字符串3因为在点击按钮的时候重新被保存在getArgument中,而没有任何的变化的被保留下来了。
因此大家在给Fragment传入参数的时候最好通过setArgument进行保存,而不是简单的通过一个变量进行保存。
注意:
直接上代码
Calendar calendar = Calendar.getInstance();
//显示当前时间
System.out.println(calendar.getTime());
//各种日期格式化
SimpleDateFormat format = new SimpleDateFormat(“yyyy-MM-dd HH:mm:ss.SSS”);
String str = format.format(calendar.getTime());
System.out.println(str);
format = new SimpleDateFormat(“yyyyMMdd”);
str = format.format(calendar.getTime());
System.out.println(str);
format = new SimpleDateFormat(“yyyy/MM/dd”);
str = format.format(calendar.getTime());
System.out.println(str);
format = new SimpleDateFormat(“yyyy/M/d”);
str = format.format(calendar.getTime());
System.out.println(str);
//获取时间戳
str = String.valueOf(calendar.getTimeInMillis());
System.out.println(“时间戳: ” + str);
//减去一天
calendar.add(Calendar.DAY_OF_YEAR, -1);
format = new SimpleDateFormat(“yyyy-MM-dd HH:mm:ss.SSS”);
str = format.format(calendar.getTime());
System.out.println(str);
//减去一个月
calendar = Calendar.getInstance();
calendar.add(Calendar.MONTH, -1);
format = new SimpleDateFormat(“yyyy-MM-dd HH:mm:ss.SSS”);
str = format.format(calendar.getTime());
System.out.println(str);
//减去一年
calendar = Calendar.getInstance();
calendar.add(Calendar.YEAR, -1);
format = new SimpleDateFormat(“yyyy-MM-dd HH:mm:ss.SSS”);
str = format.format(calendar.getTime());
System.out.println(str);
//只获取日期,不包含时间
calendar = Calendar.getInstance();
calendar.set(Calendar.HOUR_OF_DAY, 0);
calendar.set(Calendar.MINUTE, 0);
calendar.set(Calendar.SECOND, 0);
calendar.set(Calendar.MILLISECOND, 0);
format = new SimpleDateFormat(“yyyy-MM-dd HH:mm:ss.SSS”);
str = format.format(calendar.getTime());
System.out.println(str);
//获取本月的第一天
calendar = Calendar.getInstance();
calendar.set(Calendar.DAY_OF_MONTH, 1);
format = new SimpleDateFormat(“yyyy-MM-dd HH:mm:ss.SSS”);
str = format.format(calendar.getTime());
System.out.println(str);
//时间戳字符串转日期时间
calendar = Calendar.getInstance();
str = String.valueOf((calendar.getTimeInMillis() – 60 * 1000) ); //减去一分钟
calendar.setTimeInMillis(Long.parseLong(str));
format = new SimpleDateFormat(“yyyy-MM-dd HH:mm:ss.SSS”);
str = format.format(calendar.getTime());
System.out.println(str);
要给app做一个定时提醒的功能,使用到了AlarmManager,因为涉及到很多天以后的提醒,所以不好测试,但是通过adb是可以查看系统已保存的AlarmManager 的,具体命令如下:
1 |
adb shell dumpsys alarm |
如果我们只想看我们自己的应用的情况,则用linux的过滤器也可以(MAC下使用未在Windows下测试),命令如下:
1 |
adb shell dumpsys alarm|grep ebox |
1、运行时授权
6.0以后用户可以运行时对应用进行授权管理,当你的应用需要使用某个权限时可以用checkSelfPermission()检查是否拥有某个权限,如果没有这个权限的话使用requestPermissions()来申请权限。
2、磕睡模式和应用空闲状态的优化
此特性是为了更好的节省系统用电量。
3、除去Appche Http Client的支持
如果你原来使用了这个Client,并且你的目标系统在Android2.3(Api Level9)以上,那么你现在可以使用HttpURLConnection代码Apache http client,这个api的流压缩和响应缓存可以提高网络访问的效率,并降低电量的耗损。如果你还想继续使用Apache http client,那么你可以在build.gradle中加入以下代码
1 2 3 |
android { useLibrary 'org.apache.http.legacy' } |
4、BoringSSL
使用BoringSSl代替原来的OpenSSL,使用NDK的需要注意,具体查一下官网的介绍。
5、硬件标识访问
为了更好的保护用户的数据,此版本不再支持程序获取设备的本地Wifi和蓝牙的硬件标识,WifiInfo.getMACAddress()和BluetoothAdapter.getAddress()方法将始终返回值为02:00:00:00:00:00
如果要通过蓝牙或者Wifi扫描获取附近的外部设备的硬件标识,你的应用必须定义ACCESS_FINE_LOCATION和ACCESS_COARSE_LOCATION权限。
6、通知Notifications
不在支持方法Notification.setLatestEventInfo(),使用Notification.Builder类代替来创建notifications。如果要多次更新notification,定义一个全局的Notification.Builder实例并在这个对象内更新,最后使用build()方法获取更新后的notification对象。
7、AudioManager的改变
不再支持直接通过AudioManager类设置音量和静音指定的音频流。setStreamSolo()方法不再推荐使用,你可以通过requestAudioFocus()方法代替。setStreamMute()也不再推荐使用,你可以使用adjustStreamVolume()方法和参数ADJUST_MUTE or ADJUST_UNMUTE代替该方法。
8、文本的选择操作
在此版本中,用户选择文本后,你可以顶部的ActionBar中显示对选择文本的复制、粘贴、剪切等按钮,具体的参考官网中提供的步骤。
9、浏览器书签的变化
不在支持全局的书签,应用不再支持获取和保存浏览器中的书签。android.provider.Browser.getAllBookmarks() 和 android.provider.Browser.saveBookmark() 方法被移除,同样地,READ_HISTORY_BOOKMARKS和 WRITE_HISTORY_BOOKMARKS 权限被移除。
10、Android Keystore的变化
Android Keystore Provider不再支持DSA,ECDSA还在支持,没用过此功能,不知道有什么影响。
11、WIFI和网络的变化
1.首先要有一个Long型的主键
2.该主键的初始值要赋值为null
如下:
1 2 3 4 5 6 |
@Entity(nameInDb = "tags") public class TagBean { @Property(nameInDb = "id") @Id(autoincrement = true) private Long id = null; } |
原理是:
当id的初始值设为null时,执行insert into 语句时,id的值也为null,然后数据库系统会自己计算这个,如下这个sql语句
1 |
insert into tags(id, uniqid, tagname, deleted) values(null, '1bb61dad-ef47-45c6-a1a8-905cd7f7f2f1', '汽车2331', 0) |
可以通过以下几种方法实现EditText的只读属性
1. 方法一:使用EditText的android:Editable属性
将EditText的Editable属性设置为false后,EditText就成只读了,缺点是不能在java代码中动态设置,而且这个属性android官方已经不推荐使用了,官方的解释是要想一个view可编辑(Editable=true)可以用EditText,不可编辑用TextView就可以了 8-O
2. 方法二:使用TextView替代
既然TextView和EditText就差一个可编辑,那么用一个TextView去替代EditText好了。只读的时候显示TextView隐藏EditText,编辑的时候显示EditText隐藏TextView,不过TextView必须和EditText用同样的样式,以不让用户查觉到组件变换了。本人没亲测这种方法,大家有兴趣的话可以试试。
3. 方法三:设置EditText的keylistener来实现
代码不多,直接把完整的代码贴出来吧
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 |
package com.bcoder.study.edittextapp; import android.content.Context; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.text.method.KeyListener; import android.view.View; import android.view.inputmethod.InputMethodManager; import android.widget.EditText; import android.widget.TextView; public class MainActivity extends AppCompatActivity { EditText edt1; KeyListener storedKeylistener; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); edt1 = (EditText) findViewById(R.id.editText); // 保存默认的KeyListener以便恢复 storedKeylistener = edt1.getKeyListener(); } public void setReadOnly(View v){ // 设置KeyListener为null, 变为不可输入状态 edt1.setKeyListener(null); // 如果需要,设置文字可选 edt1.setTextIsSelectable(true); } public void setEditable(View v){ // 可编辑时弹出软键盘 final InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); imm.showSoftInput(edt1, 0); // 恢复KeyListener edt1.setKeyListener(storedKeylistener); // 如果需要,设置文字可选 edt1.setTextIsSelectable(true); // 恢复KeyListener后,键盘不会自动弹出,要通过代码弹出 edt1.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { imm.showSoftInput(edt1, 0); } }); // 将光标定位到最后 edt1.setSelection(edt1.getText().length()); } } |
布局文件代码
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 |
<?xml version="1.0" encoding="utf-8"?> <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:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context="com.bcoder.study.edittextapp.MainActivity"> <EditText android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/editText" android:layout_alignParentTop="true" android:layout_alignParentLeft="true" android:layout_alignParentStart="true" android:layout_alignParentRight="true" android:layout_alignParentEnd="true" android:singleLine="false" android:lines="5" android:text="http://svn1.bcoder.com" /> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Readonly" android:id="@+id/button" android:layout_below="@+id/editText" android:layout_centerHorizontal="true" android:layout_marginTop="74dp" android:onClick="setReadOnly" /> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Editable" android:id="@+id/button2" android:layout_below="@+id/button" android:layout_centerHorizontal="true" android:onClick="setEditable" /> </RelativeLayout> |
在Android的sdk/tools/proguard/docs/index.html
比如:
file:///home/liuderu/software/adt-bundle-linux-x86_64-20131030/sdk/tools/proguard/docs/index.html
当continue遇上finally,continue执行后仍会执行finally中的代码,如下代码:
1 2 3 4 5 6 7 8 9 10 11 12 |
public static void main(String[] args){ for(int i = 1; i < 11; i++){ try{ if(i % 5 == 0){ System.out.println("continue: i = " + i); continue; } } finally { System.out.println("finally: i = " + i); } } } |
运行输出结果:
1 2 3 4 5 6 7 8 9 10 11 12 |
finally: i = 1 finally: i = 2 finally: i = 3 finally: i = 4 continue: i = 5 finally: i = 5 finally: i = 6 finally: i = 7 finally: i = 8 finally: i = 9 continue: i = 10 finally: i = 10 |