第一行代码
2021-04-06 15:29:32

Toast

1
Toast.makeText(FirstActivity.this,"您点击了这个按钮",Toast.LENGTH_SHORT).show();

第一个参数:上下文

第二个参数:现实的内容

第三个参数:显示时常

获取layout中的组件

1
Button button = (Button) findViewById(R.id.mybutton);

需要事先在layout中定义id为mybutton的按钮。

fragment

使用方法

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
public class BlankFragment1 extends Fragment {


private View rootView;
private TextView textView;
private View button;

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
if (rootView == null){
rootView = inflater.inflate(R.layout.fragment_blank1,container,false);
}
textView = rootView.findViewById(R.id.tv_f1);
button = rootView.findViewById(R.id.b_f1);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
textView.setText("我一般");
}
});
return rootView;
}
}

fragment的layout

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<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=".fragments.BlankFragment1">

<!-- TODO: Update blank fragment layout -->
<TextView
android:layout_width="match_parent"
android:layout_height="40dp"
android:id="@+id/tv_f1"
android:text="@string/hello_blank_fragment" />
<Button
android:layout_width="match_parent"
android:layout_height="40dp"
android:text="你好吗"
android:id="@+id/b_f1">

</Button>

</LinearLayout>

main的layout

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<LinearLayout android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
xmlns:android="http://schemas.android.com/apk/res/android">

<fragment
android:name="com.hie.androidstudy.fragments.BlankFragment1"
android:id="@+id/fragment1"
android:layout_width="match_parent"
android:layout_height="wrap_content">

</fragment>

</LinearLayout>

fragment必须提供id,否则报错

fragment动态添加

activity的layout

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
<LinearLayout android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
xmlns:android="http://schemas.android.com/apk/res/android">

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/tv_main2"
android:text="第二个页面">

</TextView>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="切换到fragment1"
android:id="@+id/button1">

</Button>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="切换到fragment2"
android:id="@+id/button2">

</Button>

<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/f_layout"
android:background="@color/design_default_color_surface">

</FrameLayout>

</LinearLayout>

FrameLayout用来盛放切换的fragment

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
31
32
33
public class MainActivity2 extends AppCompatActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);

Button button1 = findViewById(R.id.button1);
button1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
replaceFragment(new BlankFragment1());
}
});
Button button2 = findViewById(R.id.button2);
button2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
replaceFragment(new BlankFragment2());
}
});
}


//切换fragment方法
private void replaceFragment(Fragment fragment) {
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.f_layout,fragment);
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
}
}

activity向fragment传参

activity

1
2
3
4
5
6
7
8
9
10
button1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Bundle bundle = new Bundle();
bundle.putString("message","activity传递给的参数");
BlankFragment1 blankFragment1= new BlankFragment1();
blankFragment1.setArguments(bundle);
replaceFragment(blankFragment1);
}
});

fragment

1
2
Bundle bundle = getArguments();
String message = bundle.getString("message");

Intent

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//显示intent跳转secondActivity
Intent intent = new Intent(FirstActivity.this,SecondActivity.class);
startActivity(intent);

//隐式intent
Intent intent = new Intent("com.example.activitytest.ACTION_START");

//一个intent只能指定一个action,但是能指定多个category
intent.addCategory("com.example.activitytest.MY_CATEGORY");
startActivity(intent);

//更多的隐式Intent
//打开系统自带浏览器访问百度
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse("http://www.baidu.com"));
//拨号
Intent intent = new Intent(Intent.ACTION_DIAL);
intent.setData(Uri.parse("tel:10086"));
startActivity(intent);

向下一个活动传递数据

在第一层活动中使用putExtra方法将数据存在Intent中

1
2
3
4
5
//传递数据给下一个活动
String data= "传递的数据";
Intent intent = new Intent(FirstActivity.this,SecondActivity.class);
intent.putExtra("data",data);
startActivity(intent);

在第二层活动中取出

1
2
3
4
//接收上一层活动传过来的数据
Intent intent = getIntent(); //获取用于启动第二层活动的Intent
String data = intent.getStringExtra("data"); //获取第一层传入的数据
Log.d("SecondActivity", data);

返回数据给上一个活动

在上一层活动中使用startActivityForResult()方法来跳转到下一个活动

1
2
3
4
//接受下一层活动传回来的数据
Intent intent = new Intent(FirstActivity.this,SecondActivity.class);
//第二个参数为requescode,用来判断是从哪个活动中传来的数据
startActivityForResult(intent,1);

在下一层活动中传递数据到上一层

1
2
3
4
5
6
7
8
9
10
11
12
//传递数据到上一层
Button button = (Button) findViewById(R.id.mybutton2);
button.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v) {
Intent intent = new Intent();
intent.putExtra("data_return","这是第二层向第一层传递的数据");
//第一个参数为resulcode
setResult(RESULT_OK,intent);
finish();
}
});

因为在上一层活动中使用startActivityForResult()方法来启动到下一个活动,在下一个活动销毁时会自动调用上一个活动的onActivityResult()方法,因此需要在上一层活动中重写这个方法来获取数据。

1
2
3
4
5
6
7
8
9
10
11
12
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
//通过requestCode判断是否为第二层传入的数据
switch (requestCode){
case 1:
if (resultCode == RESULT_OK){
String resultData = data.getStringExtra("data_return");
Log.d(TAG, resultData);
}
break;
}
}

生命周期

活动状态

image-20201202153001306

活动的生存期

image-20210823132015046

活动的启动模式

共有四种启动模式:standard,singleTop,singleTask,

standard:默认的启动模式,当当前活动启动的任然是当前活动时,不管返回栈是否存在这个活动,每次启动都会创建该活动一个新的实例.

singleTop:在启动活动时发现返回栈的栈顶已经是该活动,则认为可以直接使用,而不会再创建新的活动.但如果此时这个活动不在栈顶,则会再创建该活动的一个新的实例.

singleTask:当活动的启动模式指定为singleTask,每次启动该活动时系统首先会在返回栈中检查是否存在该活动的实例,如果发现已经存在则直接使用该实例,并把在这个活动之上的所有活动统统出栈,如果没有发现就会创建一个新的活动实例。

singleInstance:不同于以上3种启动模式,指定为singleInstance模式的活动会启用一个新的返回栈来管理这个活动(其实如果singleTask模式指定了不同的taskAffinity,也会启动一个新的返回栈)。那么这样做有什么意义呢?想象以下场景,假设我们的程序中有一个活动是允许其他程序调用的,如果我们想实现其他程序和我们的程序可以共享这个活动的实例,应该如何实现呢?使用前面3种启动模式肯定是做不到的,因为每个应用程序都会有自己的返回栈,同一个活动在不同的返回栈中入栈时必然是创建了新的实例。而使用singleInstance模式就可以解决这个问题,在这种模式下会有一个单独的返回栈来管理这个活动,不管是哪个应用程序来访问这个活动,都共用的同一个返回栈,也就解决了共享活动实例的问题

ListView

简单用法

首先在activity_main.xml中添加LIstView组件

1
2
3
4
5
6
<ListView
android:id="@+id/list"
android:layout_width="match_parent"
android:layout_height="wrap_content">

</ListView>

然后在activity中添加数据,ListView中的数据不能直接传入,需要使用适配器传入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class MainActivity extends AppCompatActivity {
private String[] data = { "Apple","Banana","Orange","watermelon" ,
"Pear","Grape","Pineapple", "Strawberry", "Cherry","Mango","Apple","Banana", "Orange" ,"watermelon","Pear", "Grape",
"Pineapple", "Strawberry" , "Cherry", "Mango"};

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

ArrayAdapter arrayAdapter = new ArrayAdapter(MainActivity.this,android.R.layout.simple_list_item_1,data);
ListView listView = (ListView) findViewById(R.id.list);
listView.setAdapter(arrayAdapter);

}
}

这里使用ArrayAdapter适配器,有多种构造方法,这里共有三个参数,依次传人当前上下文、ListView子项布局的 id,以及要适配的数据。注意,我们使用了android.R.layout.simple_list_item_1作为ListView子项布局的id,这是一个Android内置的布局文件,里面只有一个TextView,可用于简单地显示一段文本。这样适配器对象就构建好了。然后调用setAdapter方法传入适配器.

广播

广播分类:

标准广播(Normal broadcasts ):是一种完全异步执行的广播,在广播发出之后,所有的广播接收器几乎都会在同一时刻接收到这条广播消息,因此它们之间没有任何先后顺序可言。这种广播的效率会比较高,但同时也意味着它是无法被截断的。

有序广播(Ordered broadcasts ):则是一种同步执行的广播,在广播发出之后,同-时刻只会有一个广播接收器能够收到这条广播消息,当这个广播接收器中的逻辑执行完毕后,广播才会继续传递。所以此时的广播接收器是有先后顺序的,优先级高的广播接收器就可以先收到广播消息,并且前面的广播接收器还可以截断正在传递的广播,这样后面的广播接收器就无法收到广播消息了。

数据持久化

SharedPerferences

image-20201207140333584
1
2
3
4
5
6
7
8
9
10
11
12
Button button = (Button) findViewById(R.id.save);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {

SharedPreferences.Editor editor = getSharedPreferences("data",MODE_PRIVATE).edit();
editor.putString("name","张三");
editor.putInt("age",24);
editor.apply();
Toast.makeText(MainActivity.this,"保存成功",Toast.LENGTH_LONG).show();
}
});
image-20201207140451502
1
2
3
4
5
6
7
8
9
10
Button button1 = (Button) findViewById(R.id.read);
button1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
SharedPreferences sharedPreferences = getSharedPreferences("data",MODE_PRIVATE);
String name = sharedPreferences.getString("name","");
int age = sharedPreferences.getInt("age",0);
Log.d(TAG, "姓名是:"+name+"年龄是:"+age);
}
});

Litepal操纵数据库

创建和升级数据库

1.首先再build.gardle中引用

1
implementation 'org.litepal.android:core:1.5.0'

2.在main中新建一个assets目录,在assets目录下新建一个litepal.xml文件,内容如下

1
2
3
4
5
6
7
8
9
10
<litepal>
<!--数据库名称-->
<dbname value="BookStore" />
<!--数据库版本号-->
<version value="3" />
<!--用于设定所有的映射模型,即你定义数据库表的类名路径-->
<list>
<mapping class="com.fx.sqlitetest.Book"></mapping>
</list>
</litepal>

3.修改AndroidManifest.xml中的代码,让litepal的所有正常工作

image-20201208134121215

即在application中添加android:name=”org.litepal.LitePalApplication

下面就可以使用啦

4.创建新的类

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
package com.fx.sqlitetest;

import org.litepal.crud.DataSupport;

public class Book extends DataSupport {

private int id;
private String name;
private String author;

public int getId() {
return id;
}

public void setId(int id) {
this.id = id;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String getAuthor() {
return author;
}

public void setAuthor(String author) {
this.author = author;
}
}

在第二步的mapping中映射这个类然后进行任意数据库操作就可以自动创建相应的表和属性啦

如在主活动中使用Connector.getDatabase();

如果想要添加一个类就新建然后再mapping中设置映射,再将版本号更改成更高一级就好啦!

添加数据
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
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

Button button = (Button) findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {

Book book1 = new Book();
book1.setName("水浒传");
book1.setAuthor("梁朝伟");
book.save();

//这是更高级一些的更新方法,即对书名字为三国演义,作者为不知道的书进行更新
//book1.updateAll("name = ? and author = ?","三国演义","不知道");

List<Book> bookList = DataSupport.findAll(Book.class);
//使用循环并利用日志打印所有值
for (Book book : bookList) {
Log.d("Data", book.getName());
Log.d("Data", book.getAuthor());
}
}
});
}
删除数据
1
DataSupport.deleteAll(Book.class,"name=?","水浒传");
查询数据
1
2
3
4
5
6
List<Book> bookList = DataSupport.findAll(Book.class);
//使用循环并利用日志打印所有值
for (Book book : bookList) {
Log.d("Data", book.getName());
Log.d("Data", book.getAuthor());
}

其他的高级查询方式

image-20201208135619931

内容提供器

Adroid权限

权限分为普通权限和危险权限,普通权限会进行自动授权,危险权限则需要用户授权,其中危险权限包括如下:

image-20201208140648039
拨打电话

在Mainfest中添加

1
<uses-permission android:name="android.permission.CALL_PHONE"></uses-permission>

修改mainactivity中的代码

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
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

final Button button = (Button)findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {

if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.CALL_PHONE)
!= PackageManager.PERMISSION_GRANTED){
//拨打电话的权限未被授予
ActivityCompat.requestPermissions(
MainActivity.this,new String[] {Manifest.permission.CALL_PHONE},1);
}else {
//拨打电话的权限被授予则进行拨打
call();
}
}
});
}
//拨打电话的方法
private void call(){
try {
Intent intent = new Intent(Intent.ACTION_CALL);
intent.setData(Uri.parse("tel:10086"));
startActivity(intent);
} catch (Exception e) {
e.printStackTrace();
}
}

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
switch (requestCode){
case 1:
if (grantResults.length>0 && grantResults[0]==PackageManager.PERMISSION_GRANTED){
call();
}else {
Toast.makeText(MainActivity.this,"您未授权",Toast.LENGTH_LONG).show();

}
break;
}
}

访问其他程序中的数据

以访问联系人为例,大部分之前都涉及了,直接堆代码了

首先赋予权限

1
<uses-permission android:name="android.permission.READ_CONTACTS"></uses-permission>

主活动中代码

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
public class MainActivity extends AppCompatActivity {

ArrayAdapter<String> arrayAdapter;
List<String> contactList = new ArrayList<>();

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

ListView contactsView = (ListView)findViewById(R.id.myList);
arrayAdapter = new ArrayAdapter<String>(this,android.R.layout.simple_list_item_1,contactList);
contactsView.setAdapter(arrayAdapter);

if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_CONTACTS)
!= PackageManager.PERMISSION_GRANTED){
ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.READ_CONTACTS},1);
}else {
readContacts();
}
}

private void readContacts(){
Cursor c = null;
try {
c = getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,null,null,null,null);
if(c!=null){
while(c.moveToNext()){
String name = c.getString(c.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
String number = c.getString(c.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
contactList.add(name+"\n"+number);

}
arrayAdapter.notifyDataSetChanged();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if(c!=null){
c.close();
}
}
}

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
switch (requestCode){
case 1:
if(grantResults.length>0&&grantResults[0]==PackageManager.PERMISSION_GRANTED){
readContacts();
}else {
Toast.makeText(this,"您没有授予权限",Toast.LENGTH_LONG).show();
}
break;
}
}
}

主要观察readContacts()方法.

image-20201209123305891

使用网络技术

使用okhttp

在build.gradle的dependencies中加载依赖

1
2
3
//OkHttp
implementation 'com.squareup.okhttp3:okhttp:3.14.2'
implementation 'com.squareup.okio:okio:1.17.4'

并build.gradle的android中添加如下内容

1
2
3
4
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}

如图所示

image-20201210103636399

赋予权限

1
<uses-permission android:name="android.permission.INTERNET"></uses-permission>

在布局文件中

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
<LinearLayout android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
xmlns:android="http://schemas.android.com/apk/res/android">
<Button
android:id="@+id/send"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="发送http请求">

</Button>

<ScrollView
android:id="@+id/scrollView"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/resText"
android:layout_width="match_parent"
android:layout_height="match_parent">

</TextView>

</ScrollView>
</LinearLayout>

主活动代码

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
TextView resText;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

Button button = (Button)findViewById(R.id.send);
resText = (TextView)findViewById(R.id.resText);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
sendHttpRequest();
}
});
}

private void sendHttpRequest(){
new Thread(new Runnable() {
@Override
public void run() {
try {
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder().url("https://api-hmugo-web.itheima.net/api/public/v1/goods/detail?goods_id=1").build();
Response response = client.newCall(request).execute();
String responseData = response.body().string();
showResponse(responseData);
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
}

private void showResponse(final String responseData){
runOnUiThread(new Runnable() {
@Override
public void run() {
//在这里进行ui操作,结果将显示到界面上
resText.setText(responseData);
}
});
}

为什么要在showResponse()方法中调用runOnUiThread()这个方法呢?因为在android中是不允许在子线程中进行ui操作的,需要通过调用这个方法切换到主线程,然后再更新ui元素.

Prev
2021-04-06 15:29:32
Next